1. 程式人生 > >FFMPEG實現對AAC解碼(採用封裝格式實現)

FFMPEG實現對AAC解碼(採用封裝格式實現)

技術在於交流、溝通,轉載請註明出處並保持作品的完整性。

原文: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; }