rtsp

心不动则不痛 提交于 2019-11-30 13:16:18

第二部分、章节介绍
6.1.本季核心技术点和讲法
本节首先演示基于rtsp传输的实验例程,然后讲述本季课程的重点内容点。
6.2.H264编码原理和基本概念
本节从宏观角度讲解h264的编码原理和重要概念,包括I帧、P帧、宏块、片等。
6.3.H264的NAL单元详解1
本节讲解SODB、RBSP、NALU等h264中重要概念,同时讲解常用的h264流分析工具软件,最后从宏观上讲了H264流的一些理解
6.4.H264的NAL单元详解2
本节重点讲解H264的sequence、sps、pps、sei、NALU等,其重点是NALU的位定义和解析方法,这些是我们后续处理h264的rtsp传输的关键点。
6.5.H264的NAL单元详解3
本节重点讲解sps和pps、sei的内部帧结构,以及h264的profile和level等重要概念。
6.6.H264的NAL单元详解4
本节对h264的NAL部分进行总结,彻底打通前述概念,让大家对h264的整体码流内容和解析方法有本质的掌握。
6.7.rtsp传输源码分析1
本节开始分析rtsp传输源码,主要是代码整体架构的分析。
6.8.rtsp传输源码分析2
本节接着分析rtsp源码,主要是RtspServerListen相关的部分。
6.9.rtsp传输源码分析3
本节接着分析rtsp源码,主要是主程序部分,以及和rtsp部分
6.10.rtsp传输源码分析4
本节接着分析rtsp源码,主要是client和server之间的命令和响应,以及rtsp通信建立的过程,关键字的parser等。
6.11.rtsp传输实战分析
本节从实战角度分析rtsp传输代码,用实验验证的方式帮助我们进一步理解rtsp传输代码的工作流程。
6.12.直接发送与环状buffer发送
本节讲述2种rtp包发送策略,直接发送和环状buffer发送,这2种方式我们提供的源码中都做了演示。
6.13.rtsp分包发送h264的源码分析
本节讲解h264分包的rtp发送部分代码,核心是分包后用fu_indicator和fu_header替代nalu的部分,以及相关的一些标志位等。

第三部分、随堂记录
6.1.1、rtsp视频传输实验
(1)调试ok的源码
(2)编译、运行、测试
6.1.2、源码简单浏览
6.1.3、重点1:h.264帧结构
6.1.4、重点2:帧结构分析软件的使用
6.1.5、重点3:rtsp网络编程
6.1.6、重点4:wireshark网络抓包工具的使用

6.2.H264编码原理和基本概念
6.2.1、h.264编码原理
(1)图像冗余信息:空间冗余、时间冗余
(2)视频编码关键点:压缩比、算法复杂度、还原度
(3)H.264的2大组成部分:VCL和NAL
6.2.2、h.264编码相关的一些概念
(1)宏块 MB macroblock
(2)片 slice
(3)帧 frame
(4)I帧(无参考)、B帧(参考前后帧)、P帧(参考前面的帧)I是独立帧 B&P是参考帧
(5)帧率 fps
(6)像素->宏块->片->帧->序列->码流 从大到小依次为:序列、帧(I、P、B帧)、片组、片(I、P、B、SP、SI片)、NALU、宏块、亚宏块、块、像素
IDR帧
{
IDR帧属于I帧,但是I帧不一定是IDR帧。解码器收到IDR帧时,将驱动器参数块(DPB)清空。而I帧不会。(我自己理解为即把参考帧列表刷新从新更新,就是不再参考idr前面的帧)
由此可见,在编码器端,每发一个IDR,就相应地发一个nal。当然在现在的编码中,为了取得更高的图像质量,在一个视频文件中有好多个IDR帧
对IDR帧的处理(与I帧的处理相同):(1) 进行帧内预测,决定所采用的帧内预测模式。(2) 像素值减去预测值,得到残差。(3) 对残差进行变换和量化。(4) 变长编码和算术编码。(5) 重构图像并滤波,得到的图像作为其它帧的参考帧。
这里要提一下,当编码器处理完IDR帧遇到B帧时,编码期先把其放入缓存器中存放起来。直接对P进行编码。即编码器中编码的实际顺序是IDR P B B P B B……即1423756……
也就是说,IDR的出现其实是相当于向解码器发出了一个清理reference buffer的信号吧,上面说前于这一帧的所有已编码帧不能为inter做参考帧了。”

还有:“因为264采用了多帧预测,就有可能在display order下I帧后的P会参考I帧前的帧,这样在random access时如果只找I帧,随后的帧的参考帧可能unavailable,
IDR就是这样一种特殊的I帧,把它定义为确保后面的P一定不参考其前面的帧,可以放心地random access。 ”

}

