天天看點

FLV 封裝格式解析1、FLV 簡介

1、FLV 簡介

FLV(Flash Video) 是 Adobe 公司推出的一種流媒體格式,由于其封裝後的音視訊檔案體積小、封裝簡單等特點,非常适合于網際網路上使用。目前主流的視訊網站基本都支援FLV。采用 FLV 格式封裝的檔案字尾為.flv。直播場景下拉流比較常見的是 http-flv 直播流,具有延時低,易傳輸等特點。

2、FLV 格式

總體上看,FLV 由檔案頭(file header)和(file body)組成,其中 FLV body 由一對對的 Tag 和 Previous Tag Size(占用4個位元組,記錄前一個 Tag 的大小,用于逆向讀取處理,FLV header 後的第一個 Previous Tag Size 為 0)組成。而 Tag 一般分為三種類型:腳本資料、視訊資料、音頻資料,有 Tag header 和 Tag Data 組成。FLV 資料以大端序進行存儲,在解析時需要注意。一個标準 FLV 檔案結構如下圖:

FLV 封裝格式解析1、FLV 簡介

FLV 檔案的詳細内容結構如下:

FLV 封裝格式解析1、FLV 簡介

2.1 FLV header(檔案頭)

從上圖中可以看到,FLV 頭占用 9 個位元組,用來辨別檔案類型為 FLV 類型,以及後續的音視訊辨別。一個 FLV 檔案,每種類型的 tag 都屬于一個流,也就是一個 flv 檔案最多隻有一個音頻流,一個視訊流,不存在多個獨立的音視訊流在一個檔案的情況。FLV 頭的結構如下:

FLV 封裝格式解析1、FLV 簡介
上面的 UI 表示無符号整型,後面跟着的數字代表其長度是多少位;UB 表示位域,表示一個位元組的多少位。可以參考C語言中的結構體位域。

2.2 FLV Body(檔案體)

FLV Header之後,就是 FLV File Body。FLV File Body 是由一連串的 back-pointers + tags 構成。

FLV 封裝格式解析1、FLV 簡介

back-pointer

back-pointer 表示 Previous Tag Size(前一個 tag 的位元組資料長度),占4個位元組,第一個 back-pointer 資料為0。

Tag

音視訊資料,每一個 tag 由兩部分組成:tag header 和 tag data。

3、FLV Tag 詳解

3.1 Tag 資料結構

flv_tag_header + flv_tag_data,其中 flv_tag_header 占 11 個位元組。

3.2 FLV_tag_header

存放目前 tag 的類型、資料區長度、時間戳等資訊。tag header 一般占 11 個位元組的内粗空間。

FLV 封裝格式解析1、FLV 簡介

3.3 FLV_Tag_Data

FLV Tag 的類型可以是視訊、音頻和 Script(腳本類型)

3.3.1 Script Tag Data(腳本類型、幀類型)

腳本 Tag 一般隻有一個,是 flv 的第一個 Tag,跟在 flv header 後,用于存放 flv 視訊和音頻的元資訊,比如 duration、audiodatarate、creator、width 等。一般來說,Script Tag Data結構包含兩個 AMF 包(AMF(Action Message Format)是 Adobe 設計的一種通用資料封裝格式,在 Adobe 的很多産品中應用,簡單來說,AMF 将不同類型的資料用統一的格式來描述),結構如下:

FLV 封裝格式解析1、FLV 簡介

第一個 AMF 包(封裝字元串類型資料):

第 1 個位元組表示 AMF 包類型,一般總是 0x02,表示字元串; 第 2-3 個位元組為 UI16 類型值,表示字元串的長度,一般總是 0x000A(“onMetaData”長度); 後面位元組為字元串資料,一般總為 “onMetaData”(6F,6E,4D,65,74,61,44,61,74,61)。

第二個 AMF 包(封裝一個數組類型,這個數組中包含了音視訊資訊項的名稱和值):

