flv格式詳解+實例剖析

簡介

FLV(Flash Video)是現在非常流行的流媒體格式,由于其視頻文件體積輕巧、封裝播放簡單等特點,使其很適合在網絡上進行應用,目前主流的視頻網站無一例外地使用了FLV格式。另外由于當前瀏覽器與Flash Player緊密的結合,使得網頁播放FLV視頻輕而易舉,也是FLV流行的原因之一。

FLV是流媒體封裝格式,我們可以將其數據看為二進制字節流。總體上看,FLV包括文件頭(File Header)和文件體(File Body)兩部分,其中文件體由一系列的Tag及Tag Size對組成。


flv.jpg

FLV格式解析

先來一張圖,這是《東風破》——周杰倫(下載)的一個MV視頻。我使用的是Binary Viewer的二進制查看工具。

1.png

ffmpeg看一下視頻信息

C:\Users\li\Downloads>ffprobe -show_format dongfengpo.flv
ffprobe version 4.4-full_build-www.gyan.dev Copyright (c) 2007-2021 the FFmpeg developers
  built with gcc 10.2.0 (Rev6, Built by MSYS2 project)
  configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libdav1d --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libglslang --enable-vulkan --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint
  libavutil      56. 70.100 / 56. 70.100
  libavcodec     58.134.100 / 58.134.100
  libavformat    58. 76.100 / 58. 76.100
  libavdevice    58. 13.100 / 58. 13.100
  libavfilter     7.110.100 /  7.110.100
  libswscale      5.  9.100 /  5.  9.100
  libswresample   3.  9.100 /  3.  9.100
  libpostproc    55.  9.100 / 55.  9.100
Input #0, flv, from 'dongfengpo.flv':
  Metadata:
    encoder         : Lavf57.41.100
  Duration: 00:05:14.47, start: 0.000000, bitrate: 431 kb/s
  Stream #0:0: Video: h264 (High), yuv420p(progressive), 352x240 [SAR 3675:3674 DAR 245:167], 283 kb/s, 29.97 fps, 29.97 tbr, 1k tbn, 59.94 tbc
  Stream #0:1: Audio: aac (LC), 44100 Hz, stereo, fltp, 128 kb/s
[FORMAT]
filename=dongfengpo.flv
nb_streams=2
nb_programs=0
format_name=flv
format_long_name=FLV (Flash Video)
start_time=0.000000
duration=314.470000
size=16954257
bit_rate=431310
probe_score=100
TAG:encoder=Lavf57.41.100
[/FORMAT]

header

頭部分由一下幾部分組成
Signature(3 Byte)+Version(1 Byte)+Flags(1 Bypte)+DataOffset(4 Byte)

  • signature 占3個字節
    固定FLV三個字符作為標示。一般發現前三個字符為FLV時就認為他是flv文件。
  • Version 占1個字節
    標示FLV的版本號。這里我們看到是1
  • Flags 占1個字節
    內容標示。第0位和第2位,分別表示 video 與 audio 存在的情況.(1表示存在,0表示不存在)。截圖看到是0x05,也就是00000101,代表既有視頻,也有音頻。
  • DataOffset 4個字節
    表示FLV的header長度。這里可以看到固定是9

body

FLV的body部分是由一系列的back-pointers + tag構成

  • back-pointers 固定4個字節,表示前一個tag的size。
  • tag 分三種類型,video、audio、scripts。

tag組成

tag type+tag data size+Timestamp+TimestampExtended+stream id+ tag data

  • type 1個字節。8為Audio,9為Video,18為scripts
  • tag data size 3個字節。表示tag data的長度。從streamd id 后算起。
  • Timestreamp 3個字節。時間戳
  • TimestampExtended 1個字節。時間戳擴展字段
  • stream id 3個字節。總是0
  • tag data 數據部分

我們根據實例來分析:
看到第一個TAG
type=0x12=18。這里應該是一個scripts。
size=0x000125=293。長度為293。
timestreamp=0x000000。這里是scripts,所以為0
TimestampExtended =0x00
stream id =0x000000
我們看一下TAG的data部分:

3.png

tag的劃分

