复用附件 B MPEG-TS 时 SPS 和 PPS 的音频等效?啥是“解码器信息”?

Posted

技术标签:

【中文标题】复用附件 B MPEG-TS 时 SPS 和 PPS 的音频等效?啥是“解码器信息”?【英文标题】:Audio equivalent of SPS and PPS when muxing Annex B MPEG-TS? What is "DecoderInfo"?复用附件 B MPEG-TS 时 SPS 和 PPS 的音频等效?什么是“解码器信息”? 【发布时间】:2015-05-13 00:04:02 【问题描述】:

我正在使用 Bento4 库将 Annex B TS(MPEG-2 传输流)文件与分别从 VideoToolbox 和 AVFoundation 生成的 h264 视频和 AAC 音频流混合,作为 HLS 的源数据(HTTP 实时流)流。这个问题不一定是 Bento4 特有的:我正在尝试理解基本概念,以便我可以完成任务,最好是使用 Apple 库。

到目前为止,我已经弄清楚了如何通过从我的CMVideoFormatDescriptionRef 中获取各种数据来创建AP4_AvcSampleDescription,最重要的是通过分别使用CMVideoFormatDescriptionGetH264ParameterSetAtIndex 的索引 0 和 1 生成 SPS 和 PPS我可以作为字节缓冲区粘贴到 Bento4 中。太好了,这就是我需要的所有标头信息,这样我就可以让 Bento4 将视频复用到 ts 文件中!

现在我正在尝试将音频混合到同一个文件中。我正在使用我的CMAudioFormatDescriptionRef 来获取构建我的AP4_MpegAudiosampleDescription 所需的信息,Bento4 使用它来制作必要的 QT 原子和标题。但是,如果字段是“解码器信息”字节缓冲区,则没有解释它是什么,或者从数据生成一个的代码。我本来希望有CMAudioFormatDescriptionGetDecoderInfo 或其他东西,但我找不到类似的东西。 Apple 库中是否有这样的功能?或者有没有关于如何生成这些数据的很好的规范?

或者,我是否走错了路?有没有更简单的方法从 Mac/iOS 代码库中复用 ts 文件?

【问题讨论】:

【参考方案1】:

将音频混合到 MPEG-TS 中非常简单,并且不需要像视频流那样复杂的标头!在将其写入 PES 之前,它只需要在每个样本缓冲区之前有一个 7 字节的 ADTS 标头。

Bento4 仅使用“DecoderInfo”缓冲区将其解析为AP4_Mp4AudioDecoderConfig 实例,以便提取 ADTS 标头所需的信息。我没有在获取这些数据时如此迂回,而是复制粘贴了AP4_Mpeg2TsAudioSampleStream::WriteSample,其中写了CMSampleBufferRef。它可以很容易地推广到其他音频框架,但我将在此处按原样粘贴以供参考:

// These two functions are copy-pasted from Ap4Mpeg2Ts.cpp
static unsigned int GetSamplingFrequencyIndex(unsigned int sampling_frequency)  ... 
static void
MakeAdtsHeader(unsigned char *bits,
               size_t  frame_size,
               unsigned int  sampling_frequency_index,
               unsigned int  channel_configuration)  ... 

static const size_t kAdtsHeaderLength = 7;

- (void)appendAudioSampleBuffer2:(CMSampleBufferRef)sampleBuffer

    // Get the actual audio data from the block buffer.
    CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
    size_t blockBufferLength = CMBlockBufferGetDataLength(blockBuffer);

    // Get the audio meta-data from its AudioFormatDescRef
    CMAudioFormatDescriptionRef audioFormat = CMSampleBufferGetFormatDescription(sampleBuffer);
    const AudioStreamBasicDescription *asbd = CMAudioFormatDescriptionGetStreamBasicDescription(audioFormat);

    // These are the values we will need to build our ADTS header
    unsigned int sample_rate = asbd->mSampleRate;
    unsigned int channel_count = asbd->mChannelsPerFrame;
    unsigned int sampling_frequency_index = GetSamplingFrequencyIndex(sample_rate);
    unsigned int channel_configuration = channel_count;

    // Create a byte buffer with first the header, and then the sample data.
    NSMutableData *buffer = [NSMutableData dataWithLength:kAdtsHeaderLength + blockBufferLength];
    MakeAdtsHeader((unsigned char*)[buffer mutableBytes], blockBufferLength, sampling_frequency_index, channel_configuration);
    CMBlockBufferCopyDataBytes(blockBuffer, 0, blockBufferLength, ((char*)[buffer mutableBytes])+kAdtsHeaderLength);

    // Calculate a timestamp int64 that Bento4 can use, by converting our CMTime into an Int64 in the timescale of the audio stream.
    CMTime presentationTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
    AP4_UI64 ts = CMTimeConvertScale(presentationTime, _audioStream->m_TimeScale, kCMTimeRoundingMethod_Default).value;

    _audioStream->WritePES(
        (const unsigned char*)[buffer bytes],
        (unsigned int)[buffer length],
        ts,
        false, // don't need a decode timestamp for audio
        ts,
        true, // do write a presentation timestamp so we can sync a/v
        *_output
    );

【讨论】:

【参考方案2】:

Bento4 创建 AP4_MpegAudioSampleDescription 实例所需的“解码器信息”字节缓冲区是编解码器初始化数据,它是编解码器特定的。对于 AAC-LC 音频,它通常是 2 个字节的数据(对于 HE-AAC,您会得到更多字节),其详细信息在 AAC 规范中指定。例如,一个 44.1kHz、立体声、AAC-LC 流将具有 [0x12,0x10] 作为初始数据。 在大多数 Apple API 中,这种类型的编解码器初始化数据是通过他们所谓的“Magic Cookies”传送的。 CMAudioFormatDescriptionGetMagicCookie 函数很可能会在此处返回您需要的内容。

【讨论】:

哦,我想你可能会带着正确的标签出现:D 谢谢!!我是否可以建议 AP4_SampleDescription 采用 AP4_Mp4AudioDecoderConfig 实例,以便 API 用户不必处理该实现细节? :) 我最终复制粘贴了 WriteSample 的版本,该版本只需要我拥有的内容以及我的数据所需的内容;当我得到它的工作时,我会发布答案......(编辑:MagicCookie返回NULL:/不是我需要它,只是fyi)

以上是关于复用附件 B MPEG-TS 时 SPS 和 PPS 的音频等效?啥是“解码器信息”?的主要内容,如果未能解决你的问题,请参考以下文章

将 GStreamer 管道编码并复用为 MPEG-TS

SPS、PPS

Xuggler 编码和复用

FFmpeg 细碎知识整理

使用 ffmpeg 实时流式传输 MPEG-TS 和 windows 媒体服务

H.264---SPS和PPS