7 AMR-WB 编解码
AMR-WB 由 3GPP(第三代合作伙伴计划)制定10,是一种用于语音编码的音频压缩标准,广泛应用于移动通信领域,特别是在 3G 和 4G 网络中。 AMR-WB 支持的音频带宽范围为 50-7000 Hz,比 AMR-NB 更宽,语音更清晰、自然。 具备从 6.6 kbps 到 23.85 kbps 等多种码率,支持动态调整、优化语音质量和带宽占用。
AMR-WB 音频采样率为 16kHz,以 20ms 为一帧,即 320 个采样(AMR_WB_PCM_FRAME_16k)。
7.1 使用方法
7.1.1 编码
初始化
使用
amr_wb_encoder_init初始化编码器对象:struct amr_wb_encoder *amr_wb_encoder_init( int bit_stream_format, // 比特流格式 int allow_dtx, // 是否启用 DTX (1 或 0) int mode, // 默认模式(即码率) void *buf); // 用于存放上下文的内存支持三种比特流格式,如表 7.1 所示。当用于语音数据压缩时, 应该使用 MIME 格式(
AMR_WB_BIT_STREAM_FORMAT_MIME_IETF)。表 7.1: AMR-WB 比特流格式 格式 帧头长度(字节) 载荷格式 ETS 6 每 2 个字节表示一个比特 ITU 4 每 2 个字节表示一个比特 MIME 1 详见 RFC 3267 (5.1,5.3) 帧头长度也可以通过
amr_wb_get_frame_header_size(mode)获得。allow_dtx参数详见 AMR-WB 规范,可以填0。模式参数
mode与实际码率对应关系见表 7.2。表 7.2: AMR-WB 码率模式与帧长(MIME 格式) 模式 码率(kb/s) 每帧比特数 每帧载荷长度(字节) 0 6.6 132 17 1 8.85 177 23 2 12.65 253 32 3 14.25 285 36 4 15.85 317 40 5 18.25 365 40 6 19.85 397 50 7 23.05 461 58 8 23.85 477 60 调用
amr_wb_encoder_get_context_size()可获取buf所需大小。编码
调用
amr_wb_encoder_encode_frame编码一个音频帧,其返回值为音频帧的帧头和载荷的总长度。int amr_wb_encoder_encode_frame( struct amr_wb_encoder *ctx, // 编码器对象 const int16_t *pcm_samples, // PCM 输入 uint8_t *output, // 编码输出 void *scratch); // 临时内存编码输出
output的大小根据选择的码率确定(见表 7.2), 例如,若码率为 6.6 kb/s,则output的长度应该至少是 1 + 17 = 18 字节。调用
amr_wb_encoder_get_context_size()可获取临时内存scratch所需大小。需要切换模式时,调用
amr_wb_encoder_encode_frame2,先切换模式,再编码。
下面的代码演示了如何编码一整段数据。
void *context = malloc(amr_wb_encoder_get_context_size());
void *scratch = malloc(amr_wb_encoder_get_scratch_mem_size());
static uint8_t output[模式所对应的载荷长度 + 1];
const uint16_t *in = ... // 音频采样
const int NUM_OF_SAMPLES = .... // 总采样数
struct amr_wb_encoder *enc =
amr_wb_encoder_init(AMR_WB_BIT_STREAM_FORMAT_MIME_IETF,
0, 模式, context);
for (i = 0;
i < NUM_OF_SAMPLES - AMR_WB_PCM_FRAME_16k;
i += AMR_WB_PCM_FRAME_16k)
{
int r = amr_wb_encoder_encode_frame(
enc, in + i, output, scratch);
// 处理 pcm_output
....
}7.1.2 解码
初始化
使用
amr_wb_decoder_init初始化解码器对象:struct amr_wb_decoder *amr_wb_decoder_init( int bit_stream_format, // 比特流格式 void *buf); // 用于存放上下文的内存调用
amr_wb_decoder_get_context_size()可获取buf所需大小。比特流格式仅支持
AMR_WB_BIT_STREAM_FORMAT_MIME_IETF。解码帧头
使用
amr_wb_decoder_probe解码帧头,获得音频帧基本参数:int amr_wb_decoder_probe( struct amr_wb_decoder *ctx, // 解码器对象 const uint8_t *stream); // 音频流音频流
stream应该指向一个音频帧的帧头。这个函数将返回这个音频帧的载荷的长度。 如果出现错误,将返回负值错误码。解码载荷
使用
amr_wb_decoder_decode_frame解码载荷:int amr_wb_decoder_decode_frame( struct amr_wb_decoder *ctx, // 解码器对象 const uint8_t *payload, // 音频帧载荷 int16_t *synth_pcm, // PCM 输出 void *scratch); // 临时内存这个函数返回输出的 PCM 采样的个数,即
AMR_WB_PCM_FRAME_16k,synth_pcm的长度也应为AMR_WB_PCM_FRAME_16k。调用
amr_wb_decoder_get_scratch_mem_size()可获取临时内存scratch所需大小。
下面的代码演示了如何解码一段数据。
static uint8_t pcm_output[AMR_WB_PCM_FRAME_16k];
const uint8_t *in = ...; // 音频数据
int data_size = ...; // 音频数据总长度
void *context = malloc(amr_wb_decoder_get_context_size());
void *scratch = malloc(amr_wb_decoder_get_scratch_mem_size());
struct amr_wb_decoder *dec = amr_wb_decoder_init(
AMR_WB_BIT_STREAM_FORMAT_MIME_IETF, context);
const int header_size = amr_wb_get_frame_header_size(
AMR_WB_BIT_STREAM_FORMAT_MIME_IETF);
while (data_size > header_size)
{
int payload_len = amr_wb_decoder_probe(dec, in);
in += header_size;
data_size -= header_size;
if (payload_len > data_size) break;
if (payload_len < 0) break;
int r = amr_wb_decoder_decode_frame(
dec, in, pcm_output, scratch);
in += payload_len;
data_size -= payload_len;
// 处理 pcm_output
....
}7.2 资源消耗
以下数据仅供参考。实际表现受编译器、Cache、RTOS、中断、音频数据等因素影响。
7.2.1 ING916XX
| 功能 | context(字节) |
scratch(字节) |
|---|---|---|
| 编码 | 2788 | 11898 |
| 解码 | 1552 | 3826 |
当 CPU 主频为 112 MHz 时,AMR-WB 编解码器的处理一个音频帧所消耗的时间见表 7.4。 从表中可以看出,需要进行实时编码时,只能使用 6.6 kbps,不可使用更高速率。
| 模式 | 编码 (ms) | 解码 (ms) |
|---|---|---|
| 0 | 16.7 | 7.9 |
| 1 | 20.0 | 6.6 |
| 2 | 22.2 | 5.9 |
| 3 | 23.9 | 5.9 |
| 4 | 23.9 | 6.0 |
| 5 | 24.6 | 6.1 |
| 6 | 25.6 | 6.2 |
| 7 | 25.3 | 6.2 |
| 8 | 24.8 | 6.6 |
参见 TS 26.171 等↩︎