一、AMR简介
基于新的网络和新的要求,无论是从节省传输频带资源,还是保持线路通信的高效率等方面来看,研究采用各种可变速率语音编码技术的系统都有重要意义。目前为了适应此需要提出了AMR(Adaptive Multi-rate) 的概念,即自适应多速率语音编码器,主要用于移动设备的音频,压缩比比较大,但相对其他的压缩格式质量比较差,由于多用于人声通话。AMR又分为两种,一种是AMR-NB(AMR-NarrowBind),语音带宽范围:300-3700Hz,8KHz采样频率;另外一种是AMR-WB(AMR WideBand),语音带宽范围50-7000Hz,16KHz采样频率。但考虑语音的短时相关性,每帧长度均为20ms。这两种编码器根据带宽的要求虽然选用了不同的速率,但有异曲同工之处.
总之,知道AMR是一种压缩比较大的、多用于人声通话的语音编码技术就好了。关于AMR-NB和AMR-WB网上有较多的介绍此处也不在重复。另一个比较重要的点是“每帧长度均为20ms”,这对我们接下来解析时长比较有用。
二、AMR文件结构解析
AMR文件由文件头和数据帧组成,文件头标识占6个字节,后面紧接着的就是音频帧了,如下:
文件头(6字节) |
语音帧1 |
语音帧2 |
...... |
语音帧n |
1、文件头。关于文件头单声道和多声道情况下文件的头部是不一致的,单声道情况下的文件头只包括一个Magic number,而多声道情况下文件头既包含Magic number,在其之后还包含一个32位的Chanel description field。多声道情况下的32位通道描述字符,前28位都是保留字符,必须设置成0,最后4位说明使用的声道个数。此处我们知道占6个字节就好了。
2、语音数据。
(1)语音帧块。文件头之后就是时间连续的语音帧块了,也就是说语音帧还存在以帧块为维度的划分。每个帧块包含8位组对齐的语音帧,相对于若干个声道,从第一个声道开始一次排列。
(2)语音帧。语音帧的组成包括两部分:帧头和帧内容。每个帧都是8位组对齐的。其实语音帧就可以理解为视频的一帧一帧的画面,语音帧的概念与之相同。
1)帧头:每一帧都是从一个8位的帧头开始,而且其中的P为填充位必须设为0(感觉就是第一个bit必为0的意思)。
帧头(8bit) | 帧内容(字节数因编码模式而不同) |
2)语音帧的编码模式有如下八种,他们的音频帧的大小是不同的,比特率也是不同的。
注意,这些模式会在同一个文件amr文件中共存,这也就是Adaptive Multi-rate的真实含义吧。
模式 | 规格 | 比特率(kbps) | 音频帧大小(字节) | 帧头(字节) | FT |
0 | AMR 4.75 | 4.75 | 13 | 04 00000100 | 0000 |
1 | AMR 5.15 | 5.15 | 14 | 0C 00001100 | 0001 |
2 | AMR 5.9 | 5.90 | 16 | 14 00010100 | 0010 |
3 | AMR 6.7 | 6.70 | 18 | 1C 00011100 | 0011 |
4 | AMR 7.4 | 7.40 | 20 | 24 00100100 | 0100 |
5 | AMR 7.95 | 7.95 | 21 | 2C 00101100 | 0101 |
6 | AMR 10.2 | 10.20 | 27 | 34 00110100 | 0110 |
7 | AMR 12.2 | 12.20 | 32 | 3C 00111100 | 0111 |
由以上表格可知,八种模式的是可以根据帧头进行区分的。这个在后续的解析amr文件获取语音时长的代码中会体现出来。
3、音频数据帧大小的计算:AMR 一帧对应20ms,那么一秒有50帧的音频数据。由于比特率不同,每帧的数据大小也不同。如果比特率是12.2kbs,那么每秒采样的音频数据位数为:
12200 / 50 = 244bit = 30.5byte,取整为31字节。
再加上一个字节的帧头,这样数据帧的大小为32字节。
三、解析AMR文件的时长
根据以上介绍我们此处给出解析AMR文件获取语音时长的C++代码。
uint64_t getDuration(std::string fileContent)
{
uint64_t duration=0;//语音持续时长
//音频帧在八种编码模式下的帧内容占用字节数
int AMR_FRAME_SIZE[8] = { 13, 14, 16, 18, 20, 21, 27, 32};
size_t pos=0;//pos用来指示位置
size_t length=fileContent.length();
char toc;//toc每次代表帧头,通过运算可以知道属于哪种编码模式
pos+=6;//跳过文件头的6个字节
while(pos<length)
{
toc=fileContent[pos];//toc赋值帧头
toc=toc & 0x78;//对照表格帧头的编码一目了然
toc=toc>>3;//对照表格帧头的编码一目了然
if(toc>=8)
toc=0;
duration+=20;//每一个数据帧对应20ms
pos+=AMR_FRAME_SIZE[(int)toc];
}
duration+=500;//四舍五入
duration/=1000;//转换为秒
return duration;
}
关于时长读取提供如下具体测试代码,见本人上传资源【解析amr文件时长c++实例代码(包含arm示例文件)】。