从零开始精通RTSP之传输H265视频流

2024-05-04 11:36

本文主要是介绍从零开始精通RTSP之传输H265视频流,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概述

        在上一篇文章中,我们详细介绍了使用RTP传输H264视频流的打包方法。接下来,我们继续介绍RTP传输H265视频流的打包方法。H265,正式名称为高效视频编码,英文全称为High Efficiency Video Coding(HEVC),是国际电信联盟视频编码专家组和国际标准化组织/国际电工委员会动态图像专家组共同开发的下一代视频编码标准。作为H264/MPEG-4 AVC的继任者,H265旨在提供更高的视频压缩效率,能够在保持相同视频质量的前提下大幅度减少视频文件的大小,或者在相同的比特率下提供显著提升的图像质量。当使用RTP传输H265视频流时,也需要遵循一定的打包和传输规则。

 

H265 NALU

        H265 NALU是H265编码视频流的基本数据单元,用于承载编码后的视频数据,并提供网络传输的抽象。NALU的设计旨在使视频编码与底层网络传输协议分离,使得H265编码的视频内容能够适应各种网络环境和应用需求。

        每个NALU都以一个固定长度的NAL Unit Header开始,NAL Unit Header占用两个字节,通常包含以下几个字段。

        Forbidden Zero Bit (F): 占1位,这一位必须为0。如果为1,则表示语法错误,整个NALU将被丢弃。

        NALU Type (Type): 占6位,定义了NALU所携带数据的类型。总共有64种可能的类型(范围是0-63),其中0-31是VCL(视频编码层)NAL单元,用于携带编码的视频数据;而32-63是非VCL NAL单元,用于携带控制信息或元数据。不同的NALU Type对应着不同的编码数据或控制信息,比如:P帧和B帧为1,IDR帧为19,VPS(Video Parameter Set)为32,SPS(Sequence Parameter Set)为33,PPS(Picture Parameter Set)为34,SEI(Supplemental Enhancement Information)为39等。

        LayerId: 占6位,用于表示NAL所在的Access Unit所属的层,是为了HEVC的继续扩展而设置的。在当前的HEVC标准中,这个字段通常被设置为0,但在未来的扩展中可能会用到。

        TID: 占3位,用于指定NAL单元的时间标识符,一般取值为1。它帮助解码器确定NAL单元在视频流中的时间位置,从而正确解码和播放视频。

        紧跟在NAL Unit Header之后的是NAL Unit Payload,包含了编码视频流的核心数据和辅助信息,是视频解码和播放的基础。在实际的网络传输和存储中,NALU通常还需要进一步封装成以下格式中的一种。

        Annex B格式:在Annex B格式中,每个NALU之前添加一个Start Code Prefix,可以是0x000001或0x00000001,用于标识NALU的起始位置。相邻NALU之间,以此方式明确分隔。

        AVCC (Advanced Video Coding Container) 格式:AVCC格式常见于MP4容器中,NALU不再使用Start Code Prefix,而是通过Length字段来标识每个NALU的长度。SPS和PPS等参数以NALU形式封装,并在MP4文件的hvcC盒(Box)中以字节串的形式存储。

 

封装方法

        H265 NALU在封装到 RTP包中时,需要遵循一定的规则和流程,以确保数据能够被正确地传输、接收和解码。根据NALU的大小和传输需求,可以选择以下三种常见的封装方法。

        1、单NALU封装。对于小型的NALU,(比如:P帧、B帧),可以直接将整个NALU放入一个RTP包的Payload中,无需额外处理。此时,RTP包的结构如下。

+-----------------------------+
| RTP Header (12 Byte)        |
| NALU Header (2 Byte)        |
| NALU Data ...               |
+-----------------------------+

        2、FU-A分包。对于大型NALU(比如:某些关键帧),如果其大小超过了RTP包的最大有效载荷MTU,可以使用Fragmentation Unit A方式进行分片。原始NALU会被拆分成多个片段,每个片段作为一个独立的RTP包发送。此时,RTP包的结构如下。

