
Flash Video(简称 FLV),是一种容器文件格式,用作流媒体格式,用于使用 Adobe Flash Player 6 和更新版本通过互联网传送数字视频内容(如电视节目、电影等)。
它的出现有效地解决了视频文件导入 Flash 后,使导出的 SWF 文件体积庞大,不能在网络上有效使用等缺点。
FLV 文件通常包含采用 Sorenson Spark 或 VP6 视频压缩格式的编解码器编码的内容。截至 2010 年,Flash Player 的公开发行版也支持 H.264 视频和 HE-AAC 音频。
文件结构
FLV 文件主要由 FLV Header 和 FLV Body 两部分组成(后者由一系列交替的反向指针和 FLV tags 组成):
Field | 类型 | 说明 |
---|---|---|
Header | -- | -- |
PreviousTagSize0 | UI32 | 前一个 Tag 的大小,因为前面无 Tag 所以总为 0 |
Tag1 | FLVTAG | 第一个 Tag |
PreviousTagSize1 | UI32 | 前一个 Tag 的大小(包括 Tag 的头和内容) |
Tag2 | FLVTAG | 第二个 Tag |
... | ... | ... |
PreviousTagSizeN-1 | UI32 | |
TagN | FLVTAG | 最后一个 Tag |
PreviousTagSizeN | UI32 | 最后一个 Tag 的大小 |
FLV Header
FLV 头部(Header)主要包括签名字段、版本号和包含媒体类型等信息,详细解析如下表所示:
Field | 类型 | 说明 |
---|---|---|
Signature | UI8 | 签名, 总是 'F' (0x46) |
Signature | UI8 | 签名, 总是 'L' (0x4C) |
Signature | UI8 | 签名, 总是 'V' (0x56) |
Version | UI8 | 版本, 总是 0x01, 表示 FLV version 1 |
TypeFlagsReserved | UB[5] | 全为 0 |
TypeFlagsAudio | UB[1] | 1 = 有音频 |
TypeFlagsReserved | UB[1] | 全为 0 |
TypeFlagsVideo | UB[1] | 1 = 有视频 |
DataOffset | UI32 | 整个文件头长度, 总是 9 |
以示例文件为例,前 9 个字节的以 16 进制表示为:
00000000h: 46 4C 56 01 05 00 00 00 09
00000000h: 46 4C 56 01 05 00 00 00 09
前三个字节总是固定的签名字段 FLV,然后是文件的版本为 1;接下来 0x05 转二进制表示为 0b00000101,其中第 6 位和第 8 位都为 1,表示其中包含音频和视频。
最后四个字节表示文件头数据的偏移位置,也就是整个头文件的长度为 9 个字节。
FLV Body
接下来到了 FLV Body 部分,首先是表示前一个 Tag 长度的部分。
Field | 类型 | 说明 |
---|---|---|
PreviousTagSize | UI32 | 前一个 Tag 长度,以字节为单位 |
该部分采用四个字节表示,如前所述,第一个表示 Tag 大小的部分总为零:
00000009h: 00 00 00 00
00000009h: 00 00 00 00
Tag Header
再接着就是 FLVTAG 部分,每个 FLVTAG 主要分为 Header 和 Body 两部分,在 FLV 中 Tag 主要分为三类:Audio、Video、Script,它们的头部基本一致:
Field | 类型 | 说明 |
---|---|---|
Reserved | UB2 | 保留位,应该为 0 |
Filter | UB1 | 主要用作文件加密处理,为 0 表示不预处理,否则表示预处理 |
TagType | UB5 | 类型, 8 = audio, 9 = video, 18 = script |
DataSize | UI24 | 数据字段中数据的字节数 |
Timestamp | UI24 | 相对于第一个 tag 的时间戳(unit: ms), 第一个 tag 总是 0 |
TimestampExtended | UI8 | Timestamp 的高 8 位,扩展 Timestamp 为 SI32 类型(以毫秒为单位) |
StreamID | UI24 | 总是 0 |
可见 Tag 的头部总体大小为 11 字节,在示例文件中的数据如下:
0000000dh: 12 00 01 74 00 00 00 00 00 00 00
0000000dh: 12 00 01 74 00 00 00 00 00 00 00
此处的 0x12 表示该标签类型为 Script,0x000174 表示数据部分包含了 372 个字节的数据,后面几部分都为零。
Script Tag Body
ScriptTagBody 里面存储的数据一般为 AMF 数据,主要由多个 Name 和 Value 对组成,Name 为 Method 或对象的名称,Value 为 AMF 参数或对象属性,两者均为 SCRIPTDATAVALUE 格式。
SCRIPTDATAVALUE 包含一个字节的数据类型和后面紧跟着的特定类型的数据实体,对数据类型的定义如下:
值 | 类型 | ScriptDataValue |
---|---|---|
0 | Number | DOUBLE (8 个字节) |
1 | Boolean | UI8 ((ScriptDataValue ≠ 0) |
2 | String | SCRIPTDATASTRING |
3 | Object | SCRIPTDATAOBJECT |
4 | MovieClip (reserved, not supported) | |
5 | Null | |
6 | Undefined | |
7 | Reference | UI16 |
8 | ECMA array | SCRIPTDATAECMAARRAY |
9 | Object end marker | |
10 | Strict array | SCRIPTDATASTRICTARRAY |
11 | Date | SCRIPTDATADATE |
12 | Long string | SCRIPTDATALONGSTRING |
数据实体部分根据不同类型进行对应的 AMF 解析并可以取得数据,SCRIPTDATAVALUE 主要分为 8 种,下面列举了其中 4 中(其它四种可见附录)。
SCRIPTDATAECMAARRAY 类型:
Field | 类型 | 说明 |
---|---|---|
ECMAArrayLength | UI32 | ECMA 数组元素的数量 |
Variables | SCRIPTDATAOBJECTPROPERTY [ ] | 变量名和值的列表 |
List Terminator | SCRIPTDATAOBJECTEND | 列表终止符 |
SCRIPTDATAOBJECTPROPERTY 类型:
Field | 类型 | 说明 |
---|---|---|
PropertyName | SCRIPTDATASTRING | 对象属性或变量的名称 |
PropertyData | SCRIPTDATAVALUE | 对象属性或变量的值和类型 |
SCRIPTDATASTRING 类型:
Field | 类型 | 说明 |
---|---|---|
StringLength | UI16 | 字符串的长度(字节) |
StringData | STRING | 字符串,最大长度 65535 字节,不含 NULL 结束符 |
SCRIPTDATAOBJECTEND 类型:
Field | 类型 | 说明 |
---|---|---|
ObjectEndMarker | UI8 [3] | 必须是 0,0,9 |
通常,ScriptTagBody 中包含两个 AMF 包。第一个包封装了字符串类型数据,用来装入一个“onMetaData”标志:
00000018h: 02 00 0A 6F 6E 4D 65 74 61 44 61 74 61
00000018h: 02 00 0A 6F 6E 4D 65 74 61 44 61 74 61
如上,第一个字节 0x02 表示 String 类型,根据其对应的 SCRIPTDATASTRING 类型的定义,接下来两个字节 0x000A 表示字符串的长度为 10 个字节。
所以再之后的 10 个字节表示具体的字符串值,根据每个字节表示的数字对照 ASCII Code 表并可以得到相应的值(此处也就是“onMetaData”标识)。
第二个 AMF 包封装了一个数组类型,其中包含了具体的元数据信息。首先第一个字节仍然表示了对应的类型:
00000025h: 08
00000025h: 08
0x08 表示 ECMA array 类型,根据其对应的 SCRIPTDATAECMAARRAY 的类型的定义,接着 4 个字节表示 ECMA 数组元素的数量:
00000026h: 00 00 00 10
00000026h: 00 00 00 10
也就是说借下来将会出现 16 对 SCRIPTDATAOBJECTPROPERTY(PropertyName: PropertyData),那么后续就会按照 SCRIPTDATASTRING 和 SCRIPTDATAVALUE 成对出现的方式解析。
首先是表示属性名称的部分:
0000002ah: 00 08 64 75 72 61 74 69 6F 6E
0000002ah: 00 08 64 75 72 61 74 69 6F 6E
对于 SCRIPTDATASTRING 类型上面已经解析过了,前两个字节 ox0008 标识字符串长度, 由此可知接下来 8 个字节表示具体的属性名称。
依然是对照 ASCII Code 表可知该对象属性名称为“duration”,接着是表示对象属性值的部分:
00000034h: 00 3F F7 CE D9 16 87 2B 02
00000034h: 00 3F F7 CE D9 16 87 2B 02
作为 ScriptDataValue 类型,它的第一个字节 0x00 表示接下来的数据类型为 DOUBLE,根据 DOUBLE 类型的定义接下来 8 个字节表示其具体的值,也就是 1.488(s)。
然后就是重复这样的解析,直到解析到列表终止符,最后得到所有的元数据信息,常见的元数据属性可见附录。
Video Tag Body
到此 Script 标签已经解析完成了,接下来的 4 个字节又将表示的是前一个标签的大小:
0000018ch: 00 00 01 7F
0000018ch: 00 00 01 7F
然后是标签的头信息部分:
00000190h: 09 00 00 38 00 00 00 00 00 00 00
00000190h: 09 00 00 38 00 00 00 00 00 00 00
回到标签头的解析部分,第一个字节 0x09 表明这个标签的类型为 Video,0x000038 表示数据部分有 56 个字节,其余部分为零。
视频标签的 Body 部分主要由 VideoTagHeader 和 VideoData 两部分组成,其头部主要包括:
Field | 类型 | 说明 |
---|---|---|
FrameType | UB[4] | 视频帧的类型,详情见附录 |
CodecID | UB[4] | 编码标识,常见为 7 表示 AVC,详情见附录 |
AVCPacketType | UI8(CodecID==7) | 包的类型:0=AVC 序列头,1=AVC NALU,2=序列的 AVC 结束 |
CompositionTime | SI24 (CodecID==7) | AVCPacketType = 1 时为 PTS 相对于 DTS 的偏移值,其它均为零 |
对于 VideoTag 的 VideoData 部分会根据帧类型、编码格式和包类型的不同而不同:
- 如果 FrameType 值为 5,则视频数据体包含具有以下含义的 UI8:
- 为 0 表示 Start of client-side seeking video frame sequence;
- 为 1 表示 End of client-side seeking video frame sequence。
- 如果 FrameType 不为 5 且当 CodecID 为 7 时:
- AVCPacketType 为 0,表示 AVCDecoderConfigurationRecord;
- AVCPacketType 为 1,视频数据内容为一个或多个 NALU。
继续从示例文件中截取 5 个字节来看:
0000019bh: 17 00 00 00 00
0000019bh: 17 00 00 00 00
0x17 即为 0b00010111,前四位 0b0001 表示当前帧为关键帧,后四位 0b0111 表示当期视频采用了 AVC 编码格式。
由于 CodecID 为 7,所以再往后的 0x00 表示接下来的包类型是一个 AVC 序列头,最后的 0x000000 表示 CTS 为零。
同时因为 AVCPacketType 为 0,所以接下来的视频数据体为 AVCDecoderConfigurationRecord:
Field | 类型 | 说明 |
---|---|---|
configurationVersion | UI8 | 版本号 |
AVCProfileIndication | UI8 | 包含 ISO/IEC 14496-10 中定义的配置文件代码 |
profile_compatibility | UI8 | 定义与 ISO/IEC 14496-10 中定义的 SPS 中 profile_IDC 和 level_IDC 之间发生的字节完全相同的字节 |
AVCLevelIndication | UI8 | 包含 ISO/IEC 14496-10 中定义的等级代码 |
保留的,‘111111’b | ||
lengthSizeMinusOne | UB[2] | 指示相关流的 AVC 视频样本或 AVC 参数集样本中 NALUnitLength 字段的字节长度减壹 |
保留的,‘111’b | ||
numOfSequenceParameterSets | UB[5] | SPS 的个数,指示用作解码 AVC 基本流的初始 SPS 集的 SPS 数 |
sequenceParameterSetLength | UI16 | SPS 的长度,表示 ISO/IEC 14496-10 中定义的 SPS NAL 单元的字节长度 |
sequenceParameterSetNALUnit | UI8[n] | SPS 的数据,包含 ISO/IEC 14496-10 中规定的 SPS NAL 单元。SPS 应按参数集标识符升序出现,允许有间隙 |
... | ... | 存在多个 SPS 时,重复 SPS 的长度和数据两项 |
numOfPictureParameterSets | UI8 | PPS 的个数,指示用作解码 AVC 基本流的 PPS 初始集的图片参数集(PPS)的数量 |
pictureParameterSetLength | UI16 | PPS 的长度,表示 ISO/IEC 14496-10 中定义的 PPS NAL 单元的字节长度 |
pictureParameterSetNALUnit | UI8[n] | PPS 的数据,包含 ISO/IEC 14496-10 中规定的 PPS NAL 单元。PPS 应按参数集标识符升序出现,允许有间隙 |
... | ... | 存在多个 PPS 时,重复 PPS 的长度和数据两项 |
下面是示例文件中对应 AVCDecoderConfigurationRecord 部分的数据:
000001a0h: 01 64 00 1E FF E1 00 1E 67 64 00 1E AC D9 40 BC
000001b0h: 35 E7 F0 16 A0 20 20 28 00 00 03 00 08 00 00 03
000001c0h: 01 90 78 B1 6C B0 01 00 06 68 EB E3 CB 22 C0 FD
000001d0h: F8 F8 00
000001a0h: 01 64 00 1E FF E1 00 1E 67 64 00 1E AC D9 40 BC
000001b0h: 35 E7 F0 16 A0 20 20 28 00 00 03 00 08 00 00 03
000001c0h: 01 90 78 B1 6C B0 01 00 06 68 EB E3 CB 22 C0 FD
000001d0h: F8 F8 00
那么如果 AVCPacketType 为 1 的话,视频数据部分的结果会是怎样的呢?此时,其视频数据体部分会包含一系列的 Nalu 数据:
类型 | 说明 |
---|---|
UI32(具体由 lengthSizeMinusOne 决定,若 lengthSizeMinusOne 值为 3,则 NALUnitLength 占 4bytes,也就是 UI32) | Nalu 长度 |
UI8[n] | Nalue 数据 |
... | ... |
可见,相应的数据结构要简单很多。
Audio Tag Body
顺着示例文件,现在又来到了一个新的 Tag 面前,在解析之前还是先读取一下表示上个 Tag 长度的四个字节:
000001d3h: 00 00 00 43
000001d3h: 00 00 00 43
然后就是 Tag 的头部部分:
000001d7h: 08 00 00 07 00 00 00 00 00 00 00
000001d7h: 08 00 00 07 00 00 00 00 00 00 00
第一个字节 0x08 表明这个标签的类型为 Audio,0x000007 表示数据部分有 7 个字节,其余部分为零。
音频标签的 Body 部分主要由 AudioTagHeader 和 AudioData 两部分组成,其头部主要包括音频的描述信息:
Field | 类型 | 说明 |
---|---|---|
SoundFormat | UB[4] | 音频编码格式,10 = AAC,详情见附录 |
SoundRate | UB[2] | 采样率:0 = 5.5 kHz,1 = 11 kHz,2 = 22 kHz,3 = 44 kHz |
SoundSize | UB[1] | 采样大小:0 = 8-bit samples,1 = 16-bit samples |
SoundType | UB[1] | 音频类型:0 = Mono sound,1 = Stereo sound |
AACPacketType | UI8(SoundFormat == 10) | AAC 包类型:0=AAC sequence header,1=AAC raw |
对于 AudioTag 的 AudioData 部分会根据编码格式和包类型的不同而不同:
- SoundFormat 为 10 时:
- AACPacketType 为 0,表示在 ISO 中定义的 AudioSpecificConfig;
- AACPacketType 为 1,表示 AAC RAW Frame 的 UI8 数组数据。
- SoundFormat 不为 10 时,Varies by format
根据上面的描述,继续从示例文件中读取数据分析:
000001e2h: AF 00
000001e2h: AF 00
0xAF 即 0b10101111,前四位 0b1010 表示当期音频的编码格式为 AAC,紧跟在后面两位 0b11 表示采样率为 44kHz,第七位表示位深为 16bit,最后一位表示音频类型为 Stereo sound。
由于 SoundFormat 为 10 且 AACPacketType 为 0,所以接下来的部分表示 AudioSpecificConfig:
Field | 类型 | 说明 |
---|---|---|
audioObjectType | UB[5] | 音频对象类型 |
samplingFrequencyIndex | UB[4] | 使用的采样率下标,根据下标可以查出采样率 |
channelConfiguration | UB[4] | 声道数 |
frameLengthFlag | UB[1] | 标志位,表明 IMDCT 窗口长度 |
dependsOnCoreCoder | UB[1] | 标志位,表明是否依赖 corecoder |
extensionFlag | UB[1] | 为零 |
那么如果这里 AACPacketType 为 1 的话,音频数据部分的结果会是怎样的呢?此时,其音频数据体部分皆为 AAC 裸数据。
总结
FLV 文件由 FLV header 和 FLV File Body 两部分组成,后者由一系列的 Tag 组成,每个 Tag 前又有一个 previousTagSize 字段,标记着前面一个 Tag 的大小。

其中 Tag 根据类型可分为 “Audio Tag”、”Video Data”、”Script Data” 三种。

每个 Tag 的 Tag Header 结构基本相同,但 Tag Data 部分的组成各异,更多详细信息可参考 FLV 标准文档。
附录
包括 SCRIPTDATAVALUE 数据类型、FLV 元数据对象属性和视频帧类型等信息的说明。
SCRIPTDATAVALUE 类型(其它 4 种)
SCRIPTDATAVALUE 记录了包含类型化的 ActionScript 值。
SCRIPTDATADATE 类型:
Field | 类型 | 说明 |
---|---|---|
DateTime | DOUBLE | 1970 年 1 月 1 日以来的毫秒数(UTC) |
LocalDateTimeOffset | SI16 | 与 UTC 的本地时间偏移(以分钟为单位),东时区为正,西时区为负 |
SCRIPTDATALONGSTRING 类型:
Field | 类型 | 说明 |
---|---|---|
StringLength | UI32 | StringData 长度(多少个字节) |
StringData | STRING | String 数据,没有 NULL 结束符 |
SCRIPTDATAOBJECT 类型:
Field | 类型 | 说明 |
---|---|---|
ObjectProperties | SCRIPTDATAOBJECTPROPERTY [ ] | 对象属性列表 |
List Terminator | SCRIPTDATAOBJECTEND | List 结束符 |
SCRIPTDATASTRICTARRAY 类型:
Field | 类型 | 说明 |
---|---|---|
StrictArrayLength | UI32 | 数组中的长度 |
StrictArrayValue | SCRIPTDATAVALUE [ StrictArrayLength ] | List of typed values |
常见的元数据属性
FLV 元数据对象应包含在名为 onMetadata 的 SCRIPTDATA 标记中。可用属性根据创建 FLV 文件的软件而有所不同。典型属性包括:
Field | 类型 | 说明 |
---|---|---|
audiocodecid | Number | 音频编码方式 |
audiodatarate | Number | 音频码率 |
audiodelay | Number | 音频的延时(单位:秒) |
audiosamplerate | Number | 音频采样率 |
audiosamplesize | Number | 音频采样精度 |
canSeekToEnd | Boolean | 是否可定位到最后的关键帧 |
creationdate | String | 创建日期和时间 |
duration | Number | 时长 |
filesize | Number | 文件大小 |
framerate | Number | 视频帧率 |
height | Number | 视频高度 |
stereo | Boolean | 是否为立体声 |
videocodecid | Number | 视频编码方式 |
videodatarate | Number | 视频码率 |
width | Number | 视频宽度 |
视频帧类型和编码
在 VideoTag 中 FrameType 指明了视频帧的类型,下面的值为主要的定义:
- 1: 关键帧
- 2: P 或 B 帧
- 3: 仅用于 H.263
- 4: 生成关键帧(服务器端使用)
- 5: 视频信息/命令帧
CodecID 的类型定义,下面是对应的编码值与对应的编码:
- 2: Sorenson H.263
- 3: Screen video
- 4: On2 VP6
- 5: On2 VP6 with alpha channel
- 6: Screen video version 2
- 7: AVC
音频编码格式
在 AudioTag 中 SoundFormat 指明了音频编码格式,下面的值为主要的定义:
- 0: Linear PCM, platform endian
- 1: ADPCM
- 2: MP3
- 3: LInear PCM, little endian
- 4: Nellymoser 16kHz mono
- 5: Nellymoser 8kHz 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 8kHz
- 15: Device-specific sound
传递方式
FLV 视频格式具有占有率低、视频质量良好、体积小等特点适合网络发展,并可以通过以下几种不同的方式传递:
- 作为独立的 FLV 文件,可以从本地存储(如硬盘或 CD)播放或转换为其他格式;
- 使用 Flash 创作工具(Flash Player 6 及更高版本支持)嵌入到 SWF 文件中;
- 使用 Flash 媒体服务器、VCS 或开源 Red5 服务器,通过 RTMP 流式传输到 Flash 播放器;
- 通过 HTTP 渐进式下载(Flash Player 7 及更高版本支持)。此方法使用 ActionScript 包含外部托管的 FLV 文件客户端进行回放。
渐进式下载有几个优点,包括缓冲、使用通用的 HTTP 服务器,以及对多个 FLV 源重用单个 SWF 播放器的能力。