在复用附件B MPEG-TS时,音频等效于SPS和PPS?什么是“DecoderInfo”?

时间:2015-05-13 00:04:03

标签: ios audio avfoundation mpeg hls

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

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

现在我正在尝试将音频复用到同一个文件中。我正在使用我的AP4_MpegAudioSampleDescription获取构建我的CMAudioFormatDescriptionGetDecoderInfo所需的信息,Bento4使用它来制作必要的QT原子和标题。但是,如果字段是“解码器信息”字节缓冲区,没有解释它是什么,或者是从数据生成一个字节的代码。我希望有一个<http://jsfiddle.net/bm17cmxj/1/> 或者其他东西,但我找不到那样的东西。在任何Apple库中都有这样的功能吗?或者有一个很好的规范,我没有找到如何生成这些数据?

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

2 个答案:

答案 0 :(得分: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
    );
}

答案 1 :(得分:0)

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