6.3.H264的NAL单元详解1
6.3.1、VCL和NAL的关系
(1)VCL只关心编码部分,重点在于编码算法以及在特定硬件平台的实现,
VCL输出的是编码后的纯视频流信息XX.h264,没有任何冗余头信息
(2)NAL关心的是VCL的输出纯视频流如何被表达和封包以利于网络传输
(7)总结:做编码器的人关心的是VCL部分;做视频传输和解码播放的人关心的是NAL部分
6.3.2、H.264视频流分析工具
(1)雷神作品:SpecialVH264.exe
(2)国外工具:Elecard StreamEye Tools
(3)二进制工具:winhex
(4)网络抓包工具:wireshark
(5)播放器:vlc
6.3.3、h264视频流总体分析
(1)h264标准有多个版本,可能会有差异,具体差异不详
(2)网上看的资料有时讲法会有冲突,或者无法验证的差异
(3)我们的课程都是以海思平台为主、为准、为案例,不能保证其他平台也完全一样
(4)海思平台编码出来的H.264码流都是由多个序列组成,其中每一个一个序列包含:1sps+1pps+1sei+1I帧+若干p帧

6.4.H264的NAL单元详解2
6.4.1、相关概念
(1)序列 sequence 若I出错则扔掉这一个序列 从下一个序列开始 比如以1秒为一个序列 第一帧为I帧 后面的其他都是P帧
(2)分隔符
(3)sps 7 序列参数集(SPS)
(4)pps 8 图像参数集(PPS)
(5)sei 6 补充增强信息(SEI)
(6)NALU

6.5_6.H264的NAL单元详解3_4
6.5.1、sps和pps详解
https://www.cnblogs.com/wainiwann/p/7477794.html
SPS即Sequence Paramater Set,又称作序列参数集。SPS中保存了一组编码视频序列(Coded video sequence)的全局参数。
所谓的编码视频序列即原始视频的一帧一帧的像素数据经过编码之后的结构组成的序列。
而每一帧的编码后数据所依赖的参数保存于图像参数集中。一般情况SPS和PPS的NAL Unit通常位于整个码流的起始位置。
但在某些特殊情况下,在码流中间也可能出现这两种结构,主要原因可能为:
解码器需要在码流中间开始解码;
编码器在编码的过程中改变了码流的参数(如图像分辨率等);
在做视频播放器时,为了让后续的解码过程可以使用SPS中包含的参数,必须对其中的数据进行解析。
6.5.2、H264的profile和level
Profile是对视频压缩特性的描述(CABAC呀、颜色采样数等等)Baseline/Main/High Profile。Level是对视频本身特性的描述(码率、分辨率、fps)。
//https://blog.csdn.net/xiaojun111111/article/details/52090185
Profile越高,就说明采用了越高级的压缩特性。Level越高,视频的码率、分辨率、fps越高。
(1) profile_idc:
标识当前H.264码流的profile。我们知道,H.264中定义了三种常用的档次profile:-----对应编码工具的集合
基准档次:baseline profile; 66
主要档次:main profile; 77
扩展档次:extended profile; 88
在新版的标准中,还包括了High、High 10、High 4:2:2、High 4:4:4、High 10 Intra、High 4:2:2 Intra、High 4:4:4 Intra、CAVLC 4:4:4 Intra等,每一种都由不同的profile_idc表示。
另外,constraint_set0_flag ~ constraint_set5_flag是在编码的档次方面对码流增加的其他一些额外限制性条件。
(2) level_idc
标识当前码流的Level。编码的Level定义了某种条件下的最大视频分辨率、最大视频帧率等参数,码流所遵从的level由level_idc指定。
当前码流中,level_idc = 0x1e = 30,因此码流的级别为3。

6.5.3、sequence
(1)一段h.264的码流其实就是多个sequence组成的
(2)每个sequence均有固定结构:1sps+1pps+1sei+1I帧+若干p帧
(3)sps和pps和sei描述该sequence的图像信息,这些信息有利于网络传输或解码
(4)I帧是关键,丢了I帧整个sequence就废了,每个sequence有且只有1个I帧
(5)p帧的个数等于fps-1
(6)I帧越大则P帧可以越小,反之I帧越小则P帧会越大
(7)I帧的大小取决于图像本身内容,和压缩算法的空间压缩部分
(8)P帧的大小取决于图像变化的剧烈程度
(9)CBR和VBR下P帧的大小策略会不同,
CBR(Constants BitRate即静态码率 尽量保障码率率)时P帧大小基本恒定,
VBR(Variable Bitrate动态码率 尽量保障清晰度波动小)时变化会比较剧烈

