为什么CMSampleBufferGetImageBuffer返回NULL?

7
我已经编写了一些代码来处理OSX上的视频文件,逐帧处理。以下是从构建OK的代码中提取的内容,它打开文件,定位视频轨道(仅轨道)并开始读取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看起来很好。


如果您成功解决了这个问题 - 这个日期证实了我的假设 - 您能否友善地提供几行代码来演示如何解决?我正在努力解决类似的问题(请查看我关于相同函数调用的问题),但是我无法解决它。下面的所有答案都指出了问题所在,但没有说明正确的做法,而我已经尝试了几乎所有我能想到的方法,但仍然失败。 - Motti Shneor
3个回答

18
您在创建AVAssetReaderTrackOutput时没有指定任何outputSettings。当调用copyNextSampleBuffer以接收视频轨道的原始像素格式时,我遇到了您的问题,当指定" nil "时会出现这个问题。 在我的应用程序中,我希望确保调用copyNextSampleBuffer时不会发生转换,以提高性能,如果这对您来说不是很重要,请在输出设置中指定像素格式。
以下是基于硬件功能的Apple推荐的像素格式:

kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange kCVPixelFormatType_420YpCbCr8BiPlanarFullRange


2
这应该被接受为答案,因为当前被接受的帖子并没有解决任何问题。 - Tomasz Bąk
4
你是在问nenchev如何解决问题以确保没有进行任何转换。 - Andy Hin
@nenchev,您是如何解决这个问题的,以确保没有进行任何转换的呢? - Gwendal Roué
这些像素格式在文档(或其他地方)中推荐在哪里?它们似乎有点奇怪,因为大多数相机不会创建平面图像。然而,我正在尝试使用我从captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler接收的CMSampleBufferRef来实现这一点,并且总是收到“nil”。 - Motti Shneor
@nechev,您是如何解决这个问题的,以确保没有发生任何转换? - Roi Mulia

5
由于您没有提供任何输出设置,因此您必须使用帧中包含的原始数据。
您需要使用CMSampleBufferGetDataBuffer(sampleBuffer)从样本缓冲区中获取块缓冲区,之后您需要使用以下代码获取块缓冲区的实际位置: size_t blockBufferLength; char *blockBufferPointer; CMBlockBufferGetDataPointer(blockBuffer, 0, NULL, &blockBufferLength, &blockBufferPointer); 查看*blockBufferPointer并根据所需编解码器的帧头信息对字节进行解码。

如何使用“所需编解码器”来“解码字节”。这个编解码器在哪里被要求?如果我决定从从captureStillImageAsynchronouslyFromConnection接收到的CMSampleBufferRef中提取TIFF图像,输出组件将如何知道并相应地提供字节?我不明白。 - Motti Shneor
这是为视频分析器编写的,其中每个帧都有自己的头部信息。对于TIFF文件,在获取样本缓冲区时,系统将已经为您解码了TIFF文件。 - Pescolly
请耐心等待 - 我仍然不理解。我在哪里说“我想要Tiff”?我向谁表达这个愿望?据我所见,CMSampleBufferRef包含一些模糊的数据,可能是各种各样的东西 - 取决于实际相机、其驱动程序和其他因素 - 我对其中的期望一无所知。我甚至找不到一种方法告诉我这是什么类型的CMSampleBuffer。我已经花了很多时间尝试将静止图像保存为tiff格式 - 但没有成功。 - Motti Shneor
尝试查看CoreImage框架。 https://developer.apple.com/documentation/coreimage/ciimage?language=objc - Pescolly
我再次尝试,但仍然无济于事。CIImage不能从CMSampleBufferRef中创建,只能从CVImageBuffer或CVPixelBuffer中创建 - 但我都无法提取出来。顺便说一下 - 在调用AVCaptureStillImageOutput捕获图像之前,我确实向其提供了输出设置 - 所以我期望在那里收到更多的内容,而不仅仅是原始数据。也许我需要针对这个问题提出一个不同的问题。我快要放弃了。 - Motti Shneor
我现在设置了自己的问题 - 类似于这个问题,但是针对我的不同情境 - 关于相机捕获,您介意看一下吗? - Motti Shneor

1

FWIW:这是官方文档中关于CMSampleBufferGetImageBuffer返回值的说明:

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

还要注意的是,调用者不拥有CMSampleBufferGetImageBuffer返回的dataBuffer,并且如果调用者需要保持对其的引用,则必须显式保留它。

希望这些信息有所帮助。


谢谢!顺便问一下,你在哪里找到那个引用的?因为在这里:https://developer.apple.com/library/mac/#documentation/CoreMedia/Reference/CMSampleBuffer/Reference/Reference.html 以及我下载的XCode版本中的文档中完全没有任何评论! - Dave Durbin
在头文件中,苹果为每个方法都提供了非常详细的文档。在Xcode中,右键单击代码中的方法名称,然后点击“转到定义”(措辞可能不完全相同),它将带您进入正确的.h文件和方法定义以及文档。 - Aki
糟糕!我想我假设既然文档不在生成的文档中,它们就不在源代码中。再次感谢Aki。 - Dave Durbin
我猜测使用Swift和ARC,我不再需要手动保留,这样理解是否正确? - Kartick Vaddadi

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