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

1、README

a. 编译
编译demo

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

$ make
编译faac(可选)

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

#!/bin/bash

tar xzf faac-1.29.9.2.tar.gz
cd faac-1.29.9.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
c. 参考文章

【格式说明】

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

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

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

【编码实现】

  • 音频压缩:FAAC编码实例(wav)_铸剑娃的专栏-CSDN博客

  • 使用FAAC转换PCM为AAC_Arbboter的专栏-CSDN博客

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
│   ├── 使用FAAC转换PCM为AAC_Arbboter的专栏-CSDN博客.mhtml
│   ├── 音频压缩:FAAC编码实例_铸剑娃的专栏-CSDN博客.mhtml
│   └── 音频编码格式介绍-AAC - 简书.mhtml
├── include
│   ├── faaccfg.h
│   └── faac.h
├── lib
│   └── libfaac.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 "faac.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 long u64PcmSampleRate = 0; // 采样率
	unsigned int  u32PcmSampleBits = 0; // 采样位数
	unsigned int  u32PcmChannels   = 0; // 声道数

	/* aac编码器相关 */
	faacEncHandle           pFaacEncHandle = NULL;
	faacEncConfigurationPtr pFaacEncConf   = NULL;

	/* 编码相关参数 */
	unsigned long u64PcmInSampleCnt = 0; // 打开编码器时传出的参数,编码传入的PCM采样数(不是字节)
	unsigned long u64AacOutMaxBytes = 0; // 打开编码器时传出的参数,编码传出最大字节数
	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':
				u64PcmSampleRate = 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: %lu Hz\n"
		   "\t sample bits: %d bits\n"
		   "\t channels: %d\n"
		   "\t bits per second: %lu bps\n"
		   "output: \n"
		   "\t file name: %s\n"
		   "**************************************\n\n",
		   pcmFileName, u64PcmSampleRate, u32PcmSampleBits, u32PcmChannels,
		   u64PcmSampleRate*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/6:传递参数进去打开编码器 */
	pFaacEncHandle = faacEncOpen(u64PcmSampleRate, u32PcmChannels, &u64PcmInSampleCnt, &u64AacOutMaxBytes);
	if(pFaacEncHandle == NULL)
	{
		printf("faacEncOpen(...) error!\n");
		goto error_exit;
	}

	/* 根据上面打开编码器传出的参数分配对应大小的缓存 */
	pu8PcmInBuf = (unsigned char*)malloc(u64PcmSampleRate*u32PcmSampleBits/8);
	pu8AacEncBuf = (unsigned char*)malloc(u64AacOutMaxBytes);

	/* AAC编码 2/6:设置编码器配置 */
	// 设置编码器配置 a/c: 先获取当前配置
	pFaacEncConf = faacEncGetCurrentConfiguration(pFaacEncHandle);
	// 设置编码器配置 b/c: 填充配置
	/*
		PCM Sample Input Format
		0	FAAC_INPUT_NULL			invalid, signifies a misconfigured config
		1	FAAC_INPUT_16BIT		native endian 16bit
		2	FAAC_INPUT_24BIT		native endian 24bit in 24 bits		(not implemented)
		3	FAAC_INPUT_32BIT		native endian 24bit in 32 bits		(DEFAULT)
		4	FAAC_INPUT_FLOAT		32bit floating point
    */
	pFaacEncConf->inputFormat = FAAC_INPUT_16BIT;
#if 0
	/* 下面参数不用设置,保存默认即可 */
	pFaacEncConf->aacObjectType = LOW; 	// MAIN:1  LOW:2  SSR:3  LTP:4
	pFaacEncConf->mpegVersion = MPEG4; 	// MPEG2:0  MPEG4:1
	pFaacEncConf->useTns = 1; 			/* Use Temporal Noise Shaping */
	pFaacEncConf->shortctl = 0; 		// SHORTCTL_NORMAL:0  SHORTCTL_NOSHORT:1  SHORTCTL_NOLONG:2
	pFaacEncConf->allowMidside = 1; 	/* Allow mid/side coding */
	pFaacEncConf->quantqual = 0; 		/* Quantizer quality */
	pFaacEncConf->outputFormat = 1; 	// 0:Raw  1:ADTS
	pFaacEncConf->bandWidth = 32000;//0 /* AAC file frequency bandwidth */
	pFaacEncConf->bitRate = 48000;//0 	/* bitrate / channel of AAC file */
