前言:

RTSP,RTCP,RTP一般是一起使用,在FFmpeg和live555这些库中,它们为了更好的适用性,所以实现起来非常复杂,直接查看FFmpeg和Live555源代码来熟悉这些协议非常吃力,这里将它们独立出来实现,以便更好的理解协议。本文主要介绍RTSP,RTCP,RTP加载H264数据流。

说明:

(1)大华IPC摄像头作为服务端

(2)在ubuntu16.04中编译实现测试程序

(3)服务端IP: 192.168.0.120

(4)客户端IP: 192.168.0.128

协议介绍:

用一句简单的话总结:RTSP发起/终结流媒体、RTP传输流媒体数据 、RTCP对RTP进行控制,同步。RTSP属于四层网络当中的应用层,RTP,RTCP属于传输层,如下图所示意。

RTSP在博客《ONVIF网络摄像头(IPC)客户端开发—最简RTSP客户端实现》中已经介绍,这里不再重复,这里主要介绍RTCP和RTP。

RTCP协议:

RTCP控制协议需要与RTP数据协议一起配合使用,当应用程序启动一个RTP会话时将同时占用两个端口,分别供RTP和RTCP使用,其中RTCP端口一定要是基数,RTP端口一定要是偶数,且是两个相邻的端口。RTP本身并不能为按序传输数据包提供可靠的保证,也不提供流量控制和拥塞控制,这些都由RTCP来负责完成。通常RTCP会采用与RTP相同的分发机制,向会话中的所有成员周期性地发送控制信息,应用程序通过接收这些数据,从中获取会话参与者的相关资料,以及网络状况、分组丢失概率等反馈信息,从而能够对服务质量进行控制或者对网络状况进行诊断。

RTCP协议的功能是通过不同的RTCP数据报来实现的,主要有如下几种类型:

  • SR:发送端报告,所谓发送端是指发出RTP数据报的应用程序或者终端,发送端同时也可以是接收端。
  • RR:接收端报告,所谓接收端是指仅接收但不发送RTP数据报的应用程序或者终端。
  • SDES:源描述,主要功能是作为会话成员有关标识信息的载体,如用户名、邮件地址、电话号码等,此外还具有向会话成员传达会话控制信息的功能。
  • BYE:通知离开,主要功能是指示某一个或者几个源不再有效,即通知会话中的其他成员自己将退出会话。
  • APP:由应用程序自己定义,解决了RTCP的扩展性问题,并且为协议的实现者提供了很大的灵活性。

如果只是测试加载H264数据流,这里建立RTCP连接后不发送RTCP数据包也是可以的,那就是客户端和服务端都采用默认的发送和接收方式收发数据。下面的测试程序实现了RTCP协议,但是没有发送RTCP数据包。

RTP协议:

在加载H264数据流的时候,比较麻烦的处理环节就是RTP网络数据包的解析,这个需要完全按照协议来解析,否则会出现花屏现象或是显示不出来的情况。RTP网络数据包结构图如下:

这里对上图中的名词做个解析:

H264图像结构:

  • NAL       Network Abstraction Layer
  • NALU    Network Abstraction Layer Unit
  • VCL       Video Coding Layer
  • VCLU    Video Coding Layer Unit

H264的图像数据是在NAL里面,并且上图中00 00 00 01 6X 这些数据是解包的时候再添加上去的,在RTP网络包中并不会传输这些信息,但是正常的h264图像数据中是需要这些标签来识别不同的图片帧的。

RTP分包模式:

  • SNP     Single NALU Packet
  • AP        Aggregation Packet
  • FU       Fragmentation Units

上面说过RTP网络传输包一包大小为1500字节,那么对于大于1500字节的视频帧,比如I帧,那就需要分开很多包来传输,所采用的就是FU分片模式。如果数据包小于1500字节,比如SPS,PPS,SEI数据包,直接一个RTP包就可以发送完,那使用的就是SNP单包模式。另外组合包AP表示一个包里有多种视频帧类型。在这里我们用到的是单包SNP和分片包FU两种模式。

RTP Pack:

RTP协议从网络中接收或是发送的一个数据包,一般最大1500字节。实际解析的时候也是以这样的一个数据包为单位来解析。

RTP Header:

RTP网络数据包的包头,长度为12字节具体格式如下:

/***************************************************************
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| contributing source (CSRC) identifiers |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*****************************************************************/ /**RTP 头结构**/
typedef struct
{
/** byte 0 **/
unsigned char bit4CsrcLen:4; /** expect 0 **/
unsigned char bit1Extension:1; /** expect 1, see RTP_OP below **/
unsigned char bit1Padding:1; /** expect 0 **/
unsigned char bit1Version:2; /** expect 2 **/
/** byte 1 **/
unsigned char bit7PayLoadType:7; /** RTP_PAYLOAD_RTSP **/
unsigned char bit1Marker:1; /** expect 1 **/
/** bytes 2,3 **/
unsigned int u32SeqNum; /** RTP sequence number **/
/** bytes 4-7 **/
unsigned int u32TimeStamp; /** RTP sequence number **/
/** bytes 8-11 **/
unsigned int u32Ssrc; /**stream number is used here **/
}RTP_HEADER_S;

