目录
0、概述
本文介绍了视频编码原理、H264编码格式、RTP/RTSP/SDP,适合新手入门,从视频编码到rtsp实时流传输,帮助新手理解。
本人开源了几个关于音视频编解码、重采样的项目,感兴趣的可以关注一下:
1、ffmpeg实现音视频(H264/H265/AAC)封装、编解码pipeline,支持NVIDIA硬编解码。项目地址:
GitHub - BreakingY/FFmpeg-Media-Codec-Pipeline: ffmpeg实现音视频封装、编解码pipelineffmpeg实现音视频封装、编解码pipeline. Contribute to BreakingY/FFmpeg-Media-Codec-Pipeline development by creating an account on GitHub.https://github.com/BreakingY/FFmpeg-Media-Codec-Pipeline
2、x264、x265、openh264、libde265、fdk_aac、G711、libyuv、speexdsp音视频编解码、重采样。项目地址:GitHub - BreakingY/Media-Codec-Resample: x264、x265、openh264、libde265、fdk_aac、G711、libyuv、speexdsp测试程序。x264、x265、openh264、libde265、fdk_aac、G711、libyuv、speexdsp测试程序。 - BreakingY/Media-Codec-Resamplehttps://github.com/BreakingY/Media-Codec-Resample
3、Nvidia视频硬解码、渲染、软/硬编码并写入MP4文件。项目地址:https://github.com/BreakingY/Nvidia-Video-CodecNvidia video hard decoding, rendering, soft/hard encoding, and writing to MP4 file ; Nvidia视频硬解码、渲染、软/硬编码并写入MP4文件 - BreakingY/Nvidia-Video-Codechttps://github.com/BreakingY/Nvidia-Video-Codec
4、英伟达嵌入式设备Jetson Jetpack5.x视频编解码库。项目地址:GitHub - BreakingY/jetpack-dec-enc: Jetson Video Encoding and Decoding ; Jetson Jetpack5.x视频编解码库Jetson Video Encoding and Decoding ; Jetson Jetpack5.x视频编解码库 - BreakingY/jetpack-dec-enchttps://github.com/BreakingY/jetpack-dec-enc
1、视频编码
是指压缩编码。在计算机的世界中,一切都是0 和1 组成的,音视频的数据量庞大,如果按照裸流数据存储的话,那将需要耗费非常大的存储空间,也不利于传送。而音视频中,其实包含了大量0 和1 的重复数据,因此可以通过一定的算法来压缩这些0和1 的数据。特别在视频中,由于画面是逐渐过渡的,因此整个视频中,包含了大量画面/像素的重复,这正好提供了非常大的压缩空间。因此,编码可以大大减小音视频数据的大小,让音视频更容易存储和传送。
那么,未经编码的原始音视频,数据量至底有多大?以一个分辨率1920×1280,帧率30 的视频为例:共:1920×1280=2,073,600(Pixels 像素),每个像素点是24bit;也就是:每幅图片2073600×24=49766400 bit,8 bit(位)=1 byte(字节);所以:49766400bit=6220800byte≈6.22MB。这是一幅1920×1280 图片的原始大小(6.22MB),再乘以帧率30。也就是说:每秒视频的大小是186.6MB,每分钟大约是11GB,一部90 分钟的电影,约是1000GB。
1.1 组织
音视频编解码的国际标准
ITU(国际电信联盟)
ISO/IEC
JVT(Joint Video Team,视频联合工作组)
1)ITU 提出了H.261、H.262、H.263、H.263+、H.263++,这些统称为H.26X 系列,主要应用于实时视频通信领域,如会议电视、可视电话等;
2)ISO/IEC 提出了MPEG1、MPEG2、MPEG4、MPEG7、MPEG21,统称为MPEG系列。
3)ITU 和ISO/IEC 一开始是各自捣鼓,后来,两边成立了一个联合小组,名叫JVT(JointVideo Team,视频联合工作组)。
1.2 视频编码原理
原始视频压缩的目的是去除冗余信息,可以去除的冗余包括:
空间冗余:图像相邻像素之间有较强的相关性
时间冗余:视频序列的相邻图像之间内容相似
编码冗余:不同像素值出现的概率不同
视觉冗余:人的视觉系统对某些细节不敏感
知识冗余:规律性的结构可由先验知识和背景知识得到
视频编码技术优先消除的目标,就是空间冗余和时间冗余。
数据压缩是怎么分类的?
无损压缩(Lossless):
压缩前、解压缩后图像完全一致X=X',压缩比低(2:1~3:1)。典型格式例如:Winzip,JPEG-LS。
有损压缩(Lossy):
压缩前解压缩后图像不一致X≠X',压缩比高(10:1~20:1),利用人的视觉系统的特性。典型格式例如:MPEG-2,H.264/AVC,AVS。
形象的比喻就是把每帧都作为一张图片,采用JPEG 的编码格式对图片进行压缩,这种编码只考虑了一张图片内的冗余信息压缩,如图1,绿色的部分就是当前待编码的区域,灰色就是尚未编码的区域,绿色区域可以根据已经编码的部分进行预测(绿色的左边,下边,左下等)。
编码就是为了压缩。要实现压缩,就要设计各种算法,将视频数据中的冗余信息去除。
举个例子:如果一幅图(1920×1080 分辨率),全是红色的,我有没有必要说2073600次[255,0,0]?我只要说一次[255,0,0],然后再说2073599 次“同上”。
但是帧和帧之间因为时间的相关性,后续开发出了一些比较高级的编码器可以采用帧间编码,简单点说就是通过搜索算法选定了帧上的某些区域,然后通过计算当前帧和前后参考帧的向量差进行编码的一种形式,通过下面两个图2 连续帧我们可以看到,滑雪的同学是向前位移的,但实际上是雪景在向后位移,P 帧通过参考帧(I 或其他P 帧)就可以进行编码了,编码之后的大小非常小,压缩比非常高。
如果一段1 分钟的视频,有十几秒画面是不动的,或者,有80%的图像面积,整个过程都是不变(不动)的。那么,是不是这块存储开销,就可以节约掉了?
运动估计和补偿
我们来通过一个例子看一下。
这有两个帧:
人在动,背景是没有动的。第一帧是I 帧,第二帧是P 帧。两个帧之间的差值,就是如下:
也就是说,图中的部分像素,进行了移动。移动轨迹如下:
这个,就是运动估计和补偿。
视频编码过程如下:
2、色彩空间
这里我们只讲常用到的两种色彩空间。
1)RGB:RGB 的颜色模式应该是我们最熟悉的一种,在现在的电子设备中应用广泛。通过R G B 三种基础色,可以混合出所有的颜色。
2)YUV:这里着重讲一下YUV,这种色彩空间并不是我们熟悉的。这是一种亮度与色度分离的色彩格式。早期的电视都是黑白的,即只有亮度值,即Y。有了彩色电视以后,加入了UV 两种色度,形成现在的YUV,也叫YCbCr。
Y:亮度,就是灰度值。除了表示亮度信号外,还含有较多的绿色通道量;
U:蓝色通道与亮度的差值;
V:红色通道与亮度的差值。
如下图,可以看到Y、V、U 3 个分量的效果差值:
采用YUV 有什么优势呢?
人眼对亮度敏感,对色度不敏感,因此减少部分UV 的数据量,人眼却无法感知出来,这样可以通过压缩UV 的分辨率,在不影响观感的前提下,减小视频的体积。
视频通信系统之所以要采用YUV,而不是RGB,主要是因为RGB 信号不利于压缩。
主流的采样方式有三种
1)YUV4:4:4;YCbcr
2)YUV4:2:2;
3)YUV4:2:0
如何理解帧和场图像?一帧图像包括两场——顶场,底场:
逐行与隔行图像
逐行图像是指:一帧图像的两场在同一时间得到,ttop=tbot。
隔行图像是指:一帧图像的两场在不同时间得到, ttop≠tbot。
3、H264
3.1 基本概念
IPB 帧
I 帧:帧内编码帧(intra picture),采用帧内压缩去掉空间冗余信息。
P 帧:前向预测编码帧(predictive-frame),采用帧间编码(前向运动估计),同时利用空间和时间上的相关性。简单来说,采用运动补偿(motion compensation)算法来去掉冗余信息。参考前面的I 帧或者P 帧。
B 帧:双向预测内插编码帧(bi-directional interpolated prediction frame),既考虑源图像序列前面的已编码帧,又顾及源图像序列后面的已编码帧之间的冗余信息,来压缩传输数据量的编码图像,也称为双向编码帧。参考前面一个的I 帧或者P 帧及其后面的一个P 帧。
IDR 帧(关键帧):在编码解码中为了方便,将GOP 中首个I 帧要和其他I 帧区别开,把第一个I 帧叫IDR,这样方便控制编码和解码流程,所以IDR 帧一定是I 帧,但I 帧不一定是IDR 帧;IDR 帧的作用是立刻刷新,使错误不致传播,从IDR 帧开始算新的序列开始编码。I 帧有被跨帧参考的可能,IDR 不会。I 帧不用参考任何帧,但是之后的P 帧和B 帧是有可能参考这个I 帧之前的帧的
PTS 和DTS
DTS(Decoding Time Stamp)是标识读入内存中bit 流在什么时候开始送入解码器中进行解码。也就是解码顺序的时间戳。
PTS(Presentation Time Stamp)用于度量解码后的视频帧什么时候被显示出来。在没有B 帧的情况下,DTS 和PTS 的输出顺序是一样的,一旦存在B 帧,PTS 和DTS 则会不同。也就是显示顺序的时间戳。
GOP:即Group of picture(图像组),指两个I 帧之间的距离,Reference(参考周期)指两个P 帧之间的距离。一个I 帧所占用的字节数大于一个P 帧,一个P 帧所占用的字节数大于一个B 帧。所以在码率不变的前提下,GOP 值越大,P、B 帧的数量会越多,平均每个I、P、B 帧所占用的字节数就越多,也就更容易获取较好的图像质量;Reference 越大,B 帧的数量越多,同理也更容易获得较好的图像质量。
简而言之:
字节大小:I > P > B
解码顺序:I -> P -> B
“块(Block)”与“宏块(MacroBlock)”
如果总是按照像素来算,数据量会比较大,所以,一般都是把图像切割为不同的“块(Block)”或“宏块(MacroBlock)”,对它们进行计算。一个宏块一般为16 像素×16 像素。
3.2 H264结构
H264 压缩方式
H264 采用的核心算法是帧内压缩和帧间压缩,帧内压缩是生成I 帧的算法,帧间压缩是生成B 帧和P 帧的算法。
VCL 层是对核心算法引擎、块、宏块及片的语法级别的定义,负责有效表示视频数据的内容,最终输出编码完的数据SODB;
NAL 层定义了片级以上的语法级别(如序列参数集参数集和图像参数集,针对网络传输,后面会描述到),负责以网络所要求的恰当方式去格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传输。NAL 层将SODB 打包成RBSP 然后加上NAL 头组成一个NALU 单元,具体NAL 单元的组成也会在后面详细描述。
SODB: 数据比特串,是编码后的原始数据;
RBSP: 原始字节序列载荷,是在原始编码数据后面添加了结尾比特,一个bit“1”和若干个比特“0”,用于字节对齐
NALU 的起始码为0x000001 或0x00000001(起始码包括两种:3 字节(0x000001)和4 字节(0x00000001),起始码用来分割NALU
仿校验字节(0x03):
H264 规定,当检测到0x000000 时,也可以表示当前NALU 的结束。那这样就会产生一个问题,就是如果在NALU 的内部,出现了0x000001 或0x000000时该怎么办?在RBSP 基础上填加了仿校验字节(0x03)它的原因是:需要填加每组NALU 之前的开始码StartCodePrefix,如果该NALU 对应的slice为一帧的开始则用4 位字节表示,0x00000001,否则用3 位字节表示0x000001.为了使NALU 主体中不包括与开始码相冲突的,在编码时,每遇到两个字节连续为0,就插入一个字节的0x03。解码时将0x03 去掉。也称为脱壳操作。
想要完成准确无误视频的解码,除了需要VCL 层编码出来的视频帧数据,同时还需要传输序列参数集和图像参数集等等,所以RBSP 不单纯只保存I/B/P 帧的数据编码信息,还有其他信息也可能出现在里面。SPS、PPS、IDR 和SLICE 是NAL 单元某一类型的数据。
NAL 单元是作为实际视频数据传输的基本单元,NALU 头是用来标识后面RBSP 是什么类型的数据,同时记录RBSP 数据是否会被其他帧参考以及网络传输是否有错误
NAL 头
NAL 单元的头部是由forbidden_bit(1bit),nal_reference_bit(2bits)(优先级),nal_unit_type(5bits)(类型)三个部分组成的,组成如图所示:
1、F(forbiden):禁止位,占用NAL 头的第一个位,当禁止位值为1 时表示语法错误;
2、NRI:参考级别,占用NAL 头的第二到第三个位;值越大,该NAL 越重要。
3、Type:Nal 单元数据类型,也就是标识该NAL 单元的数据类型是哪种,占用NAL 头的第四到第8 个位;
NAL 分为VCL 和非VCL 的NAL 单元。在图中有介绍(图表中DIR 应该为IDR),其中SPS、SEI、PPS 等非VCL 的NAL 参数对解码和显示视频都是很有用的。
参数集(Parameter sets),参数集是携带解码参数的NAL 单元,参数集对于正确解码是非常重要的,在一个有损耗的传输场景中,传输过程中比特列或包可能丢失或损坏,在这种网络环境下,参数集可以通过高质量的服务来发送,比如向前纠错机制或优先级机制。Parameter sets 与其之外的句法元素之间的关系如下图所示:
非VCL 的NAL 数据类型:
1)、SPS(序列参数集):SPS 对如标识符、帧数以及参考帧数目、解码图像尺寸和帧场模式等解码参数进行标识记录。
2)、PPS(图像参数集):PPS 对如熵编码类型、有效参考图像的数目和初始化等解码参数进行标志记录。
3)、SEI(补充增强信息):这部分参数可作为H264 的比特流数据而被传输,每一个SEI信息被封装成一个NAL 单元。SEI 对于解码器来说可能是有用的,但是对于基本的解码过程来说,并不是必须的。
序列参数集(sps)NAL 单元必须在传送所有以此参数集为参考的其他NAL 单元之前传送,不过允许这些NAL 单元中间出现重复的序列参数集NAL 单元。所谓重复的详细解释为:序列参数集NAL 单元都有其专门的标识,如果两个序列参数集NAL 单元的标识相同,就可以认为后一个只不过是前一个的拷贝,而非新的序列参数集。
图像参数集(pps)NAL 单元必须在所有以此参数集为参考的其他NAL 单元之前传送,不过允许这些NAL 单元中间出现重复的图像参数集NAL 单元,这一点与上述的序列参数集NAL 单元是相同
VCL 的NAL 数据类型
1)、头信息块,包括宏块类型,量化参数,运动矢量。这些信息是最重要的,因为离开他们,被的数据块种的码元都无法使用。该数据分块称为A 类数据分块。
2)、帧内编码信息数据块,称为B 类数据分块。它包含帧内编码宏块类型,帧内编码系数。对应的slice 来说,B 类数据分块的可用性依赖于A 类数据分块。和帧间编码信息数据块不通的是,帧内编码信息能防止进一步的偏差,因此比帧间编码信息更重要。
3)、帧间编码信息数据块,称为C 类数据分块。它包含帧间编码宏块类型,帧间编码系数。它通常是slice 种最大的一部分。帧间编码信息数据块是不重要的一部分。它所包含的信息并不提供编解码器之间的同步。C 类数据分块的可用性也依赖于A 类数据分块,但于B类数据分块无关。
以上三种数据块每种分割被单独的存放在一个NAL 单元中,因此可以被单独传输。
H264 的NAL 单元与片,宏之间的联系
1 帧(一幅图像) = 1~N 个片(slice) //也可以说1 到多个片为一个片组
1 个片= 1~N 个宏块(Marcroblock)
1 个宏块= 16X16 的YUV 数据(原始视频采集数据)
同时有几点需要说明一下,这样能便于理解NAL 单元:
(1)、如果不采用FMO(灵活宏块排序) 机制,则一幅图像只有一个片组;
(2)、如果不使用多个片,则一个片组只有一个片;
(3)、如果不采用DP(数据分割)机制,则一个片就是一个NALU,一个NALU 也就是一个片。否则,一个片的组成需要由三个NALU 组成,也就是上面说到的A、B、C 类数据块。
下图是H264视频文件结构,每个NALU用起始码隔开:
4、视频文件格式、视频封装格式
视频格式那么多,MP4/RMVB/MKV/AVI 等,这些视频格式与编码压缩标准mpeg4,H.264.H.265 等有什么关系?下面通过引入下面三个概念来介绍视频压缩知识。分别是:
视频文件格式(简称:文件格式),
视频封装格式(简称:视频格式),
视频编码方式(简称:视频编码)
一,视频文件格式(简称:文件格式):
我们知道Windows 系统中的文件名都有后缀,例如1.doc,2.wps,3.psd 等等。Windows 设置后缀名的目的是让系统中的应用程序来识别并关联这些文件,让相应的文件由相应的应用程序打开。例如你双击1.doc 文件,它会知道让Microsoft Office 去打开,而不会用Photoshop 去打开这个文件。所以常见的视频文件格式如1.avi,2.mpg 这些都叫做视频的文件格式,它由你电脑上安装的视频播放器关联。
二,视频封装格式(简称:视频格式):
AVI,MPEG,VOB 是一种视频封装格式,相当于一种储存视频信息的容器。它是由相应的公司开发出来的。我们可以在自己的电脑上看到的1.avi,2.mpg,3.vob 这些视频文件格式的后缀名即采用相应的视频封装格式的名称。以下集中介绍几种封装格式:
视频数据的封装
封装:就是封装格式,简单来说,就是将已经编码压缩好的视频轨和音频轨按照一定的格式放到一个文件中。
三、视频编码方式
H264就是视频编码格式,用来压缩原始视频的。
5、RTP
5.1 基本概念:
一种数据数据传输协议,RTP 协议实际上是由实时传输协议RTP(Real-time Transport Protocol)和实时传输控制协议RTCP(Real-time Transport Control Protocol)两部分组成。
RTP 协议基于多播或单播网络为用户提供连续媒体数据的实时传输服务;RTCP 协议是RTP 协议的控制部分,用于实时监控数据传输质量,为系统提供拥塞控制和流控制。
由于TCP 需要较多的开销,故不太适合传输实时数据。在流式传输的实现方案中,一般采用RTSP/TCP 来传输控制信息,而用RTP/UDP 来传输实时声音数据。
流媒体传输的过程:
每一个RTP 数据包都由固定包头(Header )和载荷(Payload)两个部分组成,其中包头前12 个字节的含义是固定的,而载荷则可以是音频或视频数据。
*版本号(V):2比特,用来标志使用的RTP版本。
*填充位(P):1比特,如果该位置位,则该RTP包的尾部就包含附加的填充字节。
*扩展位(X):1比特,如果该位置位的话,RTP固定头部后面就跟有一个扩展头部。
*CSRC计数器(CC):4比特,含有固定头部后面跟着的CSRC的数目。
*标记位(M):1比特,该位的解释由配置文档(Profile)来承担.
*载荷类型(PT):7比特,标识了RTP载荷的类型。
*序列号(SN):16比特,发送方在每发送完一个RTP包后就将该域的值增加1,接收方可以由该域检测包的丢失及恢复包序列。序列号的初始值是随机的。
*时间戳:32比特,记录了该包中数据的第一个字节的采样时刻。在一次会话开始时,时间戳初始化成一个初始值。即使在没有信号发送时,时间戳的数值也要随时间而不断地增加(时间在流逝嘛)。时间戳是去除抖动和实现同步不可缺少的。
*同步源标识符(SSRC):32比特,同步源就是指RTP包流的来源。在同一个RTP会话中不能有两个相同的SSRC值。该标识符是随机选取的 RFC1889推荐了MD5随机算法。
*贡献源列表(CSRC List):0~15项,每项32比特,用来标志对一个RTP混合器产生的新包有贡献的所有RTP包的源。由混合器将这些有贡献的SSRC标识符插入表中。SSRC标识符都被列出来,以便接收端能正确指出交谈双方的身份
符号 位数 定义 数值
V 2bit 版本号 2
P 1bit 填充位 0
X 1bit 扩展位 0
CC 4bit CSRC数目 0
M 1bit 标志位 如果当前 NALU为一个接入单元最后的那个NALU,那么将M 位置 1;或者当前RTP 数据包为一个NALU 的最后的那个分片时(NALU 的分片在后面讲述),M位置 1。其余情况下M位保持为 0。
PT 7bit 载荷类型 96(h264为96)
SeqNum 16bit 序列号 每发一个包加1
Timestamp 32bit 时间戳 单一封包 +采样率,h264为3600; 分片封包第一个加采样率,后续不变
SSRC 32bit 同步源标识 任意指定,标准是一个MD5算法值,未明
CSRC 0bit 贡献源列表 CC为0,所以此项没有
一个RTP数据包定义:
5.2 RTP打包H264数据模式:
RTP打包原则
RTP的包长度必须要小于MTU(最大传输单元),IP协议中MTU的最大长度为1500字节。除去IP报头(20字节)、UDP报头(8字节)、RTP头(12字节),所有RTP有效载荷(即NALU内容)的长度不得超过1460字节。TCP(20字节)
RTP,序列号-没发送一个数据包就+1,时间戳--SPS/PPS时间戳不变、属于同一NALU的分片数据包时间戳不变,其余时间戳+90000/25
回顾H264类型:
0 没有定义
1-23 NAL单元 单个 NAL 单元包
24 STAP-A 单一时间的组合包
25 STAP-B 单一时间的组合包
26 MTAP16 多个时间的组合包
27 MTAP24 多个时间的组合包
28 FU-A 分片的单元
29 FU-B 分片的单元
30-31 没有定义
h264仅用1-23,24以后的用在RTP H264负载类型头中
封包介绍:单一NAL单元模式,组合封包模式,分片的单元
SDP(会话协议)文件描述和封包的关联:
m=video 49170 RTP/AVP 98
a=rtpmap:98 H264/90000
a=fmtp:98;profile-level-id=42A01E;packetization-mode=1;sprop-parameter-sets=Z0IACpZTBYmI,aMljiA==
packetization-mode: 表示支持的封包模式.
当 packetization-mode 的值为 0 时或不存在时, 必须使用单一 NALU 单元模式.
当 packetization-mode 的值为 1 时必须使用非交错(non-interleaved)封包模式.
当 packetization-mode 的值为 2 时必须使用交错(interleaved)封包模式.
每个打包方式允许的NAL单元类型总结(yes = 允许, no = 不允许, ig = 忽略)
Type Packet Single NAL Non-Interleaved Interleaved
Unit Mode Mode Mode
-------------------------------------------------------------
0 undefined ig ig ig
1-23 NAL unit yes yes no
24 STAP-A no yes no
25 STAP-B no no yes
26 MTAP16 no no yes
27 MTAP24 no no yes
28 FU-A no yes yes
29 FU-B no no yes
30-31 undefined ig ig ig
5.2.1 单一封包
对于 NALU 的长度小于 MTU 大小的包, 一般采用单一 NAL 单元模式.
对于一个原始的 H.264 NALU 单元打包时去除 "00 00 01" 或 "00 00 00 01" 的开始码, 把其他数据封包的 RTP 包即可.
如有一个 H.264 的 NALU 是这样的:
[00 00 00 01 67 42 A0 1E 23 56 0E 2F ... ]
这是一个序列参数集 NAL 单元. [00 00 00 01] 是四个字节的开始码, 67 是 NALU 头, 42 开始的数据是 NALU 内容.
封装成 RTP 包将如下:
[ RTP Header ] [ 67 42 A0 1E 23 56 0E 2F ]
即只要去掉 4 个字节的开始码就可以了。
5.2.2 组合封包模式
当 NALU 的长度特别小时, 可以把几个 NALU 单元封在一个 RTP 包中.这里只介绍STAP-A模式
如有一个 H.264 的 NALU 是这样的:
[00 00 00 01 67 42 A0 1E 23 56 0E 2F ... ]
[00 00 00 01 68 42 B0 12 58 6A D4 FF ... ]
封装成 RTP 包将如下:
[ RTP Header ] [78 (STAP-A头,占用1个字节)] [第一个NALU长度 (占用两个字节)] [ 67 42 A0 1E 23 56 0E 2F ] [第二个NALU长度 (占用两个字节)] [68 42 B0 12 58 6A D4 FF ... ]
5.2.3 分片的单元:
当NALU的长度超过MTU时,就必须对NALU单元进行分片封包.也称为Fragmentation Units(FUs).
高三位--F、NRI:与NALU第一个字节的高三位相同--F、NRI, Type:28
S:标记该分片打包的第一个RTP包 E:该分片打包的最后一个RTP包Type:NALU的Type
常用的就是单一封包模式和分片模式。
5.3 RTP抓包分析
6、RTSP
6.1 基本概念
RTSP(Real Time Streaming Protocol),RFC2326,实时流传输协议,是TCP/IP 协议体系中的一个应用层协议,由哥伦比亚大学、网景和RealNetworks 公司提交的IETF RFC 标准。该协议定义了一对多应用程序如何有效地通过IP 网络传送多媒体数据。
RTSP 在体系结构上位于RTP 和RTCP 之上,它使用TCP 或UDP 完成数据传输。
该协议目的在于控制多个数据发送连接,为选择发送通道,如UDP、组播UDP 与TCP,提供途径,并为选择基于RTP 上发送机制提供方法。
RTSP 建立并控制一个或几个时间同步的连续流媒体。通常它本身并不发送连续流。换言之,RTSP 充当多媒体服务器的网络远程控制。
和http类似
1)OPTIONS
C--->S
客户端向服务器端发现OPTIONS,请求可用的方法。
S--->C
服务器端回复客户端,消息中包含当前可用的方法。
2)DESCRIBE
C--->S
客户端向服务器请求媒体描述文件,一般通过rtsp 开头的url 来发起请求,格式为sdp。
S--->C
服务器回复客户端sdp 文件,该文件告诉客户端服务器有哪些音视频流,有什么属性,如编解码器信息,帧率等。
3)SETUP
为音视频数据的传输准备通道
C--->S
客户端向服务器端发起建立连接请求,请求建立会话连接,准备开始接收音视频数据,请求信息描述了期望音视频数据包基于UDP 还是TCP 传输,指定了RTP,RTCP 端口,以及是单播还是组播等信息!
S--->C
服务器端收到客户端请求后,根据客户端请求的端口号确定发送控制数据的端口以及音视频数据的端口!
4)PLAY
C--->S
客户端向服务端请求播放媒体。
S--->C
服务器回复客户端200 OK! 之后开始通过SETUP 中指定的端口开始发送数据!
5)TEARDOWN
C---->S
结束播放的时候,客户端向服务器端发起结束请求
S--->C
服务端收到消息后,向客户端发送200 OK,之后断开连接
上述的流程基本涵盖了RTSP 的流程, 当然, RTSP 除此之外, 还有PAUSE, SCALE ,GET_PARAMETER,SET_PARAMETER 等参数。
6.2 SDP
sdp格式由多行的type=value组成
sdp会话描述由一个会话级描述和多个媒体级描述组成。会话级描述的作用域是整个会话,媒体级描述描述的是一个视频流或者音频流
会话级描述由v=开始到第一个媒体级描述结束,媒体级描述由m=开始到下一个媒体级描述结束
下面是上面示例的sdp文件,我们就来好好分析一下这个sdp文件
v=0\r\n
o=- 91565340853 1 in IP4 192.168.31.115\r\n
t=0 0\r\n
a=contol:*\r\n
m=video 0 RTP/AVP 96\r\n
a=rtpmap:96 H264/90000\r\n
a=framerate:25\r\n
a=control:track0\r\n
这个示例的sdp文件包含一个会话级描述和一个媒体级描述,分别如下
会话级描述
v=0\r\n
o=- 91565340853 1 IN IP4 192.168.31.115\r\n
t=0 0\r\n
a=contol:*\r\n
v=0:表示sdp的版本
解释:
o=- 91565340853 1 IN IP4 192.168.31.115
格式为 o=<用户名> <会话id> <会话版本> <网络类型><地址类型> <地址>
用户名:-
会话id:91565340853,表示rtsp://192.168.31.115:8554/live请求中的live这个会话
会话版本:1
网络类型:IN,表示internet
地址类型:IP4,表示ipv4
地址:192.168.31.115,表示服务器的地址
媒体级描述
m=video 0 RTP/AVP 96\r\n
a=rtpmap:96 H264/90000\r\n
a=framerate:25\r\n
a=control:track0\r\n
解释:
m=video 0 RTP/AVP 96\r\n
格式为 m=<媒体类型> <端口号> <传输协议> <媒体格式 >
媒体类型:video
端口号:0,为什么是0?因为在SETUP过程会告知端口号,所以这里就不需要了
传输协议:RTP/AVP,表示RTP OVER UDP,如果是RTP/AVP/TCP,表示RTP OVER TCP
媒体格式:表示负载类型(payload type),一般使用96表示H.264
a=rtpmap:96 H264/90000
格式为a=rtpmap:<媒体格式><编码格式>/<时钟频率>
a=framerate:25表示帧率
a=control:track0
表示这路视频流在这个会话中的编号
6.3 RTSP抓包
6.4 单播:UDP
- OPTIONS
- DESCRIBE
- SETUP
- PLAY
- TEARDOWN
6.5 组播:UDP
DESCRIBE
SETUP
6.6 RTP OVER TCP/RTSP
当使用TCP协议承载RTSP/RTP时,所有的命令和媒体数据都将通过RTSP端口,RTP数据发送使用rtsp的socket和端口,数据将经过二元交织格式化之后才能发送。
要使用TCP连接,RTSP客户端需要在SETUP阶段请求TCP连接。SETUP命令中应该包括如下格式的Transport:
Transport: RTP/AVP/TCP;interleaved=0-1
上述Transport将告诉服务端使用TCP协议发送媒体数据,并且使用信道 0 和 1 对流数据以及控制信息进行交织。详细说来,使用偶数信道作为数据传输信道,使用奇数信道作为控制信道(数据信道 + 1)。所以,如果你设定数据信道为 0 ,那控制信道应该是 0 + 1 = 1。
RTP,RTCP数据和RTSP数据共享TCP数据通道,所以必须有一个标识来区别三种数据。
RTP和RTCP数据会以$符号+1个字节的通道编号+2个字节的数据长度,共4个字节的前缀开始,RTSP数据是没有前缀数据的。RTP数据和RTCP数据的区别在于第二个字节的通道编号,
rtp基于tcp的包头比基于udp的包头多了4个字节:
* magic固定为0x24,
* channel用来区分音视频等多路流媒体的通道,其中偶数通道为流媒体内容,奇数通道为RTCP
* len表示数据包的长度减去开始的4个字节,即len字段之后的数据长度
SETUP:
RTP OVER TCP数据传输:
7、总结
一个完整的RTSP流媒体传输过程是:
-
RTSP信令交互阶段:
- 客户端发起RTSP连接请求到服务端。
- 服务端响应,建立RTSP连接。
- 客户端与服务端交互,协商媒体传输方式(例如,使用UDP或TCP)。
- 服务端确认传输方式,建立媒体传输通道。
-
采集音视频阶段:
- 服务端开始采集音频和视频数据。
-
音视频编码阶段:
- 服务端进行H.264/H.265视频编码和AAC/PCM/PCMA/PACMU音频编码。
-
RTP封装阶段:
- 服务端将编码后的音视频数据封装成RTP数据包。
- 视频使用H.264/H.265 RTP封装,音频使用AAC/PCM/PCMA/PACMU RTP封装。
-
RTP数据传输阶段:
- 使用选择的传输方式(UDP或TCP),服务端将RTP数据包发送到客户端。
-
客户端接收与解包阶段:
- 客户端接收RTP数据包。
- 如果使用UDP传输,客户端直接解包RTP数据。
- 如果使用TCP传输,客户端从RTSP信令中获取通道信息,然后通过TCP连接接收RTP数据。
-
解码与播放阶段:
- 客户端对接收到的音视频数据进行解码。
- 解码后的数据传递给播放器进行播放。
8、我的开源
我的开源:
1、Nvidia视频硬解码、渲染、软/硬编码并写入MP4文件。项目地址:https://github.com/BreakingY/Nvidia-Video-Codec
2、Jetson Jetpack5.x视频编解码。项目地址:https://github.com/BreakingY/jetpack-dec-enc
3、ffmpeg音视频(H264/H265/AAC)封装、解封装、编解码pipeline,支持NVIDIA硬编解码。项目地址:https://github.com/BreakingY/FFmpeg-Media-Codec-Pipeline
4、simple rtsp server,小而高效的rtsp服务器,支持H264、H265、AAC、PCMA;支持TCP、UDP;支持鉴权。项目地址:https://github.com/BreakingY/simple-rtsp-server