FLV文件(H264,AAC)格式分析

FLV 文件 = File Header(FLV 文件头)+ File Body(FLV 文件体)。其中文件体又由一系列的 Tag 和 Tag Size 组成。

19978008-0014afa7b9cfa4a1.webp.jpg

使用16进制查看器打开一个FLV文件,查看数据的格式

image-20200620144713398.png

FLV File Header

image-20200620145234822.png
字段 字节 描述
signature 3 文件格式标识。('F‘ : 0x46,'L' : 0x4C,'V' : 0x56)
version 1 版本号。(0x01:版本号为1)
type flags 1 类型标识。 前5个bit是类型标志预留字段,必须是0; 第6个bit音频类型标志(TypeFlagsAudio); 第7个bit是类型标志预留字段,必须是0; 第8个bit视频类型标志(TypeFlagsVideo)。(0x05,也就是 00000101,表示既有音频也有视频)
data offset 4 文件头的长度。(对于版本号为1的FLV文件来说,文件头长度固定是9,大于9表示下面还有扩展信息)

FLV File Body

Body部分是由一系列的 PreviousTagSize + Tag 构成。

PreviousTagSize 固定为4字节,表示前一个Tag的size

Tag分为3种类型:Script(脚本)、Video(视频)、Audio(音频)
image-20200620150117227.png

FLV Tag

FLV中的Tag又分为 tag header(tag头部分)和 tag data(tag数据部分)。

FLV Tag Header(Tag头1+3+3+1+3=11个字节)

字段 字节 描述
TagType 1 当前tag的类型,值有: 0x08:audio 0x09:video 0x12:script 其他:未使用的预留值
DataSize 3 数据部分的数据长度(Data字段的数据长度)。
Timestamp 3 当前帧的时间戳,单位是毫秒。相对于第一个TAG的时间戳(第一个的时间戳总是0)
TimestampExtended 1 时间戳扩展字段。 如果时间戳大于0xFFFFFF,将会使用这个字节。这个字节是时间戳的高8位,上面的三个字节是低24位。
StreamID 3 流ID,总是0
Data n 数据部分
image-20200620151816034.png
00 01 6A代表数据长度有362个字节,所以蓝色区域都是data数据区域。

FLV Script Tag

Script Tag一般只有一个,且是FLV中第一个Tag,用来存放一些描述信息,如:duration、width、height等。Script Tag 中Data部分的数据都是以 【数据类型 + 数据长度 + 数据】的格式出现的。一般来说,该Tag Data结构包含两个AMF包。AMF(Action Message Format)是Adobe设计的一种通用数据封装格式,在Adobe的很多产品中应用,简单来说,AMF将不同类型的数据用统一的格式来描述。第一个AMF包封装字符串类型数据,用来装入一个“onMetaData”标志,这个标志与Adobe的一些API调用有关。第二个AMF包封装一个数组类型,这个数组中包含了音视频信息项的名称和值。

类型值意义

类型 说明
0 Number type double类型,后8字节为数据长度
1 Boolean type bool类型,后1字节为数据长度
2 String type string类型,后两字节为数据长度
3 Object type
4 MovieClip type
5 Null type
6 Undefined type
7 Reference type
8 ECMA array type 数组类型(类似Map),后4字节为数组长度。(key:前两字节为长度;value部分第1字节为类型)
10 Strict array type
11 Date type
12 Long string type

第一个AMF(1+2+10=13个字节)

image-20200620153530511.png

02:String类型

0A:String长度为10

后面10字节为数据的值

第二个AMF包(头5个字节)

image-20200620160959809.png

08:数组
00 00 00 10 :数组长度为16

数组中元素封装形式为:前两个字节为元素名称的长度,后面跟着长度为L的字符串。紧跟着的一个字节表示元素值的类型,后面跟着是对应值,占用的字节数取决于值的类型。

元素“duration”(19字节)

image-20200620161756106.png

00 08 代表后面8个字节长度为元素名称 
名称:duration
00 代表double类型,后8字节为数据长度

元素“width”(16个字节)

image-20200620162134609.png

00 05 长度
元素名称:width
00:代表double类型,后8字节为数据长度

元素"height"(17个字节)

image-20200620162544994.png

00 06 
68 65 69 67 68 74 height
00 代表double类型,后8字节为数据长度

元素“videodatarate”(24个字节)

image-20200620163146947.png

00 0D :长度
76 69 64 65 6F 64 61 74 61 72 61 74 65 字符串“videodatarate”
00 :代表double类型,后8字节为数据长度

元素“framerate”(20个字节)

image-20200620163652002.png

00 09 长度
66 72 61 6D 65 72 61 74 65:字符串“framerate”
00 代表double类型,后8字节为数据长度

元素“videocodecid”(23个字符)

image-20200620164044030.png

00 0c :长度
76 69 64 65 6F 63 6F 64 65 63 69 64 字符串videocodecid
00 代表double类型,后8字节为数据长度

以下就不再截图了,对比数据自己慢慢往下找

元素“audiodatarate”(24个字节)

00 0D:长度

元素“audiosamplerate”(26个字节)

00 0F:长度

元素“audiosamplesize”(26个字节)

00 0F

元素“stereo”(10个字节)

image-20200620165448830.png

00 06 长度
73 74 65 72 65 6F 字符串“stereo”
01:bool类型,后1字节为数据长度

元素“audiocodecid”(23个字节)

00 0C:长度

元素“major_brand”(20个字节)

image-20200620171222221.png

00 0B :长度
02:看上面的类型文档,string,,后两个字节代表长度
00 04 :长度为4

元素“minor_version”(19个字节)

image-20200620171639885.png

00 0D:长度为13
02:string 后两位表示长度
00 01 长度为1

元素“compatible_brands”(30个字节)

image-20200620172257155.png

00 11 :长度为17
02 :string 后两位代表长度
00 08 长度为8

元素“encoder”(字节数25)

image-20200620172617573.png

00 07 :长度为7
02 :string
00 0D:长度为13

元素“filesize”(22个字节)

image-20200620174628862.png

00 08 长度为8
00:后8位表示长度
00 00 :空字符串
09 :结束标志

16个元素长度相加19+16+17+24+20+23+...+22 = 344

第一个AMF包(13)+第二个AMF包头(5)+16个元素数组数据长度(344)=362个字节。

至此,,362个data数据全部分析完毕。

那么下一个PreviousTagSize就是362+tag头(11)=373个字节

PreviousTagSize是固定长度4

image-20200620181245785.png
00 00 01 75 = 373

上面分析的是Script Tag,一般都是flv文件的开头才有一个,中间是一个TagSize,再接下来就是第一个VideoTag,TagHaeder(11个字节)

image-20200620181921356.png
Tag头分析,按照上面的文档一个个对照
09:video
00 00 2E :data 长度
00 00 00 00 时间戳
00 00 00 流id

接下来分析VideoTagBody

image-20200620183004009.png

1700000000这五个字节为VideoTag数据部分的固定头五个字节

字段 比特位 描述
FrameType 高四位 帧类型。 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
CodecId 低四位 编码类型。 1: JPEG(目前未用到) 2: Sorenson H.263 3: Screen video 4: On2 VP6 5: On2 VP6 with alpha channel 6: Screen video version 2 7: AVC(高级视频编码)

比如上面的17就代表着是keyframe关键帧,并且是AVC(高级视频编码)

字段 字节数 描述
AVCPacketType 1 0:AVC sequence header 1:AVC NALU 2:AVC end of sequence
CompositionTime 3 合成时间。 AVCPacketType==1,表示 合成时间(单位毫秒); 否则为0

比如上面的00 00 00 00 就表示AVC sequence header和合成时间为0

Data数据

字段 字节 描述
data n 如果AVCPacketType==0,数据部分为AVCDecoderConfigurationRecord; 如果AVCPacketType==1,数据部分为1个或多个NALU; 如果AVCPacketType==2,数据部分为空
AVCDecoderConfigurationRecord

AVCDecoderConfigurationRecord 包含了H.264解码相关比较重要的SPSPPS信息,再给AVC解码器送数据流之前一定要把SPSPPS信息送出,否则的话解码器不能正常解码。而且在解码器stop之后再次start之前,如seek、快进快退状态切换等,都需要重新送一遍SPSPPS的信息。AVCDecoderConfigurationRecord在FLV文件中一般情况也是出现1次,也就是第一个video tag。

字段 字节 描述
版本 1 0x01,版本号为1
编码规格 3 sps[1]+sps[2]+sps[3]
NALU 的长度 1 0xFF,包长为 (0xFF& 3) + 1,也就是4字节表示
SPS个数 1 0xE1,个数为0xE1 & 0x1F 也就是1
SPS长度 2 整个sps长度
SPS的内容 n 整个sps
PPS个数 1 0x01,1个
PPS长度 2 整个pps长度
PPS内容 n 整个pps内容
image-20200620185347197.png
00 19 :sps长度为25
00 05 :pps长度为5

上面的头数据(11)+(固定长度17 00 00 00 00)5+(1+3+1+1+2)+25(sps长度)+(1+2)+5(pps长度)= 57

所以下一个PreviousTagSize为0x39

image-20200620190610879.png

第一个VideoTag过了之后,接下来是第一个AudioTag(Tag头11个字节)

image-20200620190851965.png

AudioTagBody与VideoTag类似

字段 比特位 描述
SoundFormat 4 音频数据格式。值: 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,15是内部预留)
SoundRate 2 音频采样率。值:
0 = 5.5-kHz
1 = 11-kHz
2 = 22-kHz
3 = 44-kHz
(对于AAC来说,该字段总是3)
SoundSize 1 采样长度。值:
0 = snd9Bit
1 = snd16Bit
(对于压缩过的音频来说,一般都是16bit)
SoundType 1 音频类型(单声道还是双声道)。值:
0 = sndMono
1 = sndStereo
(对于AAC,总是1)
SoundData n 音频数据部分(AAC则需要参考下面AACAUDIODATA部分)
AACAUDIODATA
字段 字节 描述
AACPacketType 1 0:AAC 序列头<br />1:AAC 数据
Data n 如果AACPacketType==0,参考下面的 AudioSpecificConfig 如果AACPacketType==1,即AAC原始音频数据
AudioSpecificConfig(5个字节)
字段 占位
audioObjectType 5
samplingFrequencyIndex 4
channelConfiguration 4
frameLengthFlag 1
dependsOnCoreCoder 1
extensionFlag 1
Sync Extension Type() 11
Extension Audio Object Type 5
SBR Present Flag 1
audioObjectType:2-AAC-LC,5-SBR,29-PS