+-----------------------------+
| RTP Header (12 Byte)        |
| FU Indicator (2 Byte)       |
| FU Header (1 Byte)          |
| Fragmented NALU Data ...    |
+-----------------------------+

        可以看到,FU-A分包在12个字节的RTP Header后,有三个字节的分包头,分别为:FU Indicator和FU Header。

        FU Indicator占用两个字节,由以下部分组成。

        F (1 bit): 禁止位,与NALU Header的F位一致。

        Type (6 bits): 分包类型,二进制固定为110001(对应十进制的49),表示FU-A类型。

        LayerId (6 bits): 与NALU Header的LayerId一致。

        TID (3 bits): 与NALU Header的TID一致。

        FU Header占用一个字节,由以下部分组成。

        S (1 bit): 分包起始位。如果该FU是原始NALU的第一个片段,S设为1。否则,设为0。

        E (1 bit): 分包结束位。如果该FU是原始NALU的最后一个片段,E设为1。否则,设为0。

        Type (6 bits): 原始NALU类型,与NALU Header的Type一致,用于在重组时恢复原始NALU Header。

        3、STAP-A聚合

        对于多个小尺寸NALU,如果它们具有相近的解码时间戳,且合并后总尺寸仍小于MTU,可以使用Single-Time Aggregation Packet A方式将多个NALU合并到一个RTP包中。此时,RTP包的结构如下。

+-----------------------------+
| RTP Header (12 Byte)        |
| STAP-A Header (2 Byte)      |
| NALU Payload1 Size (2 Byte) |
| NALU Payload1               |
| NALU Payload2 Size (2 Byte) |
| NALU Payload2               |
| ...                         |
+-----------------------------+

        STAP-A Header紧跟在RTP Header之后,占用两个字节(与NALU Header结构类似),用于标识这是一个STAP-A包,其Type值固定为48。在每个聚合的NALU前,会有一个长度字段(通常为2个字节),表明后续NALU数据的长度。所有聚合在STAP-A包中的NALU都共享相同的时间戳,这是STAP-A包的一个重要特征。

        注意:无论采用上面的哪种封装方法,NALU Data或NALU Payload中都不包括Annex B格式中的起始码(比如:0x000001或0x00000001),因为RTP包已经提供了足够的信息来标识NALU的边界。

 

FU-A分包及重组

        在服务端,FU-A分包的大致步骤如下。

        1、原NALU切割: 大型NALU被拆分成多个连续的片段。切割位置通常选择在NALU内部的编码块边界,以避免破坏编码结构。

        2、片段标识: 每个片段(FU)在RTP Payload中添加一个FU Header,用于标识该片段属于哪个原始NALU,以及其在原始NALU中的位置。

        3、独立传输: 每个FU作为一个独立的RTP包发送,每个RTP包的Payload仅包含一个FU。

        客户端接收到FU-A分包的RTP包后,根据RTP Header解析出Payload Type,确认为H265 FU-A数据后,按照以下步骤处理。

        1、FU分包头解析: 提取FU Indicator和FU Header中的信息。

        2、片段重组: 将收到的FU片段按照RTP包的Sequence Number顺序重新组合,将所有片段的Fragmented NALU Data拼接在一起。

        3、NALU还原: 在重组后的NALU数据前添加原始NALU Header(根据FU分包头中的信息恢复),形成完整的NALU结构。

        4、解码处理: 将还原后的完整NALU提交给H265解码器进行解码。

        使用FU-A封装方法进行分包和重组时,有以下几点需要特别注意。

        1、顺序传输: FU-A分包的RTP包必须严格按照分包顺序发送和接收,以确保正确重组。

        2、丢包处理: 如果中间某个FU片段丢失,可能导致原始NALU无法正确重组。接收端可以根据RTP包的序列号和确认机制检测丢包,并尝试通过重传请求(比如:RTCP的NACK)恢复丢失片段。

        3、时间戳同步: 所有FU片段共享同一个解码时间戳,确保解码时的正确同步。

 

 

这篇关于从零开始精通RTSP之传输H265视频流的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/959109

相关文章

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

MySQL入门到精通

一、创建数据库 CREATE DATABASE 数据库名称; 如果数据库存在,则会提示报错。 二、选择数据库 USE 数据库名称; 三、创建数据表 CREATE TABLE 数据表名称; 四、MySQL数据类型 MySQL支持多种类型,大致可以分为三类:数值、日期/时间和字符串类型 4.1 数值类型 数值类型 类型大小用途INT4Bytes整数值FLOAT4By

