直播協議 HTTP-FLV 詳解

傳統的直播協議要麼使用 Adobe 的基於 TCP 的 RTMP 協議,要麼使用 Apple 的基於 HTTP 的 HLS 協議。html

今天我要向你們介紹另一種結合了 RTMP 的低延時,以及能夠複用現有 HTTP 分發資源的流式協議 HTTP-FLV。ios

FLV

首先介紹一下 FLV 文件格式的細節。網絡

FLV Adobe 官方標準

FLV 文件格式標準是寫在 F4V/FLV file format spec v10.1 的附錄 E 裏面的 FLV File Format。ide

單位說明

類型工具

說明優化

Unitui

data編碼

types加密

 

SI8debug

Signed 8-bit integer

SI16

Signed 16-bit integer

SI24

Signed 24-bit integer

SI32

Signed 32-bit integer

SI64

Signed 32-bit integer

UI8

Unsigned 8-bit integer

UI16

Unsigned 16-bit integer

UI24

Unsigned 24-bit integer

UI32

Unsigned 32-bit integer

UI64

Unsigned 64-bit integer

xxx[]

Slice of type xxx

xxx[n]

Array of type xxx

STRING

Sequence of Unicode 8-bit characters (UTF-8), terminated with 0x00

FLV 文件頭和文件體 (E.2, E.3)

從整個文件上看,FLV = FLV File Header + FLV File Body。

字段

類型

說明

FLV File Header

   

Signature

UI8[3]

簽名,老是 「FLV」 (0x464C56)

Version

UI8

版本,老是 0x01,表示 FLV version 1

TypeFlagsReserved

UB [5]

全 0

TypeFlagsAudio

UB[1]

1 = 有音頻

TypeFlagsReserved

UB[1]

全 0

TypeFlagsVideo

UB[1]

1 = 有視頻

DataOffset

UI32

整個文件頭長度,對於FLV v1,老是 9

FLV File Body

   

PreviousTagSize0

UI32

老是 0

Tag1

FLVTAG

第一個 tag

PreviousTagSize1

UI32

前一個 tag 的大小, 包括他的 header,即:11 + 前一個 tag 的大小

Tag2

FLVTAG

第二個 tag

   

PreviousTagSizeN-1

UI32

前一個 tag 大小

TagN

FLVTAG

最後一個 tag

PreviousTagSizeN

UI32

最後一個 tag 大小,包括他的 header

一般,FLV 的前 13 個字節(flv header + PreviousTagSize0)徹底相同,因此,程序中會單獨定義一個常量來指定。

FLV Tag (E.4)

字段

類型

說明

FLV Tag

   

Reserved

UB[2]

保留給FMS, 應爲 0

Filter

UB[1]

0 = unencrypted tags,1 = encrypted tags

TagType

UB [5]

類型,0x08 = audio,0x09 = video,0x12 = script data

DataSize

UI24

message 長度,從 StreamID 到 tag 結束(len(tag) - 11)

Timestamp

UI24

相對於第一個 tag 的時間戳(unit: ms),第一個 tag 老是 0

TimestampExtended

UI8

Timestamp 的高 8 位。 擴展 Timestamp 爲 SI32 類型

StreamID

UI24

老是 0,至此爲 11 bytes

AudioTagHeader

 

IF TagType == 0x08

VideoTagHeader

 

IF TagType == 0x09

EncryptionHeader

 

IF Filter == 1

FilterParams

 

IF Filter == 1

Data

 

AUDIODATA 或者 VIDEODATA 或者 SCRIPTDATA

Timestamp 和 TimestampExtended 組成了這個 TAG 包數據的 PTS 信息,PTS = Timestamp | TimestampExtended << 24。

AudioTag (E.4.2)

因爲 AAC 編碼的特殊性,這裏着重說明了 AAC 編碼的 Tag 格式。

字段

類型

說明

Audio Tag

   

AudioTagHeader

   

SoundFormat

UB[4]

音頻編碼格式。2 = MP3,10 = AAC,11 = Speex

SoundRate

UB[2]

採樣率。0 = 5.5 kHz,1 = 11 kHz,2 = 22 kHz,3 = 44 kHz

SoundSize

UB[1]

採樣大小。 0 = 8-bit,1 = 16-bit

SoundType

UB[1]

音頻聲道數。0 = Mono,1 = Stereo

AACPacketType

UI8

只有當 SoundFormat 爲 10 時,纔有該字段。0 = AAC sequence header,1 = AAC raw

AACAUDIODATA

   

Data

AudioSpecificConfig

IF AACPacketType == 0,包含着一些更加詳細音頻的信息

Data

Raw AAC frame data in UI8 [n]

IF AACPacketType == 1,audio payload,n = [AAC Raw data length] - ([has CRC] ? 9:7)

AudioTagHeader 的第一個字節,也就是接跟着 StreamID 的 1 個字節包含了音頻類型,採樣率等的基本信息。