RTP payload:

RTP加载的实际数据,可以是视频,也可以是音频,也可以是其他类型,这里加载的是h264视频数据,对应下面的96。数据类型如下:

/***********************************************************
PT encoding media type clock rate
name (Hz)
_____________________________________________
24 unassigned V
25 CelB V 90,000
26 JPEG V 90,000
27 unassigned V
28 nv V 90,000
29 unassigned V
30 unassigned V
31 H261 V 90,000
32 MPV V 90,000
33 MP2T AV 90,000
34 H263 V 90,000
35-71 unassigned ?
72-76 reserved N/A N/A
77-95 unassigned ?
96-127 dynamic ?
dyn H263-1998 V 90,000 Table 5: Payload types (PT) for video and combined
encodings
***********************************************************/

NALU Header:

网络抽象层单元头结构体

/*****************
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
*****************/
typedef struct
{
unsigned char bit5TYPE:5;
unsigned char bit2NRI:2;
unsigned char bit1F:1;
}RTP_NALU_HEADER_S;

FU Indicator:

分片包指示符

/****************
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
*****************/
typedef struct
{
unsigned char Bit5TYPE:5;
unsigned char BitNRI:2;
unsigned char BitF:1;
}RTP_FU_INDICATOR_S;

FU Header

分片包头结构

/******************
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+---------------+
*******************/
typedef struct
{
unsigned char Bit5TYPE:5;
unsigned char Bit1R:1;
unsigned char Bit1E:1;
unsigned char Bit1S:1;
}RTP_FU_HEADER_S;

设计思路:

  1. 通过ONVIF协议获取IPC网络摄像头RTSP的URL地址,为了简化测试程序,不在这里介绍,本文中使用固定地址:rtsp://192.168.0.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif
  2. 通过RTSP协议发起数据流,同时获取服务端的RTCP和RTP的网络端口号,数据类型等信息。
  3. 建立RTCP,RTP连接,RTCP是TCP连接,RTP在这里走的是UDP连接。
  4. 客户端接收RTP网络数据包
  5. 对RTP客户端接收到的网络数据包进行解包
  6. 将解包之后的数据写入文件,对于H264视频帧的第一包数据,需要添加上H264帧头标签00 00 00 01 6X信息。
  7. 为方便其他地方使用,可以将视频数据按帧添加进队列。

问题分析:

对于网络视频流,客户端接收到视频数据,有可能出现显示不出来或是花屏的现象,问题一般定位方法有:

  1. 查看H264 帧标签没有添加或是添加错误。
  2. 查看接收到的RTP网络数据包,看网络包序号是否连续,是否有丢包,统计丢包率有多高。
  3. 查看RTP网络数据包的时间戳,看时间戳是否正常增加。
  4. 查看RTP连接的系统网络缓存有多大,看是否有数据因为缓存满了而导致数据丢失。
  5. 查看RTP数据流中是否同时传输了多个流,比如同时传输音频流和视频流。

代码实现:

完整代码结构如下:

​在 liwen01 公众号中回复 网络编程 获取工程代码,本章代码工程名为:RtspRtcpRtpLoad_h264.tar.gz

---------------------------End---------------------------
长按识别二维码
关注 liwen01 公众号

