AVAssetWriterInput H.264 Passthrough to QuickTime(.mov) - 通过SPS / PPS创建avcC原子?

时间:2013-03-28 02:46:08

标签: iphone ios avfoundation h.264 avassetwriter

我有一个H.264 / AVC NAL流,包括类型1(P帧),5(I帧),7(SPS)和8(PPS)。我想将它们写入.mov文件而不重新编码。我试图使用AVAssetWriter来执行此操作。 AVAssetWriterInput州的文档:

  

为outputSettings传递nil指示输入传递附加的样本,在将它们写入输出文件之前不进行任何处理。例如,如果要附加已经采用所需压缩格式的缓冲区,则此方法很有用。但是,仅在写入QuickTime Movie文件时才支持passthrough(即AVAssetWriter是使用AVFileTypeQuickTimeMovie初始化的)。对于其他文件类型,您必须指定非零输出设置。

我试图从这些NAL中创建CMSampleBuffers并将它们附加到资产编写器输入,但我无法以产生格式良好的.mov文件的方式输入数据,我可以&# 39;找不到任何关于如何做到这一点的线索。

我到目前为止得到的最好结果是以附件B字节流格式传递NAL(按照顺序7 8 5 1 1 1 ....重复)并在VLC中播放结果。因此,我知道NAL包含有效数据,但由于.mov文件没有avcC原子且mdat原子填充了附件B字节流,因此QuickTime不会播放视频。

现在我试图用4字节(由lengthSizeMinusOne字段指定)长度字段而不是附件B分隔符传入NAL,这就是它们的假设据我所知,被打包到mdat原子中。

我对如何让资产作者写一个avcC原子感到茫然。我附加的每个样本都被推入mdat原子。

是否有人知道如何将原始H.264数据传递到为传递(nil outputSettings)配置的AVAssetWriterInput并让它生成正确形成的QuickTime文件?

1 个答案:

答案 0 :(得分:6)

我已经提交了苹果TSI并找到答案。我希望这能节省一些时间。

CMSampleBuffers已将CMFormatDescription与它们相关联,其中包含样本缓冲区中数据的描述。

用于创建格式描述的函数原型如下:

OSStatus CMVideoFormatDescriptionCreate (
  CFAllocatorRef allocator,
  CMVideoCodecType codecType,
  int32_t width,
  int32_t height,
  CFDictionaryRef extensions,
  CMVideoFormatDescriptionRef *outDesc
);

我从Apple技术人员那里了解到,我可以使用extensions参数传入包含avcC原子数据的字典。

扩展词典应具有以下形式:

[kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms ---> ["avcC" ---> <avcC Data>]]

[]代表词典。除了avcC之外,这个字典可能用于传递任意原子的数据。

以下是我用于创建extensions字典的代码,我将其传入CMVideoFormatDescriptionCreate

    const char *avcC = "avcC";
    const CFStringRef avcCKey = CFStringCreateWithCString(kCFAllocatorDefault, avcC, kCFStringEncodingUTF8);
    const CFDataRef avcCValue = CFDataCreate(kCFAllocatorDefault, [_avccData bytes], [_avccData length]);
    const void *atomDictKeys[] = { avcCKey };
    const void *atomDictValues[] = { avcCValue };
    CFDictionaryRef atomsDict = CFDictionaryCreate(kCFAllocatorDefault, atomDictKeys, atomDictValues, 1, nil, nil);

    const void *extensionDictKeys[] = { kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms };
    const void *extensionDictValues[] = { atomsDict };
    CFDictionaryRef extensionDict = CFDictionaryCreate(kCFAllocatorDefault, extensionDictKeys, extensionDictValues, 1, nil, nil);