FFMPEG实现对AAC解码(采用封装格式实现)

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

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

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

[音频编解码系列文章]

  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解码(不采用封装格式实现)

本篇FFMEPG实现对AAC解码,解码结果保存wav格式。对AAC编码文件来说,编码根据音频参数编码,解码根据音频参数重新构建声波,FFMPEG构建的音频存储方式不一定支持播放, 所以需要重采样样本,如AAC解码的样本格式AV_SAMPLE_FMT_FLTP。AAC的解码器如果是外部解码器"aac",解码格式需要AV_SAMPLE_FMT_FLTP,如果是“libvo_aacenc”这个解码器需要格式AV_SAMPLE_FMT_S16。

DEMO源代码如下

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

Date Created:	2014-10-25
Author:			wubihe QQ:1269122125 Email:[email protected]
Description:	音频格式AAC MP3的解码,结果保存WAV格式
--------------------------------------------------------------------------------
Modification History
DATE          AUTHOR          DESCRIPTION
--------------------------------------------------------------------------------

********************************************************************************/

#include <stdlib.h>
#include <string.h>
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"

};

#define INPUT_FILE_NAME		 ("huangdun.aac")
#define OUTPUT_FILE_NAME	 ("huangdun.wav")
#define  MAXWAVESIZE         (4294967040LU)

//写WAV文件头 
static int write_wav_header(int iBitPerSample,int iChans,unsigned char ucFormat,int iSampleRate,int iTotalSamples,FILE*pFile)
{
	unsigned char header[44];
	unsigned char* p = header;
	unsigned int bytes = (iBitPerSample + 7) / 8;
	float data_size = (float)bytes * iTotalSamples;
	unsigned long word32;

	*p++ = 'R'; *p++ = 'I'; *p++ = 'F'; *p++ = 'F';

	word32 = (data_size + (44 - 8) < (float)MAXWAVESIZE) ?
		(unsigned long)data_size + (44 - 8)  :  (unsigned long)MAXWAVESIZE;
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);
	*p++ = (unsigned char)(word32 >> 16);
	*p++ = (unsigned char)(word32 >> 24);

	*p++ = 'W'; *p++ = 'A'; *p++ = 'V'; *p++ = 'E';

	*p++ = 'f'; *p++ = 'm'; *p++ = 't'; *p++ = ' ';

	*p++ = 0x10; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;

	if (ucFormat == AV_SAMPLE_FMT_FLT)
	{
		*p++ = 0x03; *p++ = 0x00;
	} else {
		*p++ = 0x01; *p++ = 0x00;
	}

	*p++ = (unsigned char)(iChans >> 0);
	*p++ = (unsigned char)(iChans >> 8);

	word32 = (unsigned long)(iSampleRate + 0.5);
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);
	*p++ = (unsigned char)(word32 >> 16);
	*p++ = (unsigned char)(word32 >> 24);

	word32 = iSampleRate * bytes * iChans;
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);
	*p++ = (unsigned char)(word32 >> 16);
	*p++ = (unsigned char)(word32 >> 24);

	word32 = bytes * iChans;
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);

	*p++ = (unsigned char)(iBitPerSample >> 0);
	*p++ = (unsigned char)(iBitPerSample >> 8);

	*p++ = 'd'; *p++ = 'a'; *p++ = 't'; *p++ = 'a';

	word32 = data_size < MAXWAVESIZE ?
		(unsigned long)data_size : (unsigned long)MAXWAVESIZE;
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);
	*p++ = (unsigned char)(word32 >> 16);
	*p++ = (unsigned char)(word32 >> 24);

	return fwrite(header, sizeof(header), 1, pFile);
}