圖中紅色部分是我標出的兩個back-pointers,都是4個字節。而中間就是第一個TAG。那是怎么計算的呢?我們就以這個做個示例。

  • 首先第一個back-pointers是0x00000000,那是因為后面是第一個TAG。所以他為0。
  • 然后根據我們我們前面格式獲取到size是0x000125。也就是說從stream id后面再加上293個字節就到了第一個TAG的末尾,我們數一下一下。stream id以前總共有24個字節(9+4+11)。那么到第一個TAG結束,下一個TAG開始的位置是293+24=137=0x13D
  • 接下來我們找到0x13D的地址,從工具上很容易找到,正好就是紅色下劃線的前面。紅色部分是0x00000130=304,這代表的是上一個TAG的大小。
  • 最后我們計算一下,上一個TAG數據部分是293個字節,前面type、stream id等字段占了11個字節。正好是匹配的。

上面我們已經知道了怎么取劃分每個TAG。接下來我們就看TAG的具體內容

tag的內容

前面已經提到tag分3種。我們一個個看

script

腳本Tag一般只有一個,是flv的第一個Tag,用于存放flv的信息,比如duration、audiodatarate、creator、width等。
首先介紹下腳本的數據類型。所有數據都是以數據類型+(數據長度)+數據的格式出現的,數據類型占1byte,數據長度看數據類型是否存在,后面才是數據。
一般來說,該Tag Data結構包含兩個AMF包。AMF(Action Message Format)是Adobe設計的一種通用數據封裝格式,在Adobe的很多產品中應用,簡單來說,AMF將不同類型的數據用統一的格式來描述。第一個AMF包封裝字符串類型數據,用來裝入一個“onMetaData”標志,這個標志與Adobe的一些API調用有,在此不細述。第二個AMF包封裝一個數組類型,這個數組中包含了音視頻信息項的名稱和值。具體說明如下,大家可以參照圖片上的數據進行理解。

類型 說明
0 Number type 8 Bypte Double
1 Boolean type 1 Bypte bool
2 String type 后面2個字節為長度
3 Object type
4 MovieClip type
5 Null type
6 Undefined type
7 Reference type
8 ECMA array type 數組,類似Map
10 Strict array type
11 Date type
12 Long string type 后面4個字節為長度
4.png

上圖為第一個AMF包

  • type=0x02對應String
  • size=0A=10
  • value=onMetaData 正好是10個字節。


    5.png

    上圖為第二個AMF

  • type=0x08 對應ECMA array type。

表示數組,類似Map。后面4個字節為數組的個數。然后是鍵值對,第一個為鍵,2個字節為長度。后面跟具體的內容。接著1個字節表示值的類型,然后根據類型判斷長度。
上圖我們可以判斷,總共有13個鍵值對。

  • 第一個長度為8個字節是duration。值類型是0x004073,第一個字節是00,所以是double,8個字節4073A7851EB851EC,通過計算Double.longBitsToDouble(0x4073A7851EB851ECL)得到314.47與視頻信息里一致 00:05:14.47。
  • 第二個長度5個字節是width。值也是double類型,8個字節。
    依次解析下去...

到處,我們已經知道了如何解析FLV中Tag為script的數據。

video

6.png

type=0x09=9。這里應該是一個video。
size=0x000030=48。長度為48。
timestreamp=0x000000
TimestampExtended =0x00
stream id =0x000000
我們看到數據部分:
視頻信息+數據

視頻信息,1個字節。

前4位為幀類型Frame Type

類型
1 keyframe (for AVC, a seekable frame) 關鍵幀
2 inter frame (for AVC, a non-seekable frame)
3 disposable inter frame (H.263 only)
4 generated keyframe (reserved for server use only)
5 video info/command frame

后4位為編碼ID (CodecID)

類型
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
特殊情況

視頻的格式(CodecID)是AVC(H.264)的話,VideoTagHeader會多出4個字節的信息,AVCPacketType 和CompositionTime。

  • AVCPacketType 占1個字節
類型
0 AVCDecoderConfigurationRecord(AVC sequence header)
1 AVC NALU
2 AVC end of sequence (lower level NALU sequence ender is not required or supported)

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

  • CompositionTime 占3個字節
條件
AVCPacketType ==1 Composition time offset
AVCPacketType !=1 0

