一、FLV 的结构
FLV Header(9 字节):
签名 "FLV"(3 字节)
版本 1(1 字节)
标志(1 字节):bit0=视频存在, bit2=音频存在
头部大小 = 9(4 字节)
FLV Tag 序列:
[PreviousTagSize=0][Tag1][PreviousTagSize][Tag2]...
每个 Tag:
┌─────────────────────────────────────┐
│ Tag 类型:8=音频, 9=视频, 18=脚本 │ 1 字节
│ 数据大小 │ 3 字节
│ 时间戳(毫秒) │ 3 字节
│ 时间戳扩展(毫秒高位) │ 1 字节
│ StreamID(总是 0) │ 3 字节
│ Tag 数据 │ 可变
└─────────────────────────────────────┘
视频 Tag 的数据格式:
[帧类型(4bit) | 编码器ID(4bit)][编码数据]
帧类型:1=关键帧, 2=非关键帧
编码器ID:7=H.264
H.264 数据开头是 AVCDecoderConfigurationRecord(编码器配置,包含 sps/pps)
音频 Tag 的数据格式:
[音频格式(4bit) | 采样率(2bit) | 位深(1bit) | 声道(1bit)][音频数据]
音频格式:10=AAC
AAC 数据开头是 AudioSpecificConfig
二、RTMP 为什么用 FLV?
RTMP 发送的流式数据本质上就是 FLV Tag 流。推流端把编码后的 H.264 帧打包成 FLV VideoTag,通过 RTMP Chunk 发送给服务器,服务器直转发给拉流端。flv.js 做的就是把收到的 FLV Tag 解包,喂给浏览器的 MediaSource API 播放。