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
因为您没有提供任何 outputSettings,所以您被迫使用框架中包含的原始数据。
您必须使用从示例缓冲区中获取块缓冲区CMSampleBufferGetDataBuffer(sampleBuffer),之后您需要使用获取块缓冲区的实际位置
size_t blockBufferLength;
char *blockBufferPointer;
CMBlockBufferGetDataPointer(blockBuffer, 0, NULL, &blockBufferLength, &blockBufferPointer);
*blockBufferPointer使用所需编解码器的帧头信息查看和解码字节。
FWIW:这是官方文档对 CMSampleBufferGetImageBuffer 的返回值的说法:
“结果是媒体数据的 CVImageBuffer。如果 CMSampleBuffer 不包含 CVImageBuffer,或者 CMSampleBuffer 包含 CMBlockBuffer,或者存在其他错误,则结果将为 NULL。”
另请注意,调用者并不拥有从 CMSampleBufferGetImageBuffer 返回的 dataBuffer,并且如果调用者需要维护对它的引用,则必须显式保留它。
希望这些信息有帮助。