生信代码入门:从零开始掌握生物信息学编程技能

少走弯路,高效分析;了解生信云,访问 【生信圆桌x生信专用云服务器】 : www.tebteb.cc 介绍 生物信息学是一个高度跨学科的领域,结合了生物学、计算机科学和统计学。随着高通量测序技术的发展,海量的生物数据需要通过编程来进行处理和分析。因此,掌握生信编程技能,成为每一个生物信息学研究者的必备能力。 生信代码入门,旨在帮助初学者从零开始学习生物信息学中的编程基础。通过学习常用

BIRT--商业智能和报表工具,从零开始

1.简介 BIRT (Business Intelligence and Reporting Tools), 是为 Web 应用程序开发的基于 Eclipse 的开源报表系统,特别之处在于它是以 Java 和 JavaEE 为基础。BIRT 有两个主要组件:基于 Eclipse 的报表设计器,以及部署到应用服务器上的运行时组件。 2.下载 官网下载网址:http://download.ec

【Python篇】PyQt5 超详细教程——由入门到精通(终篇)

文章目录 PyQt5超详细教程前言第9部分:菜单栏、工具栏与状态栏9.1 什么是菜单栏、工具栏和状态栏9.2 创建一个简单的菜单栏示例 1:创建带有菜单栏的应用程序代码详解: 9.3 创建工具栏示例 2:创建带有工具栏的应用程序代码详解: 9.4 创建状态栏示例 3:创建带有状态栏的应用程序代码详解: 9.5 菜单栏、工具栏与状态栏的结合示例 4:完整的应用程序界面代码详解: 9.6 总结

【Python篇】PyQt5 超详细教程——由入门到精通(中篇二)

文章目录 PyQt5超详细教程前言第7部分:生成图表与数据可视化7.1 matplotlib 与 PyQt5 的结合7.2 在 PyQt5 中嵌入 matplotlib 图表示例 1:嵌入简单的 matplotlib 图表代码详解: 7.3 动态生成图表示例 2:动态更新图表代码详解: 7.4 在应用程序中展示不同类型的图表示例 3:展示不同类型的图表代码详解: 7.5 总结 第8部分:对话

【Python篇】PyQt5 超详细教程——由入门到精通(序篇)

文章目录 PyQt5 超详细入门级教程前言序篇:1-3部分:PyQt5基础与常用控件第1部分:初识 PyQt5 和安装1.1 什么是 PyQt5?1.2 在 PyCharm 中安装 PyQt51.3 在 PyCharm 中编写第一个 PyQt5 应用程序1.4 代码详细解释1.5 在 PyCharm 中运行程序1.6 常见问题排查1.7 总结 第2部分:创建 PyQt5 应用程序与布局管理2

从零开始学习JVM(七)- StringTable字符串常量池

1 概述 String应该是Java使用最多的类吧,很少有Java程序没有使用到String的。在Java中创建对象是一件挺耗费性能的事,而且我们又经常使用相同的String对象,那么创建这些相同的对象不是白白浪费性能吗。所以就有了StringTable这一特殊的存在,StringTable叫做字符串常量池,用于存放字符串常量,这样当我们使用相同的字符串对象时,就可以直接从StringTable

SpringBoot, SpringCloud 入门精通 最简单的教程

Spring Boot特点 1. 创建独立的Spring应用程序 2. 嵌入的Tomcat,无需部署WAR文件 3. 简化Maven配置 4. 自动配置Spring 5. 提供生产就绪型功能,如指标,健康检查和外部配置 6. 绝对没有代码生成和对XML没有要求配置 废话少说上教程: spring boot(1)-简单搭建 Hello World spring boot简单教程(2)-@Spri

从零开始构建大语言模型并进行微调:全面指南

要从0开始搭建并训练一个大语言模型(LLM),涉及到多个步骤和资源,包括理论理解、工具使用、数据准备、模型训练与微调。以下是一个从基础到应用的指南,帮助你理解并逐步实现这一目标。 1. 理解基础概念 在开始搭建大语言模型之前,了解以下基本概念至关重要: 生成式AI:通过大语言模型生成自然语言文本,例如GPT、BERT等。机器学习:通过数据训练模型,使其具备从数据中学习规律的能力。深度学习:机