我們看第一個video tag,也就是前面那張圖。我們看到AVCPacketType =0。而后面三個字節也是0。說明這個tag記錄的是AVCDecoderConfigurationRecord。包含sps和pps數據。
再看到第二個video tag

8.png

我們看到 AVCPacketType =1,而后面三個字節為000043。這是一個視頻幀數據。

解析到的數據完全符合上面的理論。

sps pps

前面我們提到第一個video 一般存放的是sps和pps。這里我們具體解析下sps和pps內容。先看下存儲的格式(圖6):
0x01+sps[1]+sps[2]+sps[3]+0xFF+0xE1+sps size+sps+01+pps size+pps
我們看到圖 。
sps[1]=0x64
sps[2]=00
sps[3]=0D
sps size=0x001B=27
跳過27個字節后,是0x01
pps size=0x0005=5
跳過5個字節,就到了back-pointers。

視頻幀數據

解析出sps和pps tag后,后面的video tag就是真正的視頻數據內容了

9.png

這是第二個video tag其實和圖8一樣,只是我圈出來關鍵信息。先看下格式
frametype=0x17=00010111
AVCPacketType =1
Composition Time=0x000043
后面就是NALU DATA

Audio

與視頻格式類似

字段 字段類型 字段含義
SoundFormat UB[4] 音頻格式,重點關注 10 = AAC
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
SoundRate UB[2] 采樣率,對AAC來說,永遠等于3
0 = 5.5-kHz
1 = 11-kHz
2 = 22-kHz
3 = 44-kHz
SoundSize UB[1] 采樣精度,對于壓縮過的音頻,永遠是16位
0 = snd8Bit
1 = snd16Bit
SoundType UB[1] 聲道類型,對Nellymoser來說,永遠是單聲道;對AAC來說,永遠是雙聲道;
0 = sndMono 單聲道
1 = sndStereo 雙聲道
SoundData UI8[size of sound data] 如果是AAC,則為 AACAUDIODATA;

AACAUDIODATA

字段 字段類型 字段含義
AACPacketType UI8 0: AAC sequence header
1: AAC raw
Data UI8[n] 如果AACPacketType為0,則為AudioSpecificConfig
如果AACPacketType為1,則為AAC幀數據

AudioSpecificConfig

字段 字段類型 字段含義
AudioObjectType UB[5] 編碼器類型,比如2表示AAC-LC
SamplingFrequencyIndex UB[4] 采樣率索引值,比如4表示44100
ChannelConfiguration UB[4] 聲道配置,比如2代表雙聲道,front-left, front-right

我們看到第三個TAG

7.png

這個留給大家自己來解析吧。
從AF=1010 1111

  • SoundFormat = 1010 = AAC編碼

  • SoundRate = 11 = 44-kHz

  • SoundSize = 1 = snd16Bit

  • SoundType = 1 = sndStereo 雙聲道

  • AACAUDIODATA
    AACPacketType = 00 = AAC sequence header

  • AudioSpecificConfig
    AudioObjectType = 00010 = 2
    SamplingFrequencyIndex = 0100 = 4
    ChannelConfiguration = 0010

audio.png

解析工具下載地址

最后,我們使用工具來看我們的實例文件和我們自己解析的是否一致


summary.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容

  • 簡介 FLV(Flash Video)是現在非常流行的流媒體格式,由于其視頻文件體積輕巧、封裝播放簡單等特點,使其...
    輕口味閱讀 1,107評論 0 0
  • 概述 Flash Video(簡稱FLV),是一種網絡視頻格式,用作流媒體格式,它的出現有效地解決了視頻文件導入F...
    Damon_He閱讀 2,540評論 1 1
  • FLV 文件 = File Header(FLV 文件頭)+ File Body(FLV 文件體)。其中文件體又由...
    Coder_Sven閱讀 2,145評論 1 1
  • 在如何看待嗶哩嗶哩的開源 HTML5 播放器內核 flv.js?中,flv.js作者有這樣一段回復:一些人問我為什...
    合肥黑閱讀 2,452評論 1 4
  • Rtmp 分析參見:https://blog.csdn.net/fdsafwagdagadg6576/articl...
    mfdalf閱讀 1,730評論 0 0