常见flv文件封装的音频用的都是aac编码,aac文件有两种格式,一个是AIDS,一个是ADTS(Audio Data Transport Stream 音频数据传输流)。其中ADTS格式用于流式传输,因为每一帧都包含头信息,可以从任一帧开始解码,故用于流式传输。本文主要讲下flv文件中的adts。
adts的头部结构
adts头部大小7个字节或者9个字节(决定于是否包含CRC)。结构定义如下图所示:
MPEG-4 Audio Object Type
- 0: Null
- 1: AAC Main
- 2: AAC LC (Low Complexity)
- 3: AAC SSR (Scalable Sample Rate)
- 4: AAC LTP (Long Term Prediction)
- 5: SBR (Spectral Band Replication)
- 6: AAC Scalable
- 7: TwinVQ
- 8: CELP (Code Excited Linear Prediction)
- 9: HXVC (Harmonic Vector eXcitation Coding)
- 10: Reserved
- 11: Reserved
- 12: TTSI (Text-To-Speech Interface)
- 13: Main Synthesis
- 14: Wavetable Synthesis
- 15: General MIDI
······
MPEG-4 Sampling Frequency Index
- 0: 96000 Hz
- 1: 88200 Hz
- 2: 64000 Hz
- 3: 48000 Hz
- 4: 44100 Hz
- 5: 32000 Hz
- 6: 24000 Hz
- 7: 22050 Hz
- 8: 16000 Hz
- 9: 12000 Hz
- 10: 11025 Hz
- 11: 8000 Hz
- 12: 7350 Hz
- 13: Reserved
- 14: Reserved
- 15: frequency is written explictly
MPEG-4 Channel Configuration
- 0: Defined in AOT Specifc Config
- 1: 1 channel: front-center
- 2: 2 channels: front-left, front-right
- 3: 3 channels: front-center, front-left, front-right
- 4: 4 channels: front-center, front-left, front-right, back-center
- 5: 5 channels: front-center, front-left, front-right, back-left, back-right
- 6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
- 7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
- 8-15: Reserved
flv文件获取AudioSpecificConfig
在flv文件中,上述Audio Object Type,Channel Configrartion等信息存储在AudioSpecificConfig结构中,该AudioSpecificConfig结构一般存储在第一个Audio Tag数据中。在ISO 14496-3中AudioSpecificConfig结构按如下定义:
也就是:
1 2 3 4 5 6 |
5 bits: audio object type 4 bits: sampling frequency index if (frequency index == 15) 24 bits: frequency index 4 bits: channel configuration other bits: audio object type specific config |
如下图所示,我们打开一个音频为aac编码的flv视频文件(本文讨论的都是aac编码的),红色框处是tag data部分数据:
由flv标准文档AudioData定义可知,Audio Tag data部分第一个字节(0xAF)结构如下:
接着一个字节为AACPacketType(0x00):
第一个Audio Tag只包含头信息,不包含具体音频数据,所以AACPacketType值为0。Audio Tag data剩余的才是真正adts帧数据,也就是要把Audio Tag data除去前两个字节。到这里,我们得到了AudioSpecificConfig数据为:0x13 0x88 0x56 0xE5 0xA5 0x48 0x80。在程序中我们先构造一个字符数组,用于存储该数据:
1 |
char szAudioSpecificConfig[64] = {0}; |
从flv文件中读取Audio Tag data除去前两个字节的数据:
1 2 |
//第一个auido tag数据包含AudioSpecificConfig,解析后用于生成adts头 fread(szAudioSpecificConfig, 1, tagheader_datasize - 2, m_pFlvFile); |
解析AudioSpecificConfig
由前一部分得知AudioSpecificConfig按如下解析:
1 2 3 4 5 6 |
5 bits: audio object type 4 bits: sampling frequency index if (frequency index == 15) 24 bits: frequency index 4 bits: channel configuration other bits: audio object type specific config |
通过位操作得到相应信息,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
uint8_t audio_object_type = 0; uint8_t sampling_frequency_index = 0; uint8_t channel_config = 0; //audio object type:5bit audio_object_type = szAudioSpecificConfig[0] & 0xf8; audio_object_type >>= 3; //sampling frequency index:4bit //高3bits sampling_frequency_index = szAudioSpecificConfig[0] & 0x07; sampling_frequency_index <<= 1; //低1bit uint8_t tmp = szAudioSpecificConfig[1] & 0x80; tmp >>= 7; sampling_frequency_index |= tmp; //channel config:4bits channel_config = szAudioSpecificConfig[1] & 0x78; channel_config >>= 3; |
程序中得到的3个数据我们将在下一部分使用。
计算adts头部
这里我们只讨论adts头部为7个字节的,首先构造一个字符数组存储adts头部:
1 |
char szAdtsheader[7] = {0}; |
接着计算得到flv文件所有adts帧头部相同部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
szAdtsHeader[0] = 0xff; //syncword:0xfff 高8bits szAdtsHeader[1] = 0xf0; //syncword:0xfff 低4bits szAdtsHeader[1] |= (0 << 3); //MPEG Version:0 for MPEG-4,1 for MPEG-2 1bit szAdtsHeader[1] |= (0 << 1); //Layer:0 2bits szAdtsHeader[1] |= 1; //protection absent:1 1bit szAdtsHeader[2] = (audio_object_type - 1)<<6; //profile:audio_object_type - 1 2bits szAdtsHeader[2] |= (sampling_frequency_index & 0x0f)<<2; //sampling frequency index:sampling_frequency_index 4bits szAdtsHeader[2] |= (0 << 1); //private bit:0 1bit szAdtsHeader[2] |= (channel_config & 0x04)>>2; //channel configuration:channel_config 高1bit szAdtsHeader[3] = (channel_config & 0x03)<<6; //channel configuration:channel_config 低2bits szAdtsHeader[3] |= (0 << 5); //original:0 1bit szAdtsHeader[3] |= (0 << 4); //home:0 1bit szAdtsHeader[3] |= (0 << 3); //copyright id bit:0 1bit szAdtsHeader[3] |= (0 << 2); //copyright id start:0 1bit |
接下来要计算的数据跟每一个adts帧长度有关,是变化的。如下所示是flv tag的结构,在flv每个tag中,数据部分长度为datasize(tagheader_datasize)。
由前面可知flv中Audio Tag存储的真实adts帧数据长度为tagheader_datasize - 2,此时还要加上7个字节adts头部长度才是完整一帧 adts长度,我们设置该长度为:
1 |
int AdtsLen = tagheader_datasize - 2 + 7; |
然后根据该AdtsLen计算得到头部剩下几位:
1 2 3 4 5 |
szAdtsHeader[3] |= ((AdtsLen & 0x1800) >> 11); //frame length:value 高2bits szAdtsHeader[4] = (uint8_t)((AdtsLen & 0x7f8) >> 3); //frame length:value 中间8bits szAdtsHeader[5] = (uint8_t)((AdtsLen & 0x7) << 5); //frame length:value 低3bits szAdtsHeader[5] |= 0x1f; //buffer fullness:0x7ff 高5bits szAdtsHeader[6] = 0xfc; |
至此我们可以得到了每一帧7个字节的adts头部,加上每一个adts帧的数据,可以得到完整的adts文件。
参考文档
1.flv标准说明video_file_format_spec_v10.pdf:https://pan.baidu.com/s/1z8RSGdQ_wzeXf8J50JMEQA
2.ISO/IEC 14496-3ISO_IEC_14496-3.PDF:https://pan.baidu.com/s/1TNrwlSshmDM3ZcglPHlHCA
文章评论