音频demo:使用fdk-aac将PCM数据编码成aac数据

1、README

a. 编译
编译demo

本demo是使用的开源项目fdk-aac将PCM数据编码成aac音频文件。由于提供的.a静态库是在x86_64的机器上编译的,所以默认情况下仅支持该架构的主机上编译运行。

$ make
编译fdk-aac(可选)

如果想要在其他架构的CPU上编译运行,可以使用以下命令(脚本)编译fdk-aac[下载地址1][下载地址2]得到相应的库文件进行替换:

#!/bin/bashtar xzf fdk-aac-2.0.2.tar.gz
cd fdk-aac-2.0.2/
./configure --prefix=$PWD/_install # --host=arm-linux-gnueabihf CC=arm-linux-gnueabihf-gcc
make -j96
make install
b. 使用
$ ./pcm2aac -h
$ ./pcm2aac --help
$ ./pcm2aac -i ./audio/test_8000_16_1.pcm -r 8000 -b 16 -c 1 -o out_8khz_1ch.aac
$ ./pcm2aac --input_pcmfile=./audio/test_44100_16_2.pcm --sample_rate=44100 --sample_bits=16 --channels=2 --output_aacfile=out_44.1khz_2ch.aac

其中,fdk-aac对输入的编码数据格式做了些说明:网页链接

aac params

c. 参考文章

【格式说明】

  • AAC文件格式解析_cloud 的学习时代-CSDN博客_aac

  • 从零开始写一个RTSP服务器(5)RTP传输AAC_JT同学的博客-CSDN博客

  • 音频编码格式介绍-AAC - 简书

【编码实现】

  • 使用fdkaac编码_程序人生-CSDN博客

  • 【音频编码】AAC编码之FDK AAC_CWB的博客-CSDN博客_fdkaac

d. demo目录架构
.
├── audio
│   ├── out_44.1khz_2ch.aac
│   ├── out_8khz_1ch.aac
│   ├── test_44100_16_2.pcm
│   └── test_8000_16_1.pcm
├── docs
│   ├── AAC文件格式解析_cloud 的学习时代-CSDN博客_aac.mhtml
│   ├── 从零开始写一个RTSP服务器(5)RTP传输AAC_JT同学的博客-CSDN博客.mhtml
│   ├── 使用fdkaac编码_程序人生-CSDN博客.mhtml
│   ├── 【音频编码】AAC编码之FDK AAC_CWB的博客-CSDN博客_fdkaac.mhtml
│   └── 音频编码格式介绍-AAC - 简书.mhtml
├── include
│   └── fdk-aac
│       ├── aacdecoder_lib.h
│       ├── aacenc_lib.h
│       ├── FDK_audio.h
│       ├── genericStds.h
│       ├── machine_type.h
│       └── syslib_channelMapDescr.h
├── lib
│   └── libfdk-aac.a
├── main.c
├── Makefile
└── README.md

2、主要代码片段