6.78910.rtsp传输源码分析1234
6.11.rtsp传输实战分析
6.12.直接发送与环状buffer发送
6.13.rtsp分包发送h264的源码分析

rtp_timestamp:
https://blog.csdn.net/jasonhwang/article/details/7316128
RTP timestamp是用时钟频率(clock rate)计算而来表示时间的。
RTP timestamp表示每帧的时间,由于一个帧(如I帧)可能被分成多个RTP包,所以多个相同帧的RTP timestamp相等。
(可以通过每帧最后一个RTP的marker标志区别帧,但最可靠的方法是查看相同RTP timestamp包为同一帧。)
两帧之间RTP timestamp的增量 = 时钟频率 / 帧率
其中时钟频率可从SDP中获取,如:https://www.cnblogs.com/idignew/p/7249056.html
m=video 2834 RTP/AVP 96
a=rtpmap:96 H264/90000
其时钟频率为90000(通常视频的时钟频率),若视频帧率为25fps,则相邻帧间RTP timestamp增量值 = 90000/25 = 3600。
另外,通常音频的时钟频率一般为8000。

量化参数QP: QP值对应量化步长的序号,对于亮度而言,此值范围为0~51 。值越小,量化步长越小,量化的精度就越高,意味着同样画质的情况下,产生的数据量可能会更大。
QP值每增加6,量化步长就增加一倍。其对应关系如下表1。

现有的码率控制算法主要是通过调整离散余弦变换的量化参数大小输出目标码率。实际上,量化参数(QP)反映了空间细节压缩情况,如QP小,大部分的细节都会被保留;QP增大,
一些细节丢失,码率降低,但图像失真加强和质量下降。也就是说,QP和比特率成反比的关系,而且随着视频源复杂度的提高,这种反比关系会更明显

函数调用框架:
main
RtspServer_init
RtspServerListen线程函数建立服务器与客户端的连接-------------------------------------------
//①创建基本套接口s32Socket②并绑定至服务器,③listen使服务器进入监听状态
//④accept函数接受网络连接(客户端信息)并填充客户端数据结构体g_rtspClients并创建该客户端的线程RtspClientMsg

		RtspClientMsg线程函数——实现server与clinet之间的响应请求----------------
		//为每一个客户端,accept创建一个对应的s32CSocket,并为每一个客户端创建线程RtspClientMsg
		//不断循环检测:当!=RTSP_IDLE时(只要不是idle状态)接受客户端信息并处理在分情况回应(接收到paly命令时会去创建UDP通道(套接字)并进入发送状态RTSP_SENDING)
			ParseRequestString将客户端传过来的字符串拆分并提取出cmdname
			后面针对cmdname的具体值进行不同的处理
	vdRTPSendThread(不断检测环装buff是否为空,若不为空则用里面的VENC_Sent发送)
		调用VENC_Sent函数 通过TCP通道发送视频---------------------------------------------------------
		
		
		
SAMPLE_VENC_720P_CLASSIC
	开启线程SAMPLE_COMM_VENC_GetVencStreamProc
		step 2:  Start to get streams of each channel.
		while (HI_TRUE == pstPara->bThreadStart)
		{
			//前面在编码生产视频信息
            //step 2.5 : save frame to file
            //s32Ret = SAMPLE_COMM_VENC_SaveStream(enPayLoadType[i], pFile[i], &stStream);

–选择直接发送----------------------------------------------两种方式选择一种,屏蔽另一种----------------------------
SAMPLE_COMM_VENC_Sentjin(&stStream);//将编码生成的视频用VENC_Sent发送出去(一旦进入RTSP_SENDING状态就不停的编码)
//需要前面接受play命令才能将状态由RTSP_CONNET→→RTSP_SENDING
{
VENC_Sent UDP通道发送视频---------------------------------------------------------------------
//直接方式发送(编码多少发多少,编码一次发一次)实现方便简单 但是没有弹性 →用得少
//凭什么编码速度和发送速度就一定一致呢→牵扯到缓冲→环装buff(编码往里面放,发送从里面拿走)
//实际情况两者谁快谁慢是有变化的 有时编码快 有时发送快 故需要缓冲
//如果一直是一个快一个慢则说明有问题,不是一个buff能解决的 要么编码产量一直再buff中堆叠而溢出 要么发送一直在等编码
}
-利用链表buffer和线程环回发送-----------每次malloc存储视频并添加至链表-------------------------两种方式选择一种,屏蔽另一种--------------------------------
//saveStream(&stStream);将编码视频保存至环装buff中

数据流通道 UDP/TCP 要求实时→优先UDP

ENC_Sent

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!