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;
}