流媒体学习4

发布时间 2023-12-08 14:26:51作者: 泽良_小涛

5)StreamBegin

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EUW5pYklEZWxwUFVmaWJwV3BuSkxMeGliTGFRTmliMXBHcFJQVGpBelFPczNJUkFXbkt6bmU3QVY1ODRJY1VGRXgxQVM1QW9pYjlJV0lBZHZRLzY0MA?x-oss-process=image/format,png

StreamBegin属于用户控制类消息,header的typeid为0x04。而用户控制消息的类型的定义如下:

如此,我们就得出了StreamBegin的过滤条件。接下来我们看看StreamBegin消息,还是先看一下抓包文件:

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EUW5pYklEZWxwUFVmaWJwV3BuSkxMeGliTDlyZU5NaWF5MVFPSkw2ZkdCand5VlE2bVk3eDdVMUxuVkVMS3JaaWJCb284YThzcWFqMTNVVmZBLzY0MA?x-oss-process=image/format,png

RTMP服务器发送StreamBegin以通知客户端流已经可以使用并且可以用于通信。默认情况下,从客户端成功接收到connect命令后,将在ID 0上发送StreamBegin。StreamBegin的数据字段占用4字节,其类型占用2个字节,所以RTMP Body部分总共占用6个字节(类型+数据)。其中数据字段代表已开始运行的流的流ID,此例中为1。

7.createStream

​创建完RTMP连接之后就可以创建或者访问RTMP流,对于推流端,客户端要向服务器发送一个releaseStream命令消息,之后是createStream命令消息,对于拉流端,则要发送play消息请求视频资源。我们先来看看推流端的消息流程,当发送完createStream消息之后,解析服务器返回的消息会得到一个stream ID, 这个ID也就是以后和服务器通信的 message stream ID, 一般返回的是1,不固定。

1)createStream

我们来先看看createStream消息,RTMP客户端发送此消息到服务端,创建一个逻辑通道,用于消息通信。音频、视频、元数据均通过createStream创建的数据通道进行交互,而releaseStream与createStream相对应,为什么有的时候会在createStream之前先来一次releaseStream呢?这就像我们很多的服务实现中,先进行一次stop,然后再进行start一样。因为我们每次开启新的流程,并不能确保之前的流程是否正常走完,是否出现了异常情况,异常的情况是否已经处理等等,所以,做一个类似于恢复初始状态的操作,releaseStream就是这个作用。

createStream的整体架构:

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EUW5pYklEZWxwUFVmaWJwV3BuSkxMeGliTEpDa09NRlhzMjNiRE1JVzJ5a2lhQ2FQUG1jVEpZYTRJa0ZTT2VwcVBrS2liUXNHSE5JMm5TcTlnLzY0MA?x-oss-process=image/format,png

使用字符串类型标识命令的类型,恒为“createStream”;然后使用number类型标识事务ID;紧接着是command相关的信息,如果存在,用set表示,如果没有,则使用null类型表示。

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EUW5pYklEZWxwUFVmaWJwV3BuSkxMeGliTGFpYWgyYjJ2blBlcXE4SmdzenVqMkE5VWVJTkMyRjZKY0E2OXprMlNsNmY0T1h2WVU4b2xuOWcvNjQw?x-oss-process=image/format,png

该createStream消息中,事务ID为2,没有command相关的信息,使用Null类型表示。命令的名称(0x02)、事务ID(0x00)、命令的信息(0x03 or 0x05)均按照AMF0的格式进行编码,我们从抓包文件中也可以比较明显的看到。

2)_result/_error

客户端发送createStream请求之后,服务端会反馈一个结果给客户端,如果成功,则返回_result,如果失败,则返回_error。返回的消息的整体结构如下图:

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EUW5pYklEZWxwUFVmaWJwV3BuSkxMeGliTHZHRGdheFl1NVpUOHZBWHNRaWJZMTc0eDJMUEhldHZrdmpuZTRqYTR5R3RkbnROZ3JoOWo0WlEvNjQw?x-oss-process=image/format,png

