4

我正在尝试使用 AVFoundation 框架从 AVCaptureStillImageOutput 快速捕获“系列”静止图像,例如某些相机中的连拍模式。我想使用完成处理程序,

    [stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection 
                                              completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) { 

并将 imageSampleBuffer 传递给 NSOperation 对象以供以后处理。但是我找不到在 NSOperation 类中保留缓冲区的方法。

    [stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection 
                                              completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) { 

    //Add to queue
    SaveImageDataOperation *saveOperation = [[SaveImageDataOperation alloc] initWithImageBuffer:imageSampleBuffer];
    [_saveDataQueue addOperation:saveOperation];
    [saveOperation release];

    //Continue
    [self captureCompleted];
}];

有谁知道我在这里可能做错了什么?有没有更好的方法来做到这一点?

4

2 回答 2

8

“重要提示:CMSampleBuffer 的客户端必须通过调用 CFRetain 和 CFRelease 显式管理保留计数,即使在使用垃圾回收的进程中也是如此。”

来源:CoreMedia.Framework CMSampleBuffer.h

于 2012-06-24T18:44:06.890 回答
4

我最近一直在使用 CMSampleBuffer 对象做很多工作,并且我了解到操作系统在实时操作期间获取的大多数媒体缓冲区都是从池中分配的。如果 AVFoundation(或 CoreVideo/CoreMedia)用完池中的缓冲区(即,您 CFRetain 一个缓冲区“长时间”),则进程的实时方面将受到影响或阻塞,直到您 CFRelease 将缓冲区释放回游泳池。

因此,除了在 CMSampleBuffer 上操作 CFRetain/CFRelease 计数之外,您应该只保持缓冲区保留足够长的时间,以便在 CMBlockBuffer/CMFormat 中解压(深度复制位)并创建一个新的 CMSampleBuffer 以传递给您的 NSOperationQueue 或 dispatch_queue_t 以备后用加工。

在我的情况下,我想通过网络从 VideoToolbox 传递压缩的 CMSampleBuffers。我基本上创建了 CMSampleBuffer 的深层副本,我的应用程序可以完全控制内存分配/生命周期。从那里,我将复制的 CMSampleBuffer 放在一个队列中,以供网络 I/O 使用。

如果样本数据被压缩,深度复制应该会比较快。在我的应用程序中,我使用 NSKeyedArchiver 从源 CMSampleBuffer 的相关部分创建一个 NSData 对象。对于 H.264 视频数据,这意味着 CMBlockBuffer 内容、SPS/PPS 标头字节以及 SampleTimingInfo。通过序列化这些元素,我可以在网络的另一端重建一个 CMSampleBuffer,它的行为与 VideoToolbox 给我的那个相同。特别是,AVSampleBufferLayer 能够显示它们,就好像它们是在机器上本地获取的一样。

对于您的应用程序,我会推荐以下内容:

  1. 获取您的源 CMSampleBuffer 并压缩像素数据。如果可以,请使用 VideoToolbox 中的硬件编码器创建仅 I 帧的 H.264 图像,这将是非常高质量的。VT 编码器显然对电池寿命也非常有利,可能比 JPEG 好得多,除非它们在系统上也有硬件 JPEG 编解码器。
  2. 深拷贝VideoToolbox输出的压缩CMSampleBuffer,VT会将原来的CMSampleBuffer CFRelease回捕获子系统使用的池中。
  3. 将 VT 压缩的 CMSampleBuffer 保留足够长的时间,以便将深层副本排入队列以供以后处理。

由于 AVFoundation 电影记录器可以实时执行步骤 #1 和 #2 而不会耗尽缓冲区,因此您应该能够在 dispatch_queue 上深度复制和排队数据,而不会耗尽视频捕获组件和 VideoToolbox 组件使用的缓冲池.

于 2017-07-03T14:31:16.040 回答