多路复用附件 B MPEG-TS 时 SPS 和 PPS 的音频等价物?什么是 "DecoderInfo"?
Audio equivalent of SPS and PPS when muxing Annex B MPEG-TS? What is "DecoderInfo"?
我正在使用 Bento4 库将 Annex B TS(MPEG-2 传输流)文件与分别从 VideoToolbox 和 AVFoundation 生成的 h264 视频和 AAC 音频流混合,作为源HLS(HTTP Live Streaming)流的数据。这个问题不一定是特定于 Bento4 的:我正在尝试理解基本概念以便我可以完成任务,最好是使用 Apple 库。
到目前为止,我已经想出了如何通过从我的 CMVideoFormatDescriptionRef
中获取各种数据来创建 AP4_AvcSampleDescription
,最重要的是通过使用索引 0 和我可以将 CMVideoFormatDescriptionGetH264ParameterSetAtIndex
中的 1 个作为字节缓冲区分别粘贴到 Bento4 中。太好了,这就是我需要的所有 header 信息,这样我就可以让 Bento4 将视频混合到 ts 文件中!
现在我正在尝试将音频混合到同一个文件中。我正在使用我的 CMAudioFormatDescriptionRef
获取构建我的 AP4_MpegAudioSampleDescription
所需的信息,Bento4 使用它来制作必要的 QT 原子和 header。但是,如果字段是一个 "decoder info" 字节缓冲区,则没有解释它是什么,也没有代码从数据生成一个。我本来希望有一个 CMAudioFormatDescriptionGetDecoderInfo
之类的东西,但我找不到类似的东西。任何Apple库中都有这样的功能吗?或者是否有我没有找到的关于如何生成此数据的很好的规范?
或者,我是不是走错了路?有没有更简单的方法从 Mac/iOS 代码库 mux ts 文件?
Bento4 创建AP4_MpegAudioSampleDescription 实例所需的'decoder info' 字节缓冲区是编解码器初始化数据,它是特定于编解码器的。对于 AAC-LC 音频,它通常是 2 个字节的数据(对于 HE-AAC,您会得到更多字节),其详细信息在 AAC 规范中指定。例如,44.1kHz、立体声、AAC-LC 流将具有 [0x12,0x10] 作为初始数据。
在大多数 Apple API 中,这种类型的编解码器初始化数据是通过他们所谓的 'Magic Cookies' 来传送的。函数 CMAudioFormatDescriptionGetMagicCookie 很可能 return 你在这里需要的东西。
将音频混合到 MPEG-TS 非常简单,并且不需要像视频流那样复杂的 header!它只需要在每个样本缓冲区之前有一个 7 字节的 ADTS header,然后再将其写入 PES。
Bento4 仅使用 "DecoderInfo" 缓冲区将其解析为 AP4_Mp4AudioDecoderConfig
实例,以便它可以提取 ADTS header 所需的信息。我没有在获取这些数据时如此迂回,而是制作了一个 AP4_Mpeg2TsAudioSampleStream::WriteSample
的 copy-paste,写了一个 CMSampleBufferRef
。它可以很容易地推广到其他音频框架,但我只是将它粘贴到这里as-is以供参考:
// 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 库将 Annex B TS(MPEG-2 传输流)文件与分别从 VideoToolbox 和 AVFoundation 生成的 h264 视频和 AAC 音频流混合,作为源HLS(HTTP Live Streaming)流的数据。这个问题不一定是特定于 Bento4 的:我正在尝试理解基本概念以便我可以完成任务,最好是使用 Apple 库。
到目前为止,我已经想出了如何通过从我的 CMVideoFormatDescriptionRef
中获取各种数据来创建 AP4_AvcSampleDescription
,最重要的是通过使用索引 0 和我可以将 CMVideoFormatDescriptionGetH264ParameterSetAtIndex
中的 1 个作为字节缓冲区分别粘贴到 Bento4 中。太好了,这就是我需要的所有 header 信息,这样我就可以让 Bento4 将视频混合到 ts 文件中!
现在我正在尝试将音频混合到同一个文件中。我正在使用我的 CMAudioFormatDescriptionRef
获取构建我的 AP4_MpegAudioSampleDescription
所需的信息,Bento4 使用它来制作必要的 QT 原子和 header。但是,如果字段是一个 "decoder info" 字节缓冲区,则没有解释它是什么,也没有代码从数据生成一个。我本来希望有一个 CMAudioFormatDescriptionGetDecoderInfo
之类的东西,但我找不到类似的东西。任何Apple库中都有这样的功能吗?或者是否有我没有找到的关于如何生成此数据的很好的规范?
或者,我是不是走错了路?有没有更简单的方法从 Mac/iOS 代码库 mux ts 文件?
Bento4 创建AP4_MpegAudioSampleDescription 实例所需的'decoder info' 字节缓冲区是编解码器初始化数据,它是特定于编解码器的。对于 AAC-LC 音频,它通常是 2 个字节的数据(对于 HE-AAC,您会得到更多字节),其详细信息在 AAC 规范中指定。例如,44.1kHz、立体声、AAC-LC 流将具有 [0x12,0x10] 作为初始数据。 在大多数 Apple API 中,这种类型的编解码器初始化数据是通过他们所谓的 'Magic Cookies' 来传送的。函数 CMAudioFormatDescriptionGetMagicCookie 很可能 return 你在这里需要的东西。
将音频混合到 MPEG-TS 非常简单,并且不需要像视频流那样复杂的 header!它只需要在每个样本缓冲区之前有一个 7 字节的 ADTS header,然后再将其写入 PES。
Bento4 仅使用 "DecoderInfo" 缓冲区将其解析为 AP4_Mp4AudioDecoderConfig
实例,以便它可以提取 ADTS header 所需的信息。我没有在获取这些数据时如此迂回,而是制作了一个 AP4_Mpeg2TsAudioSampleStream::WriteSample
的 copy-paste,写了一个 CMSampleBufferRef
。它可以很容易地推广到其他音频框架,但我只是将它粘贴到这里as-is以供参考:
// 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
);
}