2017年8月29日 星期二

[轉] FLV文件格式官方規範詳解

http://blog.csdn.net/chgaowei/article/details/51243345

——如果要學習一個新的知識點,官方手冊可能是最快的途徑。查看網上其他人的總結也許入門更快,但是要準確,深入,完整,還是要看官方手冊。
以下內容來自對官方文檔Video File Format Specification Version 10的分析總結。過程中借助ffmpeg實際轉換了一個flv文件用例研究。
一個FLV文件,每種類型的tag都屬於一個流,也就是一個flv文件最多只有一個音頻流,一個視頻流,不存在多個獨立的音視頻流在一個文件的情況。(mp4好像是可以的)
另外,FLV文件格式所用的是大端序。
註:下面的數據type中,UI表示無符號整形,後面跟的數字表示其長度是多少位。比如UI8,表示無法整形,長度一個字節。UI24是三個字節。UB表示位域,UB5表示一個字節的5位。可以參考c中的位域結構體。
FLV頭

Field
type
Comment
簽名
UI8
』F'(0X46)
簽名
UI8
『L'(0X4C)
簽名
UI8
『V'(0x56)
版本
UI8
FLV的版本。0x01表示FLV 版本是1
保留字段
UB5
前五位必須是0
是否有音頻流
UB1
音頻流是否存在標誌
保留字段
UB1
必須是0
是否有視頻流
UB1
視頻流是否存在標誌
文件頭大小
UI32
FLV版本1時填寫9,表明的是FLV頭的大小,為後期的FLV版本擴展使用。包括這四個字節。
數據的起始位置就是從文件開頭偏移這麼多的大小。
FLV文件體

body部分由一個個Tag組成,每個Tag的下面有一塊4bytes的空間,用來記錄這個tag的長度,這個後置用於逆向讀取處理,他們的關係如下圖:

注意:頭下面四個自己就是PreviousTagSize,因為前一個沒有Tag,所以,值填寫0。
FLV tags 結構

Field
type
Comment
TAG類型
UI8
8: audio
9: video
18: script data——這裡是一些描述信息。
all others: reserved其他所有值未使用。
數據大小
UI24
數據區的大小,不包括包頭。包頭總大小是11個字節。
時戳
UI24
當前幀時戳,單位是毫秒。相對於FLV文件的第一個TAG時戳。第一個tag的時戳總是0。——不是時戳增量,rtmp中是時戳增量。
時戳擴展字段
UI8
如果時戳大於0xFFFFFF,將會使用這個字節。這個字節是時戳的高8位,上面的三個字節是低24位。
流ID
U24
總是0
數據區
UI8[n]

音頻數據

Field
type
Comment
音頻格式
UB4
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
7, 8, 14, and 15:內部保留使用。
flv是不支持g711a的,如果要用,可能要用線性音頻。
採樣率
UB2
For AAC: always 3
0 = 5.5-kHz
1 = 11-kHz
2 = 22-kHz
3 = 44-kHz
採樣大小
UB1
0 = snd8Bit
1 = snd16Bit
聲道
UB1
0=單聲道
1=立體聲,雙聲道。AAC永遠是1
聲音數據
UI8[N]
如果是PCM線性數據,存儲的時候每個16bit小端存儲,有符號。
如果音頻格式是AAC,則存儲的數據是AAC AUDIO DATA,否則為線性數組。
AAC AUDIO DATA

視頻數據

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)
4: generated keyframe (reserved for server use only)
5: video info/command frame
編碼ID
UB4
使用哪種編碼類型:
1: JPEG (currently unused) 2: Sorenson H.263
3: Screen video
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.*..@x
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 的內容了

沒有留言:

張貼留言