为什么CMSampleBufferGetImageBuffer返回NULL

Dav*_*bin 6 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( ... );
Run Code Online (Sandbox Code Playgroud)

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

nen*_*hev 14

outputSettings创建时没有指定任何内容AVAssetReaderTrackOutput.我在指定"nil"时遇到了问题,以便在调用时接收视频轨道的原始像素格式copyNextSampleBuffer.在我的应用程序中,我想确保在调用copyNextSampleBuffer性能时没有发生转换,如果这不是您的大问题,请在输出设置中指定像素格式.

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

kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange kCVPixelFormatType_420YpCbCr8BiPlanarFullRange

  • @nenchev你是如何解决这个问题以确保没有发生转换的? (3认同)
  • 这应该是接受的答案,因为目前接受的帖子没有解决任何问题. (2认同)

Pes*_*lly 5

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

您必须使用从示例缓冲区中获取块缓冲区CMSampleBufferGetDataBuffer(sampleBuffer),之后您需要使用获取块缓冲区的实际位置

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

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


Aki*_*Aki 1

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

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

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

希望这些信息有帮助。