【问题标题】:CMSampleBufferRef pool to write H.264 AVCC streamCMSampleBufferRef 池写入 H.264 AVCC 流
【发布时间】:2014-01-07 06:58:40
【问题描述】:

我正在使用 AVAssetWriter/AVAssetWriterInput 将 H.264 原始数据写入 MP4 文件。当我从远程服务器接收数据时,我使用以下 CoreMedia API 来获取包含 AVCC 格式的 H.264 数据的样本缓冲区 (CMSampleBufferRef),然后通过发送到 @987654321 将其附加到 MP4 文件@留言(BOOL)appendSampleBuffer:(CMSampleBufferRef)sampleBuffer

  1. CMBlockBufferCreateWithMemoryBlock创建内存块
  2. CMBlockBufferReplaceDataBytes 将 AVCC 格式的 H.264 写入内存块
  3. CMSampleBufferCreate 使用内存块和包含 H.264“额外数据”的格式描述符创建一个样本缓冲区

一切都按预期工作,这种方法的唯一问题是我会定期调用上述 API,而我真正想要的是能够重用分配的资源 - 特别是 CMSampleBufferRefCMBlockBufferRef . 基本上,我想拥有一个CMSampleBuffer 的池,并且能够在我从远程服务器接收新的 H.264 数据时更新其内存内容和格式描述符。。 p>

我知道存在 AVAssetWriterInputPixelBufferAdaptor 可以访问 CVPixelBufferPool 但是,我不能在我的情况下使用它,因为据我所知,要正确实例化像素缓冲区适配器,至少我需要能够传递在我解析流之前我会知道的视频帧尺寸。此外,我不知道如何使用CVPixelBuffer 编写 H.264“额外数据”。所以,我认为我需要坚持使用CMSampleBuffer。不幸的是,CoreMedia API 似乎无法在创建后更新内存块或样本缓冲区的格式描述符(据我所知,我只能访问这些对象的不可变引用)。因此,到目前为止我能做的最好的事情就是重用内存块CMBlockBufferRef,但我仍在重新创建样本缓冲区。我的代码如下。希望这里有人对如何实现CMSampleBuffer 池或将 H.264 AVCC 流写入 MP4 的更有效方法有一些想法?

- (CMSampleBufferRef)sampleBufferWithData:(NSData*)data formatDescriptor:(CMFormatDescriptionRef)formatDescription
{
    OSStatus result;

    CMSampleBufferRef sampleBuffer = NULL;

    // _blockBuffer is a CMBlockBufferRef instance variable
    if (!_blockBuffer)
    {
        size_t blockLength = MAX_LENGTH;
        result = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault,
                                                    NULL,
                                                    blockLength,
                                                    kCFAllocatorDefault,
                                                    NULL,
                                                    0,
                                                    blockLength,
                                                    kCMBlockBufferAssureMemoryNowFlag,
                                                    &_blockBuffer);

        // check error
    }

    result = CMBlockBufferReplaceDataBytes([data bytes], _blockBuffer, 0, [data length]);

    // check error

    const size_t sampleSizes = [data length];

    CMSampleTimingInfo timing = [self sampleTimingInfo];

    result = CMSampleBufferCreate(kCFAllocatorDefault,
                                  _blockBuffer,
                                  YES,
                                  NULL,
                                  NULL,
                                  formatDescription,
                                  1,
                                  1,
                                  &timing,
                                  1,
                                  &sampleSizes,
                                  &sampleBuffer);

    // check error

    return sampleBuffer;
}

【问题讨论】:

    标签: ios objective-c video avfoundation h.264


    【解决方案1】:

    如果您接收的是原始 H.264 数据,则无需做太多事情,也根本不需要处理 CoreMedia。

    缓冲所有 VCL NAL 单元,直到获得 SPS/PPS NAL 单元。从它们创建额外数据,然后将所有缓冲的和新的 VCL NAL 单元附加到文件中。如果您收到附件 B 格式的 NAL 单元,您需要将它们转换为 AVCC 格式(基本上用长度代码替换起始代码)

    如果您想要解码未压缩的图片或想要解码压缩的图片,您只需要使用“CMSampleBuffer”。由于您已经在处理原始 H.264 流并且只想将其写入 MP4 文件,因此请执行此操作。这里根本不需要接触CoreMedia。

    关于 CoreMedia:您将视频信息包装在 CMBlockBuffer 中。该缓冲区与CMVideoFormatDescriptor(从SPS/PPS 生成)加上CMTime 组成CMSampleBuffer。多个CMSampleBuffers 组成一个“CMSampleBufferPool”。

    'CVPixelBuffer' 和 'CVPixelBufferPool' 不涉及。在处理编码/解码 h.264 视频时,这些是“VTCompressionSession”或“VTDecompressionSession”的输入或输出。

    正如你所说的,你只是在创建一个文件,所以根本不需要触及任何核心框架。

    关于附件 B 和 AVCC 流格式的概述可以在这里找到:Possible Locations for Sequence/Picture Parameter Set(s) for H.264 Stream

    【讨论】:

      猜你喜欢
      • 2011-12-16
      • 1970-01-01
      • 1970-01-01
      • 2013-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-12
      • 2012-06-22
      相关资源
      最近更新 更多