#endif
	// 设置编码器配置 c/c: 重新设置编码器的配置信息
	faacEncSetConfiguration(pFaacEncHandle, pFaacEncConf);

	/* 循环操作 */
	while(1)
	{
		unsigned int u32PcmInSampleCnt = 0;
		int s32ReadPcmBytes = 0;
		int s32EncAacBytes = 0;

		/* AAC编码 3/6:从文件里读出指定大小(大小由编码器传出参数决定)PCM数据 */
		s32ReadPcmBytes = fread(pu8PcmInBuf, 1, u64PcmInSampleCnt*u32PcmSampleBits/8, fpPcm);
		if(s32ReadPcmBytes <= 0)
		{
			break;
		}
		DEBUG("Read PCM bytes: %d\n", s32ReadPcmBytes);

		// 编码传递进去的是采样数,不是字节数
		u32PcmInSampleCnt = s32ReadPcmBytes/(u32PcmSampleBits/8);
		DEBUG("Encode PCM sample count: %d\n", u32PcmInSampleCnt);

		/* AAC编码 4/6:将PCM数据(pucPcmInBuf)传进去编码得到aac数据(pucAacEncBuf)传出 */
		s32EncAacBytes = faacEncEncode(pFaacEncHandle, (int32_t*)pu8PcmInBuf, u32PcmInSampleCnt, 
														pu8AacEncBuf, (unsigned int)u64AacOutMaxBytes);
		DEBUG("Encode return aac bytes: %d\n", s32EncAacBytes);
		
		/* AAC编码 5/6:将解码得到的数据写入到AAC文件中 */
		fwrite(pu8AacEncBuf, 1, s32EncAacBytes, fpAac);
	}


	/* 记得释放内存 */
	free(pu8PcmInBuf);
	free(pu8AacEncBuf);

	/* AAC编码 6/6:用完了就关闭编码器 */
	faacEncClose(pFaacEncHandle);

error_exit:

	fclose(fpPcm);
	fclose(fpAac);

	printf("\n\033[32m%s ==> %s Success!\033[0m\n", pcmFileName, aacFileName);

	return 0;
}

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

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

  • https://gitee.com/linriming/audio_pcm2aac_with_faac.git

  • https://github.com/linriming20/audio_pcm2aac_with_faac.git

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

张量分解(1)——初探张量

&#x1f345; 写在前面 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;这里是hyk写算法了吗&#xff0c;一枚致力于学习算法和人工智能领域的小菜鸟。 &#x1f50e;个人主页&#xff1a;主页链接&#xff08;欢迎各位大佬光临指导&#xff09; ⭐️近…

解决线程不安全问题的几种方式

线程不安全问题 日常生活中我们会经常碰到在不同的平台上买各种票的问题&#xff0c;例如在App、线下售票窗口等购买火车票、电影票。这里面就存在着线程安全的问题&#xff0c;因为当多个线程访问同一个资源时&#xff0c;会导致数据出错&#xff0c;例如甲和乙两人同时看中了…

2024最新版若依-RuoYi-Vue3-PostgreSQL前后端分离项目部署手册教程

项目简介: RuoYi-Vue3-PostgreSQL 是一个基于 RuoYi-Vue3 框架并集成 PostgreSQL 数据库的项目。该项目提供了一套高效的前后端分离的开发解决方案&#xff0c;适用于中小型企业快速构建现代化的企业级应用。此项目结合了 RuoYi-Vue-Postgresql 和 RuoYi-Vue3 的优点&#xff0…

libaom 编码器实验 AV1 标准 SVC 分层编码

SVC编码 视频SVC编码&#xff0c;即Scalable Video Coding&#xff08;可适性视讯编码或可分级视频编码&#xff09;&#xff0c;是H.264/MPEG-4 AVC编码的一种扩展&#xff0c;它提供了更大的编码弹性&#xff0c;并且具有时间可适性&#xff08;Temporal Scalability&#x…

React Hooks:上天在提醒你,别再用Class组件了!

React Hooks&#xff1a;上天在提醒你&#xff0c;别再用Class组件了&#xff01; React Hooks 的出现可以说是前端界的一场革命。它不仅让我们告别了繁琐的 Class 组件&#xff0c;还让代码变得更加简洁、易读、易维护。如果你还在固守 Class 组件的阵地&#xff0c;那么这篇…

vue3项目实战中的接口调用

vue项目组成 一个项目往往由这几个部分组成。&#x1f447;&#x1f447; 其中在src文件夹中的内容如下&#x1f447;&#x1f447; 我们常常将接口文件&#xff0c;新建在文件夹src下&#xff0c;一般命名为api&#xff0c;api内的文件便是接口文件。&#x1f447;&#x1f4…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第一篇 嵌入式Linux入门篇-

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

OpenCV基础(2)

目录 滤波处理 均值滤波 基本原理 函数用法 程序示例 高斯滤波 基本原理 函数用法 程序示例 中值滤波 基本原理 函数用法 程序示例 形态学 腐蚀 膨胀 通用形态学函数 前言&#xff1a;本部分是上一篇文章的延续&#xff0c;前面部分请查看&#xff1a;OpenCV…

MyBatis的底层机制

手写MyBatis底层机制 读取配置文件&#xff0c;得到数据库连接 思路 引入必要的依赖需要写一个自己的config.xml文件&#xff0c;在里面配置一些信息&#xff0c;driver&#xff0c;url &#xff0c;password&#xff0c;username需要编写Configuration类&#xff0c;对 自己…

服务器数据恢复—同品牌不同系列服务器raid5阵列数据恢复方案分析

RAID5磁盘阵列数据恢复案例一&#xff1a; 服务器数据恢复环境&#xff1a; 一台某品牌LH6000系列服务器&#xff0c;通过NetRaid阵列卡将4块硬盘组建为一组RAID5磁盘阵列。操作系统都为Window server&#xff0c;数据库是SQLServer。 服务器故障&#xff1a; LH6000系列服务器…

四、嵌入式技术(考点篇)试题(1)

我选择C&#xff0c;实际答案选B&#xff0c;答案给出的理由是&#xff0c;SoC是片上系统&#xff0c;包含完整系统和嵌入式软件全部内容&#xff0c;B的说法有点片面。 明显选C&#xff0c;嵌入式跟通用性不太沾边。 嵌入式OS特征&#xff1a;裁剪配置安全可靠实时高确定&…

Python基础知识——(001)

文章目录 P4——3. 程序设计语言的分类 1. 程序设计语言 2. 编译与解释 P5——4. Python语言的简介与开发工具 1. Python语言的简介 2. Python语言的发展 3. Python语言的特点 4. Python的应用领域 5. Python的开发工具 P6——5. IPO编程方式 IPO程序编写方法 P7——6. print函…

大模型隐私窃取攻击

前言 对于大模型风险&#xff0c;目前大家更多关注的还是越狱攻击。隐私这一块&#xff0c;可能国内还不如欧美重视&#xff0c;在安全的学术四大会议论文中&#xff0c;有时候甚至AI隐私的论文比AI安全的论文更多。但实际上&#xff0c;除了越狱之外&#xff0c;另外一大风险…

监控电脑软件【2024最新】|6款软件保姆式解析!

在数字化办公日益普及的今天&#xff0c;很多企业为了更好的提升员工的工作效率和保障企业的数据安全&#xff0c;开始给自己的企业布局电脑监控软件。 但市面上的电脑监控软件种类繁多复杂&#xff0c;为了更好的保障企业利用&#xff0c;小编推荐了以下几款电脑监控软件供大…

阶段三:项目开发---大数据开发运行环境搭建:任务4:安装配置Spark集群

任务描述 知识点&#xff1a;安装配置Spark 重 点&#xff1a; 安装配置Spark 难 点&#xff1a;无 内 容&#xff1a; Apache Spark 是专为大规模数据处理而设计的快速通用的计算引擎。Spark是UC Berkeley AMP lab (加州大学伯克利分校的AMP实验室)所开源的类Hadoop …

Python自动化测试系列[v1.0.0][高效自动化设计]

Python多线程应用于自动化测试 将多线程在测试巧妙地应用&#xff0c;确实会带来很多好处&#xff0c;并且这是充分利用机器资源执行高效率测试很好的方式 # -*- coding: utf-8 -*- import threading from time import ctime import time from selenium import webdriverdef …

【c语言】玩转文件操作

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;C语言 目录 引言 一、文件的打开和关闭 1.流 2.标准流 3.文本文件和二进制文件 4.控制文件打开与关闭的函数 二、文件的顺序读写 三、文件的随机读写 1…

7月学术会议:7月可投的EI国际会议

随着科技的迅猛发展&#xff0c;学术交流与研讨成为了推动科研进步的重要途径。进入7月&#xff0c;众多高质量的EI国际会议纷纷拉开帷幕&#xff0c;为全球的科研工作者提供了一个展示研究成果、交流学术思想的平台。以下&#xff0c;我们将详细介绍一些在7月可投的EI国际会议…

Java集合升序降序、转Set的方法

Collections.sort(list,Comparator.comparing(OcApplySquareVo::getApplyName).reversed()); 集合转set /** 集合转set */Set<String> pkCodeSet rows.stream().map(RailwayWeighBookResult.RailwayWeighBook::getPkCode).collect(Collectors.toSet());

猫咪浮毛太多怎么处理?6年铲屎官最值得买的猫毛空气净化器分享

作为一位拥有6年铲屎经验的铲屎官&#xff0c;家中既有宝宝又有毛孩子的铲屎官家庭来说&#xff0c;空气中的宠物异味和猫毛不仅影响生活质量&#xff0c;更关乎家人的健康。普通空气净化器虽然能够提供基本的空气净化&#xff0c;但对于养猫家庭的特定需求&#xff0c;如去除宠…