linux下使用libmad库实现mp3文件的解码、播放
来源:互联网 发布:微拍网站源码带采集 编辑:程序博客网 时间:2024/05/22 16:58
linux下使用libmad库实现mp3文件的解码、播放
目录(?)[+]
- 准备工作
- 解码流程
- 播放
- 遇到的问题
据说这个更新到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、配置输入回调函数、输出回调函数、用户数据、筛选回调函数、错误回调函数、消息回调函数,参考初始化函数源代码。
回调函数中,输入(读取原始音频数据)、输出(对解码后的音频数据进行处理)是必需的。
- 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;
- }
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函数打开,那么可以定义一个对此描述的数据结构:
- 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;
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),此处贴出来大概的流程
- /*
- * 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;
- }
/* * NAME: decode->error() * DESCRIPTION: handle a decoding error */staticenum 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;}
错误处理的返回值定义如下:
- 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 */
- };
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开始解码,支持两种同步、异步两种运行方式
- enum mad_decoder_mode {
- MAD_DECODER_MODE_SYNC = 0,
- MAD_DECODER_MODE_ASYNC
- };
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文件的解码、播放
- linux下使用libmad库实现mp3文件的解码、播放
- linux 基于alsa 使用libmad 解码库实现MP3文件的播放
- MyMinimad ── Linux下用libmad写的mp3解码播放程序
- MyMinimad ── Linux下用libmad写的mp3解码播放程序(二)
- MyMinimad ── Linux下用libmad写的mp3解码播放程序
- 在 Fedora 5 Linux 下实现了一个基于 libmad 的 MP3 流媒体播放器
- libmad+alsa 实现arm下mp3播放
- 让终端支持播放mp3,移植mp3解码库libmad和madplay到嵌入式linux
- 关于libmad开源mp3音频解码库的使用
- 使用LibMad解码MP3,Windows上播放MP3,MP3转WAV实例代码
- symbian-使用libmad播放mp3
- symbian-使用libmad播放mp3
- windows下 利用CoreAudio,Libmad,和3D环绕音效原理实现的MP3播放器
- 基于 libmad 的简单 MP3 流媒体播放器的实现
- 基于 libmad 的简单 MP3 流媒体播放器的实现
- 基于 libmad 的简单 MP3 流媒体播放器的实现
- 基于 libmad 的简单 MP3 流媒体播放器的实现
- hibernate框架的简单实例
- Keras实现小数量集图片分类——6类别Birds数据集分类
- 【POJ】3040
- SpringBoot中配置使用Druid数据库连接池
- 重定位和链接脚本
- linux下使用libmad库实现mp3文件的解码、播放
- 过滤器和拦截器
- ubuntu16.04下udev权限问题
- 328. Odd Even Linked List
- 关于后缀表达式的转换
- vim快捷键使用
- 正则表达式
- Unity之图片轮播组件实现
- 无名信号量实现相关进程同步