我正在尝试使用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];
}];
有人知道我在这里做错了什么吗?有没有更好的方法来做到这一点?
答案 0 :(得分:8)
“重要信息:CMSampleBuffer的客户端必须通过调用CFRetain和CFRelease显式管理保留计数,即使在使用垃圾回收的进程中也是如此。”
消息来源:CoreMedia.Framework CMSampleBuffer.h
答案 1 :(得分:2)
我最近在CMSampleBuffer对象上做了很多工作,并且我已经了解到在实时操作期间由OS提供的大多数媒体缓冲区都是从池中分配的。如果AVFoundation(或CoreVideo / CoreMedia)用完了池中的缓冲区(即,您在一段时间内CFR获取缓冲区),则该过程的实时方面将受到影响或阻塞,直到您CF将缓冲区释放回池中。
因此,除了操作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能够将它们显示为在机器上原生来源。
对于您的申请,我建议如下:
由于AVFoundation电影录制器可以实时执行步骤#1和#2而不会耗尽缓冲区,因此您应该能够在dispatch_queue上深度复制和排队数据,而不会耗尽视频捕获组件使用的缓冲池和VideoToolbox组件。