自学内容网 自学内容网

音频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/)

tar xzf faad2-2.8.8.tar.gz
cd faad2-2.8.8/
./configure --prefix=$PWD/_install
make
make install

demo的编译使用:

$ 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目录架构
$ 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
#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
#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
#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下载地址(任选一个)


原文地址:https://blog.csdn.net/weixin_44498318/article/details/140275738

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!