第 1 個位元組表示 AMF 包類型,一般總是 0x08,表示數組。 第 2-5 個位元組為 UI32 類型值,表示數組元素的個數。 後面即為各數組元素的封裝,數組元素為元素名稱和值組成的對。表示方法如下: 第 1-2 個位元組表示元素名稱的長度,假設為 L。後面跟着為長度為 L 的字元串。第 L+3 個位元組表示元素值的類型。後面跟着為對應值,占用位元組數取決于值的類型。

FLV 封裝格式解析1、FLV 簡介

常見的數組元素表示如下表:

FLV 封裝格式解析1、FLV 簡介

【學習位址】:FFmpeg/WebRTC/RTMP/NDK/Android音視訊流媒體進階開發

【文章福利】:免費領取更多音視訊學習資料包、大廠面試題、技術視訊和學習路線圖,資料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以點選1079654574加群領取哦~

FLV 封裝格式解析1、FLV 簡介

3.3.2 Video Tag Data(視訊類型)

視訊 Tag Data 開始的第一個位元組包含視訊資料的參數資訊,從第二個位元組開始為視訊流資料。結構如下:

FLV 封裝格式解析1、FLV 簡介

第一個位元組包含視訊資訊:前4位表示幀類型;後4位表示編碼類型。

FLV 封裝格式解析1、FLV 簡介

第二個位元組開始為視訊資料

FLV 封裝格式解析1、FLV 簡介

AVC VIDEO PACKET

視訊的格式(CodecID)是 AVC(H.264)的話,VideoTagHeader 會多出 4 個位元組的資訊,AVCPacketType 和 CompositionTime,是以是 H264 編碼的情況下 VideoHeader 長度是 5 個位元組。 AVC VIDEO PACKET 結構如下:

FLV 封裝格式解析1、FLV 簡介

AVCDecoderConfigurationRecord

包含着 H.264 解碼相關比較重要的 sps 和 pps 資訊,再給 AVC 解碼器送資料流之前一定要把 sps 和 pps 資訊送出,否則的話解碼器不能正常解碼。 而且在解碼器 stop 之後再次 start 之前,如 seek、快進快退狀态切換等,都需要重新送一遍 sps 和 pps 的資訊。 AVCDecoderConfigurationRecord 在 FLV 檔案中一般情況也是出現 1 次,也就是第一個 video tag。

sps pps

第一個 video tag 一般存放的是 sps 和 pps。存儲的格式: 0x01 + sps[1] + sps[2] + sps[3] + 0xFF + 0xE1 + sps size + sps + 01 + pps size + pps 其中 sps size 和 pps siz e各占兩個位元組。 data 資料結構:

FLV 封裝格式解析1、FLV 簡介
關于 CTS:需要和 pts,dts 配合一起了解。 pts:presentation time stamps 顯示時間,也就是接收方在顯示器顯示這幀的時間。機關為1/90000 秒; dts:decoder timestamps 解碼時間,也就是rtp包中傳輸的時間戳,表明解碼的順序。機關為1/90000 秒。——根據後面的了解,pts 就是标準中的 CompositionTime; cts偏移:cts = (pts - dts) / 90。cts 的機關是毫秒; pts 和 dts 的時間不一樣,應該隻出現在含有 B 幀的情況下,也就是 profile main 以上。baseline 是沒有這個問題的,baseline 的 pts 和 dts 一直相同,是以 cts 一直為 0 。

3.3.3 Audio Tag Data(音頻類型)

音頻 Tag Data 區域開始的第一個位元組包含了音頻資料的參數資訊,從第二個位元組開始為音頻流資料。結構如下:

FLV 封裝格式解析1、FLV 簡介

第一個位元組包含音頻資訊:前 4bit 表示音頻格式;第 5、6bit 表示采樣率;第 7bit 表示采樣精度;第 8bit 表示音頻聲道。

FLV 封裝格式解析1、FLV 簡介

第二個位元組開始為音頻資料