main.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>#include "fdk-aac/aacenc_lib.h"//#define DEBUG(fmt, args...)
#define DEBUG(fmt, args...) 	printf(fmt, ##args)void print_usage(const char *process)
{printf("sample: \n""\t %s -h\n""\t %s --help\n""\t %s -i ./audio/test_8000_16_1.pcm -r 8000 -b 16 -c 1 -o out_8khz_1ch.aac\n""\t %s --input_pcmfile=./audio/test_44100_16_2.pcm --sample_rate=44100 --sample_bits=16 --channels=2 --output_aacfile=out_44.1khz_2ch.aac\n",process, process, process, process);
}int main(int argc, char *argv[])
{/* 输入/输出文件 */FILE *fpPcm = NULL;FILE *fpAac = NULL;char pcmFileName[128] = {0};char aacFileName[128] = {0};/* PCM参数 */unsigned int u32PcmSampleRate = 0; // 采样率unsigned int u32PcmSampleBits = 0; // 采样位数unsigned int u32PcmChannels   = 0; // 声道数/* aac编码器 */HANDLE_AACENCODER aacEncHandle = NULL; // HANDLE_AACENCODER其实是一个结构体指针AACENC_InfoStruct aacEncInfoSt = {0};AACENC_ERROR aacErrNum = AACENC_OK; // AACENC_OK:0/* 编码相关参数 */unsigned int u32PcmInBufBytes = 0; 	// 编码时需要传入的PCM数据大小(字节数)unsigned int u32AacOutBufMaxBytes = 0; // 编码后得到一帧aac数据最大的大小(字节数)unsigned char *pu8PcmInBuf   = NULL; // 读取pcm并传递进去编码的缓存指针,后面根据编码器传出参数malloc分配unsigned char *pu8AacEncBuf  = NULL; // 编码得到的aac缓存,后面根据编码器传出参数malloc分配/* 判断输入参数 */if(argc == 1){print_usage(argv[0]);return -1;}	/* 解析命令行参数 */char option = 0;int option_index = 0;char *short_options = "hi:r:b:c:o:";struct option long_options[] ={{"help",          no_argument,       NULL, 'h'},{"input_pcmfile", required_argument, NULL, 'i'},{"sample_rate",   required_argument, NULL, 'r'},{"sample_bits",   required_argument, NULL, 'b'},{"channels",      required_argument, NULL, 'c'},{"output_aacfile",required_argument, NULL, 'o'},{NULL,            0,                 NULL,  0 },};while((option = getopt_long_only(argc, argv, short_options, long_options, &option_index)) != -1){switch(option){case 'h':print_usage(argv[0]);return 0;case 'i':strncpy(pcmFileName, optarg, 128);break;case 'r':u32PcmSampleRate = atoi(optarg);break;case 'c':u32PcmChannels = atoi(optarg);break;case 'b':u32PcmSampleBits = atoi(optarg);break;case 'o':strncpy(aacFileName, optarg, 128);break;defalut:printf("Unknown argument!\n");break;}}printf("\n**************************************\n""input: \n""\t file name: %s\n""\t sample rate: %d Hz\n""\t sample bits: %d bits\n""\t channels: %d\n""\t bits per second: %d bps\n""output: \n""\t file name: %s\n""**************************************\n\n",pcmFileName, u32PcmSampleRate, u32PcmSampleBits, u32PcmChannels,u32PcmSampleRate*u32PcmSampleBits*u32PcmChannels, aacFileName);/* 先打开输入/输出文件 */fpPcm = fopen(pcmFileName, "rb");if(fpPcm == NULL){char errMsg[128] = {0};snprintf(errMsg, 128, "open file(%s) error", pcmFileName);perror(errMsg);return -1;}fpAac = fopen(aacFileName, "wb");if(fpAac == NULL){char errMsg[128] = {0};snprintf(errMsg, 128, "open file(%s) error", aacFileName);perror(errMsg);return -1;}/* AAC编码 1/8:打开编码器,传出编码器句柄 */aacErrNum = aacEncOpen(&aacEncHandle, 0, u32PcmChannels);if(aacErrNum != AACENC_OK){printf("Open aac encoder error!\n");goto error_exit1;}/* AAC编码 2/8:配置/初始化编码器 */// 配置编码器 a/b:设置参数aacErrNum  = aacEncoder_SetParam(aacEncHandle, AACENC_AOT, AOT_AAC_LC); 	// Audio object type, 选择输出规格aacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_SBR_MODE, 1); 		// Spectral Band Replication,是否使能SBR技术,-1:自动配置(默认) 0:关闭 1:开启aacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_SAMPLERATE, u32PcmSampleRate); // Audio input data sampling rateaacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_CHANNELMODE, (u32PcmChannels == 1) ? MODE_1 : MODE_2); // 声道模式,还有多种模式,这里只列出2种aacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_CHANNELORDER, 1); 	// 输入音频数据通道排序方案,0: MPEG频道排序(默认) 1: WAVE文件格式通道排序aacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_BITRATEMODE, 5); 		// 比特率模式,0:CBR  1~5:VBR(数值越大动态码率越高)aacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_BITRATE, 128000); 	// 设置比特率大小,只有AACENC_BITRATEMODE设置为静态码率CBR时生效,VBR时忽略aacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_TRANSMUX, TT_MP4_ADTS); // 传输类型,TT_MP4_ADIF/TT_MP4_ADTS/TT_MP4_LATM_MCP1...aacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_AFTERBURNER, 1); 		// “加力燃烧室”,提高音质,0:关闭(默认) 1:开启。官方推荐内存和性能足够的话开启// 配置编码器 b/b:设置到编码器里面去aacErrNum |= aacEncEncode(aacEncHandle, NULL, NULL, NULL, NULL);if(aacErrNum != AACENC_OK){printf("Configure aac encoder error!\n");goto error_exit1;}/* AAC编码 3/8:获取编码器信息,从这里得到输入PCM缓存应该设置多大、输出最大的aac字节数 */aacErrNum = aacEncInfo(aacEncHandle, &aacEncInfoSt);if(aacErrNum != AACENC_OK){printf("Get aac encoder info error!\n");goto error_exit2;}// 根据上面获得的编码器信息得到一些比较重要的参数u32PcmInBufBytes = aacEncInfoSt.frameLength * u32PcmSampleBits/8 * u32PcmChannels;u32AacOutBufMaxBytes = aacEncInfoSt.maxOutBufBytes;DEBUG("PCM should in bytes: %d \t AAC out max bytes: %d\n", u32PcmInBufBytes, u32AacOutBufMaxBytes);/* 根据上面打开编码器信息分配对应大小的缓存 */pu8PcmInBuf  = (unsigned char*)malloc(u32PcmInBufBytes);pu8AacEncBuf = (unsigned char*)malloc(u32AacOutBufMaxBytes);/* 循环从文件中读取PCM数据编码出aac数据写入到文件中 */while(1){/* aac编码一帧数据用到的参数 */AACENC_BufDesc inPcmBufDesc = {0};AACENC_BufDesc outAacBufDesc = {0};AACENC_InArgs inArgs = {0};AACENC_OutArgs outArgs = {0};int inIdentifier = IN_AUDIO_DATA;int outIdentifier = OUT_BITSTREAM_DATA;//int inElsize = 2;//int outElsize = 1;int inElsize = sizeof(INT_PCM); // 参考aacenc_lib.h:260示例int outElsize = sizeof(UCHAR);/* AAC编码 4/8:填充编码器需要的参数,包括编码的pcm数据地址,大小等 */int s32ReadPcmBytes = fread(pu8PcmInBuf, 1, u32PcmInBufBytes, fpPcm);if(s32ReadPcmBytes <= 0){break;}/* AAC编码 5/8:填充编码器需要的参数,包括编码的pcm数据地址,大小等 */inPcmBufDesc.numBufs = 1;inPcmBufDesc.bufs = (void **)&pu8PcmInBuf;inPcmBufDesc.bufferIdentifiers = &inIdentifier;inPcmBufDesc.bufSizes = &s32ReadPcmBytes;inPcmBufDesc.bufElSizes = &inElsize;inArgs.numInSamples = (s32ReadPcmBytes <= 0) ? -1 : s32ReadPcmBytes/2;outAacBufDesc.numBufs = 1;outAacBufDesc.bufs = (void **)&pu8AacEncBuf;outAacBufDesc.bufferIdentifiers = &outIdentifier;outAacBufDesc.bufSizes = &u32AacOutBufMaxBytes;outAacBufDesc.bufElSizes = &outElsize;/* AAC编码 6/8:将pcm编码出aac */aacErrNum = aacEncEncode(aacEncHandle, &inPcmBufDesc, &outAacBufDesc, &inArgs, &outArgs);if(aacErrNum != AACENC_OK){printf("Aac encoder encode error!\n");goto error_exit3;}DEBUG("IN(pcm): [buf bytes: %4d] [channels: %d] [sample cnt per channel: %4d]  ==>   OUT(aac): [encode out bytes: %4d] \n",s32ReadPcmBytes, u32PcmChannels, inArgs.numInSamples/u32PcmChannels, outArgs.numOutBytes);if(outArgs.numOutBytes == 0){continue;}/* AAC编码 7/8:将编码出的aac数据写入文件 */fwrite(pu8AacEncBuf, 1, outArgs.numOutBytes, fpAac);}printf("\n\033[32m%s ==> %s Success!\033[0m\n", pcmFileName, aacFileName);error_exit3:/* 记得释放内存 */free(pu8PcmInBuf);free(pu8AacEncBuf);error_exit2:/* AAC编码 8/8:关闭编码器 */aacEncClose(&aacEncHandle);error_exit1:fclose(fpPcm);fclose(fpAac);return 0;
}

