文档目录

一、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 播放。