FLV 封裝格式解析1、FLV 簡介

其中如果音頻格式為 10,即是 AAC 格式的,AudioTagHeader 中會多出一個位元組 AACPacketType,這個字段來表示 AACAUDIODATA 的類型:0 = AAC sequence header,1 = AAC raw。

  • AAC sequence header 也就是包含了 AudioSpecificConfig,AudioSpecificConfig 包含着一些更加詳細音頻的資訊。
  • AAC raw 這種包含的就是音頻 ES 流了,也就是 audio payload。
12 00 01 17 00 00 00 00 00 00 00 (tag header 11 位元組) 0x12 表示這是一個 scripts tag, 00 01 17 三子節表示 tag data 長度為 279 個位元組,Timestreamp、TimestampExtended、stream id 均為0。 下一個 back-pointers,表示該 scripts tag 的 size,即 279 + 11 = 290 = 0x122,即 00 00 01 22,可以看到最後4位元組剛好是的。 02 00 0a 6f 6e 4d 65 74 61 44 61 74 61 表示第一個 AMF 包,02 表示類型為 string type,後面兩個位元組 00 0A 表示長度是 10,值 onMetaData; 03 表示 ObjectType,此處應該一般是 08 才對,表示數組類型;表示有8個鍵值對。 00 05 表示鍵長度,77 69 64 74 68 表示 width,00 表示類型為 Number,後面 8 位元組表示值; 00 06 表示鍵長度, 68 65 69 67 68 74 表示 height,00 表示類型為 Number,後面 8 位元組表示值。 以此類推解析到最後 end marker 00 00 09,表示解析完畢。
           

4、舉例子

根據真實資料來解析 FLV 格式。

4.1 FLV header

<464c5601 05000000 09000000 00120001 17000000 00000000 02000a6f 
6e4d6574 61446174 61030005 77696474 68004084 00000000 00000006 
68656967 68740040 7e000000 00000000 0c736f75 7263655f 77696474 
6800409e 00000000 0000000d 736f7572 63655f68 65696768 74004090 
e0000000 00000009 6672616d 65726174 6500402e 00000000 0000000c 
76696465 6f636f64 65636964 00401c00 00000000 00000f61 7564696f 
73616d70 6c657261 74650040 bf400000 00000000 0f617564 696f7361 
6d706c65 73697a65 00403000 00000000 00000673 74657265 6f010000 
0c617564 696f636f 64656369 64004024 00000000 0000000c 63726561 
74696f6e 64617465 02001732 3032312d 31312d30 33203037 3a32373a 
33302055 54430006 61757468 6f720200 034c4c4c 00000900 000122>
           

46 4C 56 01 05 00 00 00 09:表示 FLV header(9 位元組),音視訊都有; 0x 00 00 00 00 表示第一個 back-pointers(前一個 tag 的 size)。因為前面沒有 tag,是以為 0。

4.2 腳本 Tag

12 00 01 17 00 00 00 00 00 00 00 (tag header 11 位元組) 0x12 表示這是一個 scripts tag, 00 01 17 三子節表示 tag data 長度為 279 個位元組,Timestreamp、TimestampExtended、stream id 均為0。 下一個 back-pointers,表示該 scripts tag 的 size,即 279 + 11 = 290 = 0x122,即 00 00 01 22,可以看到最後4位元組剛好是的。 02 00 0a 6f 6e 4d 65 74 61 44 61 74 61 表示第一個 AMF 包,02 表示類型為 string type,後面兩個位元組 00 0A 表示長度是 10,值 onMetaData; 03 表示 ObjectType,此處應該一般是 08 才對,表示數組類型;表示有8個鍵值對。 00 05 表示鍵長度,77 69 64 74 68 表示 width,00 表示類型為 Number,後面 8 位元組表示值; 00 06 表示鍵長度, 68 65 69 67 68 74 表示 height,00 表示類型為 Number,後面 8 位元組表示值。 以此類推解析到最後 end marker 00 00 09,表示解析完畢。

