by fanxiushu 2020-01-23 转载或引用请注明原始作者。
此文还是基于xdisp_virt远程项目中的一个子功能。在把xdisp_virt移植到各种平台之后,就想着再做点什么新功能,
于是干脆再次增强原先实现的直播推流功能,在xdisp_virt程序中集成直播服务端,
这样可以不用推流到第三方平台,直接使用播放器就能播放。
(xdisp_virt越玩功能越多,现在基本江郎才尽都不知道还能再添加些什么功能)

本文阐述的就是基于直播服务端比较常用的直播协议:
1,RTSP  经常用于监控行业 ,可以说是监控行业里的老大。
2,RTMP 基于Adobe Flash的协议,虽然Flash面临淘汰,但此协议还在大量使用
3,HTTP-FLV,与2类同,不过使用的是HTTP传输直播流,这样更加适合目前互联网的使用
4,HLS/DASH,HLS和DASH是同样的东西,都是把直播流切成小片组成很多的小音视频文件,
      然后客户端通过HTTP下载这些小文件然后播放。严格得说这算不上直播协议,顶多就是个点播,而且延时非常的高。

以上是查询到的目前经常使用的直播协议,于是打算把这四种协议全部集成到xdisp_virt程序中,
同样的,本文包含的内容较多,也不能面面俱到,如果对xdisp_virt没兴趣,可只关注协议内容即可。
本文是下面链接的扩展篇,并且本文中RTMP和HTTP-FLV阐述的格式,多少会牵涉到其中一些内容。
https://blog.csdn.net/fanxiushu/article/details/80996391 (Windows远程桌面实现之五(FFMPEG实现桌面屏幕RTSP,RTMP推流及本地保存)

(一)首先,我们来看看RTSP。
RTSP和HTTP协议和类似,但是也有用不同。与HTTP协议格式相同的是请求命令,
比如 OPTIONS,DESCRIBE,SETUP,PLAY,PAUSE,TEARDOWN这些命令与HTTP协议的GET,POST命令的协议格式几乎是一样的。
RTSP与HTTP不同的是流传输部分, RTSP传输音视频流使用的是RTP协议,控制流采用的是RTCP协议,
这两个协议底层即可以使用UDP传输,也可以使用TCP传输,这篇文章不介绍UDP传输流的RTP和RTCP,只介绍TCP方式传输流。
同时xdisp_virt也只实现TCP传输流。
UDP传输音视频流看起来比较快,实际上面临许多问题,最严重的就是丢包问题,也许有线网络丢包情况稍微好些,
但是WIFI无线丢包情况就挺糟糕了,因此传输高质量的视频帧的时候如果丢包多,显示的画面经常就会乱七八糟的。
RTSP在TCP中传输音视频帧,使用的是传输OPTIONS,DESCRIBE,SETUP,PLAY这些命令的同一个TCP链接,
不会另外建立链接来传输音视频流。这样的设计其实挺好,节省了建立另外的TCP链接避免浪费资源。
但是会在同一个TCP链接中,同时传输 SETUP,PLAY这些类似HTTP格式的命令,还得传输RTP和RTCP携带音视频流的数据。
同一个链接中传输这么多不同类的数据,处理起来会麻烦一些,但是其实理解了RTSP协议格式种类,也并不难。
就比如xdisp_virt项目中,在同一个TCP链接中,传输的数据种类更多。
总结起来,一个TCP链接中传输三种数据,一是RTSP命令比如PLAY,SETUP等,一个是RTP数据,一个是RTCP数据。
RTP(RTCP)数据包: RTP头(RTCP头)+负载数据。
RTP头和RTCP头定义如下:
(网路序)
struct rtp_header_t
{
    uint32_t ver : 2;        // protocol version
    uint32_t pad : 1;        // padding flag
    uint32_t x : 1;        // header extension flag
    uint32_t cc : 4;        // CSRC count
    uint32_t m : 1;        // marker bit
    uint32_t pt : 7;        // payload type  
    uint16_t seq ;    // sequence number
    uint32_t timestamp; // timestamp
    uint32_t ssrc;        // synchronization source
} ;
struct rtcp_header_t
{
    uint32_t ver : 2;        // version
    uint32_t pad : 1;        // padding
    uint32_t rc : 5;        // reception report count
    uint8_t  pkt_type;  ///packet type
    uint16_t length ; // pkt len in words, w/o this word
} ;
在UDP传输RTP和RTCP的时候,都是分开两个UDP通道(不同的UDP端口)分别传输RTP和RTCP数据包,RTSP命令则使用TCP传输。
因此也非常容易区分,当然浪费的网络资源也很多。
从以上RTP和RTCP头的定义看得出来,如果把三种数据在同一个TCP中传输,是无法区分的,因此必须在RTP头和RTCP头前面再加一个头
这个头叫interleaved,定义如下:
struct rtsp_interleaved_t
{
    unsigned char  magic; // 固定为0x24,'$' 金钱符
    unsigned char  channel; //通道类型,就是指示是传输的RTP包,还是RTCP包
    unsigned short length;  //后面的RTP包或RTCP包的大小,不超过64K
};
这样三种包在同一个TCP中的格式就是:
A), 类似HTTP格式命令
B), rtsp_interleaved_t + rtp_header_t + 音视频负载数据
C), rtsp_interleaved_t + rtcp_header_t + RTCP负载数据
其中 RTCP和RTP可以通过 rtsp_interleaved_t中的channel区分,但是rtsp_interleaved_t头和普通的RTSP请求命令如何区分呢?
其实也很好区分,我们编程的时候,先接收一个字节,
如果这个字节是 ‘$'(0x24)可以确定是rtsp_interleaved_t头,否则就是普通的OPTIONS,DESCRIBE,PLAY这些命令。

