轉載地址: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 Body 文件內容部分
Body 是由一個個Tag組成的,每個Tag下面有一塊4個字節的空間,用來記錄這個Tag 的長度。這個後置的PreviousTagSize用於逆向讀取處理,表示的是前面的Tag的大小,對於FLV版本0x01來說,數值等於 11 + Tag的DataSize。其結構排布如下:
FLV Tag
每個Tag 也是由兩部分組成的:Tag Header 和 Tag Data。Tag Header 存放了當前Tag的類型,數據長度、時間戳、時間戳擴展、StreamsID等信息,然後再接着數據區Tag Data。Tag的排布如下:
Tag Data
Tag Data分成 Audio,Video,Script 三種。
Audio Tag Data
音頻的Tag Data又分爲 AudioTagHeader 和 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> && bits_to_decode() >= <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。
Video數據區
Video數據區部分格式不確定。對於H264/AVC編碼部分,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個字節,數據長度看數據類型是否存在,後面纔是數據。數據排布如下:
其中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中對我們來說十分重要的信息,結構如下:
audiocodecid
音頻編碼類型id,跟AudioTagHeader中的SoundFormat是對應的。
videocodecid
視頻編碼類型id,跟VideoTagHeader 的 CodecID是對應的
</div>
</div>