我已经构建了一些代码来逐帧处理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看起来很好等。
答案 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
并使用所需编解码器的帧头信息解码字节。