int main()
{
	FILE *pOutFile=NULL;

	pOutFile = fopen(OUTPUT_FILE_NAME, "wb");
	if(pOutFile == NULL)
	{
		return -1;
	}
	//注册解码器
	av_register_all();
	avformat_network_init();

	AVFormatContext	* pFormatCtx = avformat_alloc_context();
	//打开封装格式
	if(avformat_open_input(&pFormatCtx,INPUT_FILE_NAME,NULL,NULL)!=0)
	{
		return -1;
	}
	//
	if(avformat_find_stream_info(pFormatCtx,NULL)<0)
	{
		printf("封装格式查找流失败.\n");
		return -1;
	}
	// Dump valid information onto standard error
	av_dump_format(pFormatCtx, 0, INPUT_FILE_NAME, false);

	// Find the first audio stream
	int audioStream = -1;
	for(int i=0; i < pFormatCtx->nb_streams; i++)
	{
		if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO)
		{
			audioStream=i;
			break;
		}
	}
	if(audioStream==-1)
	{
		printf("Didn't find a audio stream.\n");
		return -1;
	}

	// Get a pointer to the codec context for the audio stream
	AVCodecContext	*pCodecCtx=pFormatCtx->streams[audioStream]->codec;

	// Find the decoder for the audio stream
	AVCodec			*pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
	if(pCodec==NULL)
	{
		printf("Codec not found.\n");
		return -1;
	}

	// Open codec
	if(avcodec_open2(pCodecCtx, pCodec,NULL)<0)
	{
		printf("Could not open codec.\n");
		return -1;
	}

	//对AAC编码文件来说,编码根据音频参数编码,解码根据音频参数重新构建声波,FFMPEG构建的
	//音频存储方式不一定支持播放,所以需要重采样样本 如AAC解码的样本格式是AV_SAMPLE_FMT_FLTP

	uint64_t iInputLayout				= av_get_default_channel_layout(pCodecCtx->channels);
	int      iInputChans				= pCodecCtx->channels;
	AVSampleFormat eInputSampleFormat   = pCodecCtx->sample_fmt;
	int	     iInputSampleRate			= pCodecCtx->sample_rate;


	uint64_t iOutputLayout				= av_get_default_channel_layout(pCodecCtx->channels);
	int      iOutputChans				= pCodecCtx->channels;
	AVSampleFormat eOutputSampleFormat  = AV_SAMPLE_FMT_S16;
	int	     iOutputSampleRate			= pCodecCtx->sample_rate;

	SwrContext *pSwrCtx = swr_alloc_set_opts(NULL,iOutputLayout, eOutputSampleFormat, iOutputSampleRate,
		iInputLayout,eInputSampleFormat , iInputSampleRate,0, NULL);
	swr_init(pSwrCtx);

	//AVPacket读取原始解码前的数据
	AVPacket *packet=(AVPacket *)malloc(sizeof(AVPacket));
	av_init_packet(packet);


	//1帧数据样本数
	int iFrameSamples = pCodecCtx->frame_size;

	// 存储原始数据 
	int iRawLineSize = 0;
	int iRawBuffSize  = av_samples_get_buffer_size(&iRawLineSize, iInputChans, iFrameSamples, eInputSampleFormat, 0);
	uint8_t *pRawBuff = (uint8_t *)av_malloc(iRawBuffSize);

	//原始数据保存在AVFrame结构体中
	AVFrame* pRawframe = av_frame_alloc();

	pRawframe->nb_samples	= iFrameSamples;
	pRawframe->format		= eInputSampleFormat;
	pRawframe->channels     = iInputChans;


	int iReturn = avcodec_fill_audio_frame(pRawframe, iInputChans, eInputSampleFormat, (const uint8_t*)pRawBuff, iRawBuffSize, 0);
	if(iReturn<0)
	{
		return -1;
	}


	// 存储转换后数据 
	int iConvertLineSize = 0;
	int iConvertBuffSize  = av_samples_get_buffer_size(&iConvertLineSize, iOutputChans, iFrameSamples, eOutputSampleFormat, 0);
	uint8_t *pConvertBuff = (uint8_t *)av_malloc(iConvertBuffSize);

	//转换后数据保存在AVFrame结构体中
	AVFrame* pConvertframe = av_frame_alloc();
	pConvertframe->nb_samples	= iFrameSamples;
	pConvertframe->format		= eOutputSampleFormat;
	pConvertframe->channels     = iOutputChans;

	iReturn = avcodec_fill_audio_frame(pConvertframe, iOutputChans, eOutputSampleFormat, (const uint8_t*)pConvertBuff, iConvertBuffSize, 0);
	if(iReturn<0)
	{
		return -1;
	}
	int iGetPicture;
	int iDecodeRet;
	int iFrameNo = 0;

	write_wav_header(16,iOutputChans,eOutputSampleFormat,iOutputSampleRate,0,pOutFile);


	while(av_read_frame(pFormatCtx, packet)>=0)
	{
		if(packet->stream_index==audioStream)
		{

			iDecodeRet = avcodec_decode_audio4( pCodecCtx, pRawframe,&iGetPicture, packet);
			if ( iDecodeRet < 0 ) 
			{
                printf("Error in decoding audio frame.\n");
                return -1;
            }
			if ( iGetPicture > 0 )
			{
				printf("FrameNo:%5d\n",iFrameNo);
				swr_convert(pSwrCtx, (uint8_t**)pConvertframe->data, iFrameSamples ,(const uint8_t**)pRawframe->data, iFrameSamples );
		
				fwrite(pConvertframe->data[0],pConvertframe->linesize[0],1,pOutFile);
				iFrameNo++;
			}
		}
		av_free_packet(packet);
	}


	av_free(pRawBuff);
	av_free(pConvertBuff);
	swr_free(&pSwrCtx);
	avcodec_close(pCodecCtx);
	
	avformat_close_input(&pFormatCtx);

	fclose(pOutFile);
	printf("Aac encode Success!!\n");
	getchar();

	return 0;
}


猜你喜欢

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