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



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

如何将NAL单元正确打包到CMSampleBuffers中?我需要使用起始码前缀吗?长度前缀?我是否需要确保每个CMSampleBuffer仅放入一个NAL?我的最终目标是用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,并认为这是我实际尝试附加它之前的有效时间。

任何帮助表示赞赏。

最佳答案

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

我有两个主要问题:

  • 我没有正确设置CMSampleTimingInfo(如我上面的评论所述)。
  • 我没有正确打包原始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单元均以等于0x00000001的32位起始码作为前缀。

    大概是出于与不在QuickTime中播放相同的原因,我仍然无法将生成的.mov文件移动到相册中(ALAssetLibrary方法videoAtPathIsCompatibleWithSavedPhotosAlbum无法说明“电影无法播放。”希望有人有主意关于正在发生的事情可以发表评论。谢谢!

    关于iphone - 将AVAssetWriter与原始NAL单元一起使用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15629117/

    10-09 09:59