FLV格式解析

578 阅读7分钟

FLV是目前常见的一种音视频封装格式,本文将详细分析FLV文件的封装结构。

FLV文件由HeaderBody两部分组成,其中:

  • Header: 描述了FLV文件类型,版本等基本信息
  • Body: 记录了文件具体数据内容,由更小的数据单元Tag组成 因此,一个FLV文件由一个Header和一系列Tag构成。

Header

当前版本的FLV,Header固定为9个字节,它的构成如下所示:

           ----------------------------------------------
字节序     | 46 | 4c | 56 | 01 | 05 | 00 | 00 | 00 | 09 |
           ----------------------------------------------
字符序       F    L    V    1  /    \                9
                    ---------------------------------
bit序               | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
                    ---------------------------------
                                         1/0     1/0
                                        音频位  视频位

说明:字节序表示FLV文件中字节流的顺序,字符序表示字节序对应的可见字符的顺序,bit序表示字节序中第5个字节的bit位值

根据上图所示:

  • 前3个字节为文件标识,FLV文件固定为“FLV
  • 第4个字节表示FLV版本,目前固定为1
  • 第5个字节8个bit为标志位,目前只用到了两个bit位,其中第6个bit位表示是否存在音频,第8个bit位表示是否存在视频,其他bit位保留,都为0
  • 第6到9共4个字节构成一个无符号32位整数(大端字节序),表示Header的字节数,在FLV版本1中固定为9,后续有FLV新的版本,可兼容更长的Header

大小端字节序
在计算机系统中是以字节为单位的,一个字节对应8个bit,但是在C语言中,除了8bit的char,还存在超过8bit的其他数据类型(如long),因此存在超过8位的处理器,必然存在多字节安排的问题。大端字节序即在内存的低位地址放数据的高位,内存的高位地址放数据的低位,而小端字节序正好相反。

网络字节序
网络传输中,TCP/IP协议规定接收到的第一个字节作为高位字节,也就是说,发送端发送的第一个字节为高位字节,而发送的第一个字节正是要发送数值在内存中起始地址处对应的字节,因此网络字节序是大端字节序

Body

Body由一系列的Tag组成,其构成如下所示:

------------------------------------------------------------------------------------------------
|  Previous Tag Size  |  Tag  |  Previous Tag Size  |  Tag |  Previous Tag Size  |  Tag  |  ...
------------------------------------------------------------------------------------------------

说明:Previous Tag Size表示上一个Tag的长度,其固定为4个字节,即无符号32位整数, 对于第一个Previous Tag Size来说,很显然前面没有Tag,因此固定为0

Tag共有三种,分别为Audio TagVideo TagMetadata Tag,其中,Audio Tag记录着音频数据,Video Tag记录着视频数据,Metadata Tag记录着音视频元数据信息,通常该类型Tag会紧随FLV的Header作为第一个Tag出现,且只有一个。

每一个TagTag HeaderTag Data两部分组成,其中Tag Header固定为11个字节长度,Tag Data则对应着音频Data,视频Data,元数据Data

Tag Header

Tag Header的构成如下所示:

		----------------------------------------------
                |       Tag Header      |       Tag Data      |
                ----------------------------------------------
                 /                    \
--------------------------------------------------------
| 08 | 00 | 00 | 18 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
--------------------------------------------------------

根据上图所示:

  • 第1个字节表示当前Tag类型,音频(0x08),视频(0x09),元数据 Data(0x12),除此之外其他数值非法
  • 第2到4字节,构成了一个无符号24位整数,描述了当前Tag Data大小
  • 第5到7字节,构成了一个无符号24位整数,描述了当前Tag的解码时间戳DTS,单位是毫秒。FLV文件中第一个TagDTS总为0
  • 第8字节,时间戳的扩展字节,当24位不够用时,该字节作为时间戳的最高位,将时间戳扩展为32位无符号整数
  • 第9到11字节,构成了一个无符号24位整数,表示stream ID,目前总为0

Metadata Tag

Tag Data在未加密时是ScriptTagBody类型,它是以AMF编码的,AMF是一种紧凑的二进制编码方式,用于数据的序列化。ScriptTagBody包含以下两个字段:

