与原始NAL单位一起使用AVAssetWriter

我注意到在AVAssetWriterInput的iOS文档中,你可以传递niloutputSettings字典来指定input数据不应该被重新编码。

用于编码附加到输出的媒体的设置。 通过零来指定附加的样本不应该被重新编码。

我想利用这个function来传递一个H.264原始NALstream,但是我无法将我的原始字节stream转换成一个CMSampleBuffer ,我可以将它传递到AVAssetWriterInput的appendSampleBuffer方法中。 我的NALstream只包含SPS / PPS / IDR / P NAL(1,5,7,8)。 我一直无法find有关如何使用预编码的H264数据与AVAssetWriter的文件或结论性的答案。 生成的video文件无法播放。

我如何正确打包NUM单元到CMSampleBuffers ? 我是否需要使用起始码前缀? 长度前缀? 我是否需要确保每个CMSampleBuffer只放置一个NAL? 我的最终目标是创build一个H264 / AAC的MP4或MOV容器。

这是我一直在玩的代码:

 -(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]; }); } 

请注意,我在writeSampleBuffer方法的示例缓冲区中调用了CMSampleBufferSetOutputPresentationTimeStamp ,我认为这是一个有效的时间,然后才实际尝试附加它。

任何帮助表示赞赏。

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

我有两个主要问题:

  1. 我没有正确设置CMSampleTimingInfo(正如我的评论上述状态)。
  2. 我没有正确打包原始NAL数据(不知道在哪里logging,如果有的话)。

为了解决#1,我设置了timing.duration = CMTimeMake(1, fps); fps是预期的帧速率。 然后我设置timing.decodeTimeStamp = kCMTimeInvalid; 意味着样本将按解码顺序给出。 最后,我通过计算绝对时间来设置timing.presentationTimeStamp ,我也使用startSessionAtSourceTime

为了解决#2,通过试验和错误,我发现给我的NAL单位在以下forms工作:

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

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

大概出于同样的原因,它不是在QuickTime中播放,我仍然无法将生成的.mov文件移动到相册( ALAssetLibrary方法videoAtPathIsCompatibleWithSavedPhotosAlbum失败,指出“电影无法播放”。希望有人有想法关于发生了什么事可以发表评论。谢谢!