CMSampleBufferRef的深拷贝

4
我想进行CMSampleBufferRef的深层复制,用于音频和视频连接。我需要将此缓冲区用于延迟处理。有人可以提供示例代码来协助吗?
谢谢。
2个回答

2

我解决了这个问题。

我需要长时间访问示例数据。

尝试了许多方法:

CVPixelBufferRetain -----> 程序崩溃 CVPixelBufferPool -----> 程序崩溃 CVPixelBufferCreateWithBytes ----> 它可以解决这个问题,但是会降低性能,不建议使用

CMSampleBufferCreateCopy ---> 可以使用,苹果公司也推荐使用。

列表:为了保持最佳性能,一些样本缓冲区直接引用可能需要被设备系统和其他捕获输入重新使用的内存池。这通常适用于未压缩的设备本地捕获,其中尽可能少地复制内存块。如果多个样本缓冲区长时间引用此类内存池,则输入将无法再将新样本复制到内存中,并且这些样本将被丢弃。如果您的应用程序通过保留提供的CMSampleBuffer对象太长时间导致样本被丢弃,但它需要长时间访问样本数据,请考虑将数据复制到新缓冲区,然后调用CFRelease释放样本缓冲区(如果先前已保留),以便可以重新使用它引用的内存。

REF:https://developer.apple.com/reference/avfoundation/avcapturefileoutputdelegate/1390096-captureoutput

这可能是你需要的:

pragma mark -captureOutput

(注意:这是一段程序代码,不是常规文本)
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection{
    if (connection == m_videoConnection) {        
        /* if you did not read m_sampleBuffer ,here you must CFRelease m_sampleBuffer, it is causing samples to be dropped 
        */
        if (m_sampleBuffer) {
            CFRelease(m_sampleBuffer);
            m_sampleBuffer = nil;
        }

        OSStatus status = CMSampleBufferCreateCopy(kCFAllocatorDefault, sampleBuffer, &m_sampleBuffer);
        if (noErr != status) {
            m_sampleBuffer = nil;
        }
        NSLog(@"m_sampleBuffer = %p sampleBuffer= %p",m_sampleBuffer,sampleBuffer);
    }
}

pragma mark - 获取用于长期使用的CVPixelBufferRef

- (ACResult) readVideoFrame: (CVPixelBufferRef *)pixelBuffer{
    while (1) {
        dispatch_sync(m_readVideoData, ^{
            if (!m_sampleBuffer) {
                _readDataSuccess = NO;
                return;
            }

            CMSampleBufferRef sampleBufferCopy = nil;
            OSStatus status = CMSampleBufferCreateCopy(kCFAllocatorDefault, m_sampleBuffer, &sampleBufferCopy);
            if ( noErr == status)
            {
                 CVPixelBufferRef buffer  = CMSampleBufferGetImageBuffer(sampleBufferCopy);

                 *pixelBuffer = buffer;

                 _readDataSuccess = YES;

                 NSLog(@"m_sampleBuffer = %p ",m_sampleBuffer);

                 CFRelease(m_sampleBuffer);
                 m_sampleBuffer = nil;

             }
             else{
                 _readDataSuccess = NO;
                 CFRelease(m_sampleBuffer);
                 m_sampleBuffer = nil;
             }
        });

        if (_readDataSuccess) {
            _readDataSuccess = NO;
            return ACResultNoErr;
        }
        else{
            usleep(15*1000);
            continue;
        }
    }
}

然后您可以这样使用它:
-(void)getCaptureVideoDataToEncode{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(){
        while (1) {
            CVPixelBufferRef buffer = NULL;
            ACResult result= [videoCapture readVideoFrame:&buffer];
            if (ACResultNoErr == result) {
                ACResult error = [videoEncode encoder:buffer outputPacket:&streamPacket];
                if (buffer) {
                    CVPixelBufferRelease(buffer);
                    buffer = NULL;
                }
                if (ACResultNoErr == error) {
                NSLog(@"encode success");
                }
            }
        }
    });
}  

如果我想每秒获取当前流缓冲区并分析它,我是否需要无限循环? - Alexander Yakovlev
1
这样行不通。你只是在保留原始引用一次迭代,然后在下一次释放它。 - Andy Hin
我尝试了CMSampleBufferCreateCopy(),它确实解决了我的问题,就像你的一样。但是根据苹果关于CMSampleBufferCreateCopy()的文档(https://developer.apple.com/documentation/coremedia/1489543-cmsamplebuffercreatecopy?language=objc): "复制是浅层的:标量属性(大小和时间)直接复制,数据缓冲区和格式描述被保留,并且可以传播的附件由副本的字典保留。如果sbuf的数据没有准备好,复制将被设置为跟踪其准备就绪状态。" 那么为什么它有效呢?有人能解释一下吗? - godspeed1024
不,实际上并没有:仍然存在一些情况,CMSampleBufferCreateCopy()无法解决丢失输入样本的问题。因此,我认为仍然需要进行真正的深度复制。 - godspeed1024

-3

我这样做。 CMSampleBufferCreateCopy 确实可以进行深拷贝,但是出现了一个新问题,captureOutput 代理不起作用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接