1. 程式人生 > >使用FAAD庫解碼AAC例項及 及 faad解碼後的通道數不正確的問題

使用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