AudioTagHeader 以後跟着的就是 AUDIODATA 部分了。可是,這裏有個特例,若是音頻格式(SoundFormat)是 AAC,AudioTagHeader 中會多出 1 個字節的數據 AACPacketType,這個字段來表示 AACAUDIODATA 的類型:0 = AAC sequence header,1 = AAC raw。

AudioSpecificConfig 結構描述很是複雜,在標準文檔中是用僞代碼描述的,這裏先假定要編碼的音頻格式,作一下簡化。

音頻編碼爲:AAC-LC,音頻採樣率爲 44100。

字段

類型

說明

AudioSpecificConfig

   

audioObjectType

UB[5]

編碼結構類型,AAC-LC 爲 2

samplingFrequencyIndex

UB[4]

音頻採樣率索引值,44100 對應值 4

channelConfiguration

UB[4]

音頻輸出聲道,2

GASpecificConfig

   

frameLengthFlag

UB[1]

標誌位,用於代表 IMDCT 窗口長度,0

dependsOnCoreCoder

UB[1]

標誌位,代表是否依賴於 corecoder,0

extensionFlag

UB[1]

選擇了 AAC-LC,這裏必須爲 0

在 FLV 的文件中,通常狀況下 AAC sequence header 這種包只出現1次,並且是第一個 audio tag,爲何須要這種 tag,由於在作 FLV demux 的時候,若是是 AAC 的音頻,須要在每幀 AAC ES 流前邊添加 7 個字節 ADST 頭,ADST 是解碼器通用的格式,也就是說 AAC 的純 ES 流要打包成 ADST 格式的 AAC 文件,解碼器才能正常播放。就是在打包 ADST 的時候,須要 samplingFrequencyIndex 這個信息,samplingFrequencyIndex 最準確的信息是在 AudioSpecificConfig 中,這樣,你就徹底能夠把 FLV 文件中的音頻信息及數據提取出來,送給音頻解碼器正常播放了。

VideoTag (E.4.3)

因爲 AVC(H.264) 編碼的特殊性,這裏着重說明了 AVC(H.264) 編碼的 Tag 格式。

字段

類型

說明

Video Tag

   

VideoTagHeader

   

FrameType

UB[4]

1 = key frame,2 = inter frame

CodecID

UB[4]

7 = AVC

AVCPacketType

UI8

IF CodecID == 7,0 = AVC sequence header(AVCDecoderConfigurationRecord),1 = One or more AVC NALUs (Full frames are required),2 = AVC end of sequence

CompositionTime

SI24

IF AVCPacketType == 1 Composition time offset ELSE 0

VideoTagHeader 的第一個字節,也就是接跟着 StreamID 的 1 個字節包含着視頻幀類型及視頻 CodecID 等最基本信息。

VideoTagHeader 以後跟着的就是 VIDEODATA 部分了。可是,這裏有個特例,若是視頻格式(CodecID)是 AVC,VideoTagHeader 會多出 4 個字節的信息。

AVCDecoderConfigurationRecord 包含着是 H.264 解碼相關比較重要的 SPS 和 PPS 信息,在給 AVC 解碼器送數據流以前必定要把 SPS 和 PPS 信息送出,不然的話,解碼器不能正常解碼。並且在解碼器 stop 以後再次 start 以前,如 seek,快進快退狀態切換等,都須要從新送一遍 SPS 和 PPS 的信息。AVCDecoderConfigurationRecord 在 FLV 文件中通常狀況也只出現 1 次,也就是第一個 video tag。

AVCDecoderConfigurationRecord 長度爲 sizeof(UI8) * (11 + sps_size + pps_size)。

字段

類型

說明

AVCDecoderConfigurationRecord

   

configurationVersion

UI8

版本號,1

AVCProfileIndication

UI8

SPS[1]

profileCompatibility

UI8

SPS[2]

AVCLevelIndication

UI8

SPS[3]

reserved

UB[6]

111111

lengthSizeMinusOne

UB[2]

NALUnitLength - 1,通常爲 3

reserved

UB[3]

111

numberOfSequenceParameterSets

UB[5]

SPS 個數, 通常爲 1

sequenceParameterSetNALUnits

UI8[sps_size + 2]

sps_size(16bits) + sps(UI8[sps_size])

numberOfPictureParameterSets

UI8

PPS 個數, 通常爲 1

pictureParameterSetNALUnits

UI8[pps_size + 2]

pps_size(16bits) + pps(UI8[pps_size])

SCRIPTDATA (E.4.4)

ScriptTagBody 內容用 AMF 編碼

字段

類型

說明

SCRIPTDATA

   

ScriptTagBody

   

Name

SCRIPTDATAVALUE

Method or object name. SCRIPTDATAVALUE.Type = 2 (String)

Vale

SCRIPTDATAVALUE

