我使用Bento4库将附件HLS (MPEG-2传输流)文件与h264视频和AAC音频流分别从VideoToolbox和AVFoundation生成,作为HLS (HTTP )流的源数据。这个问题不一定是特定于Bento4 4的:我试图理解基本的概念,以便我能够完成任务,最好是使用Apple。
到目前为止,我已经知道了如何通过从CMVideoFormatDescriptionRef中获取各种数据来创建CMVideoFormatDescriptionRef,最重要的是使用CMVideoFormatDescriptionGetH264ParameterSetAtIndex的索引0和1生成SPS和PPS,我可以将它们作为字节缓冲区保存到Bento4中。太好了,这就是我需要的所有头信息,这样我就可以让Bento4把视频变成ts文件了!
现在我试着把音频屏蔽到同一个文件中。我正在使用我的CMAudioFormatDescriptionRef来获取构造我的AP4_MpegAudioSampleDescription所需的信息,Bento4使用它来生成必要的QT原子和头。然而,如果字段是一个“解码器信息”字节缓冲区,没有解释它是什么,或者代码从数据生成一个。我本来希望有一个CMAudioFormatDescriptionGetDecoderInfo之类的,但我找不到这样的东西。苹果的图书馆里有这样的功能吗?或者,在如何生成这些数据方面,我还没有找到一个很好的规范吗?
或者,我走错路了吗?有更简单的方法从Mac/iOS代码库中屏蔽ts文件吗?
发布于 2015-05-15 23:24:45
Muxing音频进入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
);
}发布于 2015-05-13 16:18:22
Bento4创建AP4_MpegAudioSampleDescription实例所需的“解码器信息”字节缓冲区是编解码器初始化数据,它是特定于编解码器的。对于AAC-LC音频,它通常是2个字节的数据(对于HE,您会得到一些更多的字节),其细节在AAC规范中指定。例如,一个44.1kHz,立体声,AAC-LC流将有0x12,0x10作为init数据。在大多数Apple中,这种类型的编解码器初始化数据是通过他们所谓的“魔术饼干”来传递的。函数CMAudioFormatDescriptionGetMagicCookie很可能会返回您在这里需要的内容。
https://stackoverflow.com/questions/30203441
复制相似问题