faad2交叉编译——aac解码为pcm,解决faad单通道转双通道问题

FAAD是比较成熟高效的开源AAC解码库,这里用于解码AAC生成PCM数据,用于音频播放。这里因为faad库,会将单通道转化为双通道踩了些坑,所以记录一下。

我使用的是2.11.0版本,貌似往前的版本没有使用CMake,需要configure配置编译

1.源码编译

使用git拉取

bash 复制代码
git clone https://github.com/knik0/faad2.git

因为是交叉编译,所以创建了一个cfg_file_path,其中设置一些参数,cfg_file_path内容如下:

bash 复制代码
##################################
# 配置 交叉编译
#################################

set(CMAKE_SYSTEM_NAME Linux)    #设置目标系统名字
set(CMAKE_SYSTEM_PROCESSOR aarch64) #设置目标处理器架构
set(CMAKE_C_COMPILER aarch64-ca53-linux-gnu-gcc-10.4.0)#设置交叉编译器
add_compile_definitions(DISABLE_SBR) #禁止SBR和DECODER
add_compile_definitions(LC_ONLY_DECODER)

指定cfg_file_path进行编译,编译产物输出到output目录

bash 复制代码
mkdir output
/usr/bin/cmake  -DCMAKE_TOOLCHAIN_FILE=cfg_file_path -Boutput/
cd output
make
sudo make install

这样编译完成后在output下就会有libfaad.so,libfaad.so.2,libfaad.so.2.11.1,可以拷贝到开发板即可

2.测试代码

c 复制代码
/** 
 * 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;  
    }  


    NeAACDecConfigurationPtr config = NeAACDecGetCurrentConfiguration(decoder);
    config->defObjectType = LC;
    config->defSampleRate = 8000;
    // config->defObjectType = HE_AAC;
    config->outputFormat = FAAD_FMT_16BIT;  //位深度设置成16bit
    config->downMatrix = 0;
//    源码部分如下:
//    if (*samplerate <= 24000 && (hDecoder->config.dontUpSampleImplicitSBR == 0))
//    {
//        *samplerate *= 2;
//        hDecoder->forceUpSampling = 1;
//    } else if (*samplerate > 24000 && (hDecoder->config.dontUpSampleImplicitSBR == 0)) {
//        hDecoder->downSampledSBR = 1;
//    }
//    dontUpSampleImplicitSBR 设置成1,可以禁止NeAACDecInit时,采样率(小于等于24000时)翻倍的问题
    config->dontUpSampleImplicitSBR = 1;
    NeAACDecSetConfiguration(decoder, config);
  
    //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 * 2, ofile);      //2个通道  
            fflush(ofile);  
        }          
        data_size -= size;  
        input_data += size;  
    }      
  
    NeAACDecClose(decoder);  
  
    fclose(ifile);  
    fclose(ofile);  
  
    return 0;  
}  

注意这里很多博客给的都是错的,frame_info.samples * frame_info.channels * 2 ,这里需要乘以2,因为位宽是16bit,而一个字节是8bit。在使用单通道的情况下,这里如果不乘以2,会导致音频加速等问题

3.程序运行

使用下面的编译指令编译,拷贝可执行文件和动态库到板子里。

c 复制代码
aarch64-ca53-linux-gnu-gcc-10.4.0 main.c -o main -lfaad -L/usr/local/lib/
./main_aarch high_temperature_shut_down.aac test.pcm

动态库拷贝到板子的/usr/lib下后,在板子上运行可执行文件。

4.关于单/双通道

faad这个在内部因为一些音频算法,开启一些编译选项之后,会将通道数乘以2,导致输出的音频通道数总是2,达不到预期效果,要解决这个问题,需要做以下两点

1)参考第二点测试代码,需要乘以2,否则音频加速

2)参考第一点中的编译配置选项,取消一些编译配置选项,防止通道乘以2

相关推荐
A小辣椒21 小时前
TShark:Wireshark CLI 功能
linux
A小辣椒1 天前
TShark:基础知识
linux
AlfredZhao1 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334662 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪2 天前
linux 拷贝文件或目录到指定的位置
linux
大树883 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质3 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式