使用FAAD庫解碼AAC例項及 及 faad解碼後的通道數不正確的問題
使用FAAD解碼AAC音訊為PCM資料流程可以參考下面的文章
/** * faaddec.c * use faad library to decode AAC, only can decode frame with ADTS head */ #include <stdio.h> #include <memory.h> #include "faad.h" #define FRAME_MAX_LEN 1024*5 #define BUFFER_MAX_LEN 1024*1024 void show_usage() { printf("usage\nfaaddec src_file dst_file"); } /** * fetch one ADTS frame */ int get_one_ADTS_frame(unsigned char* buffer, size_t buf_size, unsigned char* data ,size_t* data_size) { size_t size = 0; if(!buffer || !data || !data_size ) { return -1; } while(1) { if(buf_size < 7 ) { return -1; } if((buffer[0] == 0xff) && ((buffer[1] & 0xf0) == 0xf0) ) { size |= ((buffer[3] & 0x03) <<11); //high 2 bit size |= buffer[4]<<3; //middle 8 bit size |= ((buffer[5] & 0xe0)>>5); //low 3bit break; } --buf_size; ++buffer; } if(buf_size < size) { return -1; } memcpy(data, buffer, size); *data_size = size; return 0; } int main(int argc, char* argv[]) { static unsigned char frame[FRAME_MAX_LEN]; static unsigned char buffer[BUFFER_MAX_LEN] = {0}; char src_file[128] = {0}; char dst_file[128] = {0}; FILE* ifile = NULL; FILE* ofile = NULL; unsigned long samplerate; unsigned char channels; NeAACDecHandle decoder = 0; size_t data_size = 0; size_t size = 0; NeAACDecFrameInfo frame_info; unsigned char* input_data = buffer; unsigned char* pcm_data = NULL; //analyse parameter if(argc < 3) { show_usage(); return -1; } sscanf(argv[1], "%s", src_file); sscanf(argv[2], "%s", dst_file); ifile = fopen(src_file, "rb"); ofile = fopen(dst_file, "wb"); if(!ifile || !ofile) { printf("source or destination file"); return -1; } data_size = fread(buffer, 1, BUFFER_MAX_LEN, ifile); //open decoder decoder = NeAACDecOpen(); if(get_one_ADTS_frame(buffer, data_size, frame, &size) < 0) { return -1; } //initialize decoder NeAACDecInit(decoder, frame, size, &samplerate, &channels); printf("samplerate %d, channels %d\n", samplerate, channels); while(get_one_ADTS_frame(input_data, data_size, frame, &size) == 0) { // printf("frame size %d\n", size); //decode ADTS frame pcm_data = (unsigned char*)NeAACDecDecode(decoder, &frame_info, frame, size); if(frame_info.error > 0) { printf("%s\n",NeAACDecGetErrorMessage(frame_info.error)); } else if(pcm_data && frame_info.samples > 0) { printf("frame info: bytesconsumed %d, channels %d, header_type %d\ object_type %d, samples %d, samplerate %d\n", frame_info.bytesconsumed, frame_info.channels, frame_info.header_type, frame_info.object_type, frame_info.samples, frame_info.samplerate); fwrite(pcm_data, 1, frame_info.samples * frame_info.channels, ofile); //2個通道 fflush(ofile); } data_size -= size; input_data += size; } NeAACDecClose(decoder); fclose(ifile); fclose(ofile); return 0; }
之前用FAAC編碼了一段PCM資料(源資料是16000取樣率,單通道,16位取樣),編碼時設定的引數也是16000取樣率,單通道,16位取樣。。。然後用FAAD解碼時,在NeAACDecInit的時候,是先在之前編碼好的aac資料(ADTS頭封裝的)上往buffer中寫入一幀的含ADTS頭的資料,然後傳入到NeAACDecInit()中初始化解碼器,但不知道為什麼,返回的取樣率總是32000,通道數總是2,我已經檢視過編碼後的資料,其中與取樣率、通道數相應的位,表示的就是16000取樣率和1通道。。
後來跟蹤原始碼才發現 FAAD的NeAACDecInit() 原始碼,問題出現在這裡
long NEAACDECAPI NeAACDecInit(NeAACDecHandle hpDecoder, unsignedchar *buffer, unsignedlong buffer_size, unsignedlong *samplerate, unsignedchar *channels) { #if (defined(PS_DEC) || defined(DRM_PS)) /* check if we have a mono file */ if (*channels == 1) { /* upMatrix to 2 channels for implicit signalling of PS */ *channels = 2; // 這裡channels改變為2,why? } #endif hDecoder->channelConfiguration = *channels; #ifdef SBR_DEC /* implicit signalling */ if (*samplerate <= 24000 && (hDecoder->config.dontUpSampleImplicitSBR == 0)) { *samplerate *= 2; // samplerate 變為32000 hDecoder->forceUpSampling = 1; }
else if (*samplerate > 24000 && (hDecoder->config.dontUpSampleImplicitSBR == 0)) {
hDecoder->downSampledSBR = 1;
}
#endif
}
上面那些巨集,在原始碼中貌似已經定死了,不是通過條件編譯生成的,
也就是 PS_DEC 和 SBR_DEC是define過的...也不是通過./configure 的時候生成的...
再仔細看上面程式碼的if語句
if (*samplerate <= 24000 && (hDecoder->config.dontUpSampleImplicitSBR == 0))
只要讓 hDecoder->config.dontUpSampleImplicitSBR 不為0 不就OK嗎?
我們看看在neaacdec.h 檔案中該結構體NeAACDecConfiguration 的定義
現在解決這個問題就簡單了,初始化前把引數dontUpSampleImplicitSBR設定為1即可。
NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder);
conf->defObjectType = LC;
conf->defSampleRate = 8000; //real samplerate/2
conf->outputFormat = FAAD_FMT_16BIT ; //
conf->dontUpSampleImplicitSBR = 1;
NeAACDecSetConfiguration(decoder, conf);
最後吐槽一下。在從官網下載的faad 說明文件 對NeAACDecConfiguration 這個結構體說明,
居然沒有dontUpSampleImplicitSBR這個成員,太坑爹了
音視訊開發訓練營公眾號 音視訊開發訓練營QQ群: 576912843