【问题标题】:AV Foundation: AVCaptureVideoPreviewLayer and frame durationAV Foundation:AVCaptureVideoPreviewLayer 和帧持续时间
【发布时间】:2013-03-20 15:28:08
【问题描述】:

我正在使用 AV Foundation 来处理来自摄像机的帧(iPhone 4s、iOS 6.1.2)。我正在根据 AV Foundation 编程指南设置 AVCaptureSession、AVCaptureDeviceInput、AVCaptureVideoDataOutput。一切都按预期工作,我能够在 captureOutput:didOutputSampleBuffer:fromConnection: 代表中接收帧。

我也有这样的预览层设置:

AVCaptureVideoPreviewLayer *videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
[videoPreviewLayer setFrame:self.view.bounds];
videoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer insertSublayer:videoPreviewLayer atIndex:0];

问题是,在我的帧处理中我不需要每秒 30 帧,而且我无论如何也不能这么快地处理它们。所以我使用这段代码来限制帧持续时间:

// videoOutput is AVCaptureVideoDataOutput set earlier
AVCaptureConnection *conn = [videoOutput connectionWithMediaType:AVMediaTypeVideo];
[conn setVideoMinFrameDuration:CMTimeMake(1, 10)];
[conn setVideoMaxFrameDuration:CMTimeMake(1, 2)];

这可以正常工作并限制 captureOutput 委托接收的帧。

但是,这也限制了预览层上的每秒帧数,并且预览视频变得非常无响应。

我从文档中了解到,帧持续时间是在连接上独立设置的,并且预览层确实具有不同的 AVCaptureConnection。检查[videoPreviewLayer connection] 上的混合/最大帧持续时间表明它确实设置为默认值(1/30 和 1/24),并且与 AVCaptureVideoDataOutput 连接上设置的持续时间不同。

那么,是否可以仅在帧捕获输出上限制帧持续时间,而在预览视频上仍然看到 1/24-1/30 帧持续时间?怎么样?

谢谢。

