libmad 解码mp3并且播放测试

测试环境:window64  codeblock(mingw64)


下载libmad源码后发现自带的minimad.c是用了linux的API,所以修改了下,将

F:\d.mp3音乐文件解码后将pcm数据写入F:\d.pcm,并且用ffplay播放


一开始写入mp3全部的数据,minimad会发出decoding error 0x0101 (lost synchronization)等错误。

但是后面还是解码了,不明白为什么,所以去看了下mp3文件格式,发现mp3由标签头和音频数据帧组成

音频数据帧开头有11bit的同步字节,所以就明白了需要去掉标签头将后面的帧数据送入即可。

译码完成后用ffplay播放原生PCM数据

ffplay -f s16le -ac 2 -ar 44100 d.pcm

-f指定格式为有符号16bit pcm小端序   short 16 little endian (端序的话看你在输出回调里面怎么写)

-ac指定音频通道数audio channel(根据你的mp3文件的通道决定,用ffmpeg -i d.mp3就可以看)

-ar指定音频采样率44100Hz(根据你的mp3文件的采样率决定,用ffmpeg -i d.mp3就可以看)

结果如下:


代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <io.h>
# include "mad.h"

/**
  libmad测试
**/
static int decode(unsigned char const *, unsigned long);
static FILE *fout;
//得到文件的大小
int file_size(char* filename)
{
    FILE *fp=fopen(filename,"r");
    if(!fp) return -1;
    fseek(fp,0L,SEEK_END);
    int size=ftell(fp);
    fclose(fp);
    return size;
}
int main()
{
  char *fdm,*fdm2;
  FILE *p;
  char label[10];
  int label_size;
  int fileSize;
  fileSize=file_size("F:\\d.mp3");
  if(_access("F:\\d.pcm",F_OK)==0)remove("F:\\d.pcm");//如果存在就删除
  fout=fopen("F:\\d.pcm","wb");
  if(fout==NULL){
    printf("create file failed\n");
    return -1;
  }
  p=fopen("F:\\d.mp3","rb");
  if(p==NULL){
    printf("open file failed\n");
    return -1;
  }
  if(fread(label,sizeof(char),10,p)>0){
    //计算标签大小
    label_size=((label[6]&0x7F)<<21)|((label[7]&0x7F)<<14)|((label[8]&0x7F)<<7)|((label[9]&0x7F));
    label_size+=10;
    printf("label size=%d\nfileSize=%d\n",label_size,fileSize);
  //分配音频数据帧缓冲区
      fdm2=fdm=malloc(fileSize-label_size);
      if(fdm==NULL){
        printf("malloc failed\n");
      }
      fread(fdm,sizeof(char),label_size-10,p);//去掉标签头数据,剩下的就是音频数据帧
  }else return -1;

   printf("read %d bytes\n",fread(fdm,sizeof(char),fileSize-label_size,p));
   printf("decode ok %s\n",decode(fdm,fileSize-label_size)==0?"OK":"failed");
   free(fdm2);
   fclose(p);
   fclose(fout);
  return 0;
}


struct buffer {
  unsigned char const *start;
  unsigned long length;
};
/**
输入回调函数,一次性写入所有音频数据帧
**/
static
enum mad_flow input(void *data,
		    struct mad_stream *stream)
{
  struct buffer *buffer = data;

  if (!buffer->length)
    return MAD_FLOW_STOP;

  mad_stream_buffer(stream, buffer->start, buffer->length);

  buffer->length = 0;

  return MAD_FLOW_CONTINUE;
}

/*
转换24bit pcm为16bit pcm
 */
static inline
signed int scale(mad_fixed_t sample)
{
  /* round */
  sample += (1L << (MAD_F_FRACBITS - 16));

  /* clip */
  if (sample >= MAD_F_ONE)
    sample = MAD_F_ONE - 1;
  else if (sample < -MAD_F_ONE)
    sample = -MAD_F_ONE;

  /* quantize */
  return sample >> (MAD_F_FRACBITS + 1 - 16);
}

/*
输出回调函数,每译码完成一帧音频数据,就调用一次
 */
static
enum mad_flow output(void *data,
		     struct mad_header const *header,
		     struct mad_pcm *pcm)
{
  unsigned int nchannels, nsamples;
  mad_fixed_t const *left_ch, *right_ch;
  unsigned char *buf;
  int index;

  nchannels = pcm->channels;
  nsamples  = pcm->length;
  left_ch   = pcm->samples[0];
  right_ch  = pcm->samples[1];
  buf = malloc(nsamples*nchannels*2);

  index=0;
  while (nsamples--) {
    signed int sample;

    sample = scale(*left_ch++);
    *(buf+2*nchannels*index+0)=(sample >> 0) & 0xff;
    *(buf+2*nchannels*index+1)=(sample >> 8) & 0xff;

    if (nchannels == 2) {
      sample = scale(*right_ch++);
      *(buf+2*nchannels*index+2)=(sample >> 0) & 0xff;
      *(buf+2*nchannels*index+3)=(sample >> 8) & 0xff;
    }
    index++;
  }
  fwrite(buf,sizeof(char),pcm->length*nchannels*2,fout);
  free(buf);
  return MAD_FLOW_CONTINUE;
}

/*
错误回调函数,有错误就调用
 */
static
enum mad_flow error(void *data,
		    struct mad_stream *stream,
		    struct mad_frame *frame)
{
  struct buffer *buffer = data;

  fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n",
	  stream->error, mad_stream_errorstr(stream),
	  stream->this_frame - buffer->start);

  return MAD_FLOW_CONTINUE;
}

/*
译码
 */
static
int decode(unsigned char const *start, unsigned long length)
{
  struct buffer buffer;
  struct mad_decoder decoder;
  int result;

  buffer.start  = start;
  buffer.length = length;
  //初始化译码器,设置回调函数
  mad_decoder_init(&decoder, &buffer,
		   input, 0 /* header */, 0 /* filter */, output,
		   error, 0 /* message */);
  //运行译码器
  result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);

  mad_decoder_finish(&decoder);

  return result;
}



  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值