2. http-flv协议 抓包 与 简要解读

337 阅读5分钟

引用

rtmp.veriskope.com/pdf/video_f… cloud.tencent.com/developer/a… www.jianshu.com/p/b90c6ef59… www.cnblogs.com/chyingp/p/f…

基本介绍

通过将音视频数据封装成flv, 并通过http协议将其传输至客户端,故称之为http-flv。该协议是目前直播拉流端的主流协议了,虎牙,斗鱼等都使用该协议进行拉流。

基本原理

众所周知,HTTP协议会通过一个Content-length字段来标识响应体的内容大小,故有以下两种情况

  • 服务器回复 http 请求的时候如果有这个字段,客户端就接收这个长度的数据然后就认为数据传输完成了。
  • 如果服务器回复 http 请求中没有这个字段,客户端就一直接收数据,直到服务器跟客户端的 socket 连接断开。 (流式传输)

基本定义

类型定义
0x...16进制数据
SI8有符号8位整数
SI16有符号16位整数
SI24有符号24位整数
SI32有符号32位整数
STRINGSequence 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协议格式

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

以下使用flv.js连接服务器并抓包所得

FLV header

image.png

HTTP-FLV无法直接抓取,故只能查看TCP的包体

image.png

其中,0x46, 0x4c, 0x56分别表示FLV为协议魔数,后跟0x01表示版本号; 后跟0b00000101 = 0x05 表示TypeFlagsReservedTypeFlagsAudioTypeFlagsReservedTypeFlagsVideo; 之后跟了DataOffset = 0x00000009 = 9标识了header的byte长度

总而言之,FLV协议的头及其简单

FLV 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的大小;

image.png

FLV PreviousTagSizeN

这个字段就像名字,主要用于标识前一个Tag的长度

FLV tag

tag = tag header + tag body

tag header

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

(查资料时发现网上有些资料都有错误,缺少一些字段,导致和抓包结果与文档注释对不上,故修正结果如下)

字段字段类型字段含义
ReservedUB[2]
FilterUB[1]
TagTypeUB5tag类型 8:audio 9:video 18:script data 其他:保留
DataSizeUI24tag body的大小
TimestampUI24相对于第一个tag的时间戳(单位是毫秒) 第一个tag的Timestamp为0
TimestampExtendedUI8时间戳的扩展字段,当 Timestamp 3个字节不够时,会启用这个字段,代表高8位
StreamIDUI24总是0
AudioTagHeaderIF TagType==8AudioTagHeader
VideoTagHeaderIF TagType==9VideoTagHeader
EncryptionHeaderIF Filter==1EncryptionTagHeader
FilterParamsIF Filter==1FilterParams
DataIFTagType ==8 AUDIODATA; IF TagType == 9 VIDEODATA;IF TagType == 18 SCRIPTDATAData

继续使用之前的抓包图,(先把flv header抹掉

image.png

首先,0x00000000 = 0 为PreviousTagSize0(默认为零);0x12 = 0b000 10010, 前三位为Reserved + Filter,后五位为TagType; DataSize = 0x000183; Timestamp = 0x003a98(有误,待查证); TimestampExtened = 0x00; StreamID = 0x000000; 之后就是具体的数据信息了

tag body
script data

当TagType == 18时,后面是SCRIPTDATA

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

image.png

下面是ScriptTagBody的一种 ScriptTagBody = Name(ScriptDataValue) -> Value(ScriptDataValue); 更准确来说,ScriptData使用的是AMF来组织,具体类型可查询本文在上方的PDF image.png image.png

onMetaData的格式

第一个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-7个字节:0x0008,表示长度为8个字节;
    • 第8-13个字节:0x6475 7261 7469,表示 duration 这个字符串;
    • 第14个字节:0x00,表示为数值类型;
    • 第15...个字节:0x...,表示具体的时长;

具体应该去查看AMF0相关文章

aduio data

当TagType == 8时,后面是 AudioTagHeader + AUDIODATA

AudioTagHeader存放了音频的元信息

image.png

AUDIODATA则是具体的音频负载

如果SoundFormat == 10的话,则数据是 AACAUDIODATA,否则为数据

image.png

在AACAUDIODATA中,如果AACPackType==0,则表示 AudioSpecificConfig;否则为AAC行数据

伪代码如下:参考这里

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

定义如下:

字段字段类型字段含义
AudioObjectTypeUB[5]编码器类型,比如2表示AAC-LC
SamplingFrequencyIndexUB[4]采样率索引值,比如4表示44100
SamplingFrequencyIndexUB[4]采样率索引值,比如4表示44100
ChannelConfigurationUB[4]声道配置,比如2代表双声道,front-left, front-right
video data

当TagType == 9时,后面是 VideoTagHeader + VIDEODATA

image.png

image.png

如果 CodecID == 7,则为AVCVIDEOPACKET

image.png

在AVCVIDEOPACKET中,如果 AVCPacketType == 0,则为AVCDecoderConfigurationRecord

image.png