ONVIF网络摄像头(IPC)客户端开发—RTSP RTCP RTP加载H264视频流的更多相关文章

  1. Android--------WebView+H5开发仿美团 预加载,加载失败和重新加载

    Android嵌入式开发已经占大多数了,很多界面都是以网页的形式展示,WebView可以使得网页轻松的内嵌到app里,还可以直接跟js相互调用. 本博客主要是模仿美团的旅游出行模块的预加载,网页加载失 ...

  2. iOS开发UI篇—懒加载

    iOS开发UI篇—懒加载 1.懒加载基本 懒加载——也称为延迟加载,即在需要的时候才加载(效率低,占用内存小).所谓懒加载,写的是其get方法. 注意:如果是懒加载的话则一定要注意先判断是否已经有了, ...

  3. seajs实现JavaScript 的 模块开发及按模块加载

    seajs实现了JavaScript 的 模块开发及按模块加载.用来解决繁琐的js命名冲突,文件依赖等问题,其主要目的是令JavaScript开发模块化并可以轻松愉悦进行加载. 官方文档:http:/ ...

  4. Android开发中如何解决加载大图片时内存溢出的问题

    Android开发中如何解决加载大图片时内存溢出的问题    在Android开发过程中,我们经常会遇到加载的图片过大导致内存溢出的问题,其实类似这样的问题已经屡见不鲜了,下面将一些好的解决方案分享给 ...

  5. Linux内核启动代码分析二之开发板相关驱动程序加载分析

    Linux内核启动代码分析二之开发板相关驱动程序加载分析 1 从linux开始启动的函数start_kernel开始分析,该函数位于linux-2.6.22/init/main.c  start_ke ...

  6. Google官方网络框架-Volley的使用解析Json以及加载网络图片方法

    Google官方网络框架-Volley的使用解析Json以及加载网络图片方法 Volley是什么? Google I/O 大会上,Google 推出 Volley的一个网络框架 Volley适合什么场 ...

  7. 【Java Web开发学习】Spring加载外部properties配置文件

    [Java Web开发学习]Spring加载外部properties配置文件 转载:https://www.cnblogs.com/yangchongxing/p/9136505.html 1.声明属 ...

  8. 基于JRebel开发的MybatisPlus热加载插件

    前言 前天项目中使用了mybatis-plus,但是搭配Jrebel开发项目时,发现修改mapper的xml,或者mapper方法中的注解,Jrebel并没有能够reload mapper.于是就有了 ...

  9. .NET混合开发解决方案11 WebView2加载的网页中JS调用C#方法

    系列目录     [已更新最新开发文章,点击查看详细] WebView2控件应用详解系列博客 .NET桌面程序集成Web网页开发的十种解决方案 .NET混合开发解决方案1 WebView2简介 .NE ...

  10. Android 框架修炼-自己开发高效异步图片加载框架

    一.概述 目前为止,第三方的图片加载框架挺多的,比如UIL , Volley Imageloader等等.但是最好能知道实现原理,所以下面就来看看设计并开发一个加载网络.本地的图片框架. 总所周知,图 ...

随机推荐

  1. GO的逃逸分析

    逃逸分析 前言 指的就是由编译器决定内存分配的位置,不需要由程序员来指定.函数中申请一个新的对象,其目的是为了提高程序的性能,减少内存分配和垃圾回收的开销. 分配在 栈 中, 则函数执行结束则可自动将 ...

  2. CentOS 7上使用Python 3和虚拟环境

    在CentOS 7上使用Python 3和虚拟环境,请按照以下步骤操作: 首先,确保您的系统已安装Python 3.您可以使用以下命令检查Python 3是否已安装: python3 --versio ...

  3. Shell脚本实践总结

    对比大小 符号用法:(必须使用双括号) < 小于     (( "$a" < "$b" ))  <= 小于等于   (( "$a&q ...

  4. 某物流客户Elasticsearch集群性能优化案例

    客户背景 客户使用ES来进行数据存储.快速查询业务订单记录,但是经常会出现业务高峰期ES集群的cpu负载.内存使用均较高,查询延迟大,导致前端业务访问出现大量超时的情况,极大影响其客户使用体验. 部分 ...

  5. Mybatis源码3 CachingExecutor, 二级缓存,缓存的实现

    Mybatis CachingExecutor, 二级缓存,缓存的实现 一丶二级缓存概述 上一章节,我们知道mybaits在构造SqlSession的时候,需要让SqlSession持有一个执行器,如 ...

  6. CodeForces 1030E Vasya and Good Sequences 位运算 思维

    原题链接 题意 目前我们有一个长为n的序列,我们可以对其中的每一个数进行任意的二进制重排(改变其二进制表示结果的排列),问我们进行若干次操作后得到的序列,最多能有多少对 \(l, r\) 使得 \([ ...

  7. 数据库“意外失联”?华为云DRS异地多活灾备为您支招

    [摘要] 为了更好地提供灾备保护,华为云数据库在"同城两中心"的基础上提出了异地保护的方案,华为云数据复制服务DRS推出了异地多活灾备,即"两地四中心". 在D ...

  8. 10个安全问题带你了解OWASP 定义的大模型应用

    摘要:OWASP 的一群研究人员,总结目前大模型中可能存在的TOP10安全风险,很好的揭示了我们在大模型应用中需要防护的目标,以及如何采取相应的防护措施. 本文分享自华为云社区<OWASP 定义 ...

  9. Ambient Mesh:Istio 数据面新模式

    摘要:基于Istio对于Kubernetes生态的完美补充,随着Kubernetes的大规模普及,Istio 数据面新模式 -Ambient MeshIstio也实现了对用户心智以及市场的快速抢占. ...

  10. 技术实践丨基于MindSpore的ResNet-50蘑菇“君”的识别应用体验

    本文分享自华为云社区<基于MindSpore的ResNet-50蘑菇"君"的识别应用体验>,原文作者:Dasming. 摘要:基于华为MindSpore框架的ResNe ...