专栏首页腾讯IVWEB团队的专栏FLV协议5分钟入门浅析

FLV协议5分钟入门浅析

FLV协议简介

FLV(Flash Video)是一种流媒体格式,因其体积小、协议相对简单,很快便流行开来,并得到广泛的支持。

常见的HTTP-FLV直播协议,就是使用HTTP流式传输通过FLV封装的音视频数据。对想要了解HTTP-FLV的同学来说,了解FLV协议很有必要。

概括地说,FLV 由 FLV header 跟 FLV file body 两部分组成,而 FLV file body 又由多个 FLV tag组成。

FLV = FLV header + FLV file body FLV file body = PreviousTagSize0 + Tag1 + PreviousTagSize1 + Tag2 + ... + PreviousTagSizeN-1 + TagN

FLV tag又分为3种类型:

  • Video Tag:存放视频相关数据;
  • Audio Tag:存放音频相关数据;
  • Script Tag:存放音视频元数据;

在实际讲解FLV协议前,首先对单位进行约定:

类型

定义

0x...

16进制数据

SI8

有符号8位整数

SI16

有符号16位整数

SI24

有符号24位整数

SI32

有符号32位整数

STRING

Sequence of Unicode 8-bit characters (UTF-8), terminated with 0x00 (unless otherwise specified)

UI8

无符号8位整数

UI16

无符号16位整数

UI24

无符号24位整数

UI32

无符号32位整数

xxx

类型为xxx的数组

xxx n

类型为xxx的数组,数组长度为n

FLV header

FLV header由如下字段组成,其中:

  1. 前三个字节内容固定是FLV
  2. 最后4个字节内容固定是9(对FLV版本1来说)

字段

字段类型

字段含义

Signature

UI8

签名,固定为'F' (0x46)

Signature

UI8

签名,固定为'L' (0x4c)

Signature

UI8

签名,固定为'V' (0x56)

Version

UI8

版本,比如 0x01 表示 FLV 版本 1

TypeFlagsReserved

UB5

全为0

TypeFlagsAudio

UB1

1表示有audio tag,0表示没有

TypeFlagsReserved

UB1

全为0

TypeFlagsVideo

UB1

1表示有video tag,0表示没有

DataOffset

UI32

FLV header的大小,单位是字节

FLV file body

FLV file body很有规律,由一系列的TagSize和Tag组成,其中:

  1. PreviousTagSize0 总是为0;
  2. tag 由tag header、tag body组成;
  3. 对FLV版本1,tag header固定为11个字节,因此,PreviousTagSize(除第1个)的值为 11 + 前一个tag 的 tag body的大小;

字段

字段类型

字段含义

PreviousTagSize0

UI32

总是0

Tag1

FLVTAG

第1个tag

PreviousTagSize1

UI32

前一个tag的大小,包括tag header

Tag2

FLVTAG

第2个tag

...

...

...

PreviousTagSizeN-1

UI32

第N-1个tag的大小

TagN

FLVTAG

第N个tag

PreviousTagSizeN

UI32

第N个tag的大小,包含tag header

FLV tags

FLV tag由 tag header + tag body组成。

tag header如下,总共占据11个字节:

字段

字段类型

字段含义

TagType

UI8

tag类型 8:audio 9:video 18:script data 其他:保留

DataSize

UI24

tag body的大小

Timestamp

UI24

相对于第一个tag的时间戳(单位是毫秒) 第一个tag的Timestamp为0

TimestampExtended

UI8

时间戳的扩展字段,当 Timestamp 3个字节不够时,会启用这个字段,代表高8位

StreamID

UI24

总是0

Data

取决于根据TagType

TagType=8,则为AUDIODATA TagType=9,则为VIDEODATA TagType=18,则为SCRIPTDATAOBJECT

In playback, the time sequencing of FLV tags depends on the FLV timestamps only. Any timing mechanisms built into the payload data format are ignored.

Audio tags

定义如下所示:

字段

字段类型

字段含义

SoundFormat

UB4

音频格式,重点关注 10 = AAC 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

SoundRate

UB2

采样率,对AAC来说,永远等于3 0 = 5.5-kHz 1 = 11-kHz 2 = 22-kHz 3 = 44-kHz

SoundSize

UB1

采样精度,对于压缩过的音频,永远是16位 0 = snd8Bit 1 = snd16Bit

SoundType

UB1

声道类型,对Nellymoser来说,永远是单声道;对AAC来说,永远是双声道; 0 = sndMono 单声道 1 = sndStereo 双声道

SoundData

UI8size of sound data

如果是AAC,则为 AACAUDIODATA; 其他请参考规范;

备注:

