linux下使用libmad库实现mp3文件的解码、播放

目录(?)[+]

  1. 准备工作
  2. 解码流程
  3. 播放
  4. 遇到的问题

据说这个更新到2004年2月的libmad是一种高品质的MPEG音频解码器,支持24-bit输出,优点多多。

对其的详细介绍请参考主页:http://www.underbit.com/products/mad/

准备工作

x86_64平台的编译可直接运行configure,arm下

libmad: ./configure –host=arm-xxx(arm-xxx为交叉编译工具的前缀)

解码流程

libmad将mp3文件解码后生成pcm数据。libmad库自带一个非常简洁的实例:minimad.c,分析其中的decode函数可看到其解码流程非常简单:

1、配置输入回调函数、输出回调函数、用户数据、筛选回调函数、错误回调函数、消息回调函数,参考初始化函数源代码。

回调函数中,输入(读取原始音频数据)、输出(对解码后的音频数据进行处理)是必需的。

[cpp] view plain copy print ?
  1. void mad_decoder_init(struct mad_decoder *decoder, void *data,
  2. enum mad_flow(*input_func)(void *,
  3. struct mad_stream *),
  4. enum mad_flow(*header_func)(void *,
  5. struct mad_header const *),
  6. enum mad_flow(*filter_func)(void *,
  7. struct mad_stream const *,
  8. struct mad_frame *),
  9. enum mad_flow(*output_func)(void *,
  10. struct mad_header const *,
  11. struct mad_pcm *),
  12. enum mad_flow(*error_func)(void *,
  13. struct mad_stream *,
  14. struct mad_frame *),
  15. enum mad_flow(*message_func)(void *,
  16. void *, unsigned int *))
  17. {
  18. decoder->mode         = -1;
  19. decoder->options      = 0;
  20. decoder->async.pid    = 0;
  21. decoder->async.in     = -1;
  22. decoder->async.out    = -1;
  23. decoder->sync         = 0;
  24. decoder->cb_data      = data;
  25. decoder->input_func   = input_func;
  26. decoder->header_func  = header_func;
  27. decoder->filter_func  = filter_func;
  28. decoder->output_func  = output_func;
  29. decoder->error_func   = error_func;
  30. decoder->message_func = message_func;
  31. }
void mad_decoder_init(struct mad_decoder *decoder, void *data,enum mad_flow(*input_func)(void *,struct mad_stream *),enum mad_flow(*header_func)(void *,struct mad_header const *),enum mad_flow(*filter_func)(void *,struct mad_stream const *,struct mad_frame *),enum mad_flow(*output_func)(void *,struct mad_header const *,struct mad_pcm *),enum mad_flow(*error_func)(void *,struct mad_stream *,struct mad_frame *),enum mad_flow(*message_func)(void *,void *, unsigned int *))
{decoder->mode         = -1;decoder->options      = 0;decoder->async.pid    = 0;decoder->async.in     = -1;decoder->async.out    = -1;decoder->sync         = 0;decoder->cb_data      = data;decoder->input_func   = input_func;decoder->header_func  = header_func;decoder->filter_func  = filter_func;decoder->output_func  = output_func;decoder->error_func   = error_func;decoder->message_func = message_func;
}

其中的data参数是用户需要传给回调函数的自定义数据结构。比如,解码一个文件,并且采用系统函数open函数打开,那么可以定义一个对此描述的数据结构:

[cpp] view plain copy print ?
  1. typedef struct _mp3_file
  2. {
  3. int *fd;//open(“xx.mp3”,O_RDONLY)
  4. uint32_t flen;//mp3文件的长度
  5. uint32_t fpos;//当前文件指针位置
  6. uint8_t  buf[BUFSIZE];
  7. uint32_t buf_size;
  8. } mp3_file;