整体与createStream类似,commandName为固定为"_result"或者"_error",transcationID为createStream中的ID,此例中为2,comamndObject也是与createStream一样的组织方式。不同的是多了一个streamID,成功的时候,返回一个streamID,失败的时候返回失败的原因,类似于错误码。

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EUW5pYklEZWxwUFVmaWJwV3BuSkxMeGliTGFMZVU0TU5YNXFuVnVDNEVteW9saWJMWTdGVnc0OGVrZDVPSVlXTWRWdmNmaWFiZlZGM1JJZnVBLzY0MA?x-oss-process=image/format,png

3)releaseStream

说完createStream,我们就可以说说releaseStream命令了。关于releaseStream命令,我们还是通过抓包文件来进行分析,首先看一个releaseStream的抓包文件。

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EUW5pYklEZWxwUFVmaWJwV3BuSkxMeGliTEtvT003RldyamRURTh4NlROWkpNUXFoeWxQcUJNTlJHWVBCaDNDeG1nYThZSTRoWVdEeXpidy82NDA?x-oss-process=image/format,png

release消息的组织结构,comandName + transactionID + commandObject + 流的一些用户名和密码信息等(可能没有),简单示意图如下:

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EUW5pYklEZWxwUFVmaWJwV3BuSkxMeGliTFA0UXZoMUFld2RmNHdkMVB0Z25HMkVNYUZEQnNpY0NiNXMydGwyOXByeGljMEpkdzlidEZoWm1BLzY0MA?x-oss-process=image/format,png

commandName恒为“releaseStream”用以区分类型,transactionID指明要释放的stream,此处id为2,也就是我们前面createStream的id(在客户端请求下一个createStream的时候,就会先释放原有的stream),comandObject携带一些相关的信息(可能没有);userPass部分为针对流的一些用户名和密码的一些信息,本例中没有,所以,字符串中的长度为0。

8.publish推流

1) publish

对于推流端,经过releaseStream,createStream消息之后,得到了_result消息之后,接下来客户端就可以发起publish消息。推流端使用publish消息向rtmp服务器端发布一个命名的流,发布之后,任意客户端都可以以该名称请求视频、音频和数据。我们首先来看一下publish消息的组织结构:

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1ZjMWJyN1RxN2d2SlhpYmQ1YWRYQjJ4MU5DYlkxWHA3T3VXRmxJVWlhemxONEVpYnZ2cHRMcUd0eXcvNjQw?x-oss-process=image/format,png

  • commandName:使用string类型,表示消息类型(“publish”);
  • transactionID:使用number类型表示事物ID;
  • commandObject:对于publish消息,该部分为空,用null类型表示;
  • publishName:发布的流的名称,使用string类型表示,比如我们发布到rtmp://192.168.1.101:1935/rtmp_live/test,则test为流名称,也可以省略,此时该字段为空字符;
  • publishType:发布的流的类型,使用string类型表示,有3种类型,分别为live、record、append。record表示发布的视频流到rtmp服务器application对应的目录下会将发布的流录制成文件,append表示会将发布的视频流追加到原有的文件,如果原来没有文件就创建,live则不会在rtmp服务器上产生文件。

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1ZKMkdSbEd2SFdodGR4VjVzZ081MXc1VU1JQUVoaWE2Z0pCcFY3d2s1eGtEV2dTUEU2dGFtM2pnLzY0MA?x-oss-process=image/format,png

通过抓包文件,我们可以看到这一抓包文件发送一条publish的消息,事务id为5,没有指定发布的流的名称,发布流的方式是live。如果发布的地址为rtmp://192.168.1.101:1935/rtmp_live,则其他任何客户端都可以访问该url获取视频资源,进而进行播放。

2)onStatus

客户端发送publish消息给rtmp服务端后,服务端会向客户端反馈一条消息,该消息采用了onStatus,onStatus的消息格式如下:

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1ZBcFRpYkM3S01OVHFpYnVjeWh3emljMXlUYlFKaWNKZW16cHpuaWNyS0hRaWJQT05PRDNmQ1hsMTRabmcvNjQw?x-oss-process=image/format,png

