FAAD库实现RAW格式AAC封装成ADTS格式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hiwubihe/article/details/81260980

技术在于交流、沟通,转载请注明出处并保持作品的完整性。

原文:https://blog.csdn.net/hiwubihe/article/details/81260980

[音频编解码系列文章]

  1. 音频编解码基础
  2. FFMPEG实现音频重采样
  3. FFMPEG实现PCM编码(采用封装格式实现)
  4. FFMPEG实现PCM编码(不采用封装格式实现)
  5. FAAC库实现PCM编码
  6. FAAD库实现RAW格式AAC解码
  7. FAAD库实现RAW格式AAC封装成ADTS格式
  8. FAAD库实现ADTS格式解码
  9. FFMPEG实现对AAC解码(采用封装格式实现)
  10. FFMPEG实现对AAC解码(不采用封装格式实现)

AAC原始文件格式一般播放器播放不了,数据分析工具也分析不了,需要把AAC原始文件打包成网络传输格式如ADTS等。本篇介绍用FAAD解码库,把RAW的AAC文件重新打包成ADTS格式的AAC,一般播放器能成功播放。

DEMO代码如下:

/*******************************************************************************
Copyright (c) wubihe Tech. Co., Ltd. All rights reserved.
--------------------------------------------------------------------------------

Date Created:	2014-10-25
Author:			wubihe QQ:1269122125 Email:[email protected]
Description:	原始AAC音频流,格式没有打包ADTS或者ADIF,一般播放器放不了,需要
				解码器解码 区别出一帧一帧的音频,然后打包成ADTS格式
--------------------------------------------------------------------------------
Modification History
DATE          AUTHOR          DESCRIPTION
--------------------------------------------------------------------------------

********************************************************************************/
#include <stdio.h>
#include <cstddef>
#include <string>
#include <math.h>
#include "faad.h"
//待解码文件
#define  DECODE_FILE_NAME	("huangdun_uadts.aac")
//封装成ADTS格式的AAC文件
#define  DECODE_OUTPUT_FILE	("huangdun_adts.aac")
#define  MAX_CHANNELS		(8)
#define  MAXWAVESIZE        (4294967040LU)
#define  ADTS_HEAD_LEN			(7)

#define  min(a,b)            (((a) < (b)) ? (a) : (b))
typedef struct 
{
	//当前缓存总数据量
	long bytes_into_buffer;
	//当前缓存已经消耗数据量
	long bytes_consumed;
	//整个文件数据使用量
	long file_offset;
	//缓存
	unsigned char *buffer;
	//文件结束标志
	int  at_eof;
	//文件操作句柄
	FILE *infile;
} aac_buffer;

//aac数据缓存  
aac_buffer g_AacBuffer;


static int fill_buffer(aac_buffer *b)
{
	int bread;

	//解析消耗数据
	if (b->bytes_consumed > 0)
	{
		//有剩余数据 向前面移动
		if (b->bytes_into_buffer)
		{
			memmove((void*)b->buffer, (void*)(b->buffer + b->bytes_consumed),
				b->bytes_into_buffer*sizeof(unsigned char));
		}

		if (!b->at_eof)
		{
			bread = fread((void*)(b->buffer + b->bytes_into_buffer), 1,
				b->bytes_consumed, b->infile);

			if (bread != b->bytes_consumed)
				b->at_eof = 1;

			b->bytes_into_buffer += bread;
		}

		b->bytes_consumed = 0;

		if (b->bytes_into_buffer > 3)
		{
			if (memcmp(b->buffer, "TAG", 3) == 0)
				b->bytes_into_buffer = 0;
		}
		if (b->bytes_into_buffer > 11)
		{
			if (memcmp(b->buffer, "LYRICSBEGIN", 11) == 0)
				b->bytes_into_buffer = 0;
		}
		if (b->bytes_into_buffer > 8)
		{
			if (memcmp(b->buffer, "APETAGEX", 8) == 0)
				b->bytes_into_buffer = 0;
		}
	}

	return 1;
}

static void advance_buffer(aac_buffer *b, int bytes)
{
	b->file_offset += bytes;
	b->bytes_consumed = bytes;
	b->bytes_into_buffer -= bytes;
	if (b->bytes_into_buffer < 0)
		b->bytes_into_buffer = 0;
}

static int adts_sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,7350,0,0,0};

static int FindAdtsSRIndex(int sr)
{
	int i;

	for (i = 0; i < 16; i++)
	{
		if (sr == adts_sample_rates[i])
			return i;
	}
	return 16 - 1;
}