3、demo下载地址(任选一个)

  • https://download.csdn.net/download/weixin_44498318/89525141

  • https://gitee.com/linriming/audio_pcm2aac_with_fdk-aac.git

  • https://github.com/linriming20/audio_pcm2aac_with_fdk-aac.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/42991.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java语言程序设计——篇二(1)

Java语言基础 数据类型关键字与标识符关键字标识符 常量与变量1、常量2、变量 类型转换自动类型转换强制类型转换 数据类型 数据的基本要素数据的性质&#xff08;数据结构&#xff09;数据的取值范围&#xff08;字节大小&#xff09;数据的存储方式参与的运算 Java是一门强类…

常见的自动化工具开发必备的源代码!

随着科技的飞速发展&#xff0c;自动化工具已经成为我们日常工作中不可或缺的一部分&#xff0c;自动化工具不仅极大地提高了工作效率&#xff0c;还降低了人为错误的可能性。 然而&#xff0c;要想开发出高效、稳定的自动化工具&#xff0c;掌握一些常见的源代码技巧是至关重…

vue中一周的时间选择多个阶段(手动表格选择)

先给大家看一下效果图 源代码 <template><div style"width: 45%"><div style"width: 100%"><div class"time"><div class"timeleft">星期/时间</div><div class"timeright"><…

