AMR,全称是:Adaptive Multi-Rate,自适应多速率,是一种音频编码文件格式,专用于有效地压缩语音频率,用于移动设备的音频压缩,压缩比非常高,但是音质比较差,主要用于语音类的音频压缩,不适合对音质要求较高的音乐类音频的压缩。


WAV头文解析:

typedef struct
{
  char id[4];
  uint32_t size;
} chunk_t;

typedef struct
{
  uint16_t format;   // 格式类别
  uint16_t channels; // 声道数
  uint32_t sample;   // 采样速率
  uint32_t bytes;    // 数据传输速度(每秒数据量字节数)
  uint16_t align;    // 数据块对齐
  uint16_t bits;     // 采样位数
} fmt_t;

void show_wave_info(void *buff, int len)
{
  fmt_t *pfmt = (fmt_t *)buff;
  printf("格式类别:%d(1:PCM)\r\n", pfmt->format);
  printf("声 道 数:%d\r\n", pfmt->channels);
  printf("采样频率:%d\r\n", pfmt->sample);
  printf("采样位数:%d\r\n", pfmt->bits);
  printf("每秒数据量:%d\r\n", pfmt->bytes);
  printf("数据块对齐单位:%d\r\n", pfmt->align);      
}

void show_chunk(chunk_t *p)
{
  printf("%c%c%c%c %d\r\n",
         p->id[0],
         p->id[1],
         p->id[2],
         p->id[3],
         p->size);
}

int read_wave_head(int fd, fmt_t *fmt)
{
  int ret;
  char buff[1024];
  chunk_t chunk;

  // 读RIFF及WAVE
  ret = read(fd, buff, 12);

  // 读fmt字段
  ret = read(fd, &chunk, 8);
  if (ret == 8)
  {
    read(fd, fmt, chunk.size);
    show_wave_info(fmt, chunk.size);
  }

  // 读下一字段(LIST或data)
  ret = read(fd, &chunk, 8);
  if (ret == 8)
  {
    show_chunk(&chunk);
  }
  if (!strncmp(chunk.id, "data", 4))
  {
    return chunk.size;
  }
  // 读取LIST的内容字节
  read(fd, buff, chunk.size); 

  // 这里应该是data段了
  ret = read(fd, &chunk, 8);
  show_chunk(&chunk);

  return chunk.size;
}

AMR编解码:

安装开发库: libopencore-amrnb
编译选项: -lopencore-amrnb
头文件相关:

#include <opencore-amrnb/interf_dec.h>
// 通过帧头编码格式,转换帧长
const char amr_f_sizes[] = { 12, 13, 15, 17, 19, 20, 26, 31, 5, 6, 5, 5, 0, 0, 0, 0 };
AmrInterface = Decoder_Interface_init();
// 读取6个字节的文件头
ret = read(fd, inbuff, 6);
while (1)
{
  // 先读取1字节的帧头
  read(fd, inbuff, 1);
  // 剔除坏帧
  if(inbuff[0] & 0x04)
  {
    continue;
  }
  // 通过帧头计算帧长
  n = (inbuff[0] >> 3) & 0x07;
  ret = read(fd, &inbuff[1], amr_f_sizes[n]);
  // 音频解码
  Decoder_Interface_Decode(AmrInterface, inbuff, (int16_t *)(outbuff), 0);
  // 播放解码数据
  ret = snd_pcm_writei(snd_pcm, outbuff, frames);
}