音频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.xdnf.cn/news/1475315.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

权力之望怎么下载客户端 权力之望一键下载

《权力之望》是一款由NX3 Games开发、Smilegate发行的多人在线动作MMORPG游戏。这款游戏最大的特点是高度的自由度和丰富的角色定制选项。我们在游戏中不仅可以自由更换武器&#xff0c;而且游戏还提供了54种能力和60多种职业选择&#xff0c;让我们可以根据自己的游戏风格和喜…

YOLOv9报错:AttributeError: ‘list‘ object has no attribute ‘view‘

报错信息如下&#xff1a; red_distri, pred_scores torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats], 2).split( AttributeError: ‘list’ object has no attribute ‘view’ 解决方法&#xff1a; 去yolov9/utils/loss_tal.py把167行代码更改&#…

人工智能音乐软件Suno上架App Store;Meta 推出 3D 内容生成 AI 模型

&#x1f989; AI新闻 &#x1f680; 人工智能音乐软件Suno上架App Store 摘要&#xff1a;IT之家消息&#xff0c;Suno是一款AI音乐生成软件&#xff0c;已登陆苹果App Store&#xff08;国区暂未上架&#xff09;。用户可通过文字描述或录音创建音乐&#xff0c;并生成4分钟…

html+css+js随机验证码

随机画入字符、线条 源代码在图片后面 点赞❤️关注&#x1f60d;收藏⭐️ 互粉必回 图示 源代码 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"…

【Linux系列2】Cmake安装记录

方法一 1. 查看当前cmake版本 [rootlocalhost ~]# cmake -version cmake version 2.8.12.22. 进行卸载 [rootlocalhost ~]# yum remove -y cmake3. 进行安装包的下载&#xff0c;也可以下载好安装包后传至相应的目录 [rootlocalhost ~]# mkdir /opt/cmake [rootlocalhost ~…

安卓稳定性之crash详解

目录 前言一、Crash 的基本原理二、Crash 分析思路三、实例分析四、预防措施五、参考链接 前言 在开发和测试 Android 应用程序时&#xff0c;遇到应用程序崩溃是很常见的情况。 Android 崩溃指的是应用程序因为异常或错误而无法正常执行&#xff0c;并且导致应用强制关闭。 一…

算法训练营day26--455.分发饼干+376. 摆动序列+53. 最大子序和

一、455.分发饼干 题目链接&#xff1a;https://leetcode.cn/problems/assign-cookies/ 文章讲解&#xff1a;https://www.programmercarl.com/0455.%E5%88%86%E5%8F%91%E9%A5%BC%E5%B9%B2.html 视频讲解&#xff1a;https://www.bilibili.com/video/BV1MM411b7cq 1.1 初见思…

在PyTorch中使用TensorBoard

文章目录 在PyTorch中使用TensorBoard1.安装2.TensorBoard使用2.1创建SummaryWriter实例2.2利用add_scalar()记录metrics2.3关闭Writer2.4启动TensorBoard 3.本地连接服务器使用TensorBoard3.1方法一&#xff1a;使用SSH命令进行本地端口转发3.2方法二&#xff1a;启动TensorBo…

【ROS2】Ubuntu 24.04 源码编译安装 Jazzy Jalisco

目录 系统要求 系统设置 设置区域启用所需的存储库安装开发工具 构建 ROS 2 获取 ROS 2 代码使用 rosdep 安装依赖项安装额外的 RMW 实现&#xff08;可选&#xff09;在工作区构建代码 设置环境 尝试一些例子 下一步 备用编译器 Clang保持最新状态 故障排除 卸载 系统要求 当前…

软件测试下的AI之路(5)

😏作者简介:博主是一位测试管理者,同时也是一名对外企业兼职讲师。 📡主页地址:【Austin_zhai】 🙆目的与景愿:旨在于能帮助更多的测试行业人员提升软硬技能,分享行业相关最新信息。 💎声明:博主日常工作较为繁忙,文章会不定期更新,各类行业或职场问题欢迎大家…

智能遥测终端机RTU-精确监控 智能运维

