1. 主要结构
flv的文件格式主要分成两部分:FlvHeader和FlvBody构成。
其中FlvBody具体主要由不同的FlvTAG组成。
| 字段名 | size | 备注 |
|---|---|---|
| FlvHeader | 9B | 固定长度的头部 |
| PreTagSize0 | 4B | 第一个PreTagSize固定为0 |
| FlvTAG1 | (变长) | 第一个TAG |
| PreTagSize1 | 4B | FlvTAG1 字段的长度 |
| FlvTAG2 | (变长) | 第二个TAG |
| PreTagSize2 | 4B | FlvTAG2 字段的长度 |
| ... | ... | ... |
| PreTagSize(N) | 4B | FlvTagN字段的长度 |
1.1 FlvHeader
Flv全局头部,固定长度,9个字节
| 字段名 | size | 备注 |
|---|---|---|
| Signature | 3B | “FLV”(0x464C56), 固定值 |
| Version | 1B | 文件版本,一般为1 |
| TypeFlags | 1B | 类型标记(从左到右,从高到低表示) b[0]标识是否存在视频流 b[2]表示是否存在音频流 |
| DataOffset | 4B | Header字节数,固定为9 |
1.2 FlvTAG
FlvTAG的组成也包括两部分:Header和Data。其中Header为固定长度,大小为9B,Data字段变长,但长度字段由3B表示,所以最高可容纳0xFFFFFF(16777215)字节。
1.2.1 TAG Header
| 字段名 | size | 备注 |
|---|---|---|
| Reserved | 2b | 一定是0 |
| Filter | 1b | 用来做文件内容加密处理 0: 不预处理 1: 预处理 |
| TagType | 5b | TAG类型标记 0x08:音频 0x09:视频 0x12:脚本数据 |
| DataSize | 3B | Data部分长度 |
| Timestamp | 3B | 时间戳,以毫秒为单位 |
| TimestampExtended | 1B | 扩展时间戳 |
| StreamID | 3B | 流ID,不过flv中始终为0 |
| (Data) | ... | ... |
1.2.2 TAG Data
根据Header头部中的TagType字段,Data字段具体可以分为3种类型:VideoTag, AudioTag, ScriptData。
1.2.2.1 VideoTag
| 字段名 | size | 备注 |
|---|---|---|
| FrameType | 4b | 视频帧类型 1: 关键帧(H264) 2: P/B帧(H264) 3: 用于H263 ... |
| CodecID | 4b | Codec类型。 2:Sorenson H.263(用得少) 3:ScreenVideo(用得少) 4:On2VP6(偶尔用) 5:带Alpha通道的On2VP6(偶尔用) 6:ScreenVideo 2(用得少) 7:H.264(使用得非常频繁) |
| AVCPacketType | 当Codec为H264时,1B | 0: H264的Sequence Header 1: NALU 2: H264的Sequence End |
| CTS | 当Codec为H264时,3B | 表示PTS和DTS之间的差值,如果编码使用B帧,则DTS和PTS相等 |
| (VideoData) | ... | 压缩的数据帧内容,一般对应H264中的一个NALU |
有上面可以看到,使用Flv承载的视频编码格式,一般是H264,且Flv默认不支持H265。一般一个FlvTAG对应H264中一个NALU。
1.2.2.2 AudioTag
| 字段名 | size | 备注 |
|---|---|---|
| SoundFormat | 4b | 不同的值代表不同的格式。 0: 线性PCM,大小端取决于平台 1: ADPCM 2: MP3 3:线性PCM,小端 ... 10:AAC ... |
| SoundRate | 2b | 不同的值代表不同的采样率。 0: 5.5kHz 1: 11kHz 2: 22kHz 3: 44kHz |
| SoundSize | 1b | 采样点size。 0: 8bit采样 1: 16bit采样 |
| SoundType | 1b | 音频类型,区分通道 0: 单声道 1: 双声道 |
| AACPacketType | 当音频为AAC时,1B | 0: AAC Sequence Header 1: AAC raw |
| (AudioData) | ... | ... |
1.2.2.3 ScriptData
ScriptData中最常用的就是存放metadata,一般基于AMF(Action Message Format)格式来存放数据。 AMF的格式:
| 字段名 | size | 备注 |
|---|---|---|
| Type | 1B | 0: Number 1: Boolean 2: String 3:Object ... 8:ECMA Array ... |
| ScriptData | ... | ... |
以下为一个flv文件中的具体实例,记录metadata
2. 其他
2.1 SequenceHeader
由上面VideoTAG和AudioTAG的格式可以得知,在Flv中封装H264/AAC数据时,需要先写入SequenceHeader。
这个SequenceHeader,以H264为例,实际上是对于H264 SPS/PPS的封装。
// FLV序列头结构
struct {
uint8_t frame_type = 0x17; // FLV定义的帧头
uint8_t avc_packet_type = 0x00; // FLV定义的包类型
uint24_t cts = 0; // FLV定义的时间偏移
// H.264配置数据容器
struct {
uint8_t version = 0x01; // FLV定义的版本号
uint8_t profile; // 来自SPS[1]
uint8_t compat; // 来自SPS[2]
uint8_t level; // 来自SPS[3]
uint8_t nal_size_len; // FLV定义的NALU长度
// SPS/PPS数据直接复制
uint8_t sps_count;
uint16_t sps_length;
uint8_t sps_data[...]; // 原始SPS内容
uint8_t pps_count;
uint16_t pps_length;
uint8_t pps_data[...]; // 原始PPS内容
} avc_config;
} sequence_header;
// FLV 音频 TAG 结构
typedef struct {
uint8_t tag_type = 0x08; // 音频TAG标识
// 音频头
uint8_t sound_format : 4; // 格式 (10=AAC)
uint8_t sound_rate : 2; // 采样率
uint8_t sound_size : 1; // 采样大小
uint8_t sound_type : 1; // 声道类型
// AAC 特定头
uint8_t aac_packet_type = 0; // 包类型 (0=序列头)
// AudioSpecificConfig 数据
uint8_t audio_object_type : 5; // AAC 类型
uint8_t sampling_freq_index : 4; // 采样率索引
uint8_t channel_config : 4; // 声道配置
uint8_t extension_flags : 3; // 扩展标志
} FLV_AAC_Header;