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协议详解相关推荐

  1. rtmp协议封装h264与h265打包flv发送

    /*** 发送视频的sps和pps.vps信息** @param pps 存储视频的pps信息* @param pps_len 视频的pps信息长度* @param sps 存储视频的pps信息* @ ...

  2. RTP协议封装音视频媒体数据详解

    RTP协议对媒体数据(包括音频和视频)的封装是由指定的的协议文档规定. 1. RTP封装H.264视频编码数据 1.1 H.264 基本流的结构 H.264 的基本流(elementary strea ...

  3. 趣谈网络协议-第二模块-底层网络知识详解:2最重要的传输层

    趣谈网络协议-第二模块-底层网络知识详解:2最重要的传输层 1:第10讲 | UDP协议:因性善而简单,难免碰到"城会玩" TCP 和 UDP 有哪些区别? UDP 包头是什么样的 ...

  4. 趣谈网络协议-第二模块-底层网络知识详解:4陌生的数据中心2CDN和数据中心

    趣谈网络协议-第二模块-底层网络知识详解:4陌生的数据中心2CDN和数据中心 1:CDN:你去小卖部取过快递么? 使用"中间仓库"来优化 网络中的"就近配送" ...

  5. RTP协议封装H264/H265/AAC

    <RTSP实时音视频传输介绍> 目录 一.前言 二.RTP基本格式介绍 1.RTP 固定头 2.RTP 扩展头 3.RTP 载荷 三.RTP封装H264 1.封装包类型 四.RTP封装H2 ...

  6. python鸭制作类代码_Python实现多态、协议和鸭子类型的代码详解

    多态 问起面向对象的三大特性,几乎每个人都能对答如流:封装.继承.多态.今天我们就要来说一说 Python 中的多态. 所谓多态:就是指一个类实例的相同方法在不同情形有不同表现形式.多态机制使具有不同 ...

  7. Linux的远程桌面管理,密钥登陆,SSH协议,四层防御系统实验详解

    Linux的远程桌面管理,密钥登陆,SSH协议,四层防御系统 一.引子 别看上面写了这么多内容,其实都是串起来的,就是看下通过SSH(Secure Shell)协议远程连接到底要经过些什么流程,有什么 ...

  8. tcpdump抓包ftp协议_tcpdump抓包使用方法详解

    tcpdump抓包分析详解 [root@linux ~]#tcpdump [-nn] [-i 接口] [-w 储存档名] [-c 次数] [-Ae][-qX] [-r 档案] [所欲撷取的数据内容] ...

  9. TCP协议:三次握手过程详解

    本文通过图来梳理TCP-IP协议相关知识.TCP通信过程包括三个步骤:建立TCP连接通道,传输数据,断开TCP连接通道.如图1所示,给出了TCP通信过程的示意图. 上图主要包括三部分:建立连接.传输数 ...

最新文章

  1. Ubuntu root 密码 sudo passwd
  2. 计算机网络第七版(谢希仁著)课后习题答案
  3. 【牛客 - 301哈尔滨理工大学软件与微电子学院第八届程序设计竞赛同步赛(高年级 )】小乐乐和25(模拟,技巧)
  4. Windows DDK要点指南
  5. EMC测量的常用计量单位分贝(dB)及其换算
  6. 图神经网络(GNN)教程 – 用 PyTorch 和 PyTorch Geometric 实现 Graph Neural Networks
  7. 客户端主动断开连接_Go实现客户端和服务器抓包分析TCP三次握手和断开操作
  8. unity 变量的编译
  9. 基于《知网》的词汇语义相似度计算以及复现
  10. kafka_2.12-3.2.0安装包快速下载地址分享
  11. 使用福禄克CFP光纤测试仪进行Tier 1和Tier 2光纤测试
  12. 天使投资人杨宁:百度轻应用让移动时代很多不可能成为可能
  13. 木讷的程序员需要知道的事情 (二)
  14. Linux Vmware CentOS 制作yum本地资源库和局域网资源库
  15. ubuntu介绍以及使用
  16. C# asp.net 连接 Sql Server数据库 Timeout expired. 错误,怎么办?
  17. “数说故事——香港城市大学AI联合实验室”筹备会议今日召开
  18. linux设备驱动那点事儿之SD卡驱动理论篇
  19. seo (百度百科 仅截取小部分)
  20. 笨办法学Python3——习题33(巩固练习)

热门文章

  1. html制作洋葱皮,洋葱皮作用做漂染复活节彩蛋教程
  2. CentOS7 DNS配置一条龙全套服务
  3. 安卓设备逐步升级Android 9,游戏产品该如何做适配?
  4. 在 Solidity 中 ++i 为什么比 i++ 更省 Gas?
  5. 12[红+绿+蓝+Alpha]
  6. 2022最新MN梦奈宝塔主机系统V1.5版本+UI不错
  7. Excel表格转换为布尔表
  8. android拍照并剪辑
  9. AdB android 投屏 usb,QtScrcpy: Android实时投屏软件,此应用程序提供USB(或通过TCP/IP)连接的Android设备的显示和控制。它不需要任何root访问权限...
  10. Win系统 - 教你解决打印机无法安装驱动程序的问题