一.基本概念
AAC:即MPEG-2 Advanced Audio Coding,分為流格式和檔案格式。檔案格式主要用于檔案存儲和檔案播放,流格式主要用于流媒體線上播放。
檔案格式:adif格式
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5SY3EGZwEWOlRGNzATM5YWOzITOkZjMhZWMjVGZ3IWN48CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
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"#includetypedef 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-toolbinaudio.aac", "rb+"); if (fd == NULL) { printf("fopen is failed,err %d", GetLastError()); } char adts[7]; int adtslen = 7; int ret = fread(adts, adtslen, 1, fd); if (ret != 1) { printf("fread is failed,err %d", GetLastError()); } char *p = adts; GetAdtsSpecificConfig(p, &tAdtsHeader); printf("AAC key param: "); printf("id: %d", tAdtsHeader.nId); printf("layer: %d", tAdtsHeader.nLayer); printf("ProtectionAbsent: %d", tAdtsHeader.nProtectionAbsent); printf("Profile: %d", tAdtsHeader.nProfile); printf("SfIndex: %d", tAdtsHeader.nSfIndex); printf("PrivateBit: %d", tAdtsHeader.nPrivateBit); printf("ChannelConfiguration: %d", tAdtsHeader.nChannelConfiguration); printf("Original: %d", tAdtsHeader.nOriginal); printf("nHome: %d", tAdtsHeader.nHome); printf("nCopyrigthIdentificationStart: %d", tAdtsHeader.nCopyrigthIdentificationStart); printf("nAacFrameLength: %d", tAdtsHeader.nAacFrameLength); printf("nAdtsBufferFullness: %d", tAdtsHeader.nAdtsBufferFullness); printf("NoRawDataBlocksInFrame: %d", tAdtsHeader.nNoRawDataBlocksInFrame); getchar(); return 0;}
由此可見:代碼讀出來的參數和工具分析參數一緻。
更多更詳細資源請關注公衆号:AV_Chat