天天看點

AAC的ADTS頭檔案資訊介紹

<a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank">署名-相同方式共享 4.0協定</a>

作者:譚東

時間:2016年10月28日

環境:Windows 7

是AAC音頻檔案常見的傳輸格式。

有的時候當你編碼AAC裸流的時候,會遇到寫出來的AAC檔案并不能在PC和手機上播放,很大的可能就是AAC檔案的每一幀裡缺少了ADTS頭資訊檔案的包裝拼接。隻需要加入頭檔案ADTS即可。一個AAC原始資料塊長度是可變的,對原始幀加上ADTS頭進行ADTS的封裝,就形成了ADTS幀。

下面分析下ADTS頭檔案結構和資訊:

AAC音頻檔案的每一幀由ADTS Header和AAC Audio Data組成。

AAC的ADTS頭檔案資訊介紹

大家可以用AAC Audio ES Viewer工具來檢視AAC的ADTS Header。

AAC的ADTS頭檔案資訊介紹

每一幀的ADTS的頭檔案都包含了音頻的采樣率,聲道,幀長度等資訊,這樣解碼器才能解析讀取。

一般情況下ADTS的頭資訊都是7個位元組,分為2部分:

adts_fixed_header();

adts_variable_header();

先來看:adts_fixed_header();

AAC的ADTS頭檔案資訊介紹

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

AAC的ADTS頭檔案資訊介紹

sampling_frequency_index:采樣率的下标

AAC的ADTS頭檔案資訊介紹

channel_configuration:聲道數,比如2表示立體聲雙聲道

AAC的ADTS頭檔案資訊介紹

接下來看下adts_variable_header();

AAC的ADTS頭檔案資訊介紹

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。

/** 

  * 添加ADTS頭 

  * 

  * @param packet 

  * @param packetLen 

  */  

 private void addADTStoPacket(byte[] packet, int packetLen) {  

     int profile = 2; // AAC LC  

     int freqIdx = 4; // 44.1KHz  

     int chanCfg = 2; // CPE  

     // fill in ADTS data  

     packet[0] = (byte) 0xFF;  

     packet[1] = (byte) 0xF9;  

     packet[2] = (byte) (((profile - 1) &lt;&lt; 6) + (freqIdx &lt;&lt; 2) + (chanCfg &gt;&gt; 2));  

     packet[3] = (byte) (((chanCfg &amp; 3) &lt;&lt; 6) + (packetLen &gt;&gt; 11));  

     packet[4] = (byte) ((packetLen &amp; 0x7FF) &gt;&gt; 3);  

     packet[5] = (byte) (((packetLen &amp; 7) &lt;&lt; 5) + 0x1F);  

     packet[6] = (byte) 0xFC;  

 }  

這裡是調用:(可根據自己需求,這裡的AudioBufFrame是我們自己項目裡的類,其實就是個ByteBuffer封裝的類)

AudioBufFrame audioBufFrame = (AudioBufFrame) o;  

        int outBufferSize = audioBufFrame.buf.limit() + 7;  

        byte[] aacBytes = new byte[outBufferSize];  

        try {  

            if (!write) {  

                fout = new FileOutputStream(MyConfiguration.VIDEO_PATH + "/audio.aac");  

                write = true;  

            }  

            addADTStoPacket(aacBytes, outBufferSize);  

            audioBufFrame.buf.get(aacBytes, 7, audioBufFrame.buf.limit());  

            fout.write(aacBytes);  

        } catch (IOException e) {  

            e.printStackTrace();  

        }  

下面是FFMPEG參考的C的添加ADTS頭檔案代碼,供大家參考。

int ff_adts_write_frame_header(ADTSContext *ctx,    

                               uint8_t *buf, int size, int pce_size)    

{    

    PutBitContext pb;    

    init_put_bits(&amp;pb, buf, ADTS_HEADER_SIZE);    

    /* adts_fixed_header */    

    put_bits(&amp;pb, 12, 0xfff);   /* syncword */    

    put_bits(&amp;pb, 1, 0);        /* ID */    

    put_bits(&amp;pb, 2, 0);        /* layer */    

    put_bits(&amp;pb, 1, 1);        /* protection_absent */    

    put_bits(&amp;pb, 2, ctx-&gt;objecttype); /* profile_objecttype */    

    put_bits(&amp;pb, 4, ctx-&gt;sample_rate_index);    

    put_bits(&amp;pb, 1, 0);        /* private_bit */    

    put_bits(&amp;pb, 3, ctx-&gt;channel_conf); /* channel_configuration */    

    put_bits(&amp;pb, 1, 0);        /* original_copy */    

    put_bits(&amp;pb, 1, 0);        /* home */    

    /* adts_variable_header */    

    put_bits(&amp;pb, 1, 0);        /* copyright_identification_bit */    

    put_bits(&amp;pb, 1, 0);        /* copyright_identification_start */    

    put_bits(&amp;pb, 13, ADTS_HEADER_SIZE + size + pce_size); /* aac_frame_length */    

    put_bits(&amp;pb, 11, 0x7ff);   /* adts_buffer_fullness */    

    put_bits(&amp;pb, 2, 0);        /* number_of_raw_data_blocks_in_frame */    

    flush_put_bits(&amp;pb);    

    return 0;    

}    

AAC的ADTS頭檔案資訊介紹

繼續閱讀