【问题讨论】:

    标签: ios objective-c cocoa-touch avfoundation


    【解决方案1】:

    虽然有两个AVCaptureConnections 是正确的,但这并不意味着它们可以独立设置最小和最大帧持续时间。这是因为它们共享相同的物理硬件

    如果连接 #1 以 5 帧/秒的速率激活卷帘快门,帧持续时间为 1/5 秒,不可能连接 #2 可以同时以 1/30 秒的帧持续时间以 30 次/秒的速度激活快门。

    要获得您想要的效果,需要两个摄像头!

    接近你想要的唯一方法是遵循 Kaelin Colclasure 在 3 月 22 日的回答中概述的方法。

    但是,您确实可以选择在这种方法中变得更复杂一些。例如,您可以使用计数器来决定丢弃哪些帧,而不是让线程休眠。您可以使该计数器响应通过的实际帧速率(您可以从 captureOutput:didOutputSampleBuffer:fromConnection: 委托的元数据以及图像数据中获取,或者您可以通过手动定时帧来计算自己) .您甚至可以通过合成帧而不是丢弃它们来非常合理地模仿更长的曝光——就像 App Store 中的许多“慢快门”应用程序所做的那样(撇开细节——例如不同的滚动快门伪影——并没有真正一帧以 1/5 秒扫描和五帧以 1/25 秒扫描然后粘合在一起的差别很大。

    是的,这需要一些工作,但您正在尝试让一台摄像机像两台摄像机一样实时运行,而这绝非易事。

    【讨论】:

    • “这绝非易事。”夸张
    • 嗨@Wildaker你能帮助解释帧持续时间以及在这个问题中使用不同值的含义吗?谢谢! stackoverflow.com/questions/34937008/…
    • 对不起,但如果没有试验我真的不能说,@Crashalot。这不是我做过的事情。
    【解决方案2】:

    这样想: 您要求捕获设备限制帧持续时间,以便获得更好的曝光。 美好的。 您想以更高的帧速率进行预览。 如果您要以更高的速率进行预览,那么捕获设备(相机)将没有足够的时间来曝光帧,因此您可以在捕获的帧处获得更好的曝光。 这就像要求在预览中查看与捕获的帧不同的帧。

    我认为,如果可能的话,这也是一种负面的用户体验。

    【讨论】:

    • 你说的很有道理。但是,如果您阅读“AV Foundation Programming Guide”和“AVCaptureConnection class reference”的文档,您会得到一个非常有根据的印象,即预览层和实际输出设备具有不同的 AVCaptureConnection。最小/最大帧持续时间参数在 AVCaptureConnection 对象上独立设置,并且对于预览的连接和捕获输出连接确实具有不同的值。 Apple 有误导性的文档和不一致的 API 这并不奇怪,但你可以理解为什么这会完全让一个人失望......
    • 我还没有测试过,但是应该可以反过来:预览层的 fps 低,而捕获的帧的 fps 高。这可能就是您获得独立捕获连接的原因。
    • 嗨@gWiz,你能帮忙解释一下帧持续时间以及在这个问题中使用不同值的含义吗?谢谢! stackoverflow.com/questions/34937008/…
    【解决方案3】:

    我的 Cocoa (Mac OS X) 应用程序遇到了同样的问题。以下是我的解决方法:

    首先,确保在单独的调度队列中处理捕获的帧。还要确保丢弃您尚未准备好处理的任何帧;这是默认设置,但我还是在下面设置了标志,只是为了证明我依赖它。

        videoQueue = dispatch_queue_create("com.ohmware.LabCam.videoQueue", DISPATCH_QUEUE_SERIAL);
        videoOutput = [[AVCaptureVideoDataOutput alloc] init];
        [videoOutput setAlwaysDiscardsLateVideoFrames:YES];
        [videoOutput setSampleBufferDelegate:self
                                       queue:videoQueue];
        [session addOutput:videoOutput];
    

    然后在委托中处理帧时,您可以简单地让线程休眠所需的时间间隔。委托人没有醒来处理的帧被悄悄地丢弃。我在下面实现了用于计算丢帧的可选方法,作为健全性检查;我的应用程序从不使用这种技术记录丢弃任何帧。

    - (void)captureOutput:(AVCaptureOutput *)captureOutput
      didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer
           fromConnection:(AVCaptureConnection *)connection;
    {
        OSAtomicAdd64(1, &videoSampleBufferDropCount);
    }
    
    - (void)captureOutput:(AVCaptureOutput *)captureOutput
    didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
           fromConnection:(AVCaptureConnection *)connection;
    {
        int64_t savedSampleBufferDropCount = videoSampleBufferDropCount;
        if (savedSampleBufferDropCount && OSAtomicCompareAndSwap64(savedSampleBufferDropCount, 0, &videoSampleBufferDropCount)) {
            NSLog(@"Dropped %lld video sample buffers!!!", savedSampleBufferDropCount);
        }
        // NSLog(@"%s", __func__);
        @autoreleasepool {
            CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
            CIImage * cameraImage = [CIImage imageWithCVImageBuffer:imageBuffer];
            CIImage * faceImage = [self faceImage:cameraImage];
            dispatch_sync(dispatch_get_main_queue(), ^ {
                [_imageView setCIImage:faceImage];
            });
        }
        [NSThread sleepForTimeInterval:0.5]; // Only want ~2 frames/sec.
    }
    

    希望这会有所帮助。

    【讨论】:

    • 谢谢,但我想我不想这样做,只是丢帧。当您限制帧持续时间时,AV Framework 将增加每帧在低光照条件下的曝光,如果您只是丢帧,您不会获得此好处。此外,每个帧的处理时间会有所不同,当您限制最小/最大帧持续时间时,您可以让框架适应您。我想我不想自己计算间隔。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-06
    • 2020-09-12
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    相关资源
    最近更新 更多