FLV(Flash Video)是 Adobe 公司推出的一种流媒体格式,它的特点是封装后的音视频文件较小、封装规范简单,因此适合在互联网上进行传输和使用。在浏览器普遍支持 Flash 插件的时代,FLV 格式的视频非常流行。但是随着主流的浏览器平台逐步放弃了对 Flash 插件的支持后,以及移动互联网的兴起,App 取代浏览器成为更多内容的载体,在短视频领域 FLV 的地位逐步被 MP4 取代。但是,在直播领域,由于 RTMP 推流、HTTP-FLV 播放的整套方案低延时的特性,以及服务端普遍提供 HTTP Web 服务,能更广泛的兼容 HTTP-FLV,使得 FLV 仍然是大多数直播产品的首选流媒体格式。
1、FLV 格式概览
FLV 文件由一个 FLV Header 和一个 FLV Body 组成,在 FLV Body 中则由多组(PreviousTagSize + Tag)组成。
FLV 中 Tag 的类型有三种:
- Audio Tags
- Video Tags
- Data Tags
Tag 中包含着 audio、video、scripts 的元信息,加密信息(可选)以及对应的实际数据。
总体来讲,FLV 的结构大致如下表所示:

2、Audio Tags 解析
Audio Tag 的结构大致如下所示:

通常在 AudioTagHeader 后面跟着就是 AUDIODATA 数据了,但是对于 AAC 格式的音频数据来说,AudioTagHeader 会多一个字段 AACPacketType 来表示 AACAUDIODATA 的类型:如果 AACPacketType 为 0,那么数据对应的是 AudioSpecificConfig;如果 AACPacketType 为 1,那么数据对应的为 Raw AAC frame data。
为什么 AudioTagHeader 中已经有了音频的相关参数,还需要在这里来一个 AudioSpecificConfig 呢?这是因为当 SoundFormat 是 AAC 时,SoundType 需要设置为 1(立体声),SoundRate 需要设置为 4(44k Hz),但这并不说明文件中 AAC 编码的音频必须是 44k Hz 的立体声。播放器在处理 AAC 音频时,需要忽略 AudioTagHeader 中的音频参数,而使用 AudioSpecificConfig 的参数来初始化解码器。
在 FLV 的文件中,一般情况下 AudioSpecificConfig 只会出现一次,即第一个 Audio Tag。如果音频使用 AAC,那么这个 Tag 就是 AAC sequence header,即 AAC 音频同步包。AudioSpecificConfig 的结构在ISO/IEC-14496-3 Audio标准中有做说明。
下面是ISO/IEC 14496-3, 1.6.2.1 AudioSpecificConfig:
AudioSpecificConfig() {
下面是ISO/IEC 14496-3, 1.5.1.1 Audio object type definition:
下面是ISO/IEC 14496-3, 1.6.3.4 samplingFrequencyIndex:
我们常用的 AAC 音频同步包的大小固定为 4 字节,前两个字节被称为AACDecoderSpecificInfo,用于描述这个音频包应当如何被解析,后两个字节称为AudioSpecificConfig,更加详细的指定了音频格式。下图是一个 AAC 音频同步包的示例:

在完成 AAC 音频同步包的发送后,我们就可以向服务器推送普通的 AAC 数据包了。在发送数据包时,AACDecoderSpecificInfo则变为0xAF01,向服务器说明这个包是普通 AAC 数据包。如果这里的 AAC 数据有包含 7 个字节 ADTS 头(若存在 CRC 校验,则是 9 个字节),那么要去掉这个头后,把裸数据放到这里。如果这里是采集到的裸数据,没有 ADTS 头,那么这里就不需要这样处理了。下图是一个 AAC 音频数据包的示例:

对应的,在解析 FLV 时,如果封装的是 AAC 的音频,要在每帧 AAC ES 流前把 7 个字节 ADTS 头添加回来,这是因为 ADTS 是解码器通用的格式,纯的 AAC ES 流要打包成 ADTS 格式的 AAC 文件,解码器才能正常解码。在打包 ADTS 的时候,需要用到 samplingFrequencyIndex 这个信息,samplingFrequencyIndex 最准确的信息是存储在 AudioSpecificConfig 中。
有关 AudioSpecificConfig 结构解析的代码,可以参考ffmpeg/libavcodec/mpeg4audio.c中的avpriv_mpeg4audio_get_config函数。
int avpriv_mpeg4audio_get_config(MPEG4AudioConfig *c, const uint8_t *buf, int bit_size, int sync_extension)
3、Video Tags 解析
Video Tag 的结构大致如下所示:

如上图所示,一般在 VideoTagHeader 后面跟着的就是 VIDEODATA 数据了,但是对于 AVC(H.264) 的编码格式来说,VideoTagHeader 会多出两个字段 AVCPacketType 和 CompositionTime。AVCPacketType 是表示后面 VIDEODATA 的类型,CompositionTime 则表示 pts 和dts的差值。
如果 AVCPacketType 为 0,那么这里的数据对应的是 AVCDecoderConfigurationRecord;如果 AVCPacketType 为 1,那么这里的数据对应的是 One or more NALUs(Full frames are required)。
AVCDecoderConfigurationRecord 记录的是 AVC(H.264)解码相关比较重要的 sps 和 pps 信息,解码器在解码数据之前需要首先获取的sps和 pps 的信息。在做 seek 或者断流重连等操作引起解码器重启时,也需要给解码器再传一遍 sps 和 pps 信息。
在 FLV 的文件中,一般情况下 AVCDecoderConfigurationRecord 只会出现一次,即第一个 Video Tag。如果视频使用 AVC,那么这个 Tag 就是 AVC sequence header,即 AVC 视频同步包。AVCDecoderConfigurationRecord 结构的在ISO/IEC-14496-15 AVC file format标准中有做说明。
下面是ISO/IEC 14496-15, 5.3.3.1.2 AVCDecoderConfigurationRecord:
aligned(8) class AVCDecoderConfigurationRecord {
下面是ITU-T H.264(ISO/IEC 14496-10), A.2 Profiles:
下面是ITU-T H.264(ISO/IEC 14496-10), A.3 Levels:
Defined level_idc: 10, 9[^1], 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50, 51, 52
下面是ISO/IEC 14496-15, 8.3.3.1.2 HEVCDecoderConfigurationRecord:
aligned(8) class HEVCDecoderConfigurationRecord {
下面是ITU-T H.265(ISO/IEC 23008-2), A.3 Profiles:
下面是ITU-T H.265(ISO/IEC 23008-2), A.4 Tiers and levels:
下图是一个 AVC 视频同步包的示例,其中红框部分对应的是 VIDEODATA:


下图是一个 AVC 视频数据包的示例,其中红框部分对应的是 VIDEODATA:


有关 AVCDecoderConfigurationRecord 结构解析的代码,可以参考ffmpeg/libavformat/avc.c中的ff_isom_write_avcc函数。
int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
4、Data Tags 解析
Data Tag 的结构大致如下所示:

其中 ScriptTagBody 中的 Name 和 Value 字段都是 SCRIPTDATAVALUE 类型。Name 最终对应的是 String 类型,Value 最终对应的是 ECMA array 类型。
SCRIPTDATAVALUE 包含两个字段:Type 和 ScriptDataValue,前者表示数据的类型,后者装载实际数据。
- SCRIPTDATAVALUE:
- 0 = Number
- 1 = Boolean
- 2 = String
- 3 = Object
- 4 = MovieClip (reserved, not supported)
- 5 = Null
- 6 = Undefined
- 7 = Reference
- 8 = ECMA array
- 9 = Object end marker
- 10 = Strict array
- 11 = Date
- 12 = Long string
- Type:定义数据的类型
- ScriptDataValue:数据值
这些数据都是以 AMF(Action Message Format) 的形式编码。
Data Tag 里可以承载不同的数据,其中我们最关心是的音视频的 metadata 元信息数据,这些信息是以一个 Name 为onMetadata的 SCRIPTDATA Tag 来存储的。
4.1、onMetadata 解析
onMetadata 包含着不同的属性,这些属性对于不同的 FLV 文件可能各不相同。

本文参考
1)Adobe Flash Video File Format Specification
https://www.adobe.com/content/dam/acom/en/devnet/flv/video_file_format_spec_v10_1.pdf
2)基于 libRTMP 的流媒体直播之 AAC、H264 推送
https://blog.51cto.com/billhoo/1557646
3)RTMP 协议发送 H.264 编码及 AAC 编码的音视频https://www.cnblogs.com/haibindev/archive/2011/12/29/2305712.html
4)ISO IEC 14496-15-2017http://www.doc88.com/p-8951310719017.html
(通过上文的介绍,我们了解了 FLV 视频封装格式,并探讨了其中 Audio Tags、Video Tags、Data Tags 等模块的具体结构。我们将在后面继续探讨其他常见的媒体封装格式,敬请期待)