我们来看看一个RTSP播放器是如何请求播放流的,
首先播放器会发送OPTIONS命令,服务端返回 OPTIONS,PLAY,PAUSE,TEARDOWN这些命令表示服务端支持哪些RTSP命令。
接着播放器发送DESCRIBE命令请求音视频流的SDP描述信息,播放器获取到SDP之后,就知道了服务端提供了哪些流。
然后播放器发送SETUP给服务端,表示准备开始传流,其中包括采用哪种传输方式,传输通道等信息,服务端回复SETUP之后。
然后播放器发送PLAY命令开始请求播放, 这个时候,服务端就开始推送包含音视频数据的RTP包给播放器。
播放器停止播放的时候,会发送TEARDOWN命令,这个时候,服务端停止推送流。
这就是一个RTSP播放的基本流程。
其实SETUP和PLAY命令是播放器必须发送的,其他的可以可选。

下面是一个请求例子(C是播放器, S是服务端):
C:
       OPTIONS rtsp://192.168.88.1/test RTSP/1.0\r\n
       CSeq: 1\r\n
       \r\n
S:   RTSP/1.0 200 OK\r\n
       CSeq: 1\r\n
       Server: xdisp_virt\r\n
       Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE\r\n
      \r\n
C:
      DESCRIBE rtsp://192.168.88.1/test RTSP/1.0\r\n
     CSeq: 2\r\n
      \r\n
S:  RTSP/1.0 200 OK\r\n
      CSeq: 2\r\n
      Server:  xdisp_virt\r\n
      Session: 1234\r\n
      Context-Length: 345\r\n
      \r\n
      SDP 内容
C: SETUP rtsp://192.168.88.1/test/track1 RTSP/1.0\r\n   请求视频帧
     CSeq: 3\r\n
     Transport: Transport: RTP/AVP/TCP;unicast;interleaved=0-1\r\n
     Session: 1234\r\n
     \r\n
S: RTSP/1.0 200 OK\r\n
     CSeq: 3\r\n
     Session: 1234\r\n
     Transport: Transport: RTP/AVP/TCP;unicast;interleaved=0-1\r\n
     \r\n
C:
    PLAY rtsp://192.168.88.1/test RTSP/1.0\r\n
    CSeq: 4\r\n
    Session: 1234\r\n
    \r\n
