FLV視頻封裝格式詳細解析

轉載地址:https://www.jianshu.com/p/07657d85617e

FLV的定義:

Flash Video(簡稱FLV),是一種流行的網絡格式,是Adobe推出的。目前大部分視頻網站都支持這種格式。

FLV的文件結構

FLV文件由FLV Header 和 FLV Body構成。

FLV Header 頭部信息

Header 部分記錄了FLV的類型、版本、流信息、Header 長度等。一般整個Header佔用9個字節,大於9個字節則表示頭部信息在這基礎之上還存在擴展數據。Header 的頭部信息排布如下所示:


FLV頭部信息排布

FLV Body 文件內容部分

Body 是由一個個Tag組成的,每個Tag下面有一塊4個字節的空間,用來記錄這個Tag 的長度。這個後置的PreviousTagSize用於逆向讀取處理,表示的是前面的Tag的大小,對於FLV版本0x01來說,數值等於 11 + Tag的DataSize。其結構排布如下:


FLV Body結構排布

FLV Tag

每個Tag 也是由兩部分組成的:Tag Header 和 Tag Data。Tag Header 存放了當前Tag的類型,數據長度、時間戳、時間戳擴展、StreamsID等信息,然後再接着數據區Tag Data。Tag的排布如下:


Tag構成排布

Tag Data

Tag Data分成 Audio,Video,Script 三種。

Audio Tag Data

音頻的Tag Data又分爲 AudioTagHeader 和 Data 數據區,其排布結構如下圖所示:


音頻Tag Data排布

AudioTagHeader通常佔用1個字節,AAC編碼則會多出一個AACPacketType的字節,用於表示AAC的序列頭還是裸數據。
其中,前4bits表示SoundFormat,其數值對應聲音格式,如下:
0 - Linear PCM, platform endian
1 - ADPCM
2 - MP3
3 - LinearPCM,little endian
4 - Nellymoser 16-kHz mono
5 - Nellymoser 8-kHZ mono
6 - Nellymoser
7 - G.711 A-law logarithmic PCM
8 - G.711 U-law logarithmic PCM
9 - reserved
10 - AAC
11 - Speex
14 - MP3 8-kHz
15 - Device-specific sound

第5、6bit 表示SoundRate,數值對應採樣率,對於AAC來說,總是3:
0 - 5.5kHz
1 - 11kHz
2 - 22kHz
3 - 44kHz

第7bit 表示採樣大小:
0 - snd 8 bit
1 - snd 16 bit

第8bit 表示音頻聲道數,對於AAC來說,總是1:
0 - sndMono
1 - sndStereo

audio Data數據區,根據SoundFormat的數值來確定,如果SoundFormat = 10,則Data數據區是AAC編碼部分,其他聲音類型,則根據具體格式進行解析。

AAC編碼

針對AAC編碼,音頻Data數據區的定義如下:
AACPacketType = 0 時,表示AAC序列頭,也就是AudioSpecificConfig, AACPacketType = 1 時,表示AAC的裸流,也就是AAC Raw frame data。

AudioSpecificConfig

AudioSpecificConfig 只出現在第一個Audio Tag中,結構如下,

