1

我正在尝试通过 iphone 录制延时视频。我已经让它适用于慢动作(通过捕获可能的最大帧数),速度为 120 fps。

现在我正在尝试反转逻辑以捕获尽可能少的帧,以实现延时功能。

代码流程是这样的:

  1. 从 AVCaptureDevice 的可用设备格式中查询所有支持的帧范围。

  2. 检查帧速率是否低于或等于所需的 20 fps 并且尺寸是否等于或大于 1920*1080。

一切正常,除了当我按下记录时,我得到"AVCaptureMovieFileOutput - no active/enabled connections"异常。我只使用提供的帧速率和范围之一,为什么会出现此异常?

一切都适用于 30 fps。

 #define kTimelapseRequiredFPS = 20

#define kMinRequiredDimensions (1920*1080)

        - (void)configureCameraForSlowMoRecording:(AVCaptureDevice *)currentCaptureDevice
        {
            [_captureSession beginConfiguration];

            AVCaptureDeviceFormat *bestFormat = nil;

            AVFrameRateRange *bestFrameRateRange = nil;

            for ( AVCaptureDeviceFormat *format in [currentCaptureDevice formats] )
            {
                //NSLog(@"Format: %@", format);

                CMFormatDescriptionRef videoInfo = [format formatDescription];

                double videoWidth = CMVideoFormatDescriptionGetDimensions(videoInfo).width;

                double videoHeight = CMVideoFormatDescriptionGetDimensions(videoInfo).height;

                double dimensions = videoWidth * videoHeight;

                for ( AVFrameRateRange *range in format.videoSupportedFrameRateRanges )
                {
                    //NSLog(@"Range: %@", range);

                    if ((range.maxFrameRate <= kTimelapseRequiredFPS) && (dimensions >= kMinRequiredDimensions))
                    {
                        bestFormat = format;

                        bestFrameRateRange = range;
                    }
                }
            }

            if ( bestFormat )
            {
                NSLog(@"Final format: %@, Final range %@", bestFormat, bestFrameRateRange);

                if ( [currentCaptureDevice lockForConfiguration:NULL] == YES )
                {
                    currentCaptureDevice.activeFormat = bestFormat;

                    currentCaptureDevice.activeVideoMinFrameDuration = bestFrameRateRange.minFrameDuration;

                    currentCaptureDevice.activeVideoMaxFrameDuration = bestFrameRateRange.minFrameDuration;

                    [currentCaptureDevice unlockForConfiguration];
                }
            }

            [_captureSession commitConfiguration];
        }

这是 20 fps 的帧速率和范围的日志:

Format: <AVCaptureDeviceFormat: 0x1765f7a0 'vide'/'420v' 2592x1936, { 1- 20 fps}, fov:56.700, max zoom:153.00 (upscales @1.26), AF System:1, ISO:46.0-736.0, SS:0.000018-1.000000>
Range: <AVFrameRateRange: 0x176556d0 1 - 20>

Format: <AVCaptureDeviceFormat: 0x1765f750 'vide'/'420f' 2592x1936, { 1- 20 fps}, fov:56.700, max zoom:153.00 (upscales @1.26), AF System:1, ISO:46.0-736.0, SS:0.000018-1.000000>
Range: <AVFrameRateRange: 0x1750db10 1 - 20>

Format: <AVCaptureDeviceFormat: 0x1765f740 'vide'/'420v' 3264x2448, { 1- 20 fps}, fov:56.700, max zoom:153.00 (upscales @1.00), AF System:1, ISO:46.0-736.0, SS:0.000018-1.000000>
Range: <AVFrameRateRange: 0x1750dc80 1 - 20>

Format: <AVCaptureDeviceFormat: 0x1765f6f0 'vide'/'420f' 3264x2448, { 1- 20 fps}, fov:56.700, max zoom:153.00 (upscales @1.00), AF System:1, ISO:46.0-736.0, SS:0.000018-1.000000>
Range: <AVFrameRateRange: 0x1751a260 1 - 20>
4

1 回答 1

0

不确定这是否解决了,但我一直在努力让慢动作工作,并且一直在努力"AVCaptureMovieFileOutput - no active/enabled connections"(所以我真的想知道你是如何让它工作的:D)。但无论如何我解决了它,这里有一些我认为也可以解决你的问题的棘手问题:

  1. 确保在设置之前设置了一些预设activeFormat。事实证明,iOS 不仅会自动处理其他事情。我所做的是在将其设置为 120fpsAVCaptureSession.Preset.hd1280x720之前设置的 。activeFormat
  2. 完成上述操作后,我开始获得Error Domain=AVFoundationErrorDomain Code=-11803 "Cannot Record" UserInfo=0x152e60 {NSLocalizedRecoverySuggestion=Try recording again., AVErrorRecordingSuccessfullyFinishedKey=false, NSLocalizedDescription=Cannot Record}. 我找不到任何可能的原因 - 连接正常,会话正在运行。所以我再次按下录制按钮,它开始录制(哇,真的吗?只是字面意思是“再试一次”?)我猜 iOS 只是有点脾气,需要考虑更长的时间才能录制。所以我添加了一个递归函数来给movieFileOutput一些时间来记录。(对不起,它在斯威夫特)

    fileprivate func startRecording(to moviePath: URL) {
        sessionQueue.async {
            self.movieFileOutput.startRecording(to: moviePath, recordingDelegate: self)
    
            if self.movieFileOutput.isRecording {
                self.sessionQueue.asyncAfter(deadline: .now() + self.duration) {
                    self.stopRecording()
                }
            } else {
                self.startRecording(to: moviePath)
            }
        }
    }
    

希望它会有所帮助(或者可能像我一样偶然发现这个线程的其他人。)

于 2018-06-11T13:10:32.103 回答