-------------------------------------------------------------------
|     Name (SCRIPTDATAVALUE)     |     Value (SCRIPTDATAVALUE)    |
-------------------------------------------------------------------

NameValue字段都是SCRIPTDATAVALUE类型,SCRIPTDATAVALUE类型使用第一个字节表示该字段具体类型,后面的字节编码了该字段的值,可用类型如下:

类型
0Number
1Boolean
2String
3Object
4MovieClip (保留,不支持)
5Null
6Undefined
7Reference
8ECMA array
9Object end marker
10Strict array
11Date
12Long string

Metadata中使用一个固定名为onMetaData的字段来携带音频,视频和文件的元数据信息,典型的元数据信息主要有如下:

字段类型说明
audiocodecidNumber音频编解码器 ID
audiodatarateNumber音频码率,单位 kbps
audiodelayNumber由音频编解码器引入的延时,单位秒
audiosamplerateNumber音频采样率
audiosamplesizeNumber音频采样点尺寸
canSeekToEndBoolean指示最后一个视频帧是否是关键帧
creationdateString创建日期与时间
durationNumber文件总时长,单位秒
filesizeNumber文件总长度,单位字节
framerateNumber视频帧率
heightNumber视频高度,单位像素
stereoBoolean音频立体声标志
videocodecidNumber视频编解码器 ID
videodatarateNumber视频码率,单位 kbps
widthNumber视频宽度,单位像素

onMetaDataName字段主要就是存储“onMetaData”字符串。具体为:

  • 第1个字节值是0x02,表示Name字段是字符串类型。
  • 第2到3个字节为无符号16位整数,标识字符串的长度,值为 0x000A (“onMetaData”这个字符串的长度)。
  • 第4个字节及后面跟着的数据为具体的字符串,值为 “onMetaData”。 onMetaDataValue字段存储上表所示的各属性键值对。具体为:
  • 第1个字节值是 0x08,表示Value字段是数组类型。
  • 第2到5个字节为无符号32位整数,表示数组元素个数。
  • 第6个字节开始表示数组元素内容,数组元素为属性名称和值组成的对(键值对)。
  • 最后3个字节是数组的结束符,这个值固定为:0x00,0x00,0x09

Audio Tag

音频的Tag Data中使用第1个字节描述音频参数信息,后面是实际的音频数据。整体结构如下所示:

音频数据结构.png

前四位bit为音频编码格式,可用的格式如下:

声音格式
0Linear PCM, platform endian
1ADPCM
2MP3
3Linear PCM, little endian
4Nellymoser 16-kHz mono
5Nellymoser 8-kHz mono
6Nellymoser
7G.711 A-law logarithmic PCM
8G.711 mu-law logarithmic PCM 9reserved
10AAC
11Speex
14MP3 8-Khz
15Device-specific sound

第5到6位bit为采样率,可用的采样率如下:

采样率
05.5 kHz
111 kHz
222 kHz
344 kHz

可见,FLV并不支持48kHz的采样率。

第7个bit位表示采样精度,0为8bits,1为16bits

第8个bit位表示音频类型,0为单声道,1为立体声

如果声音格式为10,即AAC格式,实际上在第1个字节之后还会有1个字节用来描述AAC的帧类型,0为AAC sequence header,1为AAC raw

Video Tag

视频的Tag Data中使用第1个字节描述视频参数信息,后面是实际的视频数据。整体结构如下所示:

视频数据结构.png

前4位bit为帧类型,包括如下几种:

类型
1keyframe (for AVC, a seekable frame)
2inter frame (for AVC, a non-seekable frame)
3disposable inter frame (H.263 only)
4generated keyframe (reserved for server use only)
5video info/command frame

后4位bit表示编码方式,支持的编码如下:

编码方式
1JPEG (currently unused)
2Sorenson H.263
3Screen video
4On2 VP6
5On2 VP6 with alpha channel
6Screen video version 2
7AVC

如果编码方式为AVC,实际上在第1个字节之后还会有4个字节用来描述AVC的编码信息,这4个字节,具体为:

第1个字节描述AVC帧类型,包含如下:

AVC帧类型
0AVC sequence header
1AVC NALU
2AVC end of sequence (lower level NALU sequence ender is not required or supported)

后3个字节为PTSDTS的时间偏移值,单位ms,记作CTS