AudioSpecificConfig() {     
    audioObjectType;                              5bits
    samplingFrequencyIndex;                 4bits
    if  ( samplingFrequencyIndex == 0xf ) {
        samplingFrequency;                         24bits
    }
    channelConfiguration;                           4bits
    sbrPresentFlag = -1;
    if  ( audioObjectType == 5 ) {
        extensionAudioObjectType = audioObjectType;
        sbrPresentFlag = 1;
        extensionSamplingFrequencyIndex;            4bits
        if ( extensionSamplingFrequencyIndex == 0xf )  {
            extensionSamplingFrequency;             24bits
        }
        audioObjectType;                            5bits
    } else {
         extensionAudioObjectType = 0;
    }
<span class="hljs-keyword">if</span> ( audioObjectType == <span class="hljs-number">1</span> <span class="hljs-params">||</span> audioObjectType == <span class="hljs-number">2</span> <span class="hljs-params">||</span>
     audioObjectType == <span class="hljs-number">3</span> <span class="hljs-params">||</span> audioObjectType == <span class="hljs-number">4</span> <span class="hljs-params">||</span>
     audioObjectType == <span class="hljs-number">6</span> <span class="hljs-params">||</span> audioObjectType == <span class="hljs-number">7</span> ) {
    GASpecificConfig();
}
<span class="hljs-keyword">if</span> ( audioObjectType == <span class="hljs-number">8</span> )  {
    CelpSpecificConfig();
}
<span class="hljs-keyword">if</span> ( audioObjectType == <span class="hljs-number">9</span> ) {
    HvxcSpecificConfig();
}
<span class="hljs-keyword">if</span> ( audioObjectType == <span class="hljs-number">12</span> ) {
    TTSSpecificConfig();
}
<span class="hljs-keyword">if</span> ( audioObjectType == <span class="hljs-number">13</span> <span class="hljs-params">||</span> audioObjectType == <span class="hljs-number">14</span> <span class="hljs-params">||</span>
    audioObjectType == <span class="hljs-number">15</span> <span class="hljs-params">||</span> audioObjectType == <span class="hljs-number">16</span> ) {
    StructureAudioSpecificConfig();
}
<span class="hljs-keyword">if</span> ( audioObjectType == <span class="hljs-number">17</span> <span class="hljs-params">||</span> audioObjectType == <span class="hljs-number">19</span> <span class="hljs-params">||</span>
    audioObjectType == <span class="hljs-number">20</span> <span class="hljs-params">||</span> audioObjectType == <span class="hljs-number">21</span> <span class="hljs-params">||</span>
    audioObjectType == <span class="hljs-number">22</span> <span class="hljs-params">||</span> audioObjectType == <span class="hljs-number">23</span> ) {
    GASpecificConfig();
}
<span class="hljs-keyword">if</span> ( audioObjectType == <span class="hljs-number">24</span> ) {
    ErrorResilientCelpSpecificConfig();
}
<span class="hljs-keyword">if</span> ( audioObjectType == <span class="hljs-number">25</span> ) {
    ErrorResilientHvxcSpecificConfig();
}
<span class="hljs-keyword">if</span> ( audioObjectType == <span class="hljs-number">26</span> <span class="hljs-params">||</span> audioObjectType == <span class="hljs-number">27</span> ) {
    ParametricSpecificConfig();
}
<span class="hljs-keyword">if</span> ( audioObjectType == <span class="hljs-number">17</span> <span class="hljs-params">||</span> audioObjectType == <span class="hljs-number">19</span> <span class="hljs-params">||</span>
    audioObjectType == <span class="hljs-number">20</span> <span class="hljs-params">||</span> audioObjectType == <span class="hljs-number">21</span> <span class="hljs-params">||</span>
    audioObjectType == <span class="hljs-number">22</span> <span class="hljs-params">||</span> audioObjectType == <span class="hljs-number">23</span> <span class="hljs-params">||</span>
    audioObjectType == <span class="hljs-number">24</span> <span class="hljs-params">||</span> audioObjectType == <span class="hljs-number">25</span> <span class="hljs-params">||</span>
    audioObjectType == <span class="hljs-number">26</span> <span class="hljs-params">||</span> audioObjectType == <span class="hljs-number">27</span> )  {
    epConfig;                                      <span class="hljs-number">2</span>bits
    <span class="hljs-keyword">if</span> ( epConfig == <span class="hljs-number">2</span> <span class="hljs-params">||</span> epConfig == <span class="hljs-number">3</span> ) {
        ErrorProtectionSpecificConfig();
    }
    <span class="hljs-keyword">if</span> ( epConfig == <span class="hljs-number">3</span> ) {
        directMapping;                               <span class="hljs-number">1</span>bit
        <span class="hljs-keyword">if</span> ( ! directMapping ) {
          <span class="hljs-regexp">/* tbd */</span>
        }
    }
}
<span class="hljs-keyword">if</span> ( audioObjectType == <span class="hljs-number">28</span> ) {
    SSCSpecificConfig();
}
<span class="hljs-keyword">if</span> ( extensionAudioObjectType != <span class="hljs-number">5</span> &amp;&amp; bits_to_decode() &gt;= <span class="hljs-number">16</span> ) { 
    syncExtensionType;                                          <span class="hljs-number">11</span>bits
    <span class="hljs-keyword">if</span> ( syncExtensionType == <span class="hljs-number">0x2b7</span> ) {
        extensionAudioObjectType;                                 <span class="hljs-number">5</span>bits
        <span class="hljs-keyword">if</span> ( extensionAudioObjectType == <span class="hljs-number">5</span> ) {
            sbrPresentFlag;                                        <span class="hljs-number">1</span>bit
            <span class="hljs-keyword">if</span> ( sbrPresentFlag == <span class="hljs-number">1</span> ) {
                extensionSamplingFrequencyIndex;                     <span class="hljs-number">4</span>bits
                <span class="hljs-keyword">if</span> ( extensionSamplingFrequencyIndex == <span class="hljs-number">0xf</span> ) {
                    extensionSamplingFrequency;                      <span class="hljs-number">24</span>bits
                }
            }
        }
    }
}

}