S: RTSP/1.0 200 OK\r\n
    CSeq: 4\r\n
    Session: 1234\r\n
    \r\n
服务端开始推送携带视频数据的RTP包(rtsp_interleaved_t+rtp_header_t+视频数据)
服务端还会接收到播放器发送来的RTCP报告数据包。服务端根据情况也会发生状态报告RTCP包给播放器。
。。。。
C:
    TEARDOWN rtsp://192.168.88.1/test RTSP/1.0\r\n
    CSeq: 5\r\n
    Session: 1234\r\n
    \r\n
S: RTSP/1.0 200 OK\r\n
     \r\n
服务端停止推送视频流。

接下来就是如何把H264视频帧封包到RTP包中,
一帧H264数据包含许多NALU单元,通常就是把每个NALU单元封包成一个RTP包即可,
但是这个RTP包是有大小限制的,因为如上面rtsp_interleaved_t数据结构里边的length不超过64K,RTP包大小不能超过64K,
有可能一个NALU单元很大,会超过64K大小,因此需要把这个NALU单元拆分成多个部分,每个部分再封装成RTP包。
至于如何拆分和如何再封包成RTP包,这里也就不再赘述,有兴趣可查阅RFC文档的相关介绍。

(二),HTTP-FLV 和 RTMP 直播协议。
之所以要把这两合并到一起来讲,其实是音视频包封包格式都差不多,基本都是基于FLV文件格式。不同的是 采用的通讯协议不同。
RTMP不但支持拉流,更主要的是支持推流。在互联网应用中,采集到的直播流数据可以通过RTMP协议推送到服务器端,
服务器端再拆分成多个拉流协议,比如 HTTP-FLV, HLS,DASH等各种拉流协议。
在互联网应用中,HTTP协议是主流,因此我们对拉流的使用,使用的HTTP-FLV较多,RTMP相对会少一些,尤其在Flash面临淘汰的现在。
HTTP-FLV和RTMP实时性较高,延时一般都在1-2秒内,因此适合用于对应实时性要求高的互动直播环境中。
RTMP在浏览器中需要借助Flash才能播放,PC系统浏览器一般都支持Flash插件,但是基本也是日落西山。
除非是自己在客户端开发播放器专门使用RTMP来播放, 比如VLC播放器可运行在移动系统和PC系统中,且支持多个串流播放协议。
至于HTTP-FLV,可以在浏览器端利用js解码,转成MSE喂给video标签来播放,但是不是所有系统都支持MSE,这给兼容性带来麻烦。
至少目前iOS系统都不支持MSE,也许以后的iOS版本能支持MSE。
目前来看,兼容性最好的还是HLS,能支持所有平台的绝大部分浏览器,但是就是延迟实在太高。

HTTP-FLV是利用HTTP链接,发送一个无限大的flv文件来达到直播的效果。
FLV文件是一个 flv头 + 多个tag组成的序列流, tag包括音频tag, 视频tag,script的tag(比如媒体信息tag)。
FLV不像MP4文件格式,需要文件尾和头才能组成一个完整的MP4文件,
FLV文件只要 flv_header + meta_header(描述音视频信息)+ 无数个音视频数据的tag,
只要前面的flv_header+meta_header信息完整,后面的音视频tag可以无限个,也就是不需要文件尾部,这是实现HTTP-FLV直播的基本条件。
同时在 HTTP协议定义中,在回复中如果没有包含 Content-Length 这个字段,
客户端就会一直接收数据,直到服务端主动关闭这个HTTP链接,这样服务端就会连续不断的推送音视频tag 给客户端。

比如一个HTTP-FLV请求和回复流程:
C:
    GET /flv_stream/test.flv HTTP/1.1\r\n
    Host: ddd.com\r\n
    \r\n
S:
    HTTP/1.1 200 OK\r\n
    Server: xdisp_virt\r\n
    Connection: keep-alive\r\n
    \r\n
    FLV头 + 媒体信息tag
    持续不断的 音频tag 和 视频tag
    。。。。
    直到C或者S关闭这个链接为止。

