flv格式詳解+實(shí)例剖析

簡(jiǎn)介

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

FLV是流媒體封裝格式,我們可以將其數(shù)據(jù)看為二進(jìn)制字節(jié)流??傮w上看,F(xiàn)LV包括文件頭(File Header)和文件體(File Body)兩部分,其中文件體由一系列的Tag及Tag Size對(duì)組成。


flv.jpg

FLV格式解析

先來(lái)一張圖,這是《東風(fēng)破》——周杰倫(下載)的一個(gè)MV視頻。我使用的是Binary Viewer的二進(jìn)制查看工具。

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個(gè)字節(jié)
    固定FLV三個(gè)字符作為標(biāo)示。一般發(fā)現(xiàn)前三個(gè)字符為FLV時(shí)就認(rèn)為他是flv文件。
  • Version 占1個(gè)字節(jié)
    標(biāo)示FLV的版本號(hào)。這里我們看到是1
  • Flags 占1個(gè)字節(jié)
    內(nèi)容標(biāo)示。第0位和第2位,分別表示 video 與 audio 存在的情況.(1表示存在,0表示不存在)。截圖看到是0x05,也就是00000101,代表既有視頻,也有音頻。
  • DataOffset 4個(gè)字節(jié)
    表示FLV的header長(zhǎng)度。這里可以看到固定是9

body

FLV的body部分是由一系列的back-pointers + tag構(gòu)成

  • back-pointers 固定4個(gè)字節(jié),表示前一個(gè)tag的size。
  • tag 分三種類(lèi)型,video、audio、scripts。

tag組成

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

  • type 1個(gè)字節(jié)。8為Audio,9為Video,18為scripts
  • tag data size 3個(gè)字節(jié)。表示tag data的長(zhǎng)度。從streamd id 后算起。
  • Timestreamp 3個(gè)字節(jié)。時(shí)間戳
  • TimestampExtended 1個(gè)字節(jié)。時(shí)間戳擴(kuò)展字段
  • stream id 3個(gè)字節(jié)??偸?
  • tag data 數(shù)據(jù)部分

我們根據(jù)實(shí)例來(lái)分析:
看到第一個(gè)TAG
type=0x12=18。這里應(yīng)該是一個(gè)scripts。
size=0x000125=293。長(zhǎng)度為293。
timestreamp=0x000000。這里是scripts,所以為0
TimestampExtended =0x00
stream id =0x000000
我們看一下TAG的data部分:

3.png

tag的劃分

圖中紅色部分是我標(biāo)出的兩個(gè)back-pointers,都是4個(gè)字節(jié)。而中間就是第一個(gè)TAG。那是怎么計(jì)算的呢?我們就以這個(gè)做個(gè)示例。

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

上面我們已經(jīng)知道了怎么取劃分每個(gè)TAG。接下來(lái)我們就看TAG的具體內(nèi)容

tag的內(nèi)容

前面已經(jīng)提到tag分3種。我們一個(gè)個(gè)看

script

腳本Tag一般只有一個(gè),是flv的第一個(gè)Tag,用于存放flv的信息,比如duration、audiodatarate、creator、width等。
首先介紹下腳本的數(shù)據(jù)類(lèi)型。所有數(shù)據(jù)都是以數(shù)據(jù)類(lèi)型+(數(shù)據(jù)長(zhǎng)度)+數(shù)據(jù)的格式出現(xiàn)的,數(shù)據(jù)類(lèi)型占1byte,數(shù)據(jù)長(zhǎng)度看數(shù)據(jù)類(lèi)型是否存在,后面才是數(shù)據(jù)。
一般來(lái)說(shuō),該Tag Data結(jié)構(gòu)包含兩個(gè)AMF包。AMF(Action Message Format)是Adobe設(shè)計(jì)的一種通用數(shù)據(jù)封裝格式,在Adobe的很多產(chǎn)品中應(yīng)用,簡(jiǎn)單來(lái)說(shuō),AMF將不同類(lèi)型的數(shù)據(jù)用統(tǒng)一的格式來(lái)描述。第一個(gè)AMF包封裝字符串類(lèi)型數(shù)據(jù),用來(lái)裝入一個(gè)“onMetaData”標(biāo)志,這個(gè)標(biāo)志與Adobe的一些API調(diào)用有,在此不細(xì)述。第二個(gè)AMF包封裝一個(gè)數(shù)組類(lèi)型,這個(gè)數(shù)組中包含了音視頻信息項(xiàng)的名稱(chēng)和值。具體說(shuō)明如下,大家可以參照?qǐng)D片上的數(shù)據(jù)進(jìn)行理解。

類(lèi)型 說(shuō)明
0 Number type 8 Bypte Double
1 Boolean type 1 Bypte bool
2 String type 后面2個(gè)字節(jié)為長(zhǎng)度
3 Object type
4 MovieClip type
5 Null type
6 Undefined type
7 Reference type
8 ECMA array type 數(shù)組,類(lèi)似Map
10 Strict array type
11 Date type
12 Long string type 后面4個(gè)字節(jié)為長(zhǎng)度
4.png

上圖為第一個(gè)AMF包

  • type=0x02對(duì)應(yīng)String
  • size=0A=10
  • value=onMetaData 正好是10個(gè)字節(jié)。


    5.png

    上圖為第二個(gè)AMF

  • type=0x08 對(duì)應(yīng)ECMA array type。