samplingFrequencyIndex:0-96000,1-88200,3-64000,4-44100,5-32000,6-24000,7-22050,8-16000

channelConfiguration:1-单声道,2-双声道,依次类推....

Frame Length Flag:0-1024 samples

dependsOnCoreCoder:0-不依赖 1-依赖

extensionFlag:0-Is not extention 1-Is extention

Sync Extension Type():0x2b7表示HE-AAC的扩展

Extension Audio Object Type:

SBR Present Flag:
image-20200621134531212.png
AF:10101111  1010代表AAC  11代表44khz 1代表16Bit 1代表Stereo
00:序列头
12-10-56-E5-00:00010010-00010000-01010110-11100101-00000000
00010:表示2-AAC-LC
0100:表示4—44100
0010:表示2-双声道
0:表示0-1024samples
0:表示不依赖
0:表示is not extention
01010110111:表示0x2b7-HE-AAC的扩展
00101:表示5
0:SBR Present Flag为0
后面不足的地方全部补0

所以当前Audio Tag的body Sized为2+5=7;整个Tag的size为body+header = 7+11=18

Previous Tag Size(4个字节)

image-20200621143858604.png

接下来就是一个个普通的VideoTag和Audio Tag按照时间戳交替存放。记住每个Tag之后都有4个字节的Previous Tag Size.下面只列出一个Video Tag和一个Audio Tag的格式,其他的类似

image-20200621145623930.png
BodySize = 5+4+NALU_LENGTH;

VideoTag数据部分固定的头5个字节,4个字节表示NALU长度,最后就是NALU数据部分
image-20200621150831231.png

image-20200621151256258.png
BodySize = AAC_Data_Length+2
image-20200621151801812.png

到此为止已经介绍完FLV文件格式,flv格式还是比较简单的,header部分很简洁,body部分都是由一个个tag组成,tag的话也就三种,脚本tag一般只有一个。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342