Ios 用于写入H.264 AVCC流的CMSampleBufferRef池

Ios 用于写入H.264 AVCC流的CMSampleBufferRef池,ios,objective-c,video,avfoundation,h.264,Ios,Objective C,Video,Avfoundation,H.264,我正在使用AVAssetWriter/AVAssetWriterInput将H.264原始数据写入MP4文件。当我从远程服务器接收数据时,我使用以下CoreMedia API获取一个样本缓冲区(CMSampleBufferRef),该缓冲区包含AVCC格式的H.264数据,然后通过向AVAssetWriterInput发送消息(BOOL)appendSampleBuffer:(CMSampleBufferRef)sampleBuffer,将其追加到MP4文件中: CMBlockBufferCre

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

  • CMBlockBufferCreateWithMemoryBlock
    创建内存块
  • CMBlockBufferReplaceDataBytes
    将AVCC格式的H.264写入内存块
  • CMSampleBufferCreate
    使用内存块和包含H.264“extradata”的格式描述符创建样本缓冲区
  • 一切都按预期进行,这种方法的唯一问题是我定期调用上述API,我真正希望的是能够重用分配的资源,特别是
    CMSampleBufferRef
    CMBlockBufferRef
    基本上,我希望拥有一个
    CMSampleBuffer
    池,并能够在从远程服务器接收新的H.264数据时更新其内存内容和格式描述符

    我知道存在允许访问
    CVPixelBufferPool
    avassetwriterinportpixelbufferadapter
    ,但我不能在我的例子中使用它,因为据我所知,要正确实例化像素缓冲适配器,至少我需要能够传递视频帧维度,直到解析流为止。此外,我不知道如何使用
    CVPixelBuffer
    编写H.264“extradata”。因此,我认为我需要坚持使用
    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;
    }
    

    如果您正在接收原始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”的输入或输出

    正如在您的案例中所说的,根本不需要接触任何核心framworks,因为您只是在创建一个文件

    有关附录B和AVCC流格式的概述可在此处找到: