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

avatar
作者
筋斗云
阅读量:3

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. 参考文章

【格式说明】

【编码实现】

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下载地址(任选一个)

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!