RTMP协议封装H264和H265协议详解
RTMP协议封装H264和H265协议详解
文章目录
- RTMP协议封装H264和H265协议详解
- 1 RTMP和FLV
- 2 RTMP协议封装H264视频流
- 2.1 RTMP发送AVC sequence header
- 2.2 RTMP发送AVCC视频帧数据‘
- 3 RTMP协议封装H265视频流
1 RTMP和FLV
有关RTMP和FLV格式详细介绍可查看如下文章:
https://www.cnblogs.com/ssyfj/p/14684500.html
前文所述,RTMP传输音视频消息时,其RTMP负载采用的时FLV的封装格式,这个说法有点不太准确,RTMP音视频消息负载并不是完整的flv封装,其只是采用了FLV tag body的封装格式,这里为什么不采用完整的flv格式封装呢? 这是因为RTMP header中携带的信息及RTMP推拉流交互中的消息的传递,已经能够完全覆盖FLV头字段及tag头字段所携带的信息,本周最小数据的原则,这里只保留了flv的 video/audio tag body格式,有关Video tag和Audio tag封装格式,可查阅规范《video_file_format_spec_v10.pdf》,规范获取方式:
注公众号壹零仓,发送RTMP,获取规范文档
本文主要介绍RTMP发送H264和H265视频时,其RTMP视频消息的格式介绍及抓包分析。
2 RTMP协议封装H264视频流
从《流媒体之RTMP详解》这篇文章中我们详细介绍了RTMP推流和拉流的流程,这里就不做介绍,这里只介绍RTMP视频消息的格式,其他类型消息及交互过程可查阅此篇文章。
RTMP 视频消息与其他格式的消息一样,由消息头和消息体组成,根据前文介绍的消息分块传输的方式,拆分消息时,只把消息体拆分为多个chunk data,消息头融合进chunk header中,由chunk header + chunk data组成,很多文章直接把其称为RTMP Header和RTMP Body,wireshark中就这样标注。
chunk header中Chunk stream ID 是用来区分消息信道的,因为 RTMP 协议,所有的通信都是通过同一个 TCP 来完成的,因此所有类型的通信信道需要由 Chunk stream ID 来进行区分,从而判断当前收到的消息所属的信道类型,此是由用户定义的,Adobe 建议采用如下的分类:
其中obs推流、ffmpeg推流都有自己的定义方式,与这个略有不同,CSID再解析式可只作为一路流的通道,由Message Type来标识音视频,消息类型定义如下图所示:
这里可以看出视频消息的消息类型为9,当消息类型为9时,表示其消息体为video tag body(Video Data)封装格式的视频数据,有关Video Data的封装格式如下图所示(video_file_format_spec_v10 flv/f4v规范):
- 帧类型(frametype):占高4位,定义视频的帧类型
- 编码类型(CodecId):占低四位,定义了视频的编码格式,H264为7,videodata采用AVCVIDEOPACKET格式
- 视频数据(videoData):根据编码类型选择对应的视频数据封装格式,这里介绍H264,选择AVCVIDEOPACKET格式
AVCVIDEOPACKET格式如下图所示:
- AVC包类型(AVCPacketType):0表示为AVCC的序列头,这里视频打包格式不是我们常见的Annex B,而是AVCC方式,H264采用AVCC封包时,解码需要AVCC序列头,客户端解码必须接收到此序列头包才会解码;1表示H264的nalu,此包为H264数据包,与Annex B相比去除了nalu起始码00000001,增加了四个字节的nalu长度
- Comosition time offset:组合帧时间便宜,一般没啥用,直接赋值为0
- 视频数据(Data):根据AVC包类型,封装相应的数据,AVCPacketType=0时按照AVCC序列头格式封装,为1时按照nalu封装。
我的文章《fmp4打包H264详解》中详细介绍了AVCC H264的封装格式,RTMP发送视频数据时,客户端接收到AVCC 序列头之后,才能初始化解码器,进行后续nalu帧的解码操作,这里为了防止第一包数据丢失,一般服务器会在每一个IDR帧之前,都发送一包AVC sequence header,保证客户端能够在极端情况下,具备持续解码播放的能力,这里从RTMP发送AVC sequence header、AVCC Nalu来详细介绍封装格式。
2.1 RTMP发送AVC sequence header
RTMP发送AVC sequence header,其Video data封包方式(设包为buf数组),第一个字节为buf[0]=0x17=0B00010111,其frametype为关键帧,所以高四位为1,编码类型为H264,所以低四位为7,其视频数据采用AVCVIDEOPACKET格式,AVCPacketType为AVC序列头,所以buf[1]=0,buf[2,3,4]={0,0,0},此时其Data的格式为AVCDecoderConfigurationRecord(就是AVC sequence header),AVC sequence header格式如下
版本号固定为1,因此buf[5]=1,后面三个字节表示编码规格、编码兼容性和编码等级,从SPS中即可获取,所以buf[6]=SPS[1],buf[7=SPS[2],buf[8]=SPS[3],lengthSizeMinusOne表示用多少字节来表示nalu size,一般默认为3,其值+1,表示nalu要使用4个字节来表示长度,buf[9]= 0xFC|0x3=0xFF,下一个字节表示SPS个数,H264一般SPS只有一个,因此buf[10]=E0|01=E1,接下来就是SPS size和SPS data,SPS size站2个字节,buf[11,12,13,14]=SPS size(大端模式),后面直接为SPS的数据,这里注意要去掉起始码之后的数据,假设去掉起始码之后SPS为24,则buf[11-12]=0x0018,buf[13-26]= SPS data,下一个字节为PPS个数,一般为1,buf[27]=1,之后为PPS Size和PPS Data,这里假设PPS Size=4,则buf[28-29]=0x04,buf[30-33]=PPS Data,至此RTMP传输的起始帧AVC sequence header组装完毕,此帧可每次随IDR帧重复发送
2.2 RTMP发送AVCC视频帧数据‘
前文介绍了RTMP发送AVC序列帧方式,真正的视频帧是如何发送的呢?真正的视频帧发送很简单,如果为I帧,buf[0]=0x17,表示关键帧,H264编码;视频帧AVCPacketType类型为AVC Nalu,所以buf[1]=1,buf[2,3,4]={0,0,0},此时其Data的格式为AVCC Nalu封装方式,即是4字节nalu大小+nalu数据(去掉起始码),所以buf[5-8]=nalu size,buf[9-n]= nalu data,至此I帧的RTMP 负载就组合完了;P帧与I帧就第一个字节不同,P帧不是关键帧,因此frametype=2,buf[0]=0x27,其他组合方式一样,这里不做介绍。
3 RTMP协议封装H265视频流
RTMP协议中并没有介绍H265相关规范,可采用CDN联盟的HEVC扩展标准,将HEVC的VideoTagHeader定义为12,详见下图:
当HEVC编码时,CodecID=12,视频数据封装方式采用HEVC封装采用HVCC的封装格式,与AVCC类似,其无起始码,前面四个字节表示nalu的size大小,其客户端解码需要首先接收到HEVC的序列头,序列头格式如下:
格式中定义相关字段的值,可以直接从HEVC的SPS序列帧中解析得到,按照此格式组合成HEVC的序列头,其buf[0]=0x1C,表示关键帧,编码格式为HEVC,buf[1]=0表示HEVC的序列帧,buf[2-4]=0x000000,buf[5]=1,之后的编码信息赋值按照从H265的SPS中解析出的值赋值即可,其中numOfArrays表示后面数组的个数,一般为0x03,表示包含VPS/SPS/PPS,后面数组的封装方式示意如下(《ISO-14496-15 AVC file format》中有详细说明):
// The CodecPrivate syntax shall follow the
// syntax of HEVCDecoderConfigurationRecord
// defined in ISO/IEC 14496-15.
//
// The number zero (0) shall be written to
// the configurationVersion variable until
// official finalization of 14496-15, 3rd ed.
//
// After its finalization, this field and the
// following CodecPrivate structure shall
// follow the definition of the
// HEVCDecoderConfigurationRecord in 14496-15.unsigned int(8) configurationVersion;
unsigned int(2) general_profile_space;
unsigned int(1) general_tier_flag;
unsigned int(5) general_profile_idc;
unsigned int(32) general_profile_compatibility_flags;
unsigned int(48) general_constraint_indicator_flags;
unsigned int(8) general_level_idc;
bit(4) reserved = ‘1111’b;
unsigned int(12) min_spatial_segmentation_idc;
bit(6) reserved = ‘111111’b;
unsigned int(2) parallelismType;
bit(6) reserved = ‘111111’b;
unsigned int(2) chromaFormat;
bit(5) reserved = ‘11111’b;
unsigned int(3) bitDepthLumaMinus8;
bit(5) reserved = ‘11111’b;
unsigned int(3) bitDepthChromaMinus8;
bit(16) avgFrameRate;
bit(2) constantFrameRate;
bit(3) numTemporalLayers;
bit(1) temporalIdNested;
unsigned int(2) lengthSizeMinusOne;
unsigned int(8) numOfArrays;
for (j=0; j < numOfArrays; j++) {bit(1) array_completeness;unsigned int(1) reserved = 0;unsigned int(6) NAL_unit_type;unsigned int(16) numNalus;for (i=0; i< numNalus; i++) {unsigned int(16) nalUnitLength;bit(8*nalUnitLength) nalUnit;}
}
详细解释如下:
bits | 描述 | 备注 |
---|---|---|
1 | array_completeness | 默认0 |
1 | reserved | 默认0 |
6 | NAL_unit_type | 帧类型 |
16 | numNalus | 此种类型的帧个数,一般为1,如果大于1,下面进入循环 |
16 | nalUnitLength | 2字节表示附加帧(VPS/SPS/PPS)的长度 |
N | NALU data | 附加帧(VPS/SPS/PPS)的数据 |
一般情况下numOfArrays=3,第一个数组为VPS相关数据,第二个数组为SPS,第三个数组为PPS
Hevc视频帧的封装式与H264类似,当为I帧时,buf[0]=0x1C,表示关键帧,H265编码;视频帧类型为HEVCNalu,所以buf[1]=1,buf[2,3,4]={0,0,0},此时其Data的格式为HEVC Nalu封装方式,即是4字节nalu大小+nalu数据(去掉起始码,需要去掉转移字节),所以buf[5-8]=nalu size,buf[9-n]= nalu data,至此I帧的RTMP 负载就组合完了;P帧与I帧就第一个字节不同,P帧不是关键帧,因此frametype=2,buf[0]=0x2C,其他组合方式一样,这里不做介绍
RTMP协议封装H264和H265协议详解相关推荐
- rtmp协议封装h264与h265打包flv发送
/*** 发送视频的sps和pps.vps信息** @param pps 存储视频的pps信息* @param pps_len 视频的pps信息长度* @param sps 存储视频的pps信息* @ ...
- RTP协议封装音视频媒体数据详解
RTP协议对媒体数据(包括音频和视频)的封装是由指定的的协议文档规定. 1. RTP封装H.264视频编码数据 1.1 H.264 基本流的结构 H.264 的基本流(elementary strea ...
- 趣谈网络协议-第二模块-底层网络知识详解:2最重要的传输层
趣谈网络协议-第二模块-底层网络知识详解:2最重要的传输层 1:第10讲 | UDP协议:因性善而简单,难免碰到"城会玩" TCP 和 UDP 有哪些区别? UDP 包头是什么样的 ...
- 趣谈网络协议-第二模块-底层网络知识详解:4陌生的数据中心2CDN和数据中心
趣谈网络协议-第二模块-底层网络知识详解:4陌生的数据中心2CDN和数据中心 1:CDN:你去小卖部取过快递么? 使用"中间仓库"来优化 网络中的"就近配送" ...
- RTP协议封装H264/H265/AAC
<RTSP实时音视频传输介绍> 目录 一.前言 二.RTP基本格式介绍 1.RTP 固定头 2.RTP 扩展头 3.RTP 载荷 三.RTP封装H264 1.封装包类型 四.RTP封装H2 ...
- python鸭制作类代码_Python实现多态、协议和鸭子类型的代码详解
多态 问起面向对象的三大特性,几乎每个人都能对答如流:封装.继承.多态.今天我们就要来说一说 Python 中的多态. 所谓多态:就是指一个类实例的相同方法在不同情形有不同表现形式.多态机制使具有不同 ...
- Linux的远程桌面管理,密钥登陆,SSH协议,四层防御系统实验详解
Linux的远程桌面管理,密钥登陆,SSH协议,四层防御系统 一.引子 别看上面写了这么多内容,其实都是串起来的,就是看下通过SSH(Secure Shell)协议远程连接到底要经过些什么流程,有什么 ...
- tcpdump抓包ftp协议_tcpdump抓包使用方法详解
tcpdump抓包分析详解 [root@linux ~]#tcpdump [-nn] [-i 接口] [-w 储存档名] [-c 次数] [-Ae][-qX] [-r 档案] [所欲撷取的数据内容] ...
- TCP协议:三次握手过程详解
本文通过图来梳理TCP-IP协议相关知识.TCP通信过程包括三个步骤:建立TCP连接通道,传输数据,断开TCP连接通道.如图1所示,给出了TCP通信过程的示意图. 上图主要包括三部分:建立连接.传输数 ...
最新文章
- Ubuntu root 密码 sudo passwd
- 计算机网络第七版(谢希仁著)课后习题答案
- 【牛客 - 301哈尔滨理工大学软件与微电子学院第八届程序设计竞赛同步赛(高年级 )】小乐乐和25(模拟,技巧)
- Windows DDK要点指南
- EMC测量的常用计量单位分贝(dB)及其换算
- 图神经网络(GNN)教程 – 用 PyTorch 和 PyTorch Geometric 实现 Graph Neural Networks
- 客户端主动断开连接_Go实现客户端和服务器抓包分析TCP三次握手和断开操作
- unity 变量的编译
- 基于《知网》的词汇语义相似度计算以及复现
- kafka_2.12-3.2.0安装包快速下载地址分享
- 使用福禄克CFP光纤测试仪进行Tier 1和Tier 2光纤测试
- 天使投资人杨宁:百度轻应用让移动时代很多不可能成为可能
- 木讷的程序员需要知道的事情 (二)
- Linux Vmware CentOS 制作yum本地资源库和局域网资源库
- ubuntu介绍以及使用
- C# asp.net 连接 Sql Server数据库 Timeout expired. 错误,怎么办?
- “数说故事——香港城市大学AI联合实验室”筹备会议今日召开
- linux设备驱动那点事儿之SD卡驱动理论篇
- seo (百度百科 仅截取小部分)
- 笨办法学Python3——习题33(巩固练习)
热门文章
- html制作洋葱皮,洋葱皮作用做漂染复活节彩蛋教程
- CentOS7 DNS配置一条龙全套服务
- 安卓设备逐步升级Android 9,游戏产品该如何做适配?
- 在 Solidity 中 ++i 为什么比 i++ 更省 Gas?
- 12[红+绿+蓝+Alpha]
- 2022最新MN梦奈宝塔主机系统V1.5版本+UI不错
- Excel表格转换为布尔表
- android拍照并剪辑
- AdB android 投屏 usb,QtScrcpy: Android实时投屏软件,此应用程序提供USB(或通过TCP/IP)连接的Android设备的显示和控制。它不需要任何root访问权限...
- Win系统 - 教你解决打印机无法安装驱动程序的问题