AAC的ADTS格式分析(轉)


ADTS是Audio Data Transport Stream的簡稱。

 
是AAC音頻文件常見的傳輸格式。
有的時候當你編碼AAC裸流的時候,會遇到寫出來的AAC文件並不能在PC和手機上播放,很大的可能就是AAC文件的每一幀里缺少了ADTS頭信息文件的包裝拼接。只需要加入頭文件ADTS即可。一個AAC原始數據塊長度是可變的,對原始幀加上ADTS頭進行ADTS的封裝,就形成了ADTS幀。需要注意的是:AAC文件可以沒有文件頭,全部由幀序列組成,每個幀由幀頭和數據部分組成。幀頭包含采樣率、聲道數、幀長度等,有點類似MP3格式。
 
下面分析下ADTS頭文件結構和信息:
AAC音頻文件的每一幀由ADTS Header和AAC Audio Data組成。
 
 
大家可以用AAC Audio ES Viewer工具來查看AAC的ADTS Header。
 
每一幀的ADTS的頭文件都包含了音頻的采樣率,聲道,幀長度等信息,這樣解碼器才能解析讀取。

一般情況下ADTS的頭信息都是7個字節,分為2部分:

adts_fixed_header();

adts_variable_header();

先來看: adts_fixed_header();

 
  • syncword :總是0xFFF, 代表一個ADTS幀的開始, 用於同步.
    解碼器可通過0xFFF確定每個ADTS的開始位置.
    因為它的存在,解碼可以在這個流中任何位置開始, 即可以在任意幀解碼。
  • ID:MPEG Version: 0 for MPEG-4,1 for MPEG-2
  • Layer:always: '00'
  • protection_absent:Warning, set to 1 if there is no CRC and 0 if there is CRC
  • profile:表示使用哪個級別的AAC,如01 Low Complexity(LC) -- AAC LC
    profile的值等於 Audio Object Type的值減1.
    profile = MPEG-4 Audio Object Type - 1
  • sampling_frequency_index:采樣率的下標
  • channel_configuration:聲道數,比如2表示立體聲雙聲道
接下來看下 adts_variable_header();

  • aac_frame_length:一個ADTS幀的長度包括ADTS頭和AAC原始流。frame length, this value must include 7 or 9 bytes of header length:
    aac_frame_length = (protection_absent == 1 ? 7 : 9) + size(AACFrame)

    protection_absent=0時, header length=9bytes
    protection_absent=1時, header length=7bytes
  • 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數據塊。
    (一個AAC原始幀包含一段時間內1024個采樣及相關數據)
 
兩個頭文件就講到這里。
這里給出JAVA和Android里的給AAC添加ADTS頭文件的部分方法代碼,針對ByteBuffer。
 
[java]  view plain  copy
 
  1. /** 
  2.   * 添加ADTS頭 
  3.   * 
  4.   * @param packet 
  5.   * @param packetLen 
  6.   */  
  7.  private void addADTStoPacket(byte[] packet, int packetLen) {  
  8.      int profile = 2; // AAC LC  
  9.      int freqIdx = 4; // 44.1KHz  
  10.      int chanCfg = 2; // CPE  
  11.   
  12.      // fill in ADTS data  
  13.      packet[0] = (byte) 0xFF;  
  14.      packet[1] = (byte) 0xF9;  
  15.      packet[2] = (byte) (((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2));  
  16.      packet[3] = (byte) (((chanCfg & 3) << 6) + (packetLen >> 11));  
  17.      packet[4] = (byte) ((packetLen & 0x7FF) >> 3);  
  18.      packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F);  
  19.      packet[6] = (byte) 0xFC;  
  20.  }  

這里是調用:(可根據自己需求,這里的AudioBufFrame是我們自己項目里的類,其實就是個ByteBuffer封裝的類)
[java]  view plain  copy
 
  1. AudioBufFrame audioBufFrame = (AudioBufFrame) o;  
  2.         int outBufferSize = audioBufFrame.buf.limit() + 7;  
  3.         byte[] aacBytes = new byte[outBufferSize];  
  4.         try {  
  5.             if (!write) {  
  6.                 fout = new FileOutputStream(MyConfiguration.VIDEO_PATH + "/audio.aac");  
  7.                 write = true;  
  8.             }  
  9.             addADTStoPacket(aacBytes, outBufferSize);  
  10.             audioBufFrame.buf.get(aacBytes, 7, audioBufFrame.buf.limit());  
  11.             fout.write(aacBytes);  
  12.         } catch (IOException e) {  
  13.             e.printStackTrace();  
  14.         }  
 
