使用FAAD库解码AAC实例及 及 faad解码后的通道数不正确的问题

使用FAAD解码AAC音频为PCM数据流程可以参考下面的文章

http://blog.csdn.net/gavinr/article/details/6959198#reply

/**
 * 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;
} <pre name="code" class="cpp">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)) 

我们看看在neaacdec.h 文件中该结构体的定义

现在解决这个问题就简单了,初始化前把参数dontUpSampleImplicitSBR设置为1即可。

NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder);
	conf->defObjectType = LC;
	conf->defSampleRate = 8000; //real samplerate/2
	conf->outputFormat = FAAD_FMT_16BIT ; //
	conf->dontUpSampleImplicitSBR = 1;
<p>	NeAACDecSetConfiguration(decoder, conf);</p><p>
</p>

最后吐槽一下。在从官网下载的faad 说明文档 对NeAACDecConfiguration 这个结构体说明,

居然没有dontUpSampleImplicitSBR这个成员,太坑爹了

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-01 21:31:14

使用FAAD库解码AAC实例及 及 faad解码后的通道数不正确的问题的相关文章

解码aac,并生成wav文件

小程在讲多媒体的编码格式时,详细介绍过pcm跟aac等概念.简单来说,pcm是没有压缩的数字信号,可以直接用于音频输出,而aac则是一种音频编码格式,需要解码后才能用于音频输出. aac编码格式,已经是一种很常见的音频编码格式,硬件设备(比如电脑芯片.手机.其它终端设备)都集成了aac的解码功能,而且有些系统还提供了调用硬件解码的接口,比如iOS上的AudioConverterRef接口.Android上的MediaCodec接口等. 从性能的角度,使用硬件解码是最佳选择,但如果从通用的角度,使

视频编解码学习之二:编解码框架

第四章 视频编码基础 1. 压缩码流 语法:码流中各个元素的位置关系 01001001… 图像编码类型(01),宏块类型(00),编码系数1001等 语义:每个语法元素所表达的意义. 例如:图像编码类型 2. 编码层次 序列(Sequence) 图像组(Group of Pictures,GOP) 图像(Picture) 条带(Slice) 宏块(Macroblock,MB) 块(Block) 3. 码流结构 3. PB帧编码 4. 序列编码对象 (1)IBBP序列 序列:一段连续编码的并具有相

ORACLE 11G在同一台linux服务器从实例1全库导入到实例2上

前期导出命令: [root@powerlong4 ~]# su - oracle [oracle@powerlong4 ~]$ export ORACLE_SID=pt1; [oracle@powerlong4 ~]$ expdp \'sys/systestpd as sysdba\' DIRECTORY=dir_dump_t3 FULL=YES DUMPFILE=expdpfull_pd_20150529_02.dmp ...... 1,开始导入 先在实例2上建立管道目录: [[email p

mysql数据库建库建表实例

一.实例. drop database if exists school; //如果存在SCHOOL则删除create database school; //建立库SCHOOLuse school; //打开库SCHOOLcreate table teacher //建立表TEACHER(    id int(3) auto_increment not null primary key,    name char(10) not null,    address varchar(50) defa

动态库.so调用实例

代码业务比较复杂这里就不细说,主要记录下动态库的编译以及调用过程: 1. 创建动态链接库 gcc -shared -fPIC paraDocxml.c  -o libmyxml.so 关于 -fPIC 参考这边笔记 http://blog.csdn.net/knight1840/article/details/47206855 可以看到,当前目录下多了一个文件libmyxml.so 接着生成可执行文件: gcc TestFileOP.c   -lmyxml    -L.   -lxml2   -

RSA加解密 私钥加密公钥解密 私加公解 &amp;&amp; C++ 调用openssl库 的代码实例

前提:秘钥长度=1024 ============================================== 对一片(117字节)明文加密  私加 ============================================== // 私钥加密 std::string rsa_pri_encrypt(const std::string &clearText, std::string &pubKey) { std::string strRet; BIO *keybio

SQlite-数据库的访问实例(转)

1.DBAdapter类: 1 package com.cnzcom.android.quickdial; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import an

python学习--标准库之os 实例(3)

#!/usr/bin/env python3 # -*- coding: utf-8 -*- #列出当前目录下文件的大小和创建日期及文件名,相当于ls -l命令 from datetime import datetime import os pwd = os.path.abspath('.') print(' Size Last Modified Name') print('------------------------------------------------------------'

sklearn库kmeans实现实例

# -*- coding: utf-8 -*-from sklearn.cluster import KMeansfrom sklearn.externals import joblibimport numpyimport pandas as pddef kmeans(inputfile,n): final = open('data/dataset.csv' , 'r') data = [line.strip().split(',') for line in final] feature = [