AudioSpecificConfig 簡化格式如下:

audioObjectType               5bits    編碼結構類型,AAC-LC爲2
samplingFreguencyIndex        4bits    音頻採樣率索引值
channelConfiguration          4bits    音頻聲道數
GASpecificConfig
    frameLengthFlag           1bits    標誌位,用於表明IMDCT窗口長度,爲0
    dependsOnCoreCoder        1bits    標誌位,用於表明是否依賴corecoder,爲0
    extensionFlag             1bits    擴展標誌位,選擇了AAC-LC,這裏必須爲0

其中,samplingFreguencyIndex 對應關係如下:

0 - 96000
1 - 88200
2 - 64000
3 - 48000
4 - 44100
5 - 32000
6 - 24000
7 - 22050
8 - 16000
9 - 12000
10 - 11025
11 - 8000
12 - 7350
13 - Reserved
14 - Reserved
15 - frequency is written explictly

AAC Raw frame data

AAC裸流AAC Raw frame data,即AAC音頻原始數據,不包括AAC頭數據ADTS。

AAC頭部數據 ADTS

ADTS包括採樣頻率、幀長度等信息,共7個字節,分爲兩部分:
adts_fixed_header 、adts_variable_header

adts_fixed_header 排布如下:

adts_fixed_header() {
    syncword                  12bits    always 0xFFF
    ID                        1bit      0--MPEG-4   1--MPEG-2
    layer                     2bits     always '00'
    protection_absent         1bit
    profile                   2bits     0--Main profile     1--Low Complexity profile(LC) 
                                        2--Scalable Sampling Rate profile(SSR) 3--reserved
    sampling_frequency_index  4bits     音頻採樣率索引值
    private_bit               1bit
    channel_configuration     3bits     音頻聲道數
    original_copy             1bit
    home                      1bit
}

channel_configuration 對應關係如下:

0 bit : Defined in AOT Specific Config
1 bit : 1 channel:front-center
2 bit : 2 channels:front-left,front-right  
3 bit : 3 channels:front-center,front-left,front-right  
4 bit : 4 channels:front-center,front-left,front-right,back-center
5 bit : 5 channels:front-center,front-left,front-right,back-left,back-right  
6 bit : 6 channels:front-center,front-left,front-right,back-left,back-right,LFE-channel 
7 bit : 8 channels:front-center,front-left,front-right,side-left,side-right,back-left,back-right,LFE-channel 
8-15 bit:Reserved

adts_variable_header排布如下:

adts_variable_header() {
    copyright_identification_bit        1bit
    copyright_identification_start      1bit
    aac_frame_length                    13bits  ADTS頭 + AAC原始流     
    adts_buffer_fullness                11bits  0x7FF表示碼率可變的碼流
    number_of_raw_data_blocks_in_frame  2bits 
}

MP3編碼

如果是MP3 編碼部分,audio 數據區直接爲 MP3 頭 + MP3 原始數據。

MP3 頭部格式如下:

MP3FrameHeader
{
    sync                11bits  同步信息always 0xFFF     
    version             2bits   版本 00--MPEG 2.5  01--未定義 10--MPEG 2  11--MPEG 1    
    layer               2bits   層 00--未定義 01--Layer 3  10--Layer 2  11--Layer 1    
    error_protection    1bit    CRC校驗0--校驗  1--不校驗    
    bitrate_index       4bits   位率 
    sampling_frequency  2bits   採樣率索引值   
    padding             1bit    幀長調節    
    private             1bit    保留字    
    mode                2bits   聲道模式    
    mode_extension      2bits   擴充模式    
    copyright           1bit    版權     
    original            1bit    原版標誌    
    emphasis            2bits   強調模式 
}

sampling_frequency對應關係如下:

version   00--MPEG 2.5    01--未定義  10--MPEG 2    11--MPEG 1 
MPEG 1:   00--44.1kHz     01--48kHz   10--32kHz     11--未定義 
MPEG 2:   00--22.05kHz    01--24kHz   10--16kHz     11--未定義 
MPEG 2.5: 00--11.025kHz   01--12kHz   10--8kHz      11--未定義

mode對應關係如下:

00--立體聲Stereo   01--Joint Stereo   10--雙聲道   11--單聲道

Video Tag Data

如果Tag 包中的TagType = 9時,這個Tag就表示video數據。則StreamID之後緊跟着 VideoTagHeader 和 Video Data 數據區。
Video Tag 有一個字節的VideoTagHeader 和 Video數據區部分組成

VideoTagHeader

VideoTagHeader 通常由一個字節構成,前4bit表示類型,後4bit表示編碼器Id。


VideoTagHeader

Video數據區

Video數據區部分格式不確定。對於H264/AVC編碼部分,Video數據區排布如下:


Video數據區排布

其中,AVCsequenceheader只有出現在第一個Video Tag,只有一個。爲了能夠從FLV中獲取NALU,必須知道前面的NALU長度所佔的字節數,通常是1、2、4個字節,這個內容則必須從AVCDecoderConfigurationRecord中獲取,這個遵從標準ISO/IEC 14496-15的5.2.4小節。AVCDecoderConfigurationRecord 的結構如下:

aligned(8) class AVCDecoderConfigurationRecord {
    unsigned int(8) configurationVersion = 1;  //版本號
    unsigned int(8) AVCProfileIndication;     //sps[1],即0x67後面那個字節
    unsigned int(8) profile_compatibility;     //sps[2]
    unsigned int(8) AVCLevelIndication;      //sps[3]
    bit(6) reserved = '111111'b;
    unsigned int(2) lengthSizeMinusOne;     //NALUnitLength的長度減1,一般爲3  
    bit(3) reserved = '111'b;
    unsigned int(5) numOfSequenceParameterSets;    //sps個數,一般爲1
    for ( i=0; i<numOfSequenceParameterSets; i++ ) {
        unsigned int(16) sequenceParameterSetLength;  //sps的長度      
        bit(8*sequenceParameterSetLength) sequenceParameterSetNALUnit;
    }
    unsigned int(8) numOfPictureParameterSets;      //pps個數,一般爲1
    for ( i=0; i<numOfPictureParameterSets; i++) {
        unsigned int(16) pictureParameterSetLength;   //pps長度   
        bit(8*pictureParameterSetLength) pictureParameterSetNALUnit;
   }
}

其中,lengthSizeMinusOne + 1 = NALU長度字段所佔字節數

Script Tag

當TagType = 0x12時, 這個Tag就是Script tag。Script Tag一般只有一個,是FLV文件的第一個Tag,用於存放FLV文件信息,比如時長、分辨率、音頻採樣率等。所有的數據都是以數據類型 + (數據長度) + 數據格式出現,數據類型佔1個字節,數據長度看數據類型是否存在,後面纔是數據。數據排布如下:


ScriptTag排布

其中SCRIPTDATAOBJECTEND和SCRIPTDATAVARIABLEEND爲0x000009,用於標記結尾

SCRIPTDATASTRING結構爲:

StringLength    2bytes  
StringData      String 

SCRIPTDATALONGSTRING結構爲:

StringLength  4bytes  
StringData    String  

ECMA array type結構爲:

ECMAArrayLength   4bytes 
StringLength      2bytes 
StringData        String 
DataType          1byte 
Data              不定長 
SCRIPTDATAVARIABLEEND  

Object type結構爲:

StringLength  2bytes 
StringData    String 
DataType      1byte  
DataVale      不定長 
SCRIPTDATAOBJECTEND  

Strict array type結構爲:

ArrayNum    4bytes 
DataType    byte 
DataValue   不定長

類型在FLV的官方文檔中有詳細的介紹。

onMeteData

onMeteData 是FLV文件中的第一個Tag,是ScriptData中對我們來說十分重要的信息,結構如下:


onMeteData結構

audiocodecid

音頻編碼類型id,跟AudioTagHeader中的SoundFormat是對應的。

videocodecid

視頻編碼類型id,跟VideoTagHeader 的 CodecID是對應的

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