FLV文件格式官方規範詳解

——如果要學習一個新的知識點,官方手冊可能是最快的途徑。查看網上其他人的總結也許入門更快,但是要準確,深入,完整,還是要看官方手冊。

以下內容來自對官方文檔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 的內容了



我 的微信公衆號

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