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 Length 和 SequenceParameterSets 也会依次出现多次。 |
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 文件。