If the SoundFormat indicates AAC, the SoundType should be set to 1 (stereo) and the SoundRate should be set to 3 (44 kHz). However, this does not mean that AAC audio in FLV is always stereo, 44 kHz data. Instead, the Flash Player ignores these values and extracts the channel and sample rate data is encoded in the AAC bitstream.

AACAUDIODATA

当 SoundFormat 为10时,表示音频采AAC进行编码,此时,SoundData的定义如下:

字段

字段类型

字段含义

AACPacketType

UI8

0: AAC sequence header 1: AAC raw

Data

UI8n

如果AACPacketType为0,则为AudioSpecificConfig 如果AACPacketType为1,则为AAC帧数据

The AudioSpecificConfig is explained in ISO 14496-3. Note that it is not the same as the contents of the esds box from an MP4/F4V file. This structure is more deeply embedded.

关于AudioSpecificConfig

伪代码如下:参考这里

5 bits: object type
if (object type == 31)
    6 bits + 32: object type
4 bits: frequency index
if (frequency index == 15)
    24 bits: frequency
4 bits: channel configuration
var bits: AOT Specific Config

定义如下:

字段

字段类型

字段含义

AudioObjectType

UB5

编码器类型,比如2表示AAC-LC

SamplingFrequencyIndex

UB4

采样率索引值,比如4表示44100

SamplingFrequencyIndex

UB4

采样率索引值,比如4表示44100

ChannelConfiguration

UB4

声道配置,比如2代表双声道,front-left, front-right

Video tags

定义如下:

字段

字段类型

字段含义

FrameType

UB4

重点关注1、2: 1: keyframe (for AVC, a seekable frame) —— 即H.264的关键帧(I帧); 2: inter frame (for AVC, a non- seekable frame) —— H.264的非关键帧(P帧、B帧); 3: disposable inter frame (H.263 only) 4: generated keyframe (reserved for server use only) 5: video info/command frame

CodecID

UB4

编解码器,主要关注 7(AVC) 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

VideoData

取决于CodecID

实际的媒体类型,主要关注 7:AVCVIDEOPACKE 2: H263VIDEOPACKET 3: SCREENVIDEOPACKET 4: VP6FLVVIDEOPACKET 5: VP6FLVALPHAVIDEOPACKET 6: SCREENV2VIDEOPACKET 7: AVCVIDEOPACKE

AVCVIDEOPACKE

当 CodecID 为 7 时,VideoData 为 AVCVIDEOPACKE,也即 H.264媒体数据。

AVCVIDEOPACKE 的定义如下:

字段

字段类型

字段含义

AVCPacketType

UI8

0: AVC sequence header 1: AVC NALU 2: AVC end of sequence

CompositionTime

SI24

如果AVCPacketType=1,则为时间cts偏移量;否则,为0

Data

UI8n

1、如果如果AVCPacketType=1,则为AVCDecoderConfigurationRecord 2、如果AVCPacketType=1=2,则为NALU(一个或多个) 3、如果AVCPacketType=2,则为空

这里有几点稍微解释下:

  1. NALU:H.264中,将数据按照特定规则格式化后得到的抽象逻辑单元,称为NALU。这里的数据既包括了编码后的视频数据,也包括视频解码需要用到的参数集(PPS、SPS)。
  2. AVCDecoderConfigurationRecord:H.264 视频解码所需要的参数集(SPS、PPS)
  3. CTS:当B帧的存在时,视频解码呈现过程中,dts、pts可能不同,cts的计算公式为 pts - dts/90,单位为毫秒;如果B帧不存在,则cts固定为0;

PPS、SPS这里先不展开。

Script Data Tags

Script Data Tags通常用来存放跟FLV中音视频相关的元数据信息(onMetaData),比如时长、长度、宽度等。它的定义相对复杂些,采用AMF(Action Message Format)封装了一系列数据类型,比如字符串、数值、数组等。

字段

字段类型

字段含义

Objects

SCRIPTDATAOBJECT[]

任意数目的 SCRIPTDATAOBJECT

SCRIPTDATAOBJECTEND

UI24

永远是9,标识着Script Data的结束

SCRIPTDATAOBJECT 定义如下:

字段

字段类型

字段含义

ObjectName

SCRIPTDATASTRING

对象的名字

ObjectData

SCRIPTDATAVALUE

对象的值

SCRIPTDATAVALUE 的定义如下:

字段

字段类型

字段含义

Type

SCRIPTDATASTRING

变量类型: 0 = Number type 1 = Boolean type 2 = String type 3 = Object type 4 = MovieClip type 5 = Null type 6 = Undefined type 7 = Reference type 8 = ECMA array type 10 = Strict array type 11 = Date type 12 = Long string type

ECMAArrayLength

如果Type为8(数组),则为UI32

数组长度

ScriptDataValue

If Type == 0 DOUBLE If Type == 1 UI8 If Type == 2 SCRIPTDATASTRING ...(有点长,可以参考规范)

