[email protected] 專欄
flv檔案主要由兩部分組成:header和body。
1.header
header部分記錄了flv的型別、版本等資訊,是flv的開頭,一般都差不多,佔9bytes。具體格式如下:檔案型別 | 3 bytes | “FLV” |
版本 | 1 byte | 一般為0x01 |
流資訊 | 1 byte | 倒數第一位是1表示有視訊,倒數第三位是1表示有音訊,倒數第二、四位必須為0 |
header長度 | 4 bytes | 整個header的長度,一般為9;大於9表示下面還有擴充套件資訊 |
2.body
body部分由一個個Tag組成,每個Tag的下面有一塊4bytes的空間,用來記錄這個tag的長度,這個後置用於逆向讀取處理,他們的關係如下圖:
2.1.Tag
每個Tag由也是由兩部分組成的:Tag Header和Tag Data。Tag Header裡存放的是當前Tag的型別、資料區(Tag Data)長度等資訊,具體如下:名稱 | 長度 | 介紹 |
---|---|---|
Tag型別 | 1 bytes |
8:音訊 9:視訊 18:指令碼 其他:保留 |
資料區長度 | 3 bytes | 在資料區的長度 |
時間戳 | 3 bytes | 整數,單位是毫秒。對於指令碼型的tag總是0 |
時間戳擴充套件 | 1 bytes | 將時間戳擴充套件為4bytes,代表高8位。很少用到 |
StreamsID | 3 bytes | 總是0 |
資料區(data) | 由資料區長度決定 | 資料實體 |
2.2.Tag Data
資料區根據Tag型別的不同可分為三種,音訊資料、視訊資料和指令碼資料。2.2.1.音訊資料
第一個byte是音訊的資訊,格式如下。名稱 | 長度 | 介紹 |
---|---|---|
音訊格式 | 4 bits |
0 = Linear PCM, platform endian 1 = ADPCM 2 = MP3 3 = Linear PCM, little endian 4 = Nellymoser 16-kHz mono 5 = Nellymoser 8-kHz mono 6 = Nellymoser 7 = G.711 A-law logarithmic PCM 8 = G.711 mu-law logarithmic PCM 9 = reserved 10 = AAC 11 = Speex 14 = MP3 8-Khz 15 = Device-specific sound |
取樣率 | 2 bits |
0 = 5.5-kHz 1 = 11-kHz 2 = 22-kHz 3 = 44-kHz 對於AAC總是3 |
取樣的長度 | 1 bit |
0 = snd8Bit 1 = snd16Bit 壓縮過的音訊都是16bit |
音訊型別 | 1 bit |
0 = sndMono 1 = sndStereo 對於AAC總是1 |
2.2.2.視訊資料
Field |
type |
Comment |
幀型別 |
UB4 |
1: keyframe (for AVC, a seekable frame)——h264的IDR,關鍵幀,可重入幀。 2: inter frame (for AVC, a non- seekable frame)——h264的普通幀
3: disposable inter frame (H.263 only) 5: video info/command frame |
編碼ID |
UB4 |
使用哪種編碼型別:
1: JPEG (currently unused) 2: Sorenson H.263 4: On2 VP6 5: On2 VP6 with alpha channel 6: Screen video version 2 7: AVC |
視訊資料 |
UI[N] |
如果是avc,則參考下面的介紹: AVCVIDEOPACKET |
AVCVIDEOPACKET
Field |
type |
Comment |
AVC packet型別 |
UI8 |
0:AVC序列頭 1:AVC NALU單元 2:AVC序列結束。低級別avc不需要。 |
CTS |
SI24 |
如果AVC packet型別是1,則為cts偏移(見下面的解釋),為0則為0 |
資料 |
UI8[n] |
如果AVC packet型別是0,則是解碼器配置,sps,pps。 如果是1,則是nalu單元,可以是多個,具體格式:將下面 |
關於CTS:這是一個比較難以理解的概念,需要和pts,dts配合一起理解。
首先,pts(presentation time stamps),dts(decoder timestamps),cts(CompositionTime)的概念:
pts:顯示時間,也就是接收方在顯示器顯示這幀的時間。單位為1/90000 秒。
dts:解碼時間,也就是rtp包中傳輸的時間戳,表明解碼的順序。單位單位為1/90000 秒。——根據後面的理解,pts就是標準中的CompositionTime
cts偏移:cts = (pts - dts) / 90 。cts的單位是毫秒。
pts和dts的時間不一樣,應該只出現在含有B幀的情況下,也就是profile main以上。baseline是沒有這個問題的,baseline的pts和dts一直想吐,所以cts一直為0。
在flv tag中的時戳就是DTS。
研究 一下文件, ISO/IEC 14496-12:2005(E) 8.15 Time to Sample Boxes,發現CompositionTime就是presentation time stamps,只是叫法不同。——需要再進一步確認。
在上圖中,cp就是pts,顯示時間。DT是解碼時間,rtp的時戳。
I1是第一個幀,B2是第二個,後面的序號就是攝像頭輸出的順序。決定了顯示的順序。
DT,是編碼的順序,特別是在有B幀的情況,P4要在第二個解,因為B2和B3依賴於P4,但是P4的顯示要在B3之後,因為他的順序靠後。這樣就存在顯示時間CT(PTS)和解碼時間DT的差,就有了CT偏移。
P4解碼時間是10,但是顯示時間是40,
AVCVIDEOPACKET中data格式:
Field |
type |
Comment |
長度 |
UI32 |
nalu單元的長度,不包括長度欄位。 |
nalu資料 |
UI8[N] |
NALU資料,沒有四個位元組的nalu單元頭,直接從h264頭開始,比如:65 ** ** **,41 ** ** ** |
長度 |
UI32 |
nalu單元的長度,不包括長度欄位。 |
nalu資料 |
UI8[N] |
NALU資料,沒有四個位元組的nalu單元頭,直接從h264頭開始,比如:65 ** ** **,41 ** ** ** |
... |
... |
... |
Data tags
主要是onMeta資訊需要關注。
AVCDecoderConfigurationRecord
AVCVIDEOPACKET的資料格式,儲存控制資訊。
記錄sps,pps資訊。一般出現在第二個tag中,緊跟在onMeta之後。
一個典型的序列:
0000190: 0900 0033 0000 0000 0000 0017 0000 0000 ...3............
00001a0:0164 002a ffe1 001e 6764 002a acd9 4078 .d.*....gd.*[email protected]
00001b0:0227 e5ff c389 4388 0400 0003 0028 0000 .'....C......(..
00001c0:0978 3c60 c658 0100 0568 ebec b22c 0000 .x<`.X...h...,..
17:表示h264IDR data
00:表示是AVC序列頭
00 00 00 :cts為0
//從此往下就是AVCDecoderConfigurationRecord
01 :版本號
64 00 2a:profile level id,sps的三個位元組,64表示是h264 high profile,2a表示level。
FF:NALU長度,為3?不知道這個長度用在哪裡。
E1:表示下面緊跟SPS有一個。
//sps[N]:sps陣列。
00 1e: 前面是兩個位元組的sps長度,表示後面的sps的長度是1e大小。
6764 002a acd9 4078 0227 e5ff c389 4388 0400 0003 0028 0000 0978 3c60 c658:sps的資料。
//因為只有一個sps,跳過這些長度,然後就是pps的個數資訊:
01 :pps個數,1
//pps[n] pps 的個數
00 05:表示pps的大小是5個位元組。
68 eb ec b2 2c:pps的資料
00 00 …….這是下一個tag 的內容了
2.2.3指令碼資料 指令碼Tag一般只有一個,是flv的第一個Tag,用於存放flv的資訊,比如duration、audiodatarate、creator、width等。
首先介紹下指令碼的資料型別。所有資料都是以資料型別+(資料長度)+資料的格式出現的,資料型別佔1byte,資料長度看資料型別是否存在,後面才是資料。
其中資料型別的種類有:
- 0 = Number type
- 1 = Boolean type
- 2 = String type
- 3 = Object type
- 4 = MovieClip type
- 5 = Null type
- 6 = Undefined type
- 7 = Reference type
- 8 = ECMA array type
- 10 = Strict array type
- 11 = Date type
- 12 = Long string type
如果型別為String,後面的2bytes為字串的長度(Long String是4bytes),再後面才是字串資料;如果是Number型別,後面的8bytes為Double型別的資料;Boolean型別,後面1byte為Bool型別。
知道了這些後再來看看flv中的指令碼,一般開頭是0x02,表示String型別,後面的2bytes為字串長度,一般是0x000a(“onMetaData”的長度),再後面就是字串“onMetaData”。好像flv格式的檔案都有onMetaData標記,在執行ActionScript的時候會用到它。後面跟的是0x08,表示ECMA Array型別,這個和Map比較相似,一個鍵跟著一個值。鍵都是String型別的,所以開頭的0x02被省略了,直接跟著的是字串的長度,然後是字串,再是值的型別,也就是上面介紹的那些了。
參考連結
https://wuyuans.com/2012/08/flv-format/http://blog.csdn.net/chgaowei/article/details/51243345