onStatus消息由三部分组成:

  • command Name:表示消息类型,恒为“onStatus”;
  • transaction ID:设为0;
  • command Object:用null表示;
  • info Object:使用object类型表示多个字段,一般有warn,status,code,description等状态。

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1ZpYXRmU01qMzQ0VXdDQlVDQmhaMUppYWZ2S0VnWTZsOUtYQzV4aWJIVTFpYVBLcjdMRnpDOWVTOTd3LzY0MA?x-oss-process=image/format,png

该抓包文件使用onStatus返回了一条消息,描述的状态内容中code为NetStream.Publish.Start,description为Start publishing,该消息的目的就是告诉推流客户端,现在可以推流了。

3)SetDataFrame/OnMetaData

一般在客户端收到服务端返回的针对publish的onStatus消息之后,如果没有异常,推流端还会向服务器发送一条SetDataFrame的消息,其中包含onMetaData消息,这一条消息的主要作用是告诉服务端,推流段关于音视频的处理采用的一些参数,比如音频的采样率,通道数,帧率,视频的宽,高等信息。

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1ZJRzF3UlJRaWM4MTlwMnFpYlo1QXhSempYUVRiN3E0RzRnUEwwdVBrV25FQnBRUUxXcVAyZ05MZy82NDA?x-oss-process=image/format,png

RTMP Body部分首先以AMF0格式(string)表示SetDataFrame消息;然后以AMF0格式编码(string)表示onMetaData消息;最后描述具体的关于音视频相关的参数,该部分使用ECMA Array的类型来表示。

SetDataFrame部分

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1Z4ZktTdldLS2ljbjRHVm9NMTNCQXFyVmljMklpY1JWeXhMUWhaSnJSMVVOVlB5Y0NhMTZLMjFwaWN3LzY0MA?x-oss-process=image/format,png

onMetaData部分

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1Z4ZktTdldLS2ljbjRHVm9NMTNCQXFyVmljMklpY1JWeXhMUWhaSnJSMVVOVlB5Y0NhMTZLMjFwaWN3LzY0MA?x-oss-process=image/format,png

property部分

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1Z4bnRqWm5YZmdidG5UdWRIU2liMkcyQk1rTmtiQWVndlNWUEZPbEY3SWR2enk0aFh0ckZrWHJnLzY0MA?x-oss-process=image/format,png

ECMA Arrya本身的类型为0x08,其后紧跟着的是数组元素的个数,此处为20,占用4个字节表示,在之后便是具体的数组中的每一个元素。而数组中的每一个元素的具体编码方式又是遵循AMF0编码标准的。此例中,共表示了20个属性。包含文件大小,视频宽度和高度,视频编码codec_id,帧率信息,比特率信息,音频的codec_id,音频采样率,channel数量等,最后还有一个encoder字段来表示编码器,我们推流使用的是obs(open broad cast),所以该字段中表明了使用obs-output module,obs的版本号为25.0.0。

9.play拉流

​1)  综述

在客户端发起createStream命令之后,客户端收到服务端反馈的_result消息,接下来客户端就可以向服务端发起请求播放的指令,这个指令就是play。首先我们看一下官方给出的关于play的消息流示意图。

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1ZHQ29LaWJOZGxFZTA5VzA0am1JZ0NwQnZLSDVIU1U2amliWFFXZGlhM3BPa2ljbUhhN1Z0QllmcUV3LzY0MA?x-oss-process=image/format,png

首先我们来简单介绍一下关于play的流程,客户端向服务端发送play指令之后,服务端收到之后向客户端发送SetChunkSize消息,实际场景中大都在服务器回复客户端connect消息的时候一起发送setChunkSize消息;

服务端向客户端发送StreamIsRecorded消息(实际场景中比较少见);服务端向客户端发送StreamBegin消息,向客户端指示流传输的开始;StreamIsRecoreded消息和StreamBegin消息组织结构比较简单,RTMP Body部分使用2个字节表示事件类型,StreamBegin的类型为0x00,4个字节表示StreamID。

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1ZaTTZSNXNUTnBUbVZyaWFEcHc0WTBJMlNhNHA4cllOajhoRkVEY3FNR0FlTUhFMUtReENxQzN3LzY0MA?x-oss-process=image/format,png

说明:streamBegin wireshark过滤条件

