1. 程式人生 > >FAAD庫實現ADTS格式解碼

FAAD庫實現ADTS格式解碼

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

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

 

[音訊編解碼系列文章]

  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解碼(不採用封裝格式實現)

本篇採用FAAD對ADTS格式的AAC進行解碼,與原始AAC解碼不同的是不需要再解碼前進行解碼引數的設定。

DEMO程式碼如下:

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

Date Created:	2014-10-25
Author:			wubihe QQ:1269122125 Email:
[email protected]
Description: 用faad庫解碼ADTS格式AAC音訊流,解碼結果儲存wav -------------------------------------------------------------------------------- Modification History DATE AUTHOR DESCRIPTION -------------------------------------------------------------------------------- ********************************************************************************/ #include <stdio.h> #include <cstddef> #include <string> #include <math.h> #include "faad.h" //待解碼檔案 #define DECODE_FILE_NAME ("huangdun_adts.aac") //解碼後WAV檔案 #define DECODE_OUTPUT_FILE ("huangdun.wav") #define MAX_CHANNELS (8) #define MAXWAVESIZE (4294967040LU) #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; } //寫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 == FAAD_FMT_FLOAT) { *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); } static int write_audio_16bit( void *sample_buffer,unsigned int samples,FILE *pFile) { int ret; unsigned int i; short *sample_buffer16 = (short*)sample_buffer; char *data = (char*)malloc(samples*16*sizeof(char)/8); for (i = 0; i < samples; i++) { data[i*2] = (char)(sample_buffer16[i] & 0xFF); data[i*2+1] = (char)((sample_buffer16[i] >> 8) & 0xFF); } ret = fwrite(data, samples, 16/8, pFile); if (data) free(data); return ret; } int write_audio_file(void *sample_buffer, int samples,int outputFormat,FILE *pFile) { char *buf = (char *)sample_buffer; switch (outputFormat) { case FAAD_FMT_16BIT: return write_audio_16bit(buf,samples,pFile); case FAAD_FMT_24BIT: case FAAD_FMT_32BIT: case FAAD_FMT_FLOAT: default: return 0; } return 0; } 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; } 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; bool bFirstTime = true; int iOldPercent = 0; do { pSampleBuffer = NeAACDecDecode(hDecoder, &frameInfo, g_AacBuffer.buffer, g_AacBuffer.bytes_into_buffer); //拋棄解碼消耗的快取 advance_buffer(&g_AacBuffer, frameInfo.bytesconsumed); if (frameInfo.error > 0) { fprintf(stderr, "Error: %s\n",NeAACDecGetErrorMessage(frameInfo.error)); } /* open the sound file now that the number of channels are known */ if (bFirstTime && !frameInfo.error) { //寫WAV頭 這裡WAV標頭檔案長度值賦值是0但是不影響播放 write_wav_header(16,frameInfo.channels,ucRealFormat,frameInfo.samplerate,0,pOutputFile); bFirstTime = false; } 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); } if ((frameInfo.error == 0) && (frameInfo.samples > 0)) { if ( write_audio_file(pSampleBuffer, frameInfo.samples,ucRealFormat,pOutputFile) == 0) break; } /* 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 Adts Aac Success!\n"); getchar(); return 0; }