技术在于交流、沟通,转载请注明出处并保持作品的完整性。
原文:https://blog.csdn.net/hiwubihe/article/details/81261022
[音频编解码系列文章]
本篇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
#include
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;
}