变量的值

ScriptDataValueTerminator

如果Type==3,则为SCRIPTDATAOBJECTEND 如果 Type==8,则为SCRIPTDATAVARIABLEEND

Object、Array的结束符

可以看到,Script Data Tag 的定义相对复杂,下面通过onMetaData进行进一步讲解。

onMetaData

onMetaData中包含了音视频相关的元数据,封装在Script Data Tag中,它包含了两个AMF。

第一个AMF:

  • 第1个字节:0x02,表示字符串类型
  • 第2-3个字节:UI16类型,值为0x000A,表示字符串的长度为10(onMetaData的长度);
  • 第4-13个字节:字符串onMetaData对应的16进制数字(0x6F 0x6E 0x4D 0x65 0x74 0x61 0x44 0x61 0x74 0x61);

第二个AMF:

  • 第1个字节:0x08,表示数组类型;
  • 第2-5个字节:UI32类型,表示数组的长度,onMetaData中具体包含哪些属性是不固定的。
  • 第6个字节+:比如duration,则: 第6-9个字节:0x0008,表示长度为8个字节; 第10-17个字节:0x6475 7261 7469,表示 duration 这个字符串; 第18个字节:0x00,表示为数值类型; 第19-26个字节:0x...,表示具体的时长;

更多onMetaData字段的定义:

字段

字段类型

字段含义

duration

DOUBLE

文件的时长

width

DOUBLE

视频宽度(px)

height

DOUBLE

视频高度(px)

videodatarate

DOUBLE

视频比特率(kb/s)

framerate

DOUBLE

视频帧率(帧/s)

videocodecid

DOUBLE

视频编解码器ID(参考Video Tag)

audiosamplerate

DOUBLE

音频采样率

audiosamplesize

DOUBLE

音频采样精度(参考Audio Tag)

stereo

BOOL

是否立体声

audiocodecid

DOUBLE

音频编解码器ID(参考Audio Tag)

filesize

DOUBLE

文件总得大小(字节)

写在后面

FLV协议本身不算复杂,理解上的困难,更多时候来自音视频编解码相关的知识,比如H.264、AAC相关知识,建议不懂的时候自行查下。此外,FLV的字节序为大端序,在做协议解析的时候一定要注意。

本文为讲解方便,部分内容可能不够严谨,如有错漏敬请指出。

相关链接

video_file_format_spec_v10.pdf

https://www.adobe.com/content/dam/acom/en/devnet/flv/video_file_format_spec_v10.pdf

MPEG-4 Part 3

https://en.wikipedia.org/wiki/MPEG-4_Part_3#Audio_Profiles

flv文件分析

https://www.jianshu.com/p/e290dca02979

H.264再学习 -- 详解 H.264 NALU语法结构

https://blog.csdn.net/qq_29350001/article/details/78226286

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 移动端 tryjs 异常捕获

    上周处理了一下群活动的 badjs ,第一步是摆脱` Script error .`,捕获异常栈,找到自己是错在哪里? 分享一下移动端 tryjs 异常捕获的步...

    腾讯IVWEB团队
  • React Native渲染原理浅析

    众所周知,RN和H5的区别在于:RN是使用Native组件来渲染的,而H5是依赖WebView。那么RN是如何做到写js代码,渲染Native组件的呢,这篇文章...

    腾讯IVWEB团队
  • 来谈谈 WebAssembly 是个啥?为何说它会影响每一个 Web 开发者?

    WebAssembly是个啥?为何说它会影响每一个Web开发者?是否意味着更精简的代码,更好的性能,更少的bug?

    腾讯IVWEB团队
  • Cypress web自动化23-cypress run 命令行参数详解

    默认情况下,Cypress 会将 Electron 作为无头浏览器运行完你所有的测试用例。 加上--headed参数将强制显式运行 Electron 浏览器

    上海-悠悠
  • 浏览器同源策略及跨域的解决方法

    同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说 ...

    laixiangran
  • DAY10:阅读CUDA异步并发执行中的Streams

    GPUS Lady
  • 腾讯云广州地区DNS变更操作

    今天收到了腾讯云的推送通知,广州一区服务需要下线了,本人也在使用腾讯云的服务为,在这里分享下相关教程。

    小肚腩gg
  • 【LeetCode-010】Regular Expression Matching

    Given an input string (s) and a pattern (p), implement regular expression matchi...

    周三不加班
  • RL10 Temporal difference learning

    Following the procedure of the provided Temporal-Difference (TD) learning algori...

    安包
  • DNS从入门到管理(一)

    DNS概述 DNS(Domain Name System,域名系统),域名和IP地址相互映射的一个分布式数据库,通过主机名,最终得到该主机名对应的IP地址的过程...

    小小科

扫码关注云+社区

领取腾讯云代金券