rtmpt.ucm.eventtype == 0x00

客户端成功发送play请求后,服务端向客户端发送onStatus命令消息NetStream.Play.Start 和 NetStream.Play.Reset消息。其中NetStream.Play.Reset消息只有在客户端发送play消息的时候设置了reset标志的时候才会发。如果客户端请求播放的流不存在,服务端会返回onStatus命令消息NetStream.Play.StreamNotFound。

这些交互结束之后,服务端就会向客户端发送音频和视频数据,客户端就可以进行解码,然后渲染播放了。接下来我们来看一下这几条消息(streamBegin前面已介绍):

2) play

play消息的整体组织结构

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1ZUT3JiVFEwdldDZHZlTTFDNFc2azZUbHZrTDlLYlZMcHRVcno0aWIzZG45MUpLVzZBdTRZR2pBLzY0MA?x-oss-process=image/format,png

  • commandName:命令的名称,为“connect”;
  • transaction ID:事务ID,用number类型表示;
  • command Object:如果有,用object类型表示,如果没有,则使用null类型指明;
  • stream Name:请求的流的名称,一般在url中application后面的字段,如rtmp://192.17.1.202:1935/rtmp_live/test,rtmp_live为application,test为流的名称;
  • start:可选字段,使用number类型表示,指示开始时间,默认值为-2,表示客户端首先尝试命名为streamName的实时流(官方文档中说以秒单位,实际抓包文件中看到的单位应该是毫秒,要注意);
  • duration:可选字段,用number类型表示,指定播放时间,默认值为-1,表示播放到流结束;
  • reset:可选字段,用boolean类型表示,用来指示是否刷新之前的播放列表;

该抓包文件中的play命令,transactionID为4,commandObject中没有内容,streamName为“test”,没有duration和reset字段,有start字段,默认值为-2000,2000毫秒,即2s。

3) setChunkSize https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1ZpYVluV3lBZUN3MG03dVlTSzltc1J6YTl4MzhHM3MwMlRBOG9Tc0YwQW9BVVhIRzhZNlZzT0hBLzY0MA?x-oss-process=image/format,png

setChunkSize消息结构也比较简单,RTMP Header中的typeID,用来表示消息类型,setChunkSize的类型为0x01。RTMP Body部分直接用4个字节表示chunk size,此例中chunkSize设为4000。

说明:setChunkSize消息wireshark中的过滤条件为:

rtmpt.header.typeid == 0x01

4)onStatus-play start

如果没有任何异常情况,服务器会向客户端发送一个onStatus的状态,如果没有异常,该状态的描述为play start。

onStatus消息的组织结构如下:

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1ZBcFRpYkM3S01OVHFpYnVjeWh3emljMXlUYlFKaWNKZW16cHpuaWNyS0hRaWJQT05PRDNmQ1hsMTRabmcvNjQw?x-oss-process=image/format,png

onStatus消息由三部分组成:

  • command Name:表示消息类型,恒为“onStatus”;
  • transaction ID:设为0;
  • command Object:用null表示;
  • info Object:使用object类型表示多个字段,一般有warn,status,code,description等状态。

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1ZKYUFuelB4ZVM4UHR6bVY0dThVOFRsR1ppYjBYWkpacDZrOGpMUWlhTXdlaWJTZmljR0g4VkxnT01nLzY0MA?x-oss-process=image/format,png

command Name, command Object,transaction ID我们已经很熟悉了。我们来看看info Object中的内容,按照AMF0的格式编码,开头表示类型0x03,之后有3个字段描述object;最后有一个End of Obejct Maker用来标记。对于play命令的请求,回应的level为status,code为NetStream.Play.Start,desription为Start live。这些表示play请求命令成功,接下来可以进行音视频的播放了。

10 audio

rtmp协议wireshark中过滤音频数据包的条件为:

rtmpt.header.typeid == 0x08