AMF arguments or object properties.

SCRIPTDATAVALUE

   

Type

UI8

ScriptDataValue 的類型

ScriptDataValue

各類類型

Script data 值

一個 SCRIPTDATAVALUE 記錄包含一個有類型的 ActionScript 值。

onMetadata (E.5)

FLV metadata object 保存在 SCRIPTDATA 中, 叫 onMetaData。不一樣的軟件生成的 FLV 的 properties 不一樣。

字段

類型

說明

onMetaData

   

audiocodecid

Number

Audio codec ID used in the file

audiodatarate

Number

Audio bit rate in kilobits per second

audiodelay

Number

Delay introduced by the audio codec in seconds

audiosamplerate

Number

Frequency at which the audio stream is replayed

audiosamplesize

Number

Resolution of a single audio sample

canSeekToEnd

Boolean

Indicating the last video frame is a key frame

creationdate

String

Creation date and time

duration

Number

Total duration of the file in seconds

filesize

Number

Total size of the file in bytes

framerate

Number

Number of frames per second

height

Number

Height of the video in pixels

stereo

Boolean

Indicating stereo audio

videocodecid

Number

Video codec ID used in the file (see E.4.3.1 for available CodecID values)

videodatarate

Number

Video bit rate in kilobits per second

width

Number

Width of the video in pixels

keyframes 索引信息

官方的文檔中並無對 keyframes index 作描述,可是,flv 的這種結構每一個 tag 又不像 TS 有同步頭,若是沒有 keyframes index 的話,須要按順序讀取每個tag, seek 及快進快退的效果會很是差。後來在作 flv 文件合成的時候,發現網上有的 flv 文件將 keyframes 信息隱藏在 Script Tag 中。

keyframes 幾乎是一個非官方的標準, 也就是民間標準。兩個經常使用的操做 metadata 的工具是 flvtool2 和 FLVMDI,都是把 keyframes 做爲一個默認的元信息項目。在 FLVMDI 的主頁上有描述:

 

keyframes: (Object) This object is added only if you specify the /k switch. 'keyframes' is known to FLVMDI and if /k switch is not specified, 'keyframes' object will be deleted.

 'keyframes' object has 2 arrays: 'filepositions' and 'times'. Both arrays have the same number of elements, which is equal to the number of key frames in the FLV. Values in times array are in 'seconds'. Each correspond to the timestamp of the n'th key frame. Values in filepositions array are in 'bytes'. Each correspond to the fileposition of the nth key frame video tag (which starts with byte tag type 9).

 

也就是說 keyframes 中包含着 2 個內容 「filepositions」 和 「times」分別指的是關鍵幀的文件位置和關鍵幀的 PTS。經過 keyframes 能夠創建起本身的 Index,而後在 seek 和快進快退的操做中,快速有效地跳轉到你想要找的關鍵幀位置進行處理。

FLV 分析工具

  • http://www.flvmeta.com/

  • yamdi:將flv轉成帶索引的flv,yamdi -i i.flv -o o.flv

  • flvlib: pip install flvlib, 查看索引信息:debug-flv --metadata file.flv

  • flvcheck:http://www.adobe.com/products/adobe-media-server-family/tool-downloads.html

HTTP-FLV

HTTP-FLV,即將音視頻數據封裝成 FLV,而後經過 HTTP 協議傳輸給客戶端。

HLS 實際上是一個 「文本協議」,而並不是流媒體協議。那麼,什麼樣的協議才能稱之爲流媒體協議呢?

流(stream): 數據在網絡上按時間前後次序傳輸和播放的連續音/視頻數據流。之因此能夠按照順序傳輸和播放連續是由於在相似 RTMP、FLV 協議中,每個音視頻數據都被封裝成了包含時間戳信息頭的數據包。而當播放器拿到這些數據包解包的時候可以根據時間戳信息把這些音視頻數據和以前到達的音視頻數據連續起來播放。MP四、MKV 等等相似這種封裝,必須拿到完整的音視頻文件才能播放,由於裏面的單個音視頻數據塊不帶有時間戳信息,播放器不能將這些沒有時間戳信息數據塊連續起來,因此就不能實時的解碼播放。

延遲分析

理論上(除去網絡延遲外),FLV 能夠作到僅僅一個音視頻 tag 的延遲。

相比 RTMP 的優勢:

  • 能夠在必定程度上避免防火牆的干擾 (例如, 有的機房只容許 80 端口經過);

  • 能夠很好的兼容 HTTP 302 跳轉,作到靈活調度;

  • 可使用 HTTPS 作加密通道;

  • 很好的支持移動端(Android,IOS);

 

推薦閱讀:

基於 WEBRTC 技術的實時通訊服務開發實踐

直播卡頓緣由詳解及優化

從Html5直播到互動直播,看直播協議的選擇

相關文章
相關標籤/搜索