經過這幾天查資料,翻代碼,這里總結一下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]; //存放決議之后的pcm
static 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);
}
#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;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/233946.html
標籤:其他
上一篇:使用位元組流復制圖片和視頻
下一篇:C語言 | 函式實作比較大小
