【问题标题】:Deep copy of CMSampleBufferRefCMSampleBufferRef 的深拷贝
【发布时间】:2016-04-30 13:38:51
【问题描述】:

我正在尝试为音频和视频连接执行 CMSampleBufferRef 的深层复制?我需要使用此缓冲区进行延迟处理。有人可以通过指向示例代码来帮助这里吗?

谢谢

【问题讨论】:

    标签: ios objective-c avfoundation video-processing core-video


    【解决方案1】:

    我解决了这个问题

    我需要长时间访问样本数据。

    尝试多种方式:

    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 -get 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");
                    }
                }
            }
        });
    }  
    

    【讨论】:

    • 如果我只想获取当前流缓冲区并每秒分析一次,是否需要无限循环?
    • 这行不通。您只需保留 1 次迭代的原始引用,然后在下一次迭代中释放它。
    • 我尝试了 CMSampleBufferCreateCopy() ,它确实解决了我和你的问题一样的问题。但是根据苹果关于CMSampleBufferCreateCopy()(developer.apple.com/documentation/coremedia/…)的文档:“副本很浅:直接复制标量属性(大小和时间),保留数据缓冲区和格式描述,保留可以传播的附件通过副本的字典。如果 sbuf 的数据尚未准备好,则副本将设置为跟踪其准备情况。那么它为什么起作用呢?谁能解释一下?
    • 不,不是真的:CMSampleBufferCreateCopy() 仍然有一些时候没有解决丢失输入样本的问题。所以我认为它仍然需要一个真正的深拷贝。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2012-04-12
      • 2015-01-13
      • 2011-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多