多媒体容器格式(二):FLV

162 阅读4分钟

1. 主要结构

image.png flv的文件格式主要分成两部分:FlvHeader和FlvBody构成。
其中FlvBody具体主要由不同的FlvTAG组成。

字段名size备注
FlvHeader9B固定长度的头部
PreTagSize04B第一个PreTagSize固定为0
FlvTAG1(变长)第一个TAG
PreTagSize14BFlvTAG1 字段的长度
FlvTAG2(变长)第二个TAG
PreTagSize24BFlvTAG2 字段的长度
.........
PreTagSize(N)4BFlvTagN字段的长度

1.1 FlvHeader

Flv全局头部,固定长度,9个字节

字段名size备注
Signature3B“FLV”(0x464C56), 固定值
Version1B文件版本,一般为1
TypeFlags1B类型标记(从左到右,从高到低表示)
b[0]标识是否存在视频流
b[2]表示是否存在音频流
DataOffset4BHeader字节数,固定为9

1.2 FlvTAG

FlvTAG的组成也包括两部分:Header和Data。其中Header为固定长度,大小为9B,Data字段变长,但长度字段由3B表示,所以最高可容纳0xFFFFFF(16777215)字节。 image.png

1.2.1 TAG Header

字段名size备注
Reserved2b一定是0
Filter1b用来做文件内容加密处理
0: 不预处理
1: 预处理
TagType5bTAG类型标记
0x08:音频
0x09:视频
0x12:脚本数据
DataSize3BData部分长度
Timestamp3B时间戳,以毫秒为单位
TimestampExtended1B扩展时间戳
StreamID3B流ID,不过flv中始终为0
(Data)......

1.2.2 TAG Data

image.png 根据Header头部中的TagType字段,Data字段具体可以分为3种类型:VideoTag, AudioTag, ScriptData。

1.2.2.1 VideoTag
字段名size备注
FrameType4b视频帧类型
1: 关键帧(H264)
2: P/B帧(H264)
3: 用于H263
...
CodecID4bCodec类型。
2:Sorenson H.263(用得少)
3:ScreenVideo(用得少)
4:On2VP6(偶尔用)
5:带Alpha通道的On2VP6(偶尔用)
6:ScreenVideo 2(用得少)
7:H.264(使用得非常频繁)
AVCPacketType当Codec为H264时,1B0: 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备注
SoundFormat4b不同的值代表不同的格式。
0: 线性PCM,大小端取决于平台
1: ADPCM
2: MP3
3:线性PCM,小端
...
10:AAC
...
SoundRate2b不同的值代表不同的采样率。
0: 5.5kHz
1: 11kHz
2: 22kHz
3: 44kHz
SoundSize1b采样点size。
0: 8bit采样
1: 16bit采样
SoundType1b音频类型,区分通道
0: 单声道
1: 双声道
AACPacketType当音频为AAC时,1B0: AAC Sequence Header
1: AAC raw
(AudioData)......
1.2.2.3 ScriptData

ScriptData中最常用的就是存放metadata,一般基于AMF(Action Message Format)格式来存放数据。 AMF的格式:

字段名size备注
Type1B0: Number
1: Boolean
2: String
3:Object
...
8:ECMA Array
...
ScriptData......

以下为一个flv文件中的具体实例,记录metadata
image.png

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;