AAC的ADTS頭文件信息介紹

遵循:BY-SA

署名-相同方式共享 4.0協議

作者:譚東

時間:2016年10月28日

環境:Windows 7

ADTS是Audio Data Transport Stream的簡稱。

是AAC音頻文件常見的傳輸格式。

有的時候當你編碼AAC裸流的時候,會遇到寫出來的AAC文件並不能在PC和手機上播放,很大的可能就是AAC文件的每一幀裏缺少了ADTS頭信息文件的包裝拼接。只需要加入頭文件ADTS即可。一個AAC原始數據塊長度是可變的,對原始幀加上ADTS頭進行ADTS的封裝,就形成了ADTS幀。

下面分析下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
  /**
     * 添加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) << 6) + (freqIdx << 2) + (chanCfg >> 2));
        packet[3] = (byte) (((chanCfg & 3) << 6) + (packetLen >> 11));
        packet[4] = (byte) ((packetLen & 0x7FF) >> 3);
        packet[5] = (byte) (((packetLen & 7) << 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頭文件代碼,供大家參考。

```cpp
int ff_adts_write_frame_header(ADTSContext *ctx,  
                               uint8_t *buf, int size, int pce_size)  
{  
    PutBitContext pb;  
  
    init_put_bits(&pb, buf, ADTS_HEADER_SIZE);  
  
    /* adts_fixed_header */  
    put_bits(&pb, 12, 0xfff);   /* syncword */  
    put_bits(&pb, 1, 0);        /* ID */  
    put_bits(&pb, 2, 0);        /* layer */  
    put_bits(&pb, 1, 1);        /* protection_absent */  
    put_bits(&pb, 2, ctx->objecttype); /* profile_objecttype */  
    put_bits(&pb, 4, ctx->sample_rate_index);  
    put_bits(&pb, 1, 0);        /* private_bit */  
    put_bits(&pb, 3, ctx->channel_conf); /* channel_configuration */  
    put_bits(&pb, 1, 0);        /* original_copy */  
    put_bits(&pb, 1, 0);        /* home */  
  
    /* adts_variable_header */  
    put_bits(&pb, 1, 0);        /* copyright_identification_bit */  
    put_bits(&pb, 1, 0);        /* copyright_identification_start */  
    put_bits(&pb, 13, ADTS_HEADER_SIZE + size + pce_size); /* aac_frame_length */  
    put_bits(&pb, 11, 0x7ff);   /* adts_buffer_fullness */  
    put_bits(&pb, 2, 0);        /* number_of_raw_data_blocks_in_frame */  
  
    flush_put_bits(&pb);  
  
    return 0;  
} 

————————————————
版權聲明:本文爲CSDN博主「范特西_jay」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/jay100500/article/details/52955232

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章