我使用Bento4库多路复用器的附件B TS(MPEG-2传输流)与我的H264视频和正在从VideoToolbox和AVFoundation分别生成AAC音频流文件,作为用于HLS(HTTP实时流)的源数据流。 这个问题不一定Bento4特异性:我想了解的基本概念,这样我可以完成任务,最好用的苹果库。
到目前为止,我已经找到了如何创建一个AP4_AvcSampleDescription
通过获取各种数据从我的CMVideoFormatDescriptionRef
使用索引0和1分别产生SPS和PPS,最重要的CMVideoFormatDescriptionGetH264ParameterSetAtIndex
,我可以只是坚持为字节的缓冲区进入Bento4。 太好了,这就是我需要的,这样我可以问Bento4于MUX视频转换成TS文件头信息!
现在,我想给MUX音频到同一个文件。 我用我的CMAudioFormatDescriptionRef
以获得所需的信息来构建我AP4_MpegAudioSampleDescription
,这Bento4使用进行必要的QT原子和头。 然而,如果一个字段是“解码信息”字节的缓冲区,没有解释它是什么,或代码来生成一个与数据。 我本来希望能有一个CMAudioFormatDescriptionGetDecoderInfo
或东西,但我找不到这样的事情。 是否有任何苹果库这样的功能? 或者是有,我还没有就如何产生这个数据找到了一个很好的规范吗?
或可替换地,我是走在错误的道路? 有没有从Mac / iOS的代码库混流TS文件更简单的方法?
木星音频为MPEG-TS是非常容易的,像视频流确实不需要复杂的头! 它仅需要每个样品缓冲之前7字节的ADTS头标,则写它作为一个PES前。
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
);
}
通过Bento4创建AP4_MpegAudioSampleDescription实例所需的“解码器信息”字节缓冲器是编解码器的初始化数据,这是特定的编解码器。 对于AAC-LC音频,它通常是2个字节数据(HE-AAC,你会得到一些更多的字节),其中的细节在AAC规范中规定。 例如,44.1kHz的,立体声,AAC-LC流将具有[0x12,0x10]作为初始化数据。 在大多数苹果的API,这种类型的编解码器的初始化数据是通过他们所谓的“魔法饼干”传送。 这是可能的功能CMAudioFormatDescriptionGetMagicCookie将返回您这里需要。
文章来源: Audio equivalent of SPS and PPS when muxing Annex B MPEG-TS? What is “DecoderInfo”?