0


常用的开源MP3编解码器

前言

由于工作需要,需对MP3进行编解码处理,研究了几款开源的MP3编解码器。相对于FFMPEG来说,这几款都属于轻量级的编解码器,更容易移植。

LAME

源码下载链接:https://sourceforge.net/projects/lame/
支持MP3编解码。编码出来的MP3音色纯厚、空间宽广、低音清晰、细节表现良好,它独创的心理音响模型技术保证了CD音频还原的真实性,配合VBR和ABR参数,音质几乎可以媲美CD音频,但文件体积却非常小,是目前主流的编码器。

MAD

MAD(libmad)是一个开源的高精度MPEG音频解码库,支持MPEG-1标准。libmad提供24-bit的PCM输出,完全定点计算,非常适合在没有浮点支持的嵌入式硬件平台上使用。使用libmad提供的一系列API可以实现MP3文件的解码。
源码下载链接:https://sourceforge.net/projects/mad/
例程minimad.c是在运行前将整个MP3文件读入内存中进行处理,不适合MP3流未知的场景,需改成边解码边写入MP3的形式,即每次读入1K MP3数据,解码完成再读入1K,又不影响播放的连续性,方便在资源紧张的嵌入式系统中运用。
libmad中的mad_decoder_run()进行解码时,首先会检测待解码缓冲区中是否存在数据,有则解码,没有则调用input()函数进行装载数据,并返回MAD_FLOW_CONTINUE表示还存在数据,解码完成后调用output()函数进行处理,如此循环…直到input()函数返回MAD_FLOW_STOP表示该MP3数据流已经完全加载,output()函数输出后,表示该MP3文件已完成全部解码操作。
input()函数如下,每次调用读入FRAME_SIZE_MP3字节数据:

staticenummad_flowinput(void*data,structmad_stream*stream){
  PT_Mp3Info ptMp3Info =(PT_Mp3Info)data;int ret;int restLen;// unprocessed data's sizeint readLen;if(!feof(fin)){
    restLen = stream->bufend - stream->next_frame;memcpy(ptMp3Info->inMp3, ptMp3Info->inMp3+ptMp3Info->inLen-restLen, restLen);
    readLen = FRAME_SIZE_MP3 - restLen;int readn =fread(ptMp3Info->inMp3+restLen,sizeof(char), readLen, fin);
    ptMp3Info->inLen = restLen + readn;mad_stream_buffer(stream, ptMp3Info->inMp3, ptMp3Info->inLen);
    ret = MAD_FLOW_CONTINUE;}else{
    ret = MAD_FLOW_STOP;}return ret;}

完整代码如下:

#include<stdio.h>#include<unistd.h>#include<string.h>#include<sys/stat.h>#include<sys/mman.h>#include"mad.h"#defineFRAME_SIZE_MP3(1024)typedefstruct_Mp3Info{unsignedchar inMp3[FRAME_SIZE_MP3];unsignedint  inLen;}T_Mp3Info,*PT_Mp3Info;static FILE *fin  =NULL;static FILE *fout =NULL;staticintdecode(PT_Mp3Info ptMp3Info);intmain(int argc,char*argv[]){if(argc !=3){printf("%s <inMp3> <outPcm>\n", argv[0]);return-1;}
  
  fin  =fopen(argv[1],"r");
  fout =fopen(argv[2],"wb+");

  T_Mp3Info tMp3Info;decode(&tMp3Info);fclose(fin);fclose(fout);return0;}/*
 * This is the input callback. The purpose of this callback is to (re)fill
 * the stream buffer which is to be decoded. In this example, an entire file
 * has been mapped into memory, so we just call mad_stream_buffer() with the
 * address and length of the mapping. When this callback is called a second
 * time, we are finished decoding.
 */staticenummad_flowinput(void*data,structmad_stream*stream){
  PT_Mp3Info ptMp3Info =(PT_Mp3Info)data;int ret;int restLen;// unprocessed data's sizeint readLen;if(!feof(fin)){
    restLen = stream->bufend - stream->next_frame;memcpy(ptMp3Info->inMp3, ptMp3Info->inMp3+ptMp3Info->inLen-restLen, restLen);
    readLen = FRAME_SIZE_MP3 - restLen;int readn =fread(ptMp3Info->inMp3+restLen,sizeof(char), readLen, fin);
    ptMp3Info->inLen = restLen + readn;mad_stream_buffer(stream, ptMp3Info->inMp3, ptMp3Info->inLen);
    ret = MAD_FLOW_CONTINUE;}else{
    ret = MAD_FLOW_STOP;}return ret;}/*
 * The following utility routine performs simple rounding, clipping, and
 * scaling of MAD's high-resolution samples down to 16 bits. It does not
 * perform any dithering or noise shaping, which would be recommended to
 * obtain any exceptional audio quality. It is therefore not recommended to
 * use this routine if high-quality output is desired.
 */staticinlinesignedintscale(mad_fixed_t sample){/* round */
  sample +=(1L<<(MAD_F_FRACBITS -16));/* clip */if(sample >= MAD_F_ONE)
    sample = MAD_F_ONE -1;elseif(sample <-MAD_F_ONE)
    sample =-MAD_F_ONE;/* quantize */return sample >>(MAD_F_FRACBITS +1-16);}/*
 * This is the output callback function. It is called after each frame of
 * MPEG audio data has been completely decoded. The purpose of this callback
 * is to output (or play) the decoded PCM audio.
 */staticenummad_flowoutput(void*data,structmad_headerconst*header,structmad_pcm*pcm){unsignedint nchannels, nsamples;mad_fixed_tconst*left_ch,*right_ch;/* pcm->samplerate contains the sampling frequency */

  nchannels = pcm->channels;
  nsamples  = pcm->length;
  left_ch   = pcm->samples[0];
  right_ch  = pcm->samples[1];while(nsamples--){signedint sample;/* output sample(s) in 16-bit signed little-endian PCM */

    sample =scale(*left_ch++);char high =(sample >>0)&0xff;char low  =(sample >>8)&0xff;//    putchar((sample >> 0) & 0xff);//    putchar((sample >> 8) & 0xff);fwrite(&high,sizeof(char),1, fout);fwrite(&low,sizeof(char),1, fout);if(nchannels ==2){
      sample =scale(*right_ch++);//      putchar((sample >> 0) & 0xff);//      putchar((sample >> 8) & 0xff);
      high =(sample >>0)&0xff;
      low  =(sample >>8)&0xff;fwrite(&high,sizeof(char),1, fout);fwrite(&low,sizeof(char),1, fout);}}return MAD_FLOW_CONTINUE;}/*
 * This is the error callback function. It is called whenever a decoding
 * error occurs. The error is indicated by stream->error; the list of
 * possible MAD_ERROR_* errors can be found in the mad.h (or stream.h)
 * header file.
 */staticenummad_flowerror(void*data,structmad_stream*stream,structmad_frame*frame){
  PT_Mp3Info ptMp3Info =(PT_Mp3Info)data;fprintf(stderr,"decoding error 0x%04x (%s) at byte offset %lu\n",
      stream->error,mad_stream_errorstr(stream),
      stream->this_frame - ptMp3Info->inMp3);/* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */return MAD_FLOW_CONTINUE;}/*
 * This is the function called by main() above to perform all the decoding.
 * It instantiates a decoder object and configures it with the input,
 * output, and error callback functions above. A single call to
 * mad_decoder_run() continues until a callback function returns
 * MAD_FLOW_STOP (to stop decoding) or MAD_FLOW_BREAK (to stop decoding and
 * signal an error).
 */staticintdecode(PT_Mp3Info ptMp3Info){structmad_decoder decoder;int result;if(ptMp3Info ==NULL){printf("ptMp3Info is NULL\n");return-1;}/* configure input, output, and error functions */mad_decoder_init(&decoder, ptMp3Info,
           input,0/* header */,0/* filter */, output,
           error,0/* message */);/* start decoding */

  result =mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);/* release the decoder */mad_decoder_finish(&decoder);return result;}