FastAPI是一个现代、快速(高性能)的Web框架

FastAPI是一个现代、快速&#xff08;高性能&#xff09;的Web框架&#xff0c;专门用于构建基于Python的API。以下是对FastAPI的详细介绍&#xff1a; 一、基本概述 定义与用途&#xff1a;FastAPI是一个开源项目&#xff0c;基于Starlette和Pydantic库构建而成&#xff0c;…

奇安信20240513笔试

题目一 解题思路 n转为字符串&#xff0c;如果位数为偶数&#xff0c;取前一半设为x&#xff0c;后一段为y&#xff0c;从x最低位开始&#xff0c;9&#xff0c;9*10&#xff0c;9*10*10。。。 到最高位&#xff0c;加x&#xff0c;如果x大于或等于y&#xff0c;加1. 位数为奇数…

linux固定主机ip

1.查看虚拟网络配置 NAT设置&#xff1a; 2.修改网卡配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33 TYPE"Ethernet" PROXY_METHOD"none" BROWSER_ONLY"no" BOOTPROTO"static" DEFROUTE"yes" IPV4_FAILURE_FATAL…

idea导入opencv和mediapipe

1.参考pycharm导入cv2_pycharm import cv2-CSDN博客 2.pip install opencv-python 3. python 3.8导入mediapipe 3.1 pip install mediapipe 导入报错&#xff0c; 3.2离线导入 参考Win10安装mediapipe的步骤_mediapipe安装python版本-CSDN博客 首先安装opencv-contrib-py…

App UI性能测试 - PerfDog使用全教程

App 性能测试指标: 响应、内存、CPU、FPS、GPU渲染、耗电、耗流等。 PerfDog的性能数据更加全面,所以下面以PerfDog来介绍安装使用流程及测试数据的获取与分析。 官网: PerfDog | 全平台性能测试分析专家 第一步,先访问官网进行注册, 注册好账号后,点击下载PerfDog,下…

git 文件没有修改,但一直提示有0行改动,还原也不行

查看文件修改内容 原来是文件的模式(读写可执行权限)发生了变化,内容本是没有变化. 怎么解决 git config --add core.filemode false忽略文件模式

Vue90-Vuex模块化:namespace

一、模块化的目标 当业务很复杂的时候&#xff0c;各个模块中的内容会很多&#xff0c;所以&#xff0c;要将不同业务功能的模块放到不同的位置 二、实现 2-1、模块内容的拆分 将对应的模块的内容&#xff0c;添加到对应的对象中去。 2-2、拆分后模块的使用 1、方式一 2、方…