智能遥测终端机RTU是物联网领域中一种重要的设备&#xff0c;它的出现无疑为远程监控和数据采集提供了强大的支持。计讯物联智能遥测终端机RTU具备数据采集、处理、通信和控制功能的设备&#xff0c;可以实现对远程设备的监控与控制。它在物联网系统中扮演着桥梁的角色&#xf…

前端程序员如何转大模型?收藏这一篇就够了(非常详细)

最近各行各业都不容易啊&#xff0c;那个中金女员工跳楼事件频繁上热点&#xff0c;引起广泛的关注&#xff0c;本质上还是经济下行&#xff0c;我们互联网行业也是如此&#xff0c;特别是程序员&#xff0c;本来就有35岁危机&#xff0c;加上行业不景气&#xff0c;大厂都在裁…

MacOS和Windows中怎么安装Redis

希望文章能给到你启发和灵感&#xff5e; 如果觉得文章对你有帮助的话&#xff0c;点赞 关注 收藏 支持一下博主吧&#xff5e; 阅读指南 开篇说明一、基础环境说明1.1 硬件环境1.2 软件环境 二、MacOS中Redis的安装2.1 HomeBrew 安装&#xff08;推荐&#xff09;2.2 通过官方…

人类连接组项目(HCP)的纤维束测量:资源和见解

摘要 人类连接组项目(HCP)已成为人类神经科学研究的基石&#xff0c;在推进脑成像方法和了解人脑方面具有重要作用。本研究专注于对HCP的扩散加权磁共振成像(dMRI)数据进行纤维示踪分析。使用了一个开源软件库(pyAFQ&#xff1b;https://yeatmanlab.github.io/pyAFQ)进行概率纤…

摸鱼大数据——Spark SQL——DataFrame详解二

3.DataFrame的相关API 操作DataFrame一般有二种操作方案&#xff1a;一种为【DSL方式】&#xff0c;另一种为【SQL方式】 SQL方式: 通过编写SQL语句完成统计分析操作DSL方式: 特定领域语言&#xff0c;使用DataFrame特有的API完成计算操作&#xff0c;也就是代码形式​从使用角…

分类下两列一组统计

表格 A 列是分类&#xff0c;后面是 2N 个 key-value 列 ABCDEFG1CountryLabel1Count1Label2Count2Label3Count32USA10B9C83USD9C8A74USC8D7B65USA7C6B56CAA10B9C87CAD9C8A78CAC8D7B69INA10C9B810IND9A8B711INA8D7B6 需要对分类、key 分组&#xff0c;对 value 求和&#xff…

【Qt】Qt Creator初使用

目录 一. 创建新项目 二. 认识Qt Creator界面 2.1 main.cpp 代码解释 2.2 mywidget.h 代码解释 2.3 mywidget.cpp 代码解释 2.4 form file —— Forms里的mywidget.ui 2.5 .pro文件 2.6 编译生成的中间文件 Qt Creator是一个跨平台集成开发环境(IDE)&#xff0c;专门用…

10分钟使用网站构建框架hugo本地搭建个人网站并快速上线详细教程

文章目录 前言1. 安装环境2. 配置环境变量与hugo安装2.1 创建程序目录2.2 配置环境变量2.3 查看程序版本 3. 创建博客网站3.1 创建站点3.2 在站点中创建一篇文章3.3 为网站添加主题 4. 本地访问测试5. 安装内网穿透工具6. 配置公网地址7. 配置固定公网地址 前言 今天和大家分享…

量产工具一一UI系统(四)

前言 前面我们实现了显示系统框架&#xff0c;输入系统框架和文字系统框架&#xff0c;链接&#xff1a; 量产工具一一显示系统&#xff08;一&#xff09;-CSDN博客量产工具一一输入系统&#xff08;二&#xff09;-CSDN博客量产工具一一文字系统&#xff08;三&#xff09;…

前端面试题23(css3)

关于CSS3的面试题&#xff0c;我们可以从多个维度来探讨&#xff0c;包括但不限于选择器、盒模型、布局技术、动画与过渡、响应式设计等。下面我会列举一些典型的CSS3面试问题&#xff0c;并尽可能提供详细的解答或示例代码。 1. CSS3中新增了哪些选择器&#xff1f; 答案: C…