经过这几天查资料,翻代码。这里总结一下lame解析MP3的过程以及遇到问题。

开发环境是Linux下c++开发

使用lame解析MP3,主要包含以下几个头文件。

#include <lame.h>
#include <timestatus.h>
#include <set_get.h>
#include <get_audio.h>
#include <lame_reader_def.h>

目前网上查到有关lame 解析MP3的资料不多。大部分是使用lame压缩MP3格式。大多人用libmad解码MP3。

唯一查到的几个有关lame解析MP3的demo格式雷同,兼容性很差。在测试过程中遇到过不兼容的情况。

这种方式我也把方法列出来。主要使用mpglib_interfac.c文件中的hip_decode1_headers(……),以及hip_decode(......)方法。

点进去看一下就知道其实他们都是对hip_decode1_headerB()方法的封装,只不过前者需要提供mp3data_struct结构体指针。方便将mp3的数据格式读取出来,做一些前期工作。后者只是直接就开始解析了。

源代码在公司内网中,取不出来,所以以下代码都是手敲复制出来的,可能会拼写错。别指望照搬过去就能直接运行,看懂先。

#include <lame.h>
#include <string.h>
//定义数据
FILE* m_filename;
hip_t m_hip;
lame_t m_lame_gfp;
mp3data_struct m_mp3data; //存储MP3的各类数据,采样率,通道数,帧数等short int m_pcm_1[9000];
short int m_pcm_r[9000];unsigned char m_mp3_buffer[9000]; //mp3文件中读取解析之前的数据缓存
int sampleRate; //采样率
int channelCount; //通道数//初始化阶段
m_lame_gfp = lame_init();
lame_set_decode_only(m_lame_gfp,1);
m_hip = hip_decode_init();m_filename = fopen("voice.MP3","rb");/**
这一段的逻辑就是,循环从文件中读取16个字节出来,然后交给hip_decode1_header1函数解析。
m_hip中会保存上一次解析的位置,所以直接不断的丢一些数据给hip_decode1_header1函数就行。
当成功解析出一个帧头的数据时,实际上就得到了整个MP3的采样率和通道数了。大部分MP3每一帧的信息是一样的。当然也不是全部的。
所以说对大对数MP3是兼容的。这里成功解析出来之后,m_mp3data.header_parsed值会变成1,因此可退出这个过程。
至于每次多输入一些数据也是可以的,例如将16设置成210,418都可以。
*/
int reslen = -1;
do{reslen = fread(m_mp3_buff,,sizeof(char),16,m_filename);hip_decode1_header1(m_hip,m_mp3_buffer,reslen,m_pcm_l,m_pcm_r,&m_mp3data);sampleRate = m_mp3data.samplerate;channelCount = m_mp3data.stereo;
}while(!m_mp3data.header_parsed && relen>0);fseek(m_filename,0,SEEK_SET); //将文件指针拨回起点。//循环解析MP3音频数据阶段
int iread;
unsigned char data[8192]; //存放解析之后的pcmstatic FILE *output_file = fopen(output.pcm,"W+");/**
这里逻辑其实和上面的解析帧头是一样的。循环向hip_decode函数中投喂MP3数据,经过解析之后的pcm数据放在m_pcm_l以及m_pcm_r中。
hip_decode()返回值iread是采样数,不是字符长度,这点要注意。一般一个采样点是16位长,2个字节大小,与short int的长度一致。*/while(reslen = fread(m_mp3buff,sizeof(char),418,m_filename)){if(reslen > 0){iread = hip_decode(m_hip,m_mp3_buffer,reslen,m_pcm_l,m_pcm_r);if(iread>0){unsigned j = 0;for(int i = 0;i<sample;i++){ //双通道的话就将采样点交叉合并在一起。memcpy(data + j,m_pcm_l + i , 2);j+=2;if(m_mp3data.stereo == 2){memcpy(data + j,m_pcm_r + i , 2);j+=2;}}}}// 这里就可以将data中的数据写入文件中,或者输入至播放设备中。fwrite(data,sizeof(short)*m_mp3dtat.stereo,sample,output_file);}if(m_hip){hip_decode_exit(m_hip);
}if(m_filename){fclose(m_filename);
}
if(output_file){fclose(output_file);
}
以上代码是我制作解析MP3的程序的第一版本,能暴力解析大部分MP3.直到有一天一个大佬问我这个解析程序做的怎么样,他那边要参考一下我的解析过程,然后甩给我一个12m的MP3,说,试试解析这个MP3。这MP3能在各个播放器上正常播放。
很顺利的解析出来的pcm只有400k大小。显然是失败了,一般44100的Mp3解析出来的pcm是原来文件的2-4倍大小。解析过程一直报这个问题:(n行)。
htp: bitstream problem, resyncing skipping xxxx byte...   
网上找了一圈也没找到原因,没办法只有啃源代码,再加一点点的揣测。
大概的意思就是找到下一帧帧头,之前跳过了多少个字符数据。如果说MP3跳过一两次,百来个字符,那都算正常。
但是大佬给我的MP3解析的时候几乎跳过了99%的字符。显然是解析失败了。
这个地方卡了我一整天。剖析源代码。分析MP3格式。
在网上查了很多资料,得到一个结论。
在shell中直接通过命令lame -decode 将MP3转WAV时是能正常将上述的有问题的MP3转化的。因为,命令行的入口函数调用的方法就不是hip_decode_init()  ->  hip_decode_header()  ->  hip_decode()  -> hip_decode_exit()这个过程。
而是采用另一套流程。这里我就直接将相关的代码列出来:

#include <lame.h>
#include <timestatus.h>
#include <set_get.h>
#include <get_audio.h>
#include <lame_reader_def.h>
//定义变量
lame_t m_lame_gfp;
DecoderProgress m_dp;
int sampleRate; //采样率
int channelCount; //通道数///初始化阶段
int lame_err = 0;
m_lame_gfp = lame_init();
if(m_lame_gfp == NULL){//LOGE("初始化失败。");return -1;
}
lame_set_write_id3tag_automatic(m_lame_gfp,0);
lame_set_out_samplerate(m_lame_gfp,441000); //设置输出的pcm 的采样率
lame_set_decode_only(m_lame_gfp,1);lame_err = init_infile(m_lame_gfp,"voice.mp3"); //初始化读取文件
if(lame_err < 0){//LOGE("初始化失败。");return -1;
}lame_err = lame_init_params(m_lame_gfp);
if(lame_err < 0){//LOGE("fail");return -1;
}/**
set_get.c中包含了各类获取MP3音频信息的函数,直接调用即可。下面就是获取采样率和通道数的函数。
可以查看源代码中还有获取其他信息的函数。
*/
sampleRate = lame_get_out_samplerate(m_lame_gfp);
channelCount = lame_get_num_channels(m_lame_gfp);//解析过程
static FILE *output_file = fopen(output.pcm,"W+");
short int pcm_buffer[2][1152];
int iread = 0;
unsigned char data[8192]; //存放解析之后的pcm/**
这里一般是以帧为单位,一次循环输出一帧数据。
*/
do{iread = get_audio16(m_lame_gfp,pcm_buff);if(m_dp != NULL){decoder_progress(m_dp,&global_decode.mp3input,iread);}if(lame_get_num_channels(m_lame_gfp) !=2 ){memcpy(data,pcm_buffer[0],iread);}else{unsigned int j = 0;for(int i = 0;i < iread ; i++ , j += 4){memcpy(data + j , pcm_buffer[0] + i , 2);memcpy(data + j + 2, pcm_buffer[1] + i , 2);};}// 这里就可以将data中的数据写入文件中,或者输入至播放设备中。fwrite(data,sizeof(short)*m_mp3dtat.stereo,sample,output_file);}while(iread > 0);close_infile(); //关闭文件
if(output_file){fclose(output_file);
}
if(m_dp){decoder_progress_finish(m_dp);m_dp = NULL;
}
if(m_lame_gfp){lame_close(m_lame_gfp);m_lame_gfp = NULL;
}

使用lame解码mp3相关推荐

  1. 基于lame对mp3进行分割的简单实现

    基于lame对mp3进行分割的简单实现 一.思路: 利用lame编解码功能,在读取帧时检查下时间即可. 二.实现 1. 根据帧数计算时间: static float my_lame_get_curre ...

  2. android ios语音转码,iOS 音频转码 使用lame转为MP3格式

    由于AVAudioRecorder不能录制编码为MP3,所以就需要我们将录音后的音频文件格式进行转换(注意:AV Foundation和Core Audio提供对MP3数据解码的支持,但是不提供对其进 ...

  3. android mp3 编码,Android 如何采用Lame编码器编码mp3文件

    这篇文章会基于下面3个问题来展开讲解. 1.什么是Lame? 2.为什么采用Lame? 3.Lame在Android应用上如何使用? 一.什么是Lame LAME is a high quality ...

  4. android pcm格式转mp3,java – android最快的解码mp3到pcm数据的方法

    在我的应用程序中,我需要将mp3文件解码为pcm缓冲区.这是很多数据,所以当我读取并解码时,我将其下采样到单声道22050Hz. 它的工作速度很慢,30秒用于在运行模式下解码3分钟的歌曲,在调试模式下 ...

  5. Ubuntu下pyglet无法解码MP3

    各种尝试试了下,均不行,结果 最后找到的答案是如果是32位操作系统,似乎除了改为64位外无其他办法了,期待后续升级pyglet的某一个版本可行吧. 来源:https://stackoverflow.c ...

  6. linux下用lame压缩mp3

    [size=large]参数如下,--quiet不显示进度,--mp3input输入格式为mp3,--abr为abr格式,64是采样率 命令行调用如下 lame --quiet --mp3input ...

  7. 基于STM32音频解码MP3——vs1053

    基于正点原子教程 VS1053简介: 1.该模块采用VS1053B 作为主芯片 2.支持:MP3/WMA/OGG/WAV/FLAC/MIDI/AAC 等音频格式的解码 3.支持:OGG/WAV 音频格 ...

  8. Android录音使用LAME转MP3,附aar包

    直接上使用代码 aar包下载地址 MP3Recorder mp3Recorder = new MP3Recorder(); // mp3文件保存位置 File mp3SaveFile = new Fi ...

  9. [原创]桓泽学音频编解码(7):MP3 和 AAC 中huffman解码原理,优化设计与参考代码中实现...

    1 不同标准中的huffman解码原理 1.1标准MP3的huffman解码原理 在MP3即mpeg-1 audio标准中,无噪声编码模块的输入是一组576个己量化的频谱数据.无噪声编码首先对频谱进行 ...

最新文章

  1. C#数据结构与算法揭秘15
  2. windows下tomcat日志输出至catalina.out文件
  3. JZOJ 5678. 【GDOI2018Day2模拟4.21】果树
  4. Linux进程间通信——管道
  5. AI繁荣下的隐忧——Google Tensorflow安全风险剖析
  6. 通讯模块板载天线设计方法
  7. element里面popover里面的高度_五斗柜的高度一般是多少 五斗柜放在什么位置好
  8. C++关键字--volatile
  9. const应用(C、C++)
  10. 【Arcpy】Python in ArcGIS
  11. linux进程加载和运行,linux进程管理之可执行文件的加载和运行
  12. python库之airtest和pocoui
  13. ApacheCN 翻译/校对/笔记整理活动进度公告 2019.9.27
  14. java用下划线分开字母和数字_数字文字中的Java 7下划线
  15. pdf合并页面大小不一样
  16. sqoop connect oracle,Sqoop从Oracle导出数据出错:The Network Adapter could not establish the connection...
  17. 【自学】张量、维度、多维矩阵、dim、torch.argmax()
  18. Redis 总结 —— 2022/2/6
  19. 最新二开南风表情包小程序+前后端去授权版/最火表情包小程序源码
  20. DSP学习(8)—— linker.cmd文件解析

热门文章

  1. HTML5篇学习笔记
  2. 抖音seo账号矩阵霸屏系统源码/账号矩阵系统搭建部署
  3. 通过网线和EasyFatAP软件切换AP工作模式(瘦版切换胖版)
  4. Hand in glove 密切配合
  5. 帕斯卡三角形,二项式定理
  6. 机器学习算法[9]--集成方法之XGBoost原理详解及XGBoost库实现
  7. 嵌入式硬件: EEPROM与EPROM
  8. 最近最开心的一件事情
  9. python中arch模块_在Arch下安装pip
  10. 聊聊去年最火的前端库zx