FLV是目前常见的一种音视频封装格式,本文将详细分析FLV文件的封装结构。
FLV文件由Header和Body两部分组成,其中:
- 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 Tag,Video Tag,Metadata Tag,其中,Audio Tag记录着音频数据,Video Tag记录着视频数据,Metadata Tag记录着音视频元数据信息,通常该类型Tag会紧随FLV的Header作为第一个Tag出现,且只有一个。
每一个Tag由Tag Header和Tag 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文件中第一个Tag的DTS总为0
- 第8字节,时间戳的扩展字节,当24位不够用时,该字节作为时间戳的最高位,将时间戳扩展为32位无符号整数
- 第9到11字节,构成了一个无符号24位整数,表示stream ID,目前总为0
Metadata Tag
该Tag Data在未加密时是ScriptTagBody类型,它是以AMF编码的,AMF是一种紧凑的二进制编码方式,用于数据的序列化。ScriptTagBody包含以下两个字段:
-------------------------------------------------------------------
| Name (SCRIPTDATAVALUE) | Value (SCRIPTDATAVALUE) |
-------------------------------------------------------------------
Name和Value字段都是SCRIPTDATAVALUE类型,SCRIPTDATAVALUE类型使用第一个字节表示该字段具体类型,后面的字节编码了该字段的值,可用类型如下:
| 值 | 类型 |
|---|---|
| 0 | Number |
| 1 | Boolean |
| 2 | String |
| 3 | Object |
| 4 | MovieClip (保留,不支持) |
| 5 | Null |
| 6 | Undefined |
| 7 | Reference |
| 8 | ECMA array |
| 9 | Object end marker |
| 10 | Strict array |
| 11 | Date |
| 12 | Long string |
在Metadata中使用一个固定名为onMetaData的字段来携带音频,视频和文件的元数据信息,典型的元数据信息主要有如下:
| 字段 | 类型 | 说明 |
|---|---|---|
| audiocodecid | Number | 音频编解码器 ID |
| audiodatarate | Number | 音频码率,单位 kbps |
| audiodelay | Number | 由音频编解码器引入的延时,单位秒 |
| audiosamplerate | Number | 音频采样率 |
| audiosamplesize | Number | 音频采样点尺寸 |
| canSeekToEnd | Boolean | 指示最后一个视频帧是否是关键帧 |
| creationdate | String | 创建日期与时间 |
| duration | Number | 文件总时长,单位秒 |
| filesize | Number | 文件总长度,单位字节 |
| framerate | Number | 视频帧率 |
| height | Number | 视频高度,单位像素 |
| stereo | Boolean | 音频立体声标志 |
| videocodecid | Number | 视频编解码器 ID |
| videodatarate | Number | 视频码率,单位 kbps |
| width | Number | 视频宽度,单位像素 |
onMetaData的Name字段主要就是存储“onMetaData”字符串。具体为:
- 第1个字节值是0x02,表示Name字段是字符串类型。
- 第2到3个字节为无符号16位整数,标识字符串的长度,值为 0x000A (“onMetaData”这个字符串的长度)。
- 第4个字节及后面跟着的数据为具体的字符串,值为 “onMetaData”。 onMetaData的Value字段存储上表所示的各属性键值对。具体为:
- 第1个字节值是 0x08,表示Value字段是数组类型。
- 第2到5个字节为无符号32位整数,表示数组元素个数。
- 第6个字节开始表示数组元素内容,数组元素为属性名称和值组成的对(键值对)。
- 最后3个字节是数组的结束符,这个值固定为:0x00,0x00,0x09
Audio Tag
音频的Tag Data中使用第1个字节描述音频参数信息,后面是实际的音频数据。整体结构如下所示:
前四位bit为音频编码格式,可用的格式如下:
| 值 | 声音格式 | |
|---|---|---|
| 0 | Linear PCM, platform endian | |
| 1 | ADPCM | |
| 2 | MP3 | |
| 3 | Linear PCM, little endian | |
| 4 | Nellymoser 16-kHz mono | |
| 5 | Nellymoser 8-kHz mono | |
| 6 | Nellymoser | |
| 7 | G.711 A-law logarithmic PCM | |
| 8 | G.711 mu-law logarithmic PCM 9 | reserved |
| 10 | AAC | |
| 11 | Speex | |
| 14 | MP3 8-Khz | |
| 15 | Device-specific sound |
第5到6位bit为采样率,可用的采样率如下:
| 值 | 采样率 |
|---|---|
| 0 | 5.5 kHz |
| 1 | 11 kHz |
| 2 | 22 kHz |
| 3 | 44 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个字节描述视频参数信息,后面是实际的视频数据。整体结构如下所示:
前4位bit为帧类型,包括如下几种:
| 值 | 类型 |
|---|---|
| 1 | keyframe (for AVC, a seekable frame) |
| 2 | inter frame (for AVC, a non-seekable frame) |
| 3 | disposable inter frame (H.263 only) |
| 4 | generated keyframe (reserved for server use only) |
| 5 | video info/command frame |
后4位bit表示编码方式,支持的编码如下:
| 值 | 编码方式 |
|---|---|
| 1 | JPEG (currently unused) |
| 2 | Sorenson H.263 |
| 3 | Screen video |
| 4 | On2 VP6 |
| 5 | On2 VP6 with alpha channel |
| 6 | Screen video version 2 |
| 7 | AVC |
如果编码方式为AVC,实际上在第1个字节之后还会有4个字节用来描述AVC的编码信息,这4个字节,具体为:
第1个字节描述AVC帧类型,包含如下:
| 值 | AVC帧类型 |
|---|---|
| 0 | AVC sequence header |
| 1 | AVC NALU |
| 2 | AVC end of sequence (lower level NALU sequence ender is not required or supported) |
后3个字节为PTS与DTS的时间偏移值,单位ms,记作CTS