写点什么

如何实现 H.264 的实时传输?

用户头像
拍乐云Pano
关注
发布于: 2021 年 08 月 12 日
如何实现H.264的实时传输?

实时视频系统中的媒体传输,绝大多数都会采用 RTP(实时传输协议)标准。H.264 视频作为当前应用最广泛的视频编码标准,其传输协议也会首选 RTP 标准。在设计实现 H.264 的实时传输时,H.264 协议基于 RTP 的打包和解包定义于 IETF 标准-RFC6184,RTC 系统需要遵循这个标准来设计打包和解包处理模块。在通信理论中,这个过程可以被认为是基于传输的信道编码。本篇技术文章带你了解 H.264 在 RTP 中的基本格式和技术实践。


#01 基本格式


使用 RTP 对 H.264 打包和解包需要遵循 IETF 标准 RFC6184, 我们先来了解一下 H.264 在 RTP 中的封包协议。01H.264 的 RTP 报头



图 1 RTP 报头


对于 H.264 的 RTP 负载格式而言,RTP 报头的格式和 RFC 3550 里面的定义是一致的,不过有一些字段需要特别说明一下。标记位 (M):1 位对 RTP 时间戳所对应访问单元的最后一个数据包来设置标记位,符合视频中 M 位的正常使用格式,以允许有效的播放缓冲处理。解码器可以使用这个位作为访问单元最后一个数据包的早期指示,但是不能完全依赖这个属性。负载类型 (PT):7 位没有特别指定的负载类型,需要通过协商来确定。序列号(SN):16 位根据 RFC 3550 设置和使用。对于单 NAL 单元和非交错打包模式,序列号用于确定 NAL 单元的解码顺序。时间戳:32 位 RTP 时间戳设置为视频内容的采样时间戳。必须使用 90 kHz 时钟频率。02H.264 的 RTP 负载类型


H.264 的 RTP 负载可分为三大类,类型如下:


单个 NAL 单元数据包:此类 RTP 负载中仅包含单个 NAL 单元。负载报头类型编号等于原始 NAL 单元类型,即从 1 到 23 的范围值,详见 H.264 规范。


聚合数据包:此类型用于聚合多个 NAL 单元成为单个 RTP 负载。这类数据包有四个细分版本:单时间聚合包 A (STAP-A)、单时间聚合包 B (STAP-B)、16 位偏移多时间聚合包 (MTAP16) 和 24 位偏移多时间聚合包 (MTAP24)。负载类型编号分配给 STAP-A、STAP-B、MTAP16 和 MTAP24 的值分别为 24、25、26 和 27。


分片单元:用于将单个 NAL 单元分片到多个 RTP 数据包。存在两个版本:FU-A 和 FU-B,负载类型编号分别为 28 和 29。



表 1 H.264 负载类型 03H.264 的 RTP 打包模式


H.264 的 RTP 打包模式有三种:单 NAL 单元模式


所有的接收端都必须支持这种模式,主要应用于兼容低时延应用中的硬件设备。只有单 NAL 单元数据包可以在这种模式下使用。


非交错模式


建议接收端去支持这种模式,主要应用于低时延应用。只有单 NAL 单元、STAP-A 和 FU-A 数据包可以在这种模式下使用。


交错模式


有需求的接收端可以去支持这种模式,主要应用于非低延时应用。STAP-B、两种 MTAP、FU-A 和 FU-B 数据包可以在这种模式下使用。



表 2 H.264 打包模式允许的负载类型单 NAL 单元和非交错模式中,NAL 单元必须以 NAL 单元解码顺序传输,这两种模式更适合低延时需求的交互系统。


交错模式中 NAL 单元的传输顺序和解码顺序可以是不一致的,导致接收端的解包过程中需要按照解码顺序重新排序,引入更多的时延,因此并不适合需要低时延的交互系统。


04H.264 的 RTP 负载报头



图 2 H.264 的 RTP 负载报头 H.264 的 RTP 负载报头位于负载的第 1 个字节,分成三个字段:


F:1 位 forbidden_zero_bit。值为 0 表示 NAL 单元类型字节和负载不应包含位错误或其他语法违规。值为 1 表示 NAL 单元类型字节和负载可能包含位错误或其他语法违规。NRI:2 位 nal_ref_idc。00 值和非零值的语义与 H.264 规范保持不变。值 00 表示 NAL 单元的内容不是用于重建图片间预测的参考图片,这样的 NAL 单元可以被丢弃并不会导致参考图片的不完整。值大于 00 表示需要对 NAL 单元进行解码以保持参考图片的完整性。类型:5 位负载类型,包括表 1 里面列举的所有类型。05H.264 的 RTP 负载格式