表示數(shù)組,類(lèi)似Map。后面4個(gè)字節(jié)為數(shù)組的個(gè)數(shù)。然后是鍵值對(duì),第一個(gè)為鍵,2個(gè)字節(jié)為長(zhǎng)度。后面跟具體的內(nèi)容。接著1個(gè)字節(jié)表示值的類(lèi)型,然后根據(jù)類(lèi)型判斷長(zhǎng)度。
上圖我們可以判斷,總共有13個(gè)鍵值對(duì)。

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

到處,我們已經(jīng)知道了如何解析FLV中Tag為script的數(shù)據(jù)。

video

6.png

type=0x09=9。這里應(yīng)該是一個(gè)video。
size=0x000030=48。長(zhǎng)度為48。
timestreamp=0x000000。
TimestampExtended =0x00
stream id =0x000000
我們看到數(shù)據(jù)部分:
視頻信息+數(shù)據(jù)

視頻信息,1個(gè)字節(jié)。

前4位為幀類(lèi)型Frame Type

類(lèi)型
1 keyframe (for AVC, a seekable frame) 關(guān)鍵幀
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)

類(lèi)型
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)的話(huà),VideoTagHeader會(huì)多出4個(gè)字節(jié)的信息,AVCPacketType 和CompositionTime。

  • AVCPacketType 占1個(gè)字節(jié)
類(lèi)型
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解碼相關(guān)比較重要的spspps信息,再給AVC解碼器送數(shù)據(jù)流之前一定要把sps和pps信息送出,否則的話(huà)解碼器不能正常解碼。而且在解碼器stop之后再次start之前,如seek、快進(jìn)快退狀態(tài)切換等,都需要重新送一遍sps和pps的信息.AVCDecoderConfigurationRecord在FLV文件中一般情況也是出現(xiàn)1次,也就是第一個(gè)video tag.

  • CompositionTime 占3個(gè)字節(jié)
條件
AVCPacketType ==1 Composition time offset
AVCPacketType !=1 0

我們看第一個(gè)video tag,也就是前面那張圖。我們看到AVCPacketType =0。而后面三個(gè)字節(jié)也是0。說(shuō)明這個(gè)tag記錄的是AVCDecoderConfigurationRecord。包含sps和pps數(shù)據(jù)。
再看到第二個(gè)video tag

8.png

我們看到 AVCPacketType =1,而后面三個(gè)字節(jié)為000043。這是一個(gè)視頻幀數(shù)據(jù)。

解析到的數(shù)據(jù)完全符合上面的理論。

sps pps

前面我們提到第一個(gè)video 一般存放的是sps和pps。這里我們具體解析下sps和pps內(nèi)容。先看下存儲(chǔ)的格式(圖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
跳過(guò)27個(gè)字節(jié)后,是0x01
pps size=0x0005=5
跳過(guò)5個(gè)字節(jié),就到了back-pointers。

視頻幀數(shù)據(jù)

解析出sps和pps tag后,后面的video tag就是真正的視頻數(shù)據(jù)內(nèi)容了

9.png

這是第二個(gè)video tag其實(shí)和圖8一樣,只是我圈出來(lái)關(guān)鍵信息。先看下格式
frametype=0x17=00010111
AVCPacketType =1
Composition Time=0x000043
后面就是NALU DATA

Audio

與視頻格式類(lèi)似

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

AACAUDIODATA

字段 字段類(lèi)型 字段含義
AACPacketType UI8 0: AAC sequence header
1: AAC raw
Data UI8[n] 如果AACPacketType為0,則為AudioSpecificConfig
如果AACPacketType為1,則為AAC幀數(shù)據(jù)

AudioSpecificConfig

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

我們看到第三個(gè)TAG

7.png

這個(gè)留給大家自己來(lái)解析吧。
從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

解析工具下載地址

最后,我們使用工具來(lái)看我們的實(shí)例文件和我們自己解析的是否一致


summary.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 簡(jiǎn)介 FLV(Flash Video)是現(xiàn)在非常流行的流媒體格式,由于其視頻文件體積輕巧、封裝播放簡(jiǎn)單等特點(diǎn),使其...
    輕口味閱讀 1,207評(píng)論 0 0
  • 概述 Flash Video(簡(jiǎn)稱(chēng)FLV),是一種網(wǎng)絡(luò)視頻格式,用作流媒體格式,它的出現(xiàn)有效地解決了視頻文件導(dǎo)入F...
    Damon_He閱讀 2,759評(píng)論 1 1
  • FLV 文件 = File Header(FLV 文件頭)+ File Body(FLV 文件體)。其中文件體又由...
    Coder_Sven閱讀 2,472評(píng)論 1 1
  • 在如何看待嗶哩嗶哩的開(kāi)源 HTML5 播放器內(nèi)核 flv.js?中,flv.js作者有這樣一段回復(fù):一些人問(wèn)我為什...
    合肥黑閱讀 2,568評(píng)論 1 4
  • Rtmp 分析參見(jiàn):https://blog.csdn.net/fdsafwagdagadg6576/articl...
    mfdalf閱讀 1,876評(píng)論 0 0

友情鏈接更多精彩內(nèi)容