与原始NAL单元一起使用AVAssetWriter

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

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

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

我如何正确地将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];
    });
}

请注意,我在writeSampleBuffer方法的示例缓冲区中调用了CMSampleBufferSetOutputPresentationTimeStamp ,并在我实际尝试追加它之前认为这是有效的时间。

任何帮助表示赞赏。


我设法让视频播放在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单元的前缀是一个32位的起始码,等于0x00000001

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

    链接地址: http://www.djcxy.com/p/12493.html

    上一篇: Using AVAssetWriter with raw NAL Units

    下一篇: Epplus SetPosition picture issue