因为只有单 NAL 单元模式和非交错模式打包模式更适合应用于低时延交互系统中,而这两种打包模式所涉及的只有单 NAL 数据包、单时间聚合包 A(STAP-A)和分片单元 A(FU-A)三种 RTP 负载,所以在这里只对这三种负载格式做个简单的介绍。


单 NAL 数据包



图 3 单 NAL 数据包负载格式单 NAL 数据包就是将原始的 NAL 单元直接放置到 RTP 的负载中,NAL 单元头就是作为单 NAL 数据包的负载类型。


单时间聚合包 A(STAP-A)



图 4 聚合数据包负载格式聚合数据包的负载中包含一个或者多个聚合单元。一个聚合包可以携带尽可能多的聚合单元;不过聚合数据包中的总数据量应该选择合适大小,以便生成的 IP 数据包小于 MTU 大小。聚合数据包负载报头中的 NRI 字段的值必须是所有聚合 NAL 单元中最大值。



图 5 单时间聚合单元格式 STAP-A 数据包中,每个聚合单元的 NAL 都应该是共享相同的 NALU 时间。负载的首字节是 STAP-A 负载报头,每个聚合单元是由两字节的 NAL 单元尺寸字段和原始 NAL 单元组成。如果 STAP-A 数据包中包含两个聚合单元,负载格式如下图:



图 6 包含两个聚合单元的 STAP-A 数据包示例分片单元 A(FU-A)



图 7 FU-A 数据包负载格式 FU-A 数据包的负载包含 1 字节的分片单元标识(负载报头)、1 字节的分片单元报头和分片单元负载。分片单元负载报头中的 NRI 字段的值等同于被分片 NAL 单元的值。分片单元报头的格式如下:



图 8 分片单元报头 S: 1 位起始位。当设置为 1 时,指示一个分片 NAL 单元的开始。当 FU 负载不是分片 NAL 单元的开始片段,设置起始位为 0。E: 1 位结束位。当设置为 1 时,指示一个分片 NAL 单元的结束。当 FU 负载不是分片 NAL 单元的最后一个片段,设置结束位为 0 。R: 1 位保留位。必须等于 0,并且必须被接收者忽略。


类型:5 位被分片的原始 NAL 单元类型(1 - 23)。


#02 实践分享


RTC 系统中的视频处理的结构大致如下图,RTP 打包解包是视频编解码和传输之间的桥梁。



图 9 视频流工作流程


01H.264 打包


H.264 的打包的基本流程大致如下:


输入 H.264 NAL,判决当前的 H.264 NAL 的打包格式,可以选择单 NAL 单元包格式、STAP-A 包格式,或者是 FU-A 格式。MTAP 格式一般不在实时系统中使用,考量的重点在于兼顾打包效率和传输效率。Single-NAL-Unit 打包比较简单,一个 NAL 封装为一个 RTP 包。STAP-A 在 NAL 包比较小的时候采用,多个相同时间戳的 NAL 包被打到一个 RTP 包。FU 在 NAL 包比较大的时候采用,限制 RTP 包的大小小于 MTU。一个 NAL 包被拆成多个碎片(Fragment), 碎片被打成 RTP 包。


02H.264 解包


在此只对三种打包模式下的解包过程做一个大致的介绍。


单 NAL 单元和非交错模式接收端包括一个接收缓冲器来补偿传输延迟和抖动。接收端将传入的数据包按照接收顺序存储到接收缓冲器中。数据包按 RTP 序列号的顺序被解包。如果解包的数据包是单个 NAL 单元包,包中包含的 NAL 单元直接传递给解码器。如果解包的数据包是 STAP-A,则包含在数据包中的 NAL 单元按照它们封装在数据包中的顺序被传递给解码器。对于所有 FU-A 包含单个 NAL 单元片段的数据包,解包的片段按其发送顺序恢复出 NAL 单元,然后传递给解码器。交错模式交错模式的解包规则一般是从传输顺序到解码顺序来重新排序 NAL 单元。在实时系统中应用比较少见,具体过程在此就不展开了。参考文献 1、RFC 3550 – RTP: A Transport Protocol for Real-time Application2、RFC 6184 – RTP Payload Format for H.264 Video

用户头像

拍乐云Pano

关注

Be Sharp,be simple 2020.06.28 加入

我们是一家由顶级音视频团队构建的实时通信Paas云服务公司,在音视频领域拥有超过二十年的技术积累。 我们通过提供极简、稳定和安全的SDK服务,让你的应用轻松实现音视频通话、互动白板、互动直播等能力。

评论

发布
暂无评论
如何实现H.264的实时传输?