下面是FFMPEG參考的C的添加ADTS頭文件代碼,供大家參考。
[java]  view plain  copy
 
  1. int ff_adts_write_frame_header(ADTSContext *ctx,    
  2.                                uint8_t *buf, int size, int pce_size)    
  3. {    
  4.     PutBitContext pb;    
  5.     
  6.     init_put_bits(&pb, buf, ADTS_HEADER_SIZE);    
  7.     
  8.     /* adts_fixed_header */    
  9.     put_bits(&pb, 12, 0xfff);   /* syncword */    
  10.     put_bits(&pb, 1, 0);        /* ID */    
  11.     put_bits(&pb, 2, 0);        /* layer */    
  12.     put_bits(&pb, 1, 1);        /* protection_absent */    
  13.     put_bits(&pb, 2, ctx->objecttype); /* profile_objecttype */    
  14.     put_bits(&pb, 4, ctx->sample_rate_index);    
  15.     put_bits(&pb, 1, 0);        /* private_bit */    
  16.     put_bits(&pb, 3, ctx->channel_conf); /* channel_configuration */    
  17.     put_bits(&pb, 1, 0);        /* original_copy */    
  18.     put_bits(&pb, 1, 0);        /* home */    
  19.     
  20.     /* adts_variable_header */    
  21.     put_bits(&pb, 1, 0);        /* copyright_identification_bit */    
  22.     put_bits(&pb, 1, 0);        /* copyright_identification_start */    
  23.     put_bits(&pb, 13, ADTS_HEADER_SIZE + size + pce_size); /* aac_frame_length */    
  24.     put_bits(&pb, 11, 0x7ff);   /* adts_buffer_fullness */    
  25.     put_bits(&pb, 2, 0);        /* number_of_raw_data_blocks_in_frame */    
  26.     
  27.     flush_put_bits(&pb);    
  28.     
  29.     return 0;    
  30. }    
AAC的規格一覽:

因為AAC是一個龐大家族,他們共分為9種規格,以適應不同場合的需要,也正是由於AAC的規格(Profile)繁多,導致普通電腦用戶感覺十分困擾:

  1. MPEG-2 AAC LC低復雜度規格(Low Complexity)
  2. MPEG-2 AAC Main主規格
  3. MPEG-2 AAC SSR可變采樣率規格(Scaleable Sample Rate)
  4. MPEG-4 AAC LC低復雜度規格(Low Complexity),現在的手機比較常見的MP4文件中的音頻部分就包括了該規格音頻檔案
  5. MPEG-4 AAC Main主規格
  6. MPEG-4 AAC SSR可變采樣率規格(Scaleable Sample Rate)
  7. MPEG-4 AAC LTP長時期預測規格(Long Term Predicition)
  8. MPEG-4 AAC LD低延遲規格(Low Delay)
  9. MPEG-4 AAC HE高效率規格(High Efficiency)
上述的規格中,主規格(Main)包含了除增益控制之外的全部功能,其音質最好,而低復雜度規格(LC)則是比較簡單,沒有了增益控制,但提高了編碼效率,至“SSR”對“LC”規格大體是相同,但是多了增益的控制功能,另外,MPEG-4 AAC/LTP/LD/HE,都是用在低比特率下編碼,特別是“HE”是有Nero AAC編碼器支持,是近來常用的一種編碼器,不過通常來說,Main規格和LC規格的音質相差不大,因此目前使用最多的AAC規格多數是“LC”規格,因為要考慮手機目前的存儲器能力未達合理水准。

MPEG-4 AAC LC(Low Complexity)是最常用的規格,我們叫“低復雜度規格”,我們簡稱“LC-AAC”,這種規格在中等碼率的編碼效率以及音質方面,都能找到平衡點。所謂中等碼率,就是指:96kbps-192kbps之間的碼率。因此,如果要使用LC-AAC規格,請盡可能把碼率控制在之前說的那個區間內。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM