Как записать и сохранить при 240 кадрах в секунду? - PullRequest
0 голосов
/ 24 января 2019

Мне нужно записывать и сохранять видео с iPhone Xs с максимальной частотой кадров телефона (240 к / с).Сохраненный файл всегда заканчивается на 30 кадрах в секунду.Я прошел через дюжину руководств / документов / сообщений о переполнении стека, но пока не нашел правильного решения.Я проверил, открыв записанный файл в VLC, а также путем извлечения и подсчета кадров.

Что я делаю не так?

Среда: Xcode 10.1, сборка целевой iOS 12.1, протестирована на iPhone Xs под управлением iOS 12.1.2

Здесь я получаю доступ к устройству инастройте его на лучшую частоту кадров, которую он поддерживает:

override func viewDidLoad() {
    super.viewDidLoad()
    let deviceDiscoverSession = AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .back)
    guard let backCameraDevice = deviceDiscoverSession else {
        print("Failed to open back, wide-angle camera")
        return
    }
    self.currentDevice = backCameraDevice
    do {
        let input = try AVCaptureDeviceInput(device: backCameraDevice)
        // configureDevice() // putting this here makes no difference
        self.session.addInput(input)
        configureDevice()
    } catch {
        print(error)
        return
    }
}

func configureDevice() {
    var bestFormat: AVCaptureDevice.Format? = nil
    var bestFrameRateRange: AVFrameRateRange? = nil
    var bestPixelArea: Int32 = 0
    for format in currentDevice!.formats {
        let dims: CMVideoDimensions = CMVideoFormatDescriptionGetDimensions(format.formatDescription)
        let pixelArea: Int32 = dims.width * dims.height
        let ranges = format.videoSupportedFrameRateRanges
        for range in ranges {
            if bestFrameRateRange==nil || range.maxFrameRate > bestFrameRateRange!.maxFrameRate || ((range.maxFrameRate == bestFrameRateRange!.maxFrameRate) && (pixelArea > bestPixelArea)) {
                bestFormat = format as AVCaptureDevice.Format
                bestFrameRateRange = range
                bestPixelArea = pixelArea
            }
        }
    }
    do {
        try currentDevice!.lockForConfiguration()
        if let best_format = bestFormat {
            currentDevice!.activeFormat = best_format
            currentDevice!.activeVideoMinFrameDuration = bestFrameRateRange!.minFrameDuration
            currentDevice!.activeVideoMaxFrameDuration = bestFrameRateRange!.maxFrameDuration
        }
    } catch {
        print(error)
    }

    let movieFileOutput = AVCaptureMovieFileOutput()

    if self.session.canAddOutput(movieFileOutput) {
        self.session.beginConfiguration()
        self.session.addOutput(movieFileOutput)
        self.session.sessionPreset = .high
        if let connection = movieFileOutput.connection(with: .video) {
            if movieFileOutput.availableVideoCodecTypes.contains(.h264) {
                movieFileOutput.setOutputSettings([AVVideoCodecKey:
                    AVVideoCodecType.h264], for: connection)
            }
        }
        self.session.commitConfiguration()
        self.movieFileOutput = movieFileOutput
    }
    currentDevice!.unlockForConfiguration()
}

Когда пользователь прекращает запись, я вызываю функцию, которая частично содержит следующий код для сохранения файла во временную директорию (позже перемещенную в приложениекаталог документов)

sessionQueue.async {
    if !self.isRecording {
        self.isRecording = true
        let movieFileOutputConnection = self.movieFileOutput!.connection(with: .video)
        movieFileOutputConnection?.videoOrientation = .landscapeRight
        let availableVideoCodecTypes = self.movieFileOutput!.availableVideoCodecTypes
        if availableVideoCodecTypes.contains(.h264) {
           self.movieFileOutput!.setOutputSettings([AVVideoCodecKey: AVVideoCodecType.h264], for: movieFileOutputConnection!)
        }
        let outputFileName = NSUUID().uuidString
        let outputFilePath = (NSTemporaryDirectory() as NSString).appendingPathComponent((outputFileName as NSString).appendingPathExtension("mp4")!)
        self.movieFileOutput?.startRecording(to: URL(fileURLWithPath: outputFilePath), recordingDelegate: self)
    } else {
        self.movieFileOutput?.stopRecording()
        self.isRecording = false
    }
}

Типичным ответом является настройка устройства после добавления его в сеанс .Вызов configure до или после добавления в сеанс, похоже, не имеет значения.

Я пытался настроить movieFileOutput прямо перед вызовом self.movieFileOutput?.startRecording(), а также там, где я это показал выше.Оба дают одинаковые результаты.

1 Ответ

0 голосов
/ 01 февраля 2019

Я понял это с более глубоким чтением https://stackoverflow.com/a/41109637/292947

В configureDevice() Я устанавливал self.session.sessionPreset = .high, когда на самом деле мне нужно установить self.session.sessionPreset = .inputPriority, что является Swift 4, эквивалентным AVCaptureSessionPresetInputPriorityзначение, предложенное в ответе выше.

VLC shows 240 fps

...