iphone - AVAssetWriterInput H.264 直通到 QuickTime (.mov) - 传入 SPS/PPS 以创建 avcC 原子?

标签 iphone ios avfoundation h.264 avassetwriter

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

Passing nil for outputSettings instructs the input to pass through appended samples, doing no processing before they are written to the output file. This is useful if, for example, you are appending buffers that are already in a desirable compressed format. However, passthrough is currently supported only when writing to QuickTime Movie files (i.e. the AVAssetWriter was initialized with AVFileTypeQuickTimeMovie). For other file types, you must specify non-nil output settings.

我正在尝试从这些 NAL 创建 CMSampleBuffers 并将它们附加到 Assets 写入器输入,但我无法以生成格式正确的 .mov 文件的方式输入数据,而且我找不到关于如何执行此操作的任何线索。

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

现在我正在尝试使用 4 字节(由 lengthSizeMinusOne 字段指定)长度字段而不是 Annex B 定界符传递 NAL,这是它们应该的方式据我所知被打包到 mdat 原子中。

我不知道如何让 Assets 编写者编写 avcC 原子。我附加的每个样本都会被插入 mdat 原子。

有谁知道我如何将原始 H.264 数据传递到配置为直通(nil outputSettings)的 AVAssetWriterInput 并让它生成格式正确的 QuickTime 文件?

最佳答案

我已经和apple提交了一个TSI,找到了答案。我希望这可以在将来节省一些时间。

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

创建格式描述的函数原型(prototype)如下:

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

我从 Apple 技术人员那里了解到,我可以使用扩展参数传入包含 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);

关于iphone - AVAssetWriterInput H.264 直通到 QuickTime (.mov) - 传入 SPS/PPS 以创建 avcC 原子?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15673379/

相关文章:

iphone - iTunesConnect测试用户验证

iOS:未调用 captureOutput:didOutputSampleBuffer:fromConnection

swift - Capture API 在黑暗中效果不佳,尤其是在夜间或通过相机预览暗角时

ios - avplayer item的重定向播放输出

iphone - 使用 nsdata 在 <img> 标签中显示图像

ios - 按关键字过滤传入的短信(IOS\IPHONE)

ios - 向服务器发送简单的 POST 消息

ios - 使用 AVAudioConverter Swift 将 AAC 解码为 PCM 格式

ios - 如何使通用 Xcode 5 应用程序项目以横向启动?

ios - 如何停止/取消 UIProgressView 进度动画?