音频demo:使用faad2将AAC数据解码出PCM数据

1、README

前言

本demo是使用的开源项目faad2将aac数据解码成pcm数据。

a. 编译使用

faad2的编译: (faad2下载地址:https://sourceforge.net/projects/faac/files/faad2-src/faad2-2.8.0/)

bash 复制代码
tar xzf faad2-2.8.8.tar.gz
cd faad2-2.8.8/
./configure --prefix=$PWD/_install
make
make install

demo的编译使用:

bash 复制代码
$ make clean && make
$ 
$ ./aac2pcm 
Usage:
    ./aac2pcm <in aac file> <out pcm file>
Examples:
    ./aac2pcm ./audio/test1_44100_stereo.aac  out1_44100_16bit_stereo.pcm
    ./aac2pcm ./audio/test2_8000_mono.aac     out2_16000_16bit_stereo.pcm  # output [samplerate] and [channels] will be auto configured.
b. 参考文章
c. demo目录架构
bash 复制代码
$ tree
.
├── aac_adts.c
├── aac_adts.h
├── audio
│   ├── out1_44100_16bit_stereo.pcm
│   ├── out2_16000_16bit_stereo.pcm
│   ├── test1_44100_stereo.aac
│   └── test2_8000_mono.aac
├── docs
│   └── 用faad解码AAC(ADTS封装)_gavinr的博客-CSDN博客_faad解码aac.mhtml
├── include
│   ├── faad.h
│   └── neaacdec.h
├── lib
│   └── libfaad.a
├── main.c
├── Makefile
└── README.md

2、主要代码片段

aac_adts.c
c 复制代码
#include "aac_adts.h"


int getAdtsFrame(FILE *fp, uint8_t *pAdtsFrameData, T_AdtsHeader *ptAdtsHeaderInfo)
{
	uint32_t readBytes = 0;

	if(!fp || !pAdtsFrameData || !ptAdtsHeaderInfo)
		return -1;

	// ADTS header size is AAC_ADTS_HEADER_SIZE(=7) bytes
	readBytes = fread(pAdtsFrameData, 1, AAC_ADTS_HEADER_SIZE, fp);
	if(readBytes <= 0)
		return -2;

	ptAdtsHeaderInfo->syncword              = (pAdtsFrameData[0] << 4 ) | (pAdtsFrameData[1]  >> 4);
	ptAdtsHeaderInfo->id                    = (pAdtsFrameData[1] & 0x08) >> 3;
	ptAdtsHeaderInfo->layer                 = (pAdtsFrameData[1] & 0x06) >> 1;
	ptAdtsHeaderInfo->protection_absent     =  pAdtsFrameData[1] & 0x01;
	ptAdtsHeaderInfo->profile               = (pAdtsFrameData[2] & 0xc0) >> 6;
	ptAdtsHeaderInfo->sampling_freq_index   = (pAdtsFrameData[2] & 0x3c) >> 2;
	ptAdtsHeaderInfo->private_bit           = (pAdtsFrameData[2] & 0x02) >> 1;
	ptAdtsHeaderInfo->channel_configuration = (((pAdtsFrameData[2] & 0x01) << 2) | ((pAdtsFrameData[3] & 0xc0) >> 6));
	ptAdtsHeaderInfo->original_copy         = (pAdtsFrameData[3] & 0x20) >> 5;
	ptAdtsHeaderInfo->home                  = (pAdtsFrameData[3] & 0x10) >> 4;
	ptAdtsHeaderInfo->copyright_identification_bit   = (pAdtsFrameData[3] & 0x08) >> 3;
	ptAdtsHeaderInfo->copyright_identification_start = (pAdtsFrameData[3] & 0x04) >> 2;
	ptAdtsHeaderInfo->aac_frame_length = ((pAdtsFrameData[3] & 0x03) << 11) |
										 ((pAdtsFrameData[4] & 0xFF) << 3) |
										 ((pAdtsFrameData[5] & 0xE0) >> 5);
	ptAdtsHeaderInfo->adts_buffer_fullness = ((pAdtsFrameData[5] & 0x1f) << 6 | (pAdtsFrameData[6] & 0xfc) >> 2);
	ptAdtsHeaderInfo->number_of_raw_data_blocks_in_frame = (pAdtsFrameData[6] & 0x03);

	if (ptAdtsHeaderInfo->syncword != 0xFFF)
		return -3;

	/* read the remaining frame of ADTS data outside the AAC_ADTS_HEADER_SIZE(=7) bytes header,
	 * and it should be written after offsetting the header by AAC_ADTS_HEADER_SIZE(=7) bytes
	 */
	readBytes = fread(pAdtsFrameData + AAC_ADTS_HEADER_SIZE, 1, ptAdtsHeaderInfo->aac_frame_length - AAC_ADTS_HEADER_SIZE, fp);
	if(readBytes <= 0)
		return -4;

	return 0;
}
aac_adts.h
c 复制代码
#ifndef __AAC_ADTS_H__
#define __AAC_ADTS_H__

#include <stdio.h>
#include <stdint.h>


#define AAC_ADTS_HEADER_SIZE 	(7)

#define MAX_ADTS_SIZE 			(1024) /* 1K Bytes */


typedef enum{
    MPEG_4 = 0x0,
    MPEG_2 = 0x1,
}aac_id_t;


typedef enum{
    SFI_96000 = 0x0,
    SFI_88200 = 0x1,
    SFI_64000 = 0x2,
    SFI_48000 = 0x3,
    SFI_44100 = 0x4,
    SFI_32000 = 0x5,
    SFI_24000 = 0x6,
    SFI_22050 = 0x7,
    SFI_16000 = 0x8,
    SFI_12000 = 0x9,
    SFI_11025 = 0xa,
    SFI_8000  = 0xb,
    SFI_7350  = 0xc,
    SFI_ERROR = 0xd,
}sampling_freq_index_t;


/* AAC(ADTS) Header element member.
 * [Note: It is not stored as defined type size!!!]
 */
typedef struct{
	/* fixed header */
    uint32_t syncword;              // 12bit  '1111 1111 1111' is stand by ADTS frame
    uint32_t id;                    // 1 bit  0 for MPEG-4, 1 for MPEG-2
    uint32_t layer;                 // 2 bit  always '00'
    uint32_t protection_absent;     // 1 bit  1 not crc, 0 have crc 1
    uint32_t profile;               // 2 bit  AAC profile, '01' for AAC-LC
    uint32_t sampling_freq_index;   // 4 bit  reference to 'sampling_freq_index_t'
    uint32_t private_bit;           // 1 bit  always '0'
    uint32_t channel_configuration; // 3 bit  channels count
    uint32_t original_copy;         // 1 bit  always '0'
    uint32_t home;                  // 1 bit

    /* varible header */
    uint32_t copyright_identification_bit;   // 1 bit  always '0'
    uint32_t copyright_identification_start; // 1 bit  always '0'
    uint32_t aac_frame_length;               // 13bit  length of [adts header] + [adts data]
    uint32_t adts_buffer_fullness;           // 11bit  0x7FF stand by varible bit rate
    uint32_t number_of_raw_data_blocks_in_frame;  // 2 bit  always '00', number of AAC Frames(RDBs) in ADTS frame minus 1
}T_AdtsHeader, *PT_AdtsHeader;



/************************************************************************
 * function describe: get one frame aac(adts, include adts header) from
 *                    aac file.
 * params:
 *   [fp]: aac file handler.(in)
 *   [pAdtsFrameData]: the function will fill the aac data in it, must be
 *                     alloced memory before call this function.(out)
 *   [ptAdtsHeaderInfo]: AAC-ADTS header information in this frame.(out)
 * return: 0-success  other-error
 ************************************************************************/
int getAdtsFrame(FILE *fp, uint8_t *pAdtsFrameData, T_AdtsHeader *ptAdtsHeaderInfo);


#endif /*  __AAC_ADTS_H__ */
main.c
c 复制代码
#include <stdio.h>
#include <stdlib.h>

#include "aac_adts.h"
#include "faad.h"


#define MAX_DEC_SIZE   (128 * 1024)


int main(int argc, char *argv[])
{
	int ret = -1;
	FILE *fpAAC = NULL;
	FILE *fpPCM = NULL;
	unsigned char *aacBuf = NULL;
	unsigned char *pcmPtr = NULL;
	unsigned char channels = 0;
	unsigned long sampleRate = 0;
	T_AdtsHeader adtsHeader = {};
	NeAACDecHandle aacDecHandler = 0;
	NeAACDecFrameInfo aacDecFrameInfo = {};
	uint32_t audioSampleRate = -1;

	if(argc != 3)
	{
		printf("Usage:\n"
			   "    %s <in aac file> <out pcm file>\n"
			   "Examples:\n"
			   "    %s ./audio/test1_44100_stereo.aac  out1_44100_16bit_stereo.pcm\n"
			   "    %s ./audio/test2_8000_mono.aac     out2_16000_16bit_stereo.pcm  # output [samplerate] and [channels] will be auto configured.\n",
			   argv[0], argv[0], argv[0]);
		return -1;
	}

	/* open file */
	fpAAC = fopen(argv[1], "rb");
	fpPCM = fopen(argv[2], "wb");
	if(!fpAAC || !fpPCM)
	{
		printf("[%s:%d] open <%s> or <%s> file failed!\n", __FUNCTION__, __LINE__, argv[1], argv[2]);
		goto exit;
	}

	/* alloc memory */
	aacBuf = (unsigned char *)malloc(MAX_DEC_SIZE);
	if(!aacBuf)
	{
		printf("[%s:%d] alloc memory for aacBuf failed!\n", __FUNCTION__, __LINE__);
		goto exit;
	}

	/* aac decode 1/4: open aac decoder */
	aacDecHandler = NeAACDecOpen();

	/* use to configure decoder params */
	ret = getAdtsFrame(fpAAC, aacBuf, &adtsHeader);
	if(ret < 0)
	{
		if(ret == -2)
		{
			printf("aac file end!\n");
			goto exit;
		}
		else
		{
			printf("[%s:%d] get adts frame failed with %d!\n", __FUNCTION__, __LINE__, ret);
			goto exit;
		}
	}
	else
	{
		fseek(fpAAC, 0, SEEK_SET); // reset

		/* aac decode 2/4: init aac decoder params */
		NeAACDecInit(aacDecHandler, aacBuf, adtsHeader.aac_frame_length, &sampleRate, &channels);
		printf("\e[32m>>> will be decoded output with [samplerate: %lu], [channels: %d]<<<\e[0m\n", sampleRate, channels);
	}

	while(1)
	{
		ret = getAdtsFrame(fpAAC, aacBuf, &adtsHeader);
		if(ret < 0)
		{
			if(ret == -2)
			{
				printf("aac file end!\n");
				break;
			}
			else
			{
				printf("[%s:%d] get adts frame failed with %d!\n", __FUNCTION__, __LINE__, ret);
				goto exit;
			}
		}
		//printf("get one adts frame with size: %d\n", adtsHeader.aac_frame_length);

		/* aac decode 3/4: decode */
		pcmPtr = (unsigned char*)NeAACDecDecode(aacDecHandler, &aacDecFrameInfo, aacBuf, adtsHeader.aac_frame_length/* include header */);
		if(aacDecFrameInfo.error > 0)
		{
			printf("[%s:%d] %s\n", __FUNCTION__, __LINE__, NeAACDecGetErrorMessage(aacDecFrameInfo.error));
			goto exit;
		}
		else if(pcmPtr && aacDecFrameInfo.samples > 0)
		{
			printf("<in> [aac frame size: %lu] [header type: %s] "
                "[profile: %s]    |    <out> [samplerate: %lu] [samples cnt: %lu] [channels: %d] \n",
				aacDecFrameInfo.bytesconsumed, 
				aacDecFrameInfo.header_type == 2 ? "ADTS" : "Other", 
				aacDecFrameInfo.object_type == 2 ? "LC" : "Other", 
				aacDecFrameInfo.samplerate,
				aacDecFrameInfo.samples,
				aacDecFrameInfo.channels);

			fwrite(pcmPtr, 1, aacDecFrameInfo.samples * aacDecFrameInfo.channels, fpPCM);
		}
		else
		{
			printf("[%s:%d] Unknown decode error!\n", __FUNCTION__, __LINE__);
		}
	}

	/* aac decode 1/4: close aac decoder */
	NeAACDecClose(aacDecHandler);

	printf("\e[32mSuccess!\e[0m\n");

exit:
	if(fpAAC) fclose(fpAAC);
	if(fpPCM) {fflush(fpPCM); fclose(fpPCM);}
	if(aacBuf) free(aacBuf);

	return 0;
}

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

相关推荐
mo47763 小时前
Webrtc音频模块(四) 音频采集
音视频·webrtc
icy、泡芙3 小时前
T527-----音频调试
linux·驱动开发·音视频
易我数据恢复大师3 小时前
怎么提取音频保存到本地?电脑音频提取方法
音视频·软件·音频提取
野蛮的大西瓜3 小时前
开源呼叫中心中,如何将ASR与IVR菜单结合,实现动态的IVR交互
人工智能·机器人·自动化·音视频·信息与通信
嘟嘟实验室6 小时前
微信小程序xr-frame透明视频实现
微信小程序·ffmpeg·音视频·xr
红米饭配南瓜汤7 小时前
WebRTC服务质量(09)- Pacer机制(01) 流程概述
网络·音视频·webrtc
是十一月末10 小时前
Python进阶之opencv图片和视频基本读取关闭
python·opencv·音视频·cv2
gomogomono12 小时前
HDR视频技术之十一:HEVCH.265 的 HDR 编码方案
音视频·h.265·hdr·yuv
Eric.Lee202114 小时前
moviepy将图片序列制作成视频并加载字幕 - python 实现
开发语言·python·音视频·moviepy·字幕视频合成·图像制作为视频
却道天凉_好个秋14 小时前
音视频学习(二十四):hls协议
音视频·hls