创建react的脚手架

Create React App 中文文档 (bootcss.com) 网址&#xff1a;creat-react-app.bootcss.com 主流的脚手架&#xff1a;creat-react-app 创建脚手架的方法&#xff1a; 方法一&#xff08;JS默认&#xff09;&#xff1a; 1. npx create-react-app my-app 2. cd my-app 3. …

2024年信息素养大赛图形化编程小低组复赛真题-附答案 6547网

2024年全国青少年信息素养大赛图形化编程小低组复赛真题 题目总数&#xff1a;6 总分数&#xff1a;100 第1部分 第 1 题 问答题 【编程实现】点击小绿旗&#xff0c;实现将鱼的所有造型印到舞台区 【具体要求】 1. 将鱼显示出来 全部擦除所有内容 2. 将鱼的造型设…

python 10个自动化脚本

目录 &#x1f31f; 引言 &#x1f4da; 理论基础 &#x1f6e0;️ 使用场景与代码示例 场景一&#xff1a;批量重命名文件 场景二&#xff1a;自动下载网页内容 场景三&#xff1a;数据清洗 场景四&#xff1a;定时执行任务 场景五&#xff1a;自动化邮件发送 场景六…

极品AI大模型,抓紧收藏!整合包!

近期&#xff0c;科技巨头谷歌终于发布了1个月前在I/O开发者大会上预告过的Gemma 2大模型。据谷歌介绍&#xff0c;与第1代Gemma模型相比&#xff0c;新模型拥有更优的性能&#xff0c;推理效率也更高。我当然是&#xff0c;“无所谓&#xff0c;我会出手.jpg”&#xff0c;给大…

Linux 常见命令使用(超详细版)

文章目录 基本echo关机、重启命令上传下载工具rz/sz<、>、>>ls管道clearcdpwd 文件处理类命令mkdirrmdirtouchcpmv 文件查看类命令catmorelessheadtail 用户管理命令useraddpasswdusermoduserdelgroupaddgroupdel 文件属性类命令chmodchownchgrpln 文件压缩类命令t…

【多模态】40、ConvLLaVA | 使用 ConvNeXt 为 LLaVA 实现更高分辨率的输入

论文&#xff1a;ConvLLaVA: Hierarchical Backbones as Visual Encoder for Large Multimodal Models 代码&#xff1a;https://github.com/alibaba/conv-llava 出处&#xff1a;阿里 | 清华 时间&#xff1a;2024.05 一、背景 LMM 在很多任务上都表现出来很好的效果&…

ROS编译错误: fatal error: test_pkg/test_pkg.h: 没有那个文件

在ROS安装完毕后编译ros工作空间&#xff0c;出现了以下错误: 解决方法: 删除工作空间&#xff0c;重建再重新编译

vue3+ el-tree 展开和折叠,默认展开第一项

默认第一项展开: 展开所有项&#xff1a; 折叠所有项&#xff1a; <template><el-treestyle"max-width: 600px":data"treeData"node-key"id":default-expanded-keys"defaultExpandedKey":props"defaultProps"…

超好用的傲软录屏下载和解锁版安装教程 (专业好用的桌面录屏软件)

录屏系列软件安装目录 一、ZD屏幕录像机解锁版下载及安装教程 (一款小巧的轻量级屏幕录像工具) 二、班迪录屏Bandicam v7解锁版安装教程&#xff08;高清录屏软件&#xff09; 三、Mirillis Action v4 解锁版安装教程(专业高清屏幕录像软件) 四、Aiseesoft Screen Recorder…

支持图片识别语音输入的LobeChat保姆级本地部署流程

文章目录 前言1. LobeChat对我们有哪些帮助?2. 本地安装LobeChat3. 如何使用LobeChat工具4. 安装Cpolar内网穿透5. 实现公网访问LobeChat6. 固定LobeChat公网地址 前言 本文主要介绍如何在Windows系统电脑本地部署LobeChat&#xff0c;一款高颜值的开源AI大模型智能应用&…