将AVAssetWriter与原始NAL单元一起使用

时间:2013-03-26 03:53:22

标签: iphone ios h.264 avassetwriter cmsamplebufferref

我注意到在AVAssetWriterInput的iOS文档中,您可以为nil字典传递outputSettings,以指定不应重新编码输入数据。

  

用于编码附加到输出的媒体的设置。传递nil以指定不应重新编码附加的样本。

我想利用此功能传入原始H.264 NAL流,但我无法将原始字节流调整为CMSampleBuffer,我可以将其传递给AVAssetWriterInput的{{1} } 方法。我的NAL流只包含SPS / PPS / IDR / P NAL(1,5,7,8)。我无法找到有关如何使用AVAssetWriter预编码H264数据的文档或结论性答案。生成的视频文件无法播放。

如何将NAL单位正确打包到appendSampleBuffer?我需要使用开始代码前缀吗?长度前缀?我是否需要确保每CMSampleBuffers只放一个NAL?我的最终目标是使用H264 / AAC创建MP4或MOV容器。

这是我一直在玩的代码:

CMSampleBuffer

请注意,我在-(void)addH264NAL:(NSData *)nal { dispatch_async(recordingQueue, ^{ //Adapting the raw NAL into a CMSampleBuffer CMSampleBufferRef sampleBuffer = NULL; CMBlockBufferRef blockBuffer = NULL; CMFormatDescriptionRef formatDescription = NULL; CMItemCount numberOfSampleTimeEntries = 1; CMItemCount numberOfSamples = 1; CMVideoFormatDescriptionCreate(kCFAllocatorDefault, kCMVideoCodecType_H264, 480, 360, nil, &formatDescription); OSStatus result = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, NULL, [nal length], kCFAllocatorDefault, NULL, 0, [nal length], kCMBlockBufferAssureMemoryNowFlag, &blockBuffer); if(result != noErr) { NSLog(@"Error creating CMBlockBuffer"); return; } result = CMBlockBufferReplaceDataBytes([nal bytes], blockBuffer, 0, [nal length]); if(result != noErr) { NSLog(@"Error filling CMBlockBuffer"); return; } const size_t sampleSizes = [nal length]; CMSampleTimingInfo timing = { 0 }; result = CMSampleBufferCreate(kCFAllocatorDefault, blockBuffer, YES, NULL, NULL, formatDescription, numberOfSamples, numberOfSampleTimeEntries, &timing, 1, &sampleSizes, &sampleBuffer); if(result != noErr) { NSLog(@"Error creating CMSampleBuffer"); } [self writeSampleBuffer:sampleBuffer ofType:AVMediaTypeVideo]; }); } 方法内部的示例缓冲区上调用CMSampleBufferSetOutputPresentationTimeStamp,我认为这是我实际尝试追加它之前的有效时间。

感谢任何帮助。

1 个答案:

答案 0 :(得分:3)

我设法让视频播放工作在VLC但不是QuickTime。我使用类似于上面发布的代码将H.264 NAL放入CMSampleBuffers。

我有两个主要问题:

  1. 我没有正确设置CMSampleTimingInfo(正如我上面的评论所述)。
  2. 我没有正确打包原始NAL数据(不确定记录在哪里,如果有的话)。
  3. 要解决#1,我设置timing.duration = CMTimeMake(1, fps);,其中fps是预期的帧速率。然后我设置timing.decodeTimeStamp = kCMTimeInvalid;表示将按解码顺序给出样本。最后,我通过计算绝对时间来设置timing.presentationTimeStamp,我也使用了startSessionAtSourceTime

    要解决#2,通过反复试验我发现以下列形式提供我的NAL单位:

    [7 8 5] [1] [1] [1]..... [7 8 5] [1] [1] [1]..... (repeating)
    

    每个NAL单元的前缀是32位起始码,等于0x00000001

    大概是因为它没有在QuickTime中播放,我仍然无法将生成的.mov文件移动到相册(ALAssetLibrary方法videoAtPathIsCompatibleWithSavedPhotosAlbum未能说明“电影”无法播放。“希望有人知道发生了什么事可以评论。谢谢!