unsigned bool MakeAdtsHeader(unsigned char *pHead,int *HeadSize,int iProfile,int iSampleRate,int iChan ,int iFramelen)
{
	unsigned char *data = pHead;
	int iHeadLen		= *HeadSize;
	if(iHeadLen<7)
	{
		return false;
	}
	*HeadSize = iHeadLen = 7;

	int profile   = (iProfile - 1) & 0x3;
	int sr_index  = FindAdtsSRIndex(iSampleRate);
	int framesize = iFramelen + iHeadLen;

	memset(data, 0, iHeadLen);

	data[0] += 0xFF; /* 8b: syncword */

	data[1] += 0xF0; /* 4b: syncword */
	/* 1b: mpeg id = 0 */
	/* 2b: layer = 0 */
	data[1] += 1; /* 1b: protection absent */

	data[2] += ((profile << 6) & 0xC0); /* 2b: profile */
	data[2] += ((sr_index << 2) & 0x3C); /* 4b: sampling_frequency_index */
	/* 1b: private = 0 */
	data[2] += ((iChan >> 2) & 0x1); /* 1b: channel_configuration */

	data[3] += ((iChan << 6) & 0xC0); /* 2b: channel_configuration */
	/* 1b: original */
	/* 1b: home */
	/* 1b: copyright_id */
	/* 1b: copyright_id_start */
	data[3] += ((framesize >> 11) & 0x3); /* 2b: aac_frame_length */

	data[4] += ((framesize >> 3) & 0xFF); /* 8b: aac_frame_length */

	data[5] += ((framesize << 5) & 0xE0); /* 3b: aac_frame_length */
	data[5] += ((0x7FF >> 6) & 0x1F); /* 5b: adts_buffer_fullness */

	data[6] += ((0x7FF << 2) & 0x3F); /* 6b: adts_buffer_fullness */
	/* 2b: num_raw_data_blocks */

	return true;
}