typedef struct _mp3_file
{int *fd;//open("xx.mp3",O_RDONLY)uint32_t flen;//mp3文件的长度uint32_t fpos;//当前文件指针位置uint8_t  buf[BUFSIZE];uint32_t buf_size;} mp3_file;

数据成员buf、buf_size传递给mad_stream_buffer,用来设置流缓冲区指针。

错误处理在minimad中被忽略了,可参考madplay中处理方法(player.c:1776),此处贴出来大概的流程

[cpp] view plain copy print ?
  1. /*
  2. * NAME:    decode->error()
  3. * DESCRIPTION: handle a decoding error
  4. */
  5. static
  6. enum mad_flow decode_error(void *data, struct mad_stream *stream,
  7. struct mad_frame *frame)
  8. {
  9. struct player *player = data;
  10. signed long tagsize;
  11. switch (stream->error)
  12. {
  13. case MAD_ERROR_BADDATAPTR:
  14. /*do something*/
  15. return MAD_FLOW_CONTINUE;
  16. case MAD_ERROR_LOSTSYNC:
  17. /* todo*/
  18. default:
  19. /*todo*/
  20. }
  21. if (stream->error == MAD_ERROR_BADCRC)
  22. {
  23. return MAD_FLOW_IGNORE;
  24. }
  25. return MAD_FLOW_CONTINUE;
  26. }
/** NAME:    decode->error()* DESCRIPTION: handle a decoding error*/
static
enum mad_flow decode_error(void *data, struct mad_stream *stream,struct mad_frame *frame)
{struct player *player = data;signed long tagsize;switch (stream->error){case MAD_ERROR_BADDATAPTR:/*do something*/return MAD_FLOW_CONTINUE;case MAD_ERROR_LOSTSYNC:/* todo*/default:/*todo*/}if (stream->error == MAD_ERROR_BADCRC){return MAD_FLOW_IGNORE;}return MAD_FLOW_CONTINUE;
}

错误处理的返回值定义如下:

[cpp] view plain copy print ?
  1. enum mad_flow {
  2. MAD_FLOW_CONTINUE = 0x0000,   /* continue normally */
  3. MAD_FLOW_STOP     = 0x0010,   /* stop decoding normally */
  4. MAD_FLOW_BREAK    = 0x0011,   /* stop decoding and signal an error */
  5. MAD_FLOW_IGNORE   = 0x0020    /* ignore the current frame */
  6. };
enum mad_flow {MAD_FLOW_CONTINUE = 0x0000,   /* continue normally */MAD_FLOW_STOP     = 0x0010,   /* stop decoding normally */MAD_FLOW_BREAK    = 0x0011,   /* stop decoding and signal an error */MAD_FLOW_IGNORE   = 0x0020    /* ignore the current frame */
};

可视情况选择继续或者终止解码。

2、调用mad_decoder_run开始解码,支持两种同步、异步两种运行方式

[cpp] view plain copy print ?
  1. enum mad_decoder_mode {
  2. MAD_DECODER_MODE_SYNC  = 0,
  3. MAD_DECODER_MODE_ASYNC
  4. };
enum mad_decoder_mode {MAD_DECODER_MODE_SYNC  = 0,MAD_DECODER_MODE_ASYNC
};

3、解码结束后调用mad_decoder_finish释放解码器

播放

在输出回调函数中,将解码数据直接写入“/dev/dsp”即可实现mp3文件的播放,也可以生成pcm文件,供支持pcm解码的音频芯片使用。

遇到的问题

1、解码错误 (0x0101 lost synchronization)

对于这个错误的解释可参考http://www.mars.org/pipermail/mad-dev/2004-January/000975.html

需要的两个库的下载地址以及编译方法如下:

zlib

这个库的configure脚本没有提供编译器选项。直接运行configure程序后,打开产生的Makefile,将CC=gcc改为你要使用的编译器的名字。

libid3tag

依赖于zlib,需要指定交叉编译工具名称,以及zlib库的头文件路径(-I)、库路径(-L)

运行./configure  –host=arm-xxx CPPFLAGS=-I(zlib头文件路径) LDFLAGS=-L(zlib库路径)

2、找不到“/dev/dsp”

对于无法正常播放声音的系统,可采用手动建立dsp设备的方式:

sudo mknod /dev/dsp c 14 3 (其中的设备号可通过Linux源码目录下/Documentation/devices.txt文件中查找/dev/dsp得到)

sudo chmod 666 /dev/dsp (设置普通用户可用)

对于弃用/dev/dsp方式的系统来说,不能采用上述方式,可使用padsp程序,如:

padsp madplay xxx.mp3

linux下使用libmad库实现mp3文件的解码、播放相关推荐

  1. Linux下基于Libmad库的MP3音乐播放器编写

    linux下基于Libmad库的MP3音乐播放器编写 libmad是一个开源mp3解码库,其对mp3解码算法做了很多优化,性能较好,很多播放器如mplayer.xmms等都是使用这个开源库进行解码的: ...

  2. linux中从内存解析xml格式的库,Linux下使用libxml库解析xml文件

    目录 libxml简介 libxml库安装 libxml2中的数据类型和函数 xml文档解析实例 运行结果 libxml简介 libxml是一个用于解析xml文件的库,在各个平台下都能使用,也支持多种 ...

  3. 基于libmad库的MP3解码简析

    基于libmad库的MP3解码简析  MAD (libmad)是一个开源的高精度 MPEG 音频解码库,支持 MPEG-1(Layer I, Layer II 和 LayerIII(也就是 MP3). ...

  4. Linux下的静态库、动态库和动态加载库

    from: http://www.techug.com/linux-static-lib-dynamic-lib 库的存在极大的提高了C/C++程序的复用性,但是库对于初学者来说有些难以驾驭,本文从L ...

  5. linux 下基于jrtplib库的实时传送实现

    linux 下基于jrtplib库的实时传送实现 一.RTP 是进行实时流媒体传输的标准协议和关键技术 实时传输协议(Real-time Transport Protocol,PRT)是在 Inter ...

  6. linux下基于jrtplib库的实时传送实现

    linux 下基于jrtplib库的实时传送实现 一.RTP 是进行实时流媒体传输的标准协议和关键技术  实时传输协议(Real-time Transport Protocol,PRT)是在 Inte ...

  7. linux dlopen 内存,Linux下加载库的有关问题(dlopenm, dlsym)

    Linux下加载库的问题(dlopenm, dlsym) 如题, 程序中发现load库成功,但是加载函数的时候报错: undefined symbol functionname 是很简单的一个东西,因 ...

  8. linux下生成静态库和动态库

    linux下生成静态库和动态库 一.动态库.静态库简介 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常.本质上 ...

  9. Linux下curses函数库的详细介绍

    Linux下curses函数库的详细介绍 curses库介绍 安装 curses库函数介绍 初始化和重置函数 管理屏幕的函数 输出到屏幕 从屏幕读取 清除屏幕 移动光标 字符属性 管理键盘的函数 键盘 ...

最新文章

  1. cv_bridge中的编码模式与实现
  2. 夯实基础js - 语句篇
  3. 推荐一款免费国产远程办公神器ToDesk,TeamViewer完美替代品
  4. db2插入的时候怎么自增_3篇长文讲“自增ID”,大部分人仍然搞错了!?
  5. java返回ajax的请求值
  6. No_16_0225 Java基础学习第六天
  7. pat A1032:sharing 题解(简单静态链表)
  8. 有DMX512协议控制的整套硬件解决方案吗?来看一下,舞台灯光同步视频播放DMX控制台
  9. 嵌入式 职位描述 职位要求
  10. 无向图的极大团、最大团(Bron-Kerbosch算法)
  11. Office2021安装全教程
  12. 3D设计软件中怎么快速建模?浩辰3D快速建模教程
  13. mysql config.xml_generatorConfig-mysql.xml中连接数据库的正确书写方式。
  14. 单元测试的必要性?一文聊聊单元测试
  15. 痞子衡嵌入式:可通过USB Device Path来唯一指定i.MXRT设备进行ROM/Flashloader通信
  16. From Big to Small
  17. 计算机仿真的理论依据,复杂系统的理论依据
  18. odoo小程序商城概览(睿鸥商城)
  19. 安装部署halo博客
  20. 分布式存储系统的分类

热门文章

  1. linux cat时间段,Linux Cat命令及使用详解时间
  2. 【Hive】删除表(drop、truncate)
  3. Porting-Buffer
  4. linux重启python服务_linux重启服务命令
  5. 电脑如何录制视频?分享两种电脑录屏的方法
  6. oracle虚拟内存命令,资源供给:内存和虚拟内存
  7. python 滑动验证码_python:TX滑动验证码识别方案一
  8. php生成游客id_PHP根据用户ID生成唯一的邀请码 | 剑花烟雨江南
  9. 程序切片(定义+用途)
  10. 食品商城网站设计—食品商城购物网站(8页) HTML+CSS+JavaScript 静态网页的制作