如何使用AVCaptureDeviceFormat从iPhone录制缩时视频? [英] How to record timelapse video from iPhone using AVCaptureDeviceFormat?

查看:113
本文介绍了如何使用AVCaptureDeviceFormat从iPhone录制缩时视频?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过iphone录制延时录像.我已经可以以120 fps的速度(通过捕获最大可能的帧数)来慢动作工作.

I am trying to record a timelapse video via iphone. I have already got it working for slow motion (by capturing maximum frames possible), with 120 fps.

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

Now I am trying to reverse the logic to capture least frames possible, to achieve timelapse functionality.

代码流是这样的:

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

  1. Query all the supported frame range from the available device formats of the AVCaptureDevice.

检查帧频是否低于或等于所需的20 fps,尺寸是否等于或大于1920 * 1080.

Check if the frame rate is below or equal to the desired 20 fps and dimensions are equal to or greater than 1920*1080.

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

All works fine except, when I press record, I get "AVCaptureMovieFileOutput - no active/enabled connections" exception. I am only using one of the provided frame rate and range, why am I getting this exception?

所有内容都能以30 fps的速度正常播放.

All works well for 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的帧率和范围的日志:

Here is the log of frame rate and range with 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>

推荐答案

不确定是否解决了这个问题,但是我一直在努力使慢动作开始起作用,并且也不断得到"AVCaptureMovieFileOutput - no active/enabled connections"(所以我真的很想知道你如何得到它可以工作:D).但是无论如何我都解决了它,以下是一些棘手的东西,我认为它们也可以解决您的问题:

Not sure if this is solved, but I was struggling in making slow motion to work, and kept getting "AVCaptureMovieFileOutput - no active/enabled connections" too (so I really wonder how you get it to work :D ). But anyways I solved it, and here are some tricky stuff that I think might as well solve your problem:

  1. 在设置activeFormat之前,请确保已设置一些预设.事实证明,iOS不仅会自动处理其他内容.我所做的是先设置AVCaptureSession.Preset.hd1280x720,然后再设置 activeFormat到具有120fps的帧.
  2. 完成上述操作后,我开始获得Error Domain=AVFoundationErrorDomain Code=-11803 "Cannot Record" UserInfo=0x152e60 {NSLocalizedRecoverySuggestion=Try recording again., AVErrorRecordingSuccessfullyFinishedKey=false, NSLocalizedDescription=Cannot Record}.我找不到任何可能的原因-连接正常,会话正在运行.因此,我再次按下了录制按钮,它开始录制(哇,真的吗?只是从字面上重试"?)我想iOS只是有些发脾气,还需要考虑更长的录制时间.因此,我添加了一个递归函数来给movieFileOutput一些记录时间. (很抱歉,它在Swift中)

  1. Make sure that you set some preset before setting activeFormat. Turns out iOS won't just handle other stuff automatically. What I did is set AVCaptureSession.Preset.hd1280x720 before setting the activeFormat to the one with 120fps.
  2. After I did the above, I started to get Error Domain=AVFoundationErrorDomain Code=-11803 "Cannot Record" UserInfo=0x152e60 {NSLocalizedRecoverySuggestion=Try recording again., AVErrorRecordingSuccessfullyFinishedKey=false, NSLocalizedDescription=Cannot Record}. I couldn't find any possible cause - the connection was fine, the session was running. So I pressed the record button again, and it starts to record (Wow, really? Just literally "try again"?) I guess iOS's just got some temper and has to think a little bit longer to record. So I added a recursive function to give movieFileOutput some time to record. (Sorry it's in Swift)

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)
        }
    }
}

希望它会有所帮助(或也许其他像我一样偶然发现此线程的人.)

Hope it'll help (or maybe others who just stumble on this thread just like I did.)

这篇关于如何使用AVCaptureDeviceFormat从iPhone录制缩时视频?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