# mp3-decoder **Repository Path**: Jumping99/mp3-decoder ## Basic Information - **Project Name**: mp3-decoder - **Description**: 使用C++编写的基于libmad封装的mp3解码器 - **Primary Language**: C++ - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2024-11-05 - **Last Updated**: 2025-04-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 基于libmad封装的MP3解码器 ### 介绍 基于libmad封装的mp3解码器,使用了多线程的方式,输入源为文件路径,输出为PCM音频数据。采用分块解码, 块大小可配置,以便在小内存设备上使用。 ### 如何使用 此仓库为解码器例程,解码器本体为`MP3Decode`文件夹,移植到自己的项目只需要拷贝此文件夹到工程中即可。 如果你没有自己安装libmad,可以使用`libmad`文件夹,此为作者移植过的libmad,下文介绍。 ### 附加的libmad 附加的libmad版本为`0.15.1b`,是经过移植的,删除了部分依赖进程的功能,可以用于MCU平台。 当然也可以在PC上使用,不过PC上可以直接使用完整版,自行编译原本的libmad源码,或者使用包管理器下载。 然后直接作为库链接进来。 ```shell sudo apt install libmad0-dev ``` ### 根据不同平台配置附加的libmad libmad提供了针对不同平台的底层汇编运算代码,如果你的平台是其中之一,则可以选择对应的 汇编代码来优化解码速度。 在附加的libmad的头文件`fixed.h`中,可以看到诸如以下的代码块 ```c # elif defined(FPM_INTEL) // X86架构支持的汇编 # if defined(_MSC_VER) # pragma warning(push) # pragma warning(disable: 4035) /* no return value */ static __forceinline mad_fixed_t mad_f_mul_inline(mad_fixed_t x, mad_fixed_t y) { enum { fracbits = MAD_F_FRACBITS }; __asm { mov eax, x imul y shrd eax, edx, fracbits } // .... ``` 类似的还有`FPM_ARM`、`FPM_MIPS`和`FPM_DEFAULT`等,最后一个`FPM_DEFAULT`是纯C语言实现的, 所有CPU架构都可以使用,如果你的CPU架构不在其中(如esp32),则可以使用这个。 在附加的libmad的头文件`config.h`的末尾设置对应的宏定义即可 ```c #define FPM_DEFAULT ``` ### 选择解码器的底层接口 解码器使用了信号量、多线程和文件系统,为了避免在移植时不必要的麻烦,因此解码器中使用了 一个中间层解耦了这些API。解码器已对接了一些常用的API,可以直接使用。也可以自己实现其他的API对接。 #### 选择文件系统API 解码器中已支持的文件系统API有`FatFs`、`posix`和`stdio`,只需要在解码器配置头文件`decoder_conf.h` 中,设置`DECODER_FS`宏为对应的值即可。 #### 选择操作系统API 解码器中已支持的操作系统API有`FreeRTOS`和`posix`,主要使用到了操作系统的**信号量**、**多线程**和**延时休眠** 功能。只需要在解码器配置头文件`decoder_conf.h`中,设置`DECODER_THREAD`宏为对应的值即可。 ### 解码器方法说明 #### 1.打开mp3文件`open` ```cpp bool MP3Decoder::open(const char *path); ``` **功能**: 打开mp3文件并进行MP3帧头解析。 **参数**`path`: mp3文件路径。 **返回值**: `true`成功, `false`失败。 打开文件成功后即可获取**音频时长**、**采样率**等信息,且解码线程立即开始解码第一帧。 #### 2.获取解码数据帧`readDecodeFrame` ```cpp uint8_t *MP3Decoder::readDecodeFrame(void); ``` **功能**: 阻塞获取解码后的pcm数据。 **返回值**: 指向数据缓存区指针,可以直接交给声卡播放,使用完需要使用`delete[]`释放。 当缓存区没有未读取的数据帧时,会阻塞直到新的数据帧解码完成。且如果一直未读取解码完成缓存区中的数据, 则解码过程也会被阻塞,可以用来实现*播放暂停*的功能,只要不读取,下一帧解码就不会进行。 #### 3.设置播放时间点`setCurrent` ```cpp void MP3Decoder::setCurrent(uint32_t _destSec); ``` **功能**: 设置解码时间点。 **参数**`_destSec`: 解码的时间点(秒)。 #### 4.关闭解码器`close` ```cpp void MP3Decoder::close(void); ``` **功能**: 关闭解码器并释放资源。 任何时候都可以调用此方法来停止解码,解码器被析构时也会被调用。 #### 5.一些get方法 ```cpp // 获取当前解码时间点(秒) inline int16_t MP3Decoder::getCurrrentSec(void); // 获取当前音频总时长(秒) inline uint16_t MP3Decoder::getTotalSec(void); // 获取当前音频采样率(Hz) inline uint32_t MP3Decoder::getRate(void); // 获取当前音频声道数(1或2) inline uint8_t MP3Decoder::getChannels(void); // 获取mp3解码后的数据帧大小 inline uint16_t MP3Decoder::getFrameSize(void); ```