4.3 第一個 video tag

一般包含 sps、pps

<09000022 00000000 00000017 00000000 014d401e ffe1000e 674d401e 
a680a03d a6e02020 20400100 0468ee3c 80000000 2d>
           

09 00 00 22 00 00 00 00 00(tag header 11 位元組) 09 表示視訊 tag; 00 00 22 表示長度為 0x22 = 34,加上頭部長度 11 位元組,為 45。下一個 back-pointers 是 00 00 00 2D(上面資料的最後的四位元組), Timestreamp、TimestampExtended、stream id 均為 0; 下面就是 tag data 資料: 0x17 即 0001 0111,前 4 位表示幀類型,1 為關鍵幀;後 4 位表示編碼 ID,7 表示 AVC。 視訊格式是AVC(H.264)類型的話,後面 1 個位元組表示 AVCPacketType,再後三個位元組表示 CompositionTime: 00 AVCPacketType 為 0,表示是 AVCDecoderConfigurationRecord。就表示包含着 sps 和 pps 了。這個東西要第一個發給解碼器,要不然不能正常解碼。 00 00 00 CompositionTime 為 0。接下來就是 sps 和 pps 的資訊了。 按照 0x01 + sps[1] + sps[2] + sps[3] + 0xFF + 0xE1 + sps size + sps + 01 + pps size + pps 的格式,參照二進制資料: sps[1] = 4d;sps[2] = 40;sps[3] = 1e;sps size = 000e,表示 sps 的長度為 14,14 位元組的資料讀取完,讀到 01;pps size = 0004,表示 pps 的長度為 4,讀取完後該 tag 結束。下一個back-pointers。

4.4 第二個 video tag 以及後續的 video tag

<09002374 00000000 00000017 01000000 0000236b 65b82129 7f7ae073 
74574ffe 0fd1ebcc 6851014a d25aa986 6daee3a1 6f0d7b77 734e17a9 
0fe00e56 a92b864b 3d423839 c229a2ab 23208467 ... ...00 00237f>
           

下一個 video 長度為 9076 的視訊資料,0x17 後一位 AVCPacketType 01,表示 NALU 資料,三個 CompositionTime 位元組過後,就是 NALU 資料了。

4.5 第一個 audio tag 以及後續的 audio tag

<08000004 00005d00 000000ae 00158800 00000f>
           

08 00 00 04 00 00 5d 00 00 00 00 0x08 表示音頻,00 00 04 表示長度為 4,時間戳為 93;加上頭部長度 11,為 15,下一個 back-pointers 是 0x 00 00 00 0F(最後四子節);接下來就是 tag data: AE: 即 0b10101110,前 4 位為 10,表示音頻格式是 AAC;10 會多一個位元組 AACPacketType,表示該 AACAUDIODATA 的類型;第 5、6 位為 11,十進制 3,表示采樣率為 44kHz;第 7 位為1,表示 16 位采樣精度;第 8 位為 0,表示 sndMono 單聲道。 00: 表示 AACPacketType,為 0 表示該 Tag 是 AAC sequence header。接下來兩個位元組表示 AudioSpecificConfig,包含更加詳細音頻的資訊。讀取完後該 tag 結束。下一個 back-pointers。

4.6 第二個 audio tag 以及後續的 audio tag

<080002fb 00005d00 000000ae 01010e34 14564a2d 92154484 d0602e72 
f7cab6d6 af82156c cae24cba a6f8d2b9 d2d512d3 db8b5632 ef76c8a9 
95225c3b 69e84d7d 03a6fa66 7b475759 0ead71f5 37c73379 fd124cd5 
1ba64d95 48d7aa3b c558863e 090fc9ae ... ...0000 0306>
           

下一個長度為 752 的音頻資料,時間戳為 93,0xae 後一位為 01,表示 ACC raw,即音頻 NALU 資料。

原文連結:FLV 封裝格式解析 - 簡書

繼續閱讀