通过抓包文件,我们看到音频数据也是按照RTMP Header + Rtmp Body的组织结构来进行封装的。Header部分之前的文章解析过,我们主要来看Body部分。因为rtmp是Adobe公司开发的协议,所以对自己东西当然是青睐有加,音频的数据的Body部分正是按照FLV的格式进行组装的。而Flv的封装以tag为单位来进行组织,对于音频数据,包含tagHeader + tagData,tagHeader占用一个字节,表明音频编码的相关参数,tagData为具体的音频编码数据。

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1ZvbEI2dmdGa1VpYjFTTEttbHRUN1Z6enZadnYzNGZpY29EanM3aWJkVFVLUVJkbm8zSk90aHVYY1EvNjQw?x-oss-process=image/format,png

小的红色框中的数据即为audioTag的header,此处值为0xaf。接下来,我们就看下flv中audioTag的Header是如何组织的。

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1ZmcEIwcGlhdGQ3Z2I3aWJDMEJvUHIzdGhyNFE3YmcxbFVrclBQWjQ0VW9UaWNDaWFhV2lhTlJwcGRjZy82NDA?x-oss-process=image/format,png

tag占用1个字节,我们从高到低,依次来看:

1)音频编码格式

高4比特,用于表示音频编码格式,具体可选值如下。

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EVHZwOVdiOGlhRHdhYVljVmoxUVIzM1ZpYk1MVmhseDI0dFA5UUlvaWFpY0dsNmJFT1ZNakpoaHltQ1BGdDluTlpMOGRMRDJGQlBqdzNRTXcvNjQw?x-oss-process=image/format,png

2)音频采样率

在之后的2个bit,表示音频采样率。

3)位深

之后的1个bit表示采样位深度,可选值为0,1,0表示8比特深度,1表示16比特深度。

4)声道

之后的1个bit表示声道数的参数,可选值为0,1,0表示sndMono,1表示sndStereo。

5)举例

rtmp Body中的数据是audio类型,audio类型的第一个字节表示header,其值为0xaf=0x10101111,将二进制隔开为4段:

0x1010=10

0x11=3

0x1=1

0x1=1

我们可以得出,该音频书包的编码格式为AAC,采样率为44KHz,位深度为16bit,声道模式为strereo。

11. videoData

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EUnRRM2tNRDZhYVlMajFqd2lhWXhFbDZER1JpY0Y2TXRtTDk0YXRMaWE0U2xFeG5TMk5tUW5aQU1jQ2p2OXFtbG1yc09DbjA0QW1NbkwzZy82NDA?x-oss-process=image/format,png

通过抓包文件,我们可以看到,熟悉的Rtmp Header + Rtmp Body的组织结构,Body中打包的是经过压缩的视频数据。Body中打包视频数据的方式也与音频类似。首先用一个字节表示视频数据的header,之后是压缩后的视频数据(压缩后的数据是使用FLV的标准进行封装的)。

我们来看一下videoData中的header部分的组织结构:

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EUnRRM2tNRDZhYVlMajFqd2lhWXhFbDZwekUwMkdxSWpsRlJJWUNrSUhmMnBhMnk1cEZDU1hJaWFGaWFMUG9jRTVuMjhmaWJUVVQ3R3ZVUmcvNjQw?x-oss-process=image/format,png

相比音频比较简单,1个字节,高4位表示视频帧类型,低4位表示codecID。

1)帧类型

表示该帧视频是关键帧还是非关键帧。可选值如下:

这么多值,当前主要用的无非就是1和2,即H264的关键帧和非关键帧,其他类型当下几乎见不到了。

2)codecID

表示该帧的数据编码codecID。可选值如下:

对于codecID,其实我们主要关注AVC即可,它代表的是H264编码。

3)例子

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9rYVk0SkcxdE9EUnRRM2tNRDZhYVlMajFqd2lhWXhFbDZhNVZOSFhUSVNVQUVEVzh4RGljRVNSTEtpYU1ZbFNBVmtlekJDWGliM09GdmxCOEE5eEZydnRzemcvNjQw?x-oss-process=image/format,png

可以看出videoData中Body中,第一个字节为0x17,二进制为:0001 0111。所以type=0001=1,codec_id=0111=7,所以表示该视频数据采用H264编码,该帧是关键帧。

在头信息之后,就是具体的压缩后的视频编码数据,不过基于FLV的格式对视频数据做了封装,这里就不展开了。