FLV 文件格式解析

FLV 是 Adobe 推出的一个视频容器格式,主要用于 Flash 的在线视频播放。虽然说 Flash 已经日薄西山,但是还是有很多直播平台选择 Flash + FLV 进行在线播放。

本文希望能够通过正常人类的语言,较详细地描述 FLV (内含 AVC + AAC) 的文件格式。

FLV 文件

FLV 文件开头为 FLV Header,后接数个 FLV Tag,直到文件末尾。

FLV 文件中的数据均使用 Big-Endian(Network Order)储存。

所有的时间戳均使用毫秒数储存。

FLV Header

数据大小 名称 备注
byte Signature 总是 ASCII 字符 ‘F’
byte Signature 总是 ASCII 字符 ‘L’
byte Signature 总是 ASCII 字符 ‘V’
byte Version 总是 1 (0x1)
bit[5] reserved 总是 0 (0b00000)
bit Audio Bit 1 (0b1) - 文件含有音频
0 (0b0) - 文件不含音频
bit reserved 总是 0 (0b0)
bit Video Bit 1 (0b1) - 文件含有视频
0 (0b0) - 文件不含视频
uint32 Header Size 总是 9 (0x9)

FLV Tag

文件的最后一个 Tag:

数据大小 名称 备注
uint32 Previous Tag Size 倒数第二个 Tag 的大小

非最后一个 Tag:

数据大小 名称 备注
uint32 Previous Tag Size 上一个 Tag 的大小;
如为第一个 _Tag_,则为 0
byte Type 8 (0x8) - 音频 Tag
9 (0x9) - 视频 Tag
18 (0x12) - 元数据 Tag
uint24 Payload Size Data 的字节大小
uint24 Timestamp Low 时间戳低 24 位
uint8 Timestamp High 时间戳高 8 位(按照 Big-Endian,这不就是个 uint32 吗?)
uint24 Stream ID 总是 0 (0x0)
byte[Payload Size] Data 根据 Type 不同,以下详细说明

Audio Tag

数据大小 名称 备注
bit[4] Sound Format 2   (0x2) - MP3
3   (0x3) - PCM
10 (0xA) - AAC
其它省略,以下仅说明 AAC
bit[2] Sample Rate 0 (0x0) - 5500Hz
1 (0x1) - 11025Hz
2 (0x2) - 22050Hz
3 (0x3) - 44100Hz
bit Sample Size 0 (0x0) - 8bit
1 (0x1) - 16bit
bit Channel Count 0 (0x0) - Mono
1 (0x1) - Stereo
byte[Payload Size - 1] Sound Data 音频数据,随 Sound Format 不同,格式亦不同

如果 Sound Format 为 0xA (AAC),Sound Data 为:

数据大小 名称 备注
byte Type 0 (0x0) - Sequence Header
1 (0x1) - Raw
一般 Sequence Header 为第一个 Audio Tag,并且全文件只出现一次
bit[5] Object Type 如果 Type 为 0 (Sequence Header),这里开始就是 AudioSpecificConfig 了,到处是位操作,设计的人真是脑残。
1   (0x1) - AAC Main
2   (0x2) - AAC LC
31 (0xFE) - Escape
其它省略,一般既然是 AAC 了,常用编码方式就只有 Main 和 LC(Low Complexity)两种了
bit[6] Extend Object Type 如果 Object Type 为 0xFE (Escape),此处才是扩展 Object Type,否则表示的是以下的数据
bit[4] Sample Frequency Index 采样率索引
0 ~ 12 分别为 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350;
15 - 下一数据
uint24(unaligned) Sample Frequency 如果 Sample Frequency Index 为 15,此处才是 Sample Frequency。
bit[4] Channel Count 声道数,4 为 Stereo

如果 Type 为 1 (Raw),Type 的后面就是 Raw AAC Packet。不管是以上 AudioSpecificConfig 还是 Raw AAC Packet,长度均为 Payload Size - 2,即后方不再有其它数据。

因为包含的是 RAW AAC,所以如果你的解码器必须要 AAC ADTS 的话,就需要记住第一个 Sequence Header 的 AudioSpecificConfig,并根据它构造出 ADTS 头,加在 RAW 数据之前送给解码器。至于怎么构造 ADTS 头,下回分解。

Video Tag

数据大小 名称 备注
byte Type 0 (0x0) - Keyframe
1 (0x1) - Interframe
还有 2 和 3,AVC 并不会用到
byte Video Format 7 (0x7) - AVC
其它省略

Video Format 为 0x7 (AVC) 时,接下来的数据为:

数据大小 名称 备注
byte Type 0 (0x0) - SequenceHeader
1 (0x1) - NALU
2 (0x2) - SequenceEnd
uint24 Decode Timestamp 并没有什么卵用

如果 Type 为 0 (Sequence Header),一般是第一个 Video Tag,且文件中仅有一个,接下来是 AVCDecoderConfigurationRecord,又是位操作,这些做 C++ 开发的为什么都这么喜欢位操作:

数据大小 名称 备注
byte Version 没注意过值是什么
byte AVC Profile Indication 没注意过值是什么
byte Profile Compatibility 没注意过值是什么
bit[6] reserved 没注意过值是什么
bit[2] NALU Size Length Minus One 接下来要用的,表示每个 NALU 的长度的长度的,而且要 +1 使用
一般为 3,所以 NALU 的长度的长度就是 4
bit[3] reserved 没注意过值是什么
bit[5] Number Of SequenceParameterSets 接下来的 SequenceParameterSets (SPS) 的个数,虽然不知道 SPS 是什么鬼,但是有用
一般是一个,如果有多个,下面的 SequenceParameterSets LengthSequenceParameterSets 也会依次出现多次。
uint16 SequenceParameterSet Length 下一个 SPS 的长度
byte[SequenceParameterSet Length] SequenceParameterSet SPS
uint8 Number Of PictureParameterSets 和上面的 Number Of SequenceParameterSets 类似的功能
uint16 PictureParameterSet Length 下一个 PPS 的长度
byte[PictureParameterSet Length] PictureParameterSet PPS

一般 AVC 解码器使用的则是 CodePrivateData,从 AVCDecoderConfigurationRecord 到 CodePrivateData,需要用 0x00000001 连接 SPS 和 PPS,即:

CodePrivateData = 0x00000001 concat SPS 1 concat 0x00000001 concat SPS 2
CodePrivateData = CodePrivateData concat 0x00000001 concat PPS 1 concat 0x00000001 concat PPS 2

如果 Type 为 1 (NALU),接下来是 NALU:

数据大小 名称 备注
byte[NALU Size Length Minus One + 1] NALU Size 如果 NALU Size Length Minus One 为 1,本数据为 uint16;
如果为 3,本数据为 uint32
byte[NALU Size] NALU Data 数据

Windows 的 AVC 解码器,需要在第一帧前面加上 CodePrivateData,第二帧开始的数据是 0x00000001 concat NALU Data 1 concat 0x00000001 concat NALU Data 2 …,一个 Video Tag 中至少包含一帧的 NALU Data,相连传输给 AVC 解码器即可。

基于以上的定义,就可以分离 AVC + AAC 编码的 FLV 了,如果有对应的解码器即可播放;如果加上 MP4 Box 之类的库,即可无损转换 FLV 为 MP4 文件。