FLV头一共9个字节,前3个是’FLV‘,第4个字节是版本号,第5个是支持audio+video类型,接下来4个字节是头长度,这里为9,
再接下来4个字节全是0, 这个意思是PreviousTagSize0,就是第一个前Tag的大小。
接下来就是以TAG为单位的组合:
11个字节的TAG头 + 负载数据内容 + 4个字节的这段数据大小(11 + 负载数据大小)

TAG头包括TAG类型(比如 audio,video, script等),负载数据大小,timestamp,流ID。
第一个TAG是 meta类型的TAG, 用来描述接下来的音视频流的相关信息,比如SPS,PPS信息,视频宽高,音频采集率等。
这个是必须有的,否则客户端无法获取到音视频相关信息。
接下来视频帧,除了11个字节的TAG头之外,还包含5个字节描述video相关信息,比如是否关键帧,
接下来就是一帧的H264数据,采用AVCC编码,最后就是4个字节用来指示当前tag的大小。
音频帧,除了11个字节的TAG,还包含2个字节的描述Audio信息,接下来就是一帧Audio数据,最后4个字节就是当前tag的大小。

(三),HLS,DASH切片直播。
严格得说,这不是个直播协议,它是把连续不断的直播流,切片成很多的小文件。
客户端先从服务端获取到一个列表,然后根据列表分别下载这些小文件,然后再连续不断的播放这些小文件。
直播流是连续不断的,小文件会越生成越多,服务端因此会删除先前的小文件,比如同时只保留20个小文件,
文件按照序号不断的生成和不断的删除不用的小文件,总数保持20个不变。
同时这个列表上的小文件名字也会不断更新,客户端会定时重新获取这个列表,从而按照顺序不断的下载新的小文件,然后再播放。
这样的效果就造成好像在不断的播放一样,其实就是在连续不断的下载和播放小视频文件而已。

为何会设计出这么一个不伦不类的直播协议,(不伦不类这么说可能有点过分)
其实我想跟目前浏览器video标签播放视频的方式有关系,
目前浏览器的内嵌的 video标签强项是播放单个视频文件,而不是播放直播流。
这也是直播协议在浏览器中面临的尴尬局面。

以前在研究如何直接在浏览器中实现远程控制的时候,也是面临同样的问题。
在不需要给浏览器安装插件的情况下,而且要兼容各个系统的浏览器,
当时也是折腾来折腾去,最终选择了使用WebSocket传输音视频数据,然后js解码,然后使用canvas画图来解决。
目前来看,这也是目前实现浏览器方式远程控制的最好方式,实时性也是非常高,符合远程控制对实时性的要求。
就是这个时候浏览器占用的系统资源比较高些,但是基本也能给接受。

下图是最新版本的xdisp_virt实现的四种直播服务端:

下图是在iPhone手机浏览器中直接打开上面第4个切片直播的URL地址的播放效果图:

Windows远程桌面实现之十一:桌面屏幕通过各种直播服务端直播(RTSP, RTMP, HTTP-FLV, HLS)相关推荐

  1. otp远程服务器,通过 Yubico OTP 进行双因素认证(服务端)

    使用 Yubico OTP 进行双因素验证(服务端) 提高环境安全的第一步是提高客户端安全性(利用 PIV 进行 SSH 认证)和简化服务器上的管理任务(通过用户证书进行 SSH 认证),不过它们依然 ...

  2. windows平台VR全景播放器,支持图片视频,rtsp,rtmp,http,udp,hls等网络格式

    QQ: 515311445 先上下载链接:点击下载VR全景播放器 本工具使用开源的vlc做为核心播放器,添加全景代码而成,编译vlc时建议使用linux电脑编译,目前vlc已经支持全景图片和视频了,但 ...

  3. Windows远程命令执行0day漏洞安全预警

      网站安全云检测这不是腾讯公司的官方邮件. 为了保护邮箱安全,内容中的图片未被显示. 显示图片 信任此发件人的图 片 一.概要 Shadow Brokers泄露多个Windows 远程漏洞利用工具, ...

  4. Windows平台RTSP|RTMP播放端SDK集成说明

    2.1 demo说明 大牛直播SDK提供C++/C#两套接口,对外提供32/64位debug/release库,C++和C#接口一一对应,C#接口比C++接口增加前缀NT_PB_: WIN-Playe ...

  5. Windows远程桌面实现之五(FFMPEG实现桌面屏幕RTSP,RTMP推流及本地保存)

    by fanxiushu 2018-07-10 转载或引用请注明原始作者. 前面文章分别阐述了,如何抓取电脑屏幕数据,如何采集电脑声音, 如何实现在现代浏览器中通过HTML5和WebSocket直接进 ...

  6. windows远程桌面linux系统,Windows远程桌面控制Linux图文详解

    随着互联网的高速发展以及Linux企业应用的成熟,Linux被广泛应用于服务器领域,如何实现Linux的远程管理成为网络管理员的首要任务. 我们经常见到的几种最为常用的windows下远程管理Linu ...

  7. windows 命令行远程连接_CentOS系列001:windows远程桌面连接CentOS

    在阿里云申请了一台CentOS云服务器后,希望通过windows的远程桌面连接这台服务器,以方便后续维护,这里特此记录操作过程 一.登录密码设置 在阿里云实例里可以重置实例密码,此密码是用户root的 ...

  8. windows远程桌面_如何使用Windows远程桌面连接Ubuntu 干货

    近期网盾科技给大家分享了一些教程类的干货,有很多小伙伴都收藏了网盾科技的文章,能对大家有帮助就好.今天网盾科技再给小伙伴们讲解一下如何使用Windows远程桌面连接Ubuntu,干货收藏! Windo ...

  9. Windows远程桌面(mstsc) 无法全屏显示的解决方法

    目录 问题描述 解决方法 问题解决 问题描述 我们通过mstsc远程登录windows服务器时,远程登录的桌面无法全屏显示,这样操作起来特别不方便,还需要滚动条来处理远程的屏幕,极易操作误操作. wi ...

最新文章

  1. 工厂模式(Factory)(转)
  2. AWS推出深度学习容器,简化AI程序开发
  3. 蓝桥杯-逆序对(java)
  4. Docker Compose安装Registry后配置WebUI与客户端
  5. oracle关闭 manager,Oracle Enterprise Manager 11g 启停
  6. (Android开发辅助工具)动态广播注册解注工具
  7. 威纶触摸屏使用说明书_「西门子1200PLC教程」20.PLC变量表的使用
  8. linux满负荷运行tail,linux内核tcp调优规范与方案
  9. F5和nginx配合转发前端请求
  10. DLL注入之修改PE静态注入
  11. js 公共库 cdn 推荐
  12. 华云天下荣膺“2021年度十佳呼叫中心硬件及软件设备供应商”
  13. 算法设计与分析——顺序统计量:最大值与最小值
  14. C语言数组 一维数组篇
  15. diskgenius创建efi分区_手动创建EFI分区安装系统|重装系统前EFI分区教程
  16. 小程序解码wx.getUserInfo中的decryptData数据
  17. 毕业后的去向:继续读研还是直接就业?
  18. 最新公众号今日头条自媒体视频课程
  19. C++下编译和运行C语言程序
  20. 以firejail sandbox解析Docker核心原理依赖的四件套

热门文章

  1. 励志用 | ACM-ICPC/CCPC 个人经历总结_楚东方(转)
  2. 渗透测试之信息收集DNS篇
  3. Day2:03Windows常用快捷键
  4. Git 升级版本(windows)
  5. 抖音小程序request封装,登陆授权获取头像方案,及广告加载注意事项
  6. 关于小红伞免费V9简体中文版、v10 出现“SSL提示不能安装的解决方法
  7. 级联样式表_级联样式表| 第1部分
  8. 如何把ipa文件(iOS安装包)安装到iPhone手机上? 附方法汇总
  9. openGL API glUniformMatrix4fv详解
  10. 视频也能磨皮美白?教你4步搞定!