int main()
{
	memset(&g_AacBuffer, 0, sizeof(aac_buffer));
	g_AacBuffer.infile = fopen(DECODE_FILE_NAME, "rb");
	if (g_AacBuffer.infile == NULL)
	{
		/* unable to open file */
		fprintf(stderr, "Error opening file: %s\n", DECODE_FILE_NAME);
		return 1;
	}

	fseek(g_AacBuffer.infile, 0, SEEK_END);
	double dTotalFileSize = ftell(g_AacBuffer.infile);
	fseek(g_AacBuffer.infile, 0, SEEK_SET);

	if (!(g_AacBuffer.buffer = (unsigned char*)malloc(FAAD_MIN_STREAMSIZE*MAX_CHANNELS)))
	{
		fprintf(stderr, "Memory allocation error\n");
		return 0;
	}
	memset(g_AacBuffer.buffer, 0, FAAD_MIN_STREAMSIZE*MAX_CHANNELS);

	size_t sRealRead = fread(g_AacBuffer.buffer, 1, FAAD_MIN_STREAMSIZE*MAX_CHANNELS, g_AacBuffer.infile);
	g_AacBuffer.bytes_into_buffer = sRealRead;
	g_AacBuffer.bytes_consumed = 0;
	g_AacBuffer.file_offset	   = 0;

	if (sRealRead != FAAD_MIN_STREAMSIZE*MAX_CHANNELS)
	{
		g_AacBuffer.at_eof = 1;
	}
	//判断文件格式

	int iAacType = 0;
	if ((g_AacBuffer.buffer[0] == 0xFF) && ((g_AacBuffer.buffer[1] & 0xF6) == 0xF0))
	{
		iAacType = 1;
		fprintf(stderr, "AAC file Format is: ADTS\n");
	} 
	else if (memcmp(g_AacBuffer.buffer, "ADIF", 4) == 0) 
	{
		iAacType = 2;
		fprintf(stderr, "AAC file Format is: ADIF\n");
	}
	else
	{
		iAacType = 0;
		fprintf(stderr, "AAC file Format is: RAW AAC\n");
	}

	

	FILE *pOutputFile = fopen(DECODE_OUTPUT_FILE, "wb");
	if(pOutputFile == NULL)
	{
		fprintf(stderr, "Error opening file: %s\n", DECODE_OUTPUT_FILE);
		return 1;
	}
	

	//打开解码器
	NeAACDecHandle hDecoder = NeAACDecOpen();

	//设置解码器音频参数 该设置对于原始AAC数据是必须的 否则解码器不知道音频封装信息
	//对于ADTS封装的AAC 不需要设置 解码器可以从视频数据中获取
	NeAACDecConfigurationPtr pDecodeConfig = NeAACDecGetCurrentConfiguration(hDecoder);
	
	pDecodeConfig->defSampleRate	= 44100;
	pDecodeConfig->defObjectType	= LC;
	pDecodeConfig->outputFormat		= FAAD_FMT_16BIT;
	pDecodeConfig->downMatrix		= 0;
	pDecodeConfig->useOldADTSFormat = 0;

	NeAACDecSetConfiguration(hDecoder, pDecodeConfig);

	long lRealUse =0;

	unsigned long lRealSampleRate	;
	unsigned char ucRealChans		;
	unsigned char ucRealFormat = FAAD_FMT_16BIT;
	//数据初始化
	if ((lRealUse = NeAACDecInit(hDecoder, g_AacBuffer.buffer,
			g_AacBuffer.bytes_into_buffer, &lRealSampleRate, &ucRealChans)) < 0)
	{
		/* If some error initializing occured, skip the file */
		fprintf(stderr, "Error initializing decoder library.\n");
		if (g_AacBuffer.buffer)
		{
			free(g_AacBuffer.buffer);
		}
		NeAACDecClose(hDecoder);
		fclose(g_AacBuffer.infile);
		return 1;
	}
	//抛弃已经使用过的数据
	advance_buffer(&g_AacBuffer, lRealUse);
	//空的缓存填充新的数据
	fill_buffer(&g_AacBuffer);

	NeAACDecFrameInfo frameInfo;
	void *pSampleBuffer = NULL;

	int iAdtsHeadLen = ADTS_HEAD_LEN;
	unsigned char szAdtsHead[ADTS_HEAD_LEN];
	int iAacProfile  = LC;

	int iOldPercent		= 0;
	do
	{
		pSampleBuffer = NeAACDecDecode(hDecoder, &frameInfo,
			g_AacBuffer.buffer, g_AacBuffer.bytes_into_buffer);
		//原始AAC格式
		if(iAacType == 0)
		{
			MakeAdtsHeader(szAdtsHead,&iAdtsHeadLen,iAacProfile,frameInfo.samplerate,frameInfo.channels ,frameInfo.bytesconsumed);
			fwrite(szAdtsHead, 1, iAdtsHeadLen, pOutputFile);
			fwrite(g_AacBuffer.buffer, 1, frameInfo.bytesconsumed, pOutputFile);
		}
		//原本就是ADTS格式
		else if (iAacType == 1)
		{
			MakeAdtsHeader(szAdtsHead,&iAdtsHeadLen,iAacProfile,frameInfo.samplerate,frameInfo.channels ,frameInfo.bytesconsumed - 7);
			fwrite(szAdtsHead, 1, iAdtsHeadLen, pOutputFile);
			fwrite(g_AacBuffer.buffer, 1, frameInfo.bytesconsumed - 7, pOutputFile);
		}
		//抛弃解码消耗的缓存
		advance_buffer(&g_AacBuffer, frameInfo.bytesconsumed);

		if (frameInfo.error > 0)
		{
			fprintf(stderr, "Error: %s\n",NeAACDecGetErrorMessage(frameInfo.error));
		}


		int iPercent = min((int)((g_AacBuffer.file_offset*100))/dTotalFileSize, 100);
		if (iPercent > iOldPercent)
		{
			iOldPercent = iPercent;
			fprintf(stderr, "%d%% decoding %s.\n", iOldPercent, DECODE_FILE_NAME);
		}

		

		/* fill buffer */
		fill_buffer(&g_AacBuffer);

		if (g_AacBuffer.bytes_into_buffer == 0)
		{
			pSampleBuffer = NULL; /* to make sure it stops now */
		}
	} while (pSampleBuffer != NULL);

	NeAACDecClose(hDecoder);


	fclose(pOutputFile);
	fclose(g_AacBuffer.infile);

	if (g_AacBuffer.buffer)
	{
		free(g_AacBuffer.buffer);
	}

	printf("Decode Raw Aac Success!\n");
	getchar();

	return 0;
}

程序运行完成 生成huangdun_adts.aac用elecard stream analysis分析如下:

猜你喜欢

转载自blog.csdn.net/hiwubihe/article/details/81260980