音频码流在视频播放器中的位置如下所示。
一、AAC音频编码介绍
AAC共有9种规格,以适应不同的场合的需要:
MPEG-2 AAC LC 低复杂度规格(Low Complexity) | 比较简单,没有增益控制,但提高了编码效率,在中等码率的编码效率以及音质方面,都能找到平衡点 |
---|---|
MPEG-2 AAC Main 主规格 | |
MPEG-2 AAC SSR 可变采样率规格(Scaleable Sample Rate) | |
MPEG-4 AAC LC 低复杂度规格(Low Complexity) | 现在的手机比较常见的MP4文件中的音频部份就包括了该规格音频文件 |
MPEG-4 AAC Main 主规格 | 包含了除增益控制之外的全部功能,其音质最好 |
MPEG-4 AAC SSR 可变采样率规格(Scaleable Sample Rate) | |
MPEG-4 AAC LTP 长时期预测规格(Long Term Predicition) | |
MPEG-4 AAC LD 低延迟规格(Low Delay) | |
MPEG-4 AAC HE 高效率规格(High Efficiency) | 这种规格适合用于低码率编码,有Nero ACC 编码器支持 |
目前使用最多的是LC和HE(适合低码率)。
流行的Nero AAC编码程序只支持LC,HE,HEv2这三种规格,编码后的AAC音频,规格显示都是LC。
HE其实就是AAC(LC)+SBR技术,HEv2就是AAC(LC)+SBR+PS技术;
1.1 AAC的音频文件格式
AAC的音频文件格式有ADIF & ADTS:
ADIF:Audio Data Interchange Format 音频数据交换格式。
这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中。
ADTS:Audio Data Transport Stream 音频数据传输流。
这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。
简单说,ADTS可以在任意帧解码,也就是说它每一帧都有头信息。
ADIF只有一个统一的头,所以必须得到所有的数据后解码。
且这两种的header的格式也是不同的,目前一般编码后的和抽取出的都是ADTS格式的音频流。
ADTS流结构如下:
其中每个ADTS frame之间通过syncword(同步字)进行分隔。
同步字为0xFFF
(二进制“1111 1111 1111
”)。
AAC码流解析的步骤就是首先从码流中搜索0x0FFF,分离出ADTS frame;然后再分析ADTS frame的首部各个字段。
(1)帧同步目的在于找出帧头在比特流中的位置,13818-7规定,aac ADTS格式的帧头,同步字为12比特的“ 1111 1111 1111
”.
(2)ADTS的头信息为两部分组成,其一为固定头信息,紧接着是可变头信息。固定头信息中的数据每一帧都相同,而可变头信息则在帧与帧之间可变。
数据解析如下:
ff f1 4c 80 2a 9f fc 27 0c 54 15
------------>
ff f1
--->fff :Byte[0,1](ff f1) syncword (12bit)
--->0 :Byte[1](f1) ID (1bit)
--->00 :Byte[1](f1) LAYer (2bit)
--->1 :Byte[1](f1) protection_absent (1bit)
4c(0100 1100) 80(1000 0000) 2a(0010 1010) 9f(1001 1111) fc(1111 1100)
--->01 :Byte[2](4c) LC (2bit)
--->00 11 :Byte[2](4c) 48000HZ (4bit)
--->0 :Byte[2](4c) private_bit(1bit)
--->010 :Byte[2,3](4c 80) channel_configuration (3bit)
--->0 :Byte[3](80) original/copy (1bit)
--->0 :Byte[3](80) home(1bit)
--->0 :Byte[3](80) copyright_identification_bit(1bit)
--->0 :Byte[3](80) copyright_idectification_start(1bit)
--->00 0010 1001 100 :Byte[3,4,5](80 2a 9f) frame_lenght (13bit) 332 数据大小
--->1 1111 1111 11 :Byte[5,6](9f fc) adts_buffer_fullness (11bit)
--->00 :Byte[6](fc) number_of_raw_data_blocks_in_frame (2bit)
1.2 AAC的解码流程
在主控模块开始运行后,主控模块将AAC比特流的一部分放入输入缓冲区,通过查找同步字 得到一帧的起始,找到后,根据ISO/IEC 13818-7所述的语法开始进行Noisless Decoding(无 噪解码),无噪解码实际上就是哈夫曼解码,通过反量化(Dequantize)、联合立体声(Joint Stereo),知觉噪声替换(PNS),瞬时噪声整形(TNS),反离散余弦变换(IMDCT),频段复制(SBR)这几个模块之后,得出左右声道的PCM码流,再由主控模块将其放入输出缓冲区输出到 声音播放设备。
1.3 AAC的Profiles
1.4 AAC的Frequency
二、准备AAC素材
先从网上下载一首歌,我下载了一首 flac格式 的《平凡之路》,
通过ffmpeg 转换aac 的合令为: ffmpeg -i input.wav -acodec libfaac output.aac
如果报错:Unknown encoder ‘libfaac’
就需要去下载编译 libfaac,添加让其支持。
我们此处获取aac 的方式为,直接从 mp4视频中获取,
ffmpeg命令为:ffmpeg -i HarryPotter.mp4 -vn -y -acodec copy video.aac
可以看出提取出来的aac格式为:aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 131 kb/s
C:\Users\ciellee\Desktop\YUV420\H.264>ffmpeg -i HarryPotter.mp4 -vn -y -acodec copy video.aac
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'HarryPotter.mp4':
Metadata:
major_brand : mp42
minor_version : 0
compatible_brands: mp41isom
creation_time : 2014-12-21T08:40:48.000000Z
Duration: 00:06:57.51, start: 0.000000, bitrate: 2096 kb/s
Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1961 kb/s, 30 fps, 30 tbr, 30k tbn, 60 tbc (default)
Metadata:
creation_time : 2020-08-30T11:01:59.000000Z
handler_name : VideoHandler
encoder : AVC Coding
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 131 kb/s (default)
Metadata:
creation_time : 2020-08-30T11:01:59.000000Z
handler_name : SoundHandler
Output #0, adts, to 'video.aac':
Metadata:
major_brand : mp42
minor_version : 0
compatible_brands: mp41isom
encoder : Lavf58.30.100
Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 131 kb/s (default)
Metadata:
creation_time : 2020-08-30T11:01:59.000000Z
handler_name : SoundHandler
Stream mapping:
Stream #0:1 -> #0:0 (copy)
Press [q] to stop, [?] for help
size= 6829kB time=00:06:57.49 bitrate= 134.0kbits/s speed=8.2e+03x
video:0kB audio:6696kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 1.998099%
我们把生成的 video.aac 文件,通过hexdump 导出成txt 看下它的内容:
hexdump video.acc >video.acc.txt
解析举例:
ff f1 4c 80 2a 9f fc 27 0c 54 15
------------>
ff f : syncword
1: MPEG identifier 1
4c(0100 1100)
===>01 : LC profile
===>00 11 : 48000HZ AAC的频率
80(1000 0000) 2a(0010 1010) 9f(1001 1111)
===>1000 00
===>00 0010 1001 100: 332 数据大小
三、获取所有ADTS frame内容 - 程序代码实现
本程序的目的是,通过解析同步字为0xFFF
,获取每个ADTS frame的内容。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int Get_ADTS_Frame(unsigned char *buff, int buff_size, unsigned char* frame, int *frame_size)
{
int size = 0;
if(buff==NULL || frame==NULL || buff_size==0)
{
return -1;
}
while(1){
if(buff_size < 7)
return -1;
// Sync Word 0xff f1
if((buff[0] == 0xff) && ((buff[1] & 0xff) == 0xf1)){
size |= ((buff[3] & 0x03) << 11); // high 2bit
size |= buff[4] << 3; // middle 8bit
size |= ((buff[5] & 0xe0) >> 5); // low 3bit
break;
}
buff_size--;
buff++;
}
if(buff_size < size)
{
return 1;
}
memcpy(frame, buff, size);
*frame_size = size;
return 0;
}
int parser_aac(char *url)
{
int data_size=0, frame_size=0, offset=0, count=0;
unsigned char *input_data=NULL;
FILE *aac_file = fopen(url, "rb+"); // 打开aac文件
// 申请内存空间
unsigned char *aac_frame = (unsigned char *)malloc(1024 * 10);
unsigned char *aac_buffer = (unsigned char *)malloc(1024 * 1024 * 2);
printf("-----+- ADTS Frame Table -+------+\n");
printf(" NUM | Profile | Frequency| Size |\n");
printf("-----+---------+----------+------+\n");
while(!feof(aac_file))
{
data_size = fread(aac_buffer + offset, 1, 1024*1024*2 -offset, aac_file);
input_data = aac_buffer;
printf("---------\n");
while(1)
{
// 解析每一个ADTS Frame
int ret = Get_ADTS_Frame(input_data, data_size, aac_frame, &frame_size);
if(ret == -1)
break;
else if(ret == 1){
// 解析成功后,将数据拷贝到 aac_buffer 中
memcpy(aac_buffer, input_data, data_size);
offset = data_size;
break;
}else{
// 解析 Profile
char profile_str[10] = {0};
char frequence_str[10] = {0};
unsigned char profile = aac_frame[2] & 0xC0;
profile = profile>>6;
switch(profile){
case 0: sprintf(profile_str,"Main");break;
case 1: sprintf(profile_str,"LC");break;
case 2: sprintf(profile_str,"SSR");break;
default:sprintf(profile_str,"unknown");
printf("%x %x %x %x %x %x %x %x\n",
aac_frame[0], aac_frame[1], aac_frame[2], aac_frame[3], aac_frame[4], aac_frame[5], aac_frame[6], aac_frame[7]);
break;
}
// 解析 frequence
unsigned char sampling_frequency_index = aac_frame[2] & 0x3C;
sampling_frequency_index = sampling_frequency_index >> 2;
switch(sampling_frequency_index){
case 0: sprintf(frequence_str,"96000Hz");break;
case 1: sprintf(frequence_str,"88200Hz");break;
case 2: sprintf(frequence_str,"64000Hz");break;
case 3: sprintf(frequence_str,"48000Hz");break;
case 4: sprintf(frequence_str,"44100Hz");break;
case 5: sprintf(frequence_str,"32000Hz");break;
case 6: sprintf(frequence_str,"24000Hz");break;
case 7: sprintf(frequence_str,"22050Hz");break;
case 8: sprintf(frequence_str,"16000Hz");break;
case 9: sprintf(frequence_str,"12000Hz");break;
case 10:sprintf(frequence_str,"11025Hz");break;
case 11:sprintf(frequence_str,"8000Hz") ;break;
default:sprintf(frequence_str,"unknown");
printf("%x %x %x %x %x %x %x %x\n",
aac_frame[0], aac_frame[1], aac_frame[2], aac_frame[3], aac_frame[4], aac_frame[5], aac_frame[6], aac_frame[7]);
break;
}
printf("%5d| %8s| %8s| %5d|\n",count, profile_str, frequence_str, frame_size);
data_size -= frame_size;
input_data = input_data+frame_size;
count++;
}
}
}
printf("解析结束\n\n");
}
int main(void)
{
parser_aac("video.aac");
return 0;
}
运行结果为:
-----+- ADTS Frame Table -+------+
NUM | Profile | Frequency| Size |
-----+---------+----------+------+
0| LC| 48000Hz| 200|
1| LC| 48000Hz| 207|
2| LC| 48000Hz| 211|
3| LC| 48000Hz| 302|
4| LC| 48000Hz| 306|
5| LC| 48000Hz| 327|
6| LC| 48000Hz| 326|
7| LC| 48000Hz| 298|
8| LC| 48000Hz| 325|
9| LC| 48000Hz| 302|
10| LC| 48000Hz| 323|
11| LC| 48000Hz| 334|
12| LC| 48000Hz| 340|
13| LC| 48000Hz| 309|
14| LC| 48000Hz| 337|
15| LC| 48000Hz| 318|
16| LC| 48000Hz| 337|
17| LC| 48000Hz| 332|
18| LC| 48000Hz| 338|
19| LC| 48000Hz| 313|
20| LC| 48000Hz| 310|
21| LC| 48000Hz| 342|
22| LC| 48000Hz| 337|
23| LC| 48000Hz| 338|
24| LC| 48000Hz| 328|
25| LC| 48000Hz| 330|
26| LC| 48000Hz| 329|
27| LC| 48000Hz| 340|
28| LC| 48000Hz| 320|
29| LC| 48000Hz| 341|
30| LC| 48000Hz| 314|
31| LC| 48000Hz| 322|
32| LC| 48000Hz| 339|
33| LC| 48000Hz| 328|
34| LC| 48000Hz| 343|
35| LC| 48000Hz| 331|
36| LC| 48000Hz| 326|
37| LC| 48000Hz| 321|
38| LC| 48000Hz| 323|
39| LC| 48000Hz| 336|
40| LC| 48000Hz| 323|
41| LC| 48000Hz| 341|
42| LC| 48000Hz| 316|
43| LC| 48000Hz| 329|
44| LC| 48000Hz| 326|
45| LC| 48000Hz| 325|
46| LC| 48000Hz| 318|
47| LC| 48000Hz| 341|
48| LC| 48000Hz| 315|
-----+- ADTS Frame Table -+------+
NUM | Profile | Frequency| Size |
-----+---------+----------+------+
0| LC| 48000Hz| 200| -- ff f1 4c 80 19 1f
1| LC| 48000Hz| 207| -- ff f1 4c 80 19 ff
2| LC| 48000Hz| 211| -- ff f1 4c 80 1a 7f
3| LC| 48000Hz| 302| -- ff f1 4c 80 25 df
4| LC| 48000Hz| 306| -- ff f1 4c 80 26 5f
5| LC| 48000Hz| 327| -- ff f1 4c 80 28 ff
6| LC| 48000Hz| 326| -- ff f1 4c 80 28 df
7| LC| 48000Hz| 298| -- ff f1 4c 80 25 5f
8| LC| 48000Hz| 325| -- ff f1 4c 80 28 bf
9| LC| 48000Hz| 302| -- ff f1 4c 80 25 df
10| LC| 48000Hz| 323| -- ff f1 4c 80 28 7f
11| LC| 48000Hz| 334| -- ff f1 4c 80 29 df
12| LC| 48000Hz| 340| -- ff f1 4c 80 2a 9f
13| LC| 48000Hz| 309| -- ff f1 4c 80 26 bf
14| LC| 48000Hz| 337| -- ff f1 4c 80 2a 3f
15| LC| 48000Hz| 318| -- ff f1 4c 80 27 df
16| LC| 48000Hz| 337| -- ff f1 4c 80 2a 3f
FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发 学习资料、教学视频和学习路线图 分享有需要的可以自行添加 学习交流群 或者 资料获取