9

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

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

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

如何正确地将 NAL 单元打包成CMSampleBuffers? 我需要使用起始代码前缀吗?长度前缀?我需要确保我只放一个 NALCMSampleBuffer吗?我的最终目标是使用 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];
    });
}

请注意,在我实际尝试附加它之前,我使用我认为有效的时间调用方法CMSampleBufferSetOutputPresentationTimeStamp内部的示例缓冲区。writeSampleBuffer

任何帮助表示赞赏。

4

1 回答 1

3

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

我有两个主要问题:

  1. 我没有正确设置 CMSampleTimingInfo(正如我上面的评论所述)。
  2. 我没有正确打包原始 NAL 数据(不确定记录在哪里,如果有的话)。

为了解决 #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失败,说明“无法播放电影。”希望有人知道什么是继续可以评论。谢谢!

于 2013-03-27T02:34:22.427 回答