AAC音頻格式詳解和實戰解析
一.基本概念
AAC:即MPEG-2 Advanced Audio Coding,分爲流格式和文件格式。文件格式主要用於文件存儲和文件播放,流格式主要用於流媒體在線播放。
文件格式:adif格式
adif格式
該格式特點:只有開頭有一個頭部信息,後面都是AAC裸數據。適應磁盤存儲和文件播放
流格式:adts_frame格式
adts_frame格式
該格式特點:每一幀數據=固定頭(fixed_header)+ 可變頭(variable_header)+幀數據(raw_data),適合流媒體在線播放。
流式AAC可以簡單理解如下圖:
固定頭如下:
syncword 同步字The bit string ‘1111 1111 1111’,說明一個ADTS幀的開始。
ID MPEG 標示符, 設置爲1.
layer Indicates which layer is used. Set to ‘00’
protection_absent 表示是否誤碼校驗
profile 表示使用哪個級別的AAC,如01 Low Complexity(LC)--- AACLC
sampling_frequency_index 表示使用的採樣率下標
channel_configuration 表示聲道數
frame_length 一個ADTS幀的長度包括ADTS頭和raw data block.
可變頭如下:
adts_buffer_fullness 0x7FF 說明是碼率可變的碼流
number_of_raw_data_blocks_in_frame
表示ADTS幀中有number_of_raw_data_blocks_in_frame + 1個AAC原始幀.
所以說number_of_raw_data_blocks_in_frame == 0 表示說ADTS幀中有一個AAC數據塊並不是說沒有。
其他字段爲定義,可以忽略。
Raw數據塊:
一個幀包含1024個採樣
Duration算法:
一個AAC原始幀包含一段時間內1024個採樣及相關數據。
一個AAC音頻幀的播放時間=一個AAC幀對應的採樣樣本的個數/採樣率。總時間t=總幀數x一個AAC音頻幀的播放時間
時間t=總幀數x一個AAC音頻幀的播放時間
二. 實戰演練
1)使用ffmpeg抽取一個mp4文件中的aac音頻如下:
ffmpeg.exe -i CCTV-2-dszg-1.mp4 -vn -y -acodec copy audio.aac
2)利用工具分析該aac音頻固定頭和可變頭字段如下:
adts頭解析
3)使用程序代碼解析
#include "stdafx.h"
#include<windows.h>
typedef struct _AdtsHeader
{
unsigned int nSyncWord;
unsigned int nId;
unsigned int nLayer;
unsigned int nProtectionAbsent;
unsigned int nProfile;
unsigned int nSfIndex;
unsigned int nPrivateBit;
unsigned int nChannelConfiguration;
unsigned int nOriginal;
unsigned int nHome;
unsigned int nCopyrightIdentificationBit;
unsigned int nCopyrigthIdentificationStart;
unsigned int nAacFrameLength;
unsigned int nAdtsBufferFullness;
unsigned int nNoRawDataBlocksInFrame;
} AdtsHeader;
int _tmain(int argc, _TCHAR* argv[])
{
FILE *fd = fopen("D:\\ffmpeg-4.1-tool\\bin\\audio.aac", "rb+");
if (fd == NULL)
{
printf("fopen is failed,err %d\n", GetLastError());
}
char adts[7];
int adtslen = 7;
int ret = fread(adts, adtslen, 1, fd);
if (ret != 1)
{
printf("fread is failed,err %d\n", GetLastError());
}
char *p = adts;
GetAdtsSpecificConfig(p, &tAdtsHeader);
printf("AAC key param: \n");
printf("id: %d\n", tAdtsHeader.nId);
printf("layer: %d\n", tAdtsHeader.nLayer);
printf("ProtectionAbsent: %d\n", tAdtsHeader.nProtectionAbsent);
printf("Profile: %d\n", tAdtsHeader.nProfile);
printf("SfIndex: %d\n", tAdtsHeader.nSfIndex);
printf("PrivateBit: %d\n", tAdtsHeader.nPrivateBit);
printf("ChannelConfiguration: %d\n", tAdtsHeader.nChannelConfiguration);
printf("Original: %d\n", tAdtsHeader.nOriginal);
printf("nHome: %d\n", tAdtsHeader.nHome);
printf("nCopyrigthIdentificationStart: %d\n", tAdtsHeader.nCopyrigthIdentificationStart);
printf("nAacFrameLength: %d\n", tAdtsHeader.nAacFrameLength);
printf("nAdtsBufferFullness: %d\n", tAdtsHeader.nAdtsBufferFullness);
printf("NoRawDataBlocksInFrame: %d\n", tAdtsHeader.nNoRawDataBlocksInFrame);
getchar();
return 0;
}
編譯運行結果如下:
由此可見:代碼讀出來的參數和工具分析參數一致。
更多更詳細資源請關注公衆號:AV_Chat