为什么CMSampleBufferGetImageBuffer返回NULL

时间:2013-05-31 15:40:11

标签: macos avfoundation avassetreader

我已经构建了一些代码来逐帧处理OSX上的视频文件。以下是从构建好的代码中提取,打开文件,定位视频轨道(仅跟踪)并开始阅读CMSampleBuffers而没有问题。但是,当我尝试提取像素缓冲帧时,我获得的每个CMSampleBufferRef都返回NULL。在iOS文档中没有任何迹象表明为什么我可以期望NULL返回值或我可以期望如何解决问题。它与我测试过的所有视频一起发生,无论是捕获源还是CODEC。

非常感谢任何帮助。

NSString *assetInPath = @"/Users/Dave/Movies/movie.mp4";
NSURL *assetInUrl = [NSURL fileURLWithPath:assetInPath];
AVAsset *assetIn = [AVAsset assetWithURL:assetInUrl];

NSError *error;
AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:assetIn error:&error];
AVAssetTrack *track = [assetIn.tracks objectAtIndex:0];
AVAssetReaderOutput *assetReaderOutput = [[AVAssetReaderTrackOutput alloc]
                                              initWithTrack:track
                                              outputSettings:nil];
[assetReader addOutput:assetReaderOutput];

// Start reading
[assetReader startReading];

CMSampleBufferRef sampleBuffer;
do {
       sampleBuffer = [assetReaderOutput copyNextSampleBuffer];

       /**
        ** At this point, sampleBuffer is non-null, has all appropriate attributes to indicate that
        ** it's a video frame, 320x240 or whatever and looks perfectly fine. But the next
        ** line always returns NULL without logging any obvious error message
        **/

       CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);

       if( pixelBuffer != NULL ) {
           size_t width = CVPixelBufferGetWidth(pixelBuffer);
           size_t height = CVPixelBufferGetHeight(pixelBuffer);
           CVPixelBufferLockBaseAddress(pixelBuffer, 0);
           ...
           other processing removed here for clarity
        }
} while( ... );

要清楚,我已经删除了所有错误检查代码,但该代码中没有指出任何问题。即AVAssetReader正在读取,CMSampleBufferRef看起来很好等。

3 个答案:

答案 0 :(得分:13)

在创建outputSettings时,您尚未指定任何AVAssetReaderTrackOutput。在指定" nil"时,我遇到了您的问题。为了在调用copyNextSampleBuffer时接收视频轨道的原始像素格式。在我的应用中,我想确保在为了性能而调用copyNextSampleBuffer时没有发生转换,如果这不是您的主要问题,请在输出设置中指定像素格式。

以下是Apple推荐的基于硬件功能的像素格式:

  

<强> kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange   的 kCVPixelFormatType_420YpCbCr8BiPlanarFullRange

答案 1 :(得分:2)

FWIW:以下是官方文档对CMSampleBufferGetImageBuffer的返回值的说法:

“结果是媒体数据的CVImageBuffer。如果CMSampleBuffer不包含CVImageBuffer,或者CMSampleBuffer包含CMBlockBuffer,或者存在其他错误,结果将为NULL。”

另请注意,调用者不拥有CMSampleBufferGetImageBuffer中返回的dataBuffer,如果调用者需要维护对它的引用,则必须显式保留它。

希望这些信息有所帮助。

答案 2 :(得分:2)

因为您没有提供任何outputSettings,所以您被迫使用框架中包含的原始数据。

您必须使用CMSampleBufferGetDataBuffer(sampleBuffer)从示例缓冲区获取块缓冲区,之后需要使用

获取块缓冲区的实际位置

size_t blockBufferLength; char *blockBufferPointer; CMBlockBufferGetDataPointer(blockBuffer, 0, NULL, &blockBufferLength, &blockBufferPointer);

查看*blockBufferPointer并使用所需编解码器的帧头信息解码字节。