tinymp3

支持MP3编解码,代码量少,适合在单片机上移植。
源码下载链接:https://github.com/cpuimage/tinymp3

minimp3

仅支持MP3解码,只有一个头文件,适合在单片机上移植。
源码下载链接:https://github.com/lieff/minimp3
minimp3的使用只需调用一个函数即可实现解码

intmp3dec_decode_frame(mp3dec_t*dec,constuint8_t*mp3,int mp3_bytes,mp3d_sample_t*pcm,mp3dec_frame_info_t*info);

消耗的 MP3 数据的大小在定义的mp3dec_frame_info_t结构中的frame_bytes字段中返回,必须在下一次解码器调用之前从输入缓冲区中删除对应于 frame_bytes 字段的数据。
解码函数返回已解码样本的数量samples。可能出现以下情况:
0: 在输入缓冲区中未找到 MP3 数据
384: Layer 1
576: MPEG 2 Layer 3
1152: Otherwise

samples 和 frame_bytes 字段值:
samples > 0 和 frame_bytes > 0: 成功解码
samples == 0 和 frame_bytes > 0: 解码器跳过了 ID3 或无效数据
samples == 0 和 frame_bytes == 0: 数据不足

参考代码如下:

#include<stdint.h>#include<string.h>#include<stdbool.h>#include<stdio.h>#defineMINIMP3_IMPLEMENTATION#include"minimp3.h"intmain(int argc,char*argv[]){unsignedchar*inMp3 =NULL;int totalLen =0;if(argc !=3){printf("%s <inMp3> <outPcm>\n", argv[0]);return-1;}//打开MP3文件
    FILE* fin =fopen(argv[1],"r");//获取MP3文件长度fseek(fin,0,SEEK_END);
    totalLen =(int)ftell(fin);//读取整个MP3文件fseek(fin,0,SEEK_SET);
    inMp3 =malloc(totalLen);fread(inMp3,1, totalLen, fin);fclose(fin);//定义mp3dec_frame_info_tmp3dec_frame_info_t info;short outPcm[MINIMP3_MAX_SAMPLES_PER_FRAME];int inLen =0;//逐帧解码int samples =mp3dec_decode_frame(&mp3d, inMp3, totalLen, outPcm,&info);while(samples){fwrite(outPcm,sizeof(short), samples, fout);
        inLen += info.frame_bytes;
        samples =mp3dec_decode_frame(&mp3d, inMp3 + inLen, totalLen - inLen, outPcm,&info);}free(inMp3);
    inMp3 =NULL;fclose(fout);return0;}
标签: 音视频

本文转载自: https://blog.csdn.net/liang_zhaocong/article/details/127828585
版权归原作者 ZC_L 所有, 如有侵权,请联系我们删除。

“常用的开源MP3编解码器”的评论:

还没有评论