网络协议-流媒体协议

视频编码与直播的实现原理介绍

为什么要对视频进行编码

流媒体协议主要用于流媒体视频的直播和点播,在介绍流媒体协议之前,先给大家介绍下视频的压缩和编码机制。

说到视频播放,其实就是快速播放一系列连续的图片而已,其中的每一张图片称之为一帧,只要每秒钟帧的数量足够多,也即播放得足够快,比如每秒 30 帧,以人眼的敏感程度,就看不出这是一张张独立的图片,我们把每秒的帧数叫做帧率(FPS)。

图片是由像素构成的,每个像素由 RGB 三种颜色构成,每个颜色又由 8bit 二进制来表示,三种颜色就是 24 个 bit,假设构成视频的图片平均都是由 1024*768 像素(有时我们也将这个单位称之为分辨率)组成,这样下来,一秒钟视频的容量就是:

30*1024*768*24 bit = 566,231,040 bit = 70,778,880 Byte = 67.5 MB

相应的,一分钟视频对应的容量差不多有 4 GB,相当惊人,仅仅是一分钟啊,而且图片的分辨率并不是很高,如果是一部电视剧呢(45分钟),一部电影呢(2小时),或者同时对实时性要求很高的直播呢?这样大小的视频流目前主流的带宽根本扛不住,另外我们的磁盘空间也不够存。

但我们在网上在线看视频、直播都很顺畅啊,甚至充会员还可以看 1080p(分辨率19201080) 或者 4k(分辨率38402160) 的高清视频也不在话下,这又是怎么做到的呢?

这就涉及到了编码的概念,通过编码可以对视频进行压缩(想想在数据结构与算法系列中介绍的赫夫曼编码),在保证清晰度的前提下实现以尽可能少的比特数存储视频数据。

视频压缩与编码的常见标准

视频编码实现方案主要分为两个流派:

  • 流派一:国际电信联盟电信标准化部门(简称 ITU-T)旗下的 VCEG(Video Coding Experts Group,视频编码专家组),因为是电信联盟,所以他们最初做视频编码主要侧重传输,这个编码组制定的视频通信协议包括 H.261、 H.262、H.263、H.264、H.265 等;
  • 流派二:国际标准组织(简称 ISO)旗下的 MPEG(Moving Picture Experts Group,动态图像专家组),他们本来是做视频存储的,例如将编码后的视频保存在 VCD 和 DVD 中,随着 VCD 和 DVD 的消逝,后来也慢慢侧重视频传输了,这个编码组制定了的视频编码标准包括 MPEG-1、MPEG-2、MPEG-4、MPEG-7 等。

后来,ITU-T VCEG 与 ISO MPEG 联合制定了 H.264/MPEG-4(两者等价,是同一个标准,也被称作 AVC),这才是我们要重点关注的。该标准引入了一系列新的能够大大提高压缩性能的技术,并能够同时在高码率端和低码率端大大超越以前的诸标准,我们常见的一些视频编解码器如 AVI、MPEG、RMVB、MP4、MOV、FLV、WebM、WMV、ASF、MKV 等即是在该标准下实现的。

经过视频编码器编码之后,生动活泼的一帧帧图片,就变成了一串串让人看不懂的二进制代码,这个二进制代码可以放在一个文件里面,按照一定的格式保存起来,对应的视频格式与视频编码器一致,比如 .avi、.flv、.mp4、.mov 等,然后用户需要通过相应的视频解码器才能播放这些视频,比如 AVI 解码器可以播放 .avi 格式视频,依次类推。

视频直播的实现原理

当然,这个二进制代码也可以通过某种网络协议进行封装,放在互联网上传输,这个时候就可以进行网络直播了。

首先,网络协议将编码好的视频流,从主播端推送到服务器,在服务器上有个运行了同样协议的服务端来接收这些网络包,从而得到里面的视频流,这个过程称为接流。

服务端接到视频流之后,可以对视频流进行一定的处理,例如转码,也即从一个编码格式,转成另一种格式。因为观众使用的客户端千差万别,要保证他们都能看到直播。流处理完毕之后,就可以等待观众的客户端来请求这些视频流,观众的客户端请求的过程称为拉流。

如果有非常多的观众,同时看一个视频直播,那都从一个服务器上拉流,压力太大了,因而需要一个视频的分发网络(CDN),将视频预先加载到就近的边缘节点,这样大部分观众看的视频,是从边缘节点拉取的,就能降低服务器的压力。

当观众的客户端将视频流拉下来之后,就需要进行解码,也即通过上述过程的逆过程,将一串串看不懂的二进制代码,再转变成一帧帧生动的图片,在客户端播放出来,这样你就能看到直播视频啦。

整个直播过程的流程图如下所示:

常见的流媒体协议介绍

1、HTTP 和 HLS

HTTP 视频协议是在互联网普及之后在互联网上看视频的需求下形成的。最初的 HTTP 视频协议,没有任何特别之处,就是通用的 HTTP 文件渐进式下载,但是在这种情况下,视频无法快进或者跳转到文件尚未被下载到的部分,这就对 HTTP 协议提出了范围请求(Range Request)的要求,目前几乎所有 HTTP 服务器都支持范围请求。所谓范围请求指的是请求文件的部分数据,这可以在 HTTP 请求头中通过 Range 字段设置偏移量来实现。

这种方式应用于视频点播还可以,用于直播的话实时性较差,延迟也很高,于是,苹果公司又在 HTTP 协议的基础上推出了 HTTP Live Streaming(简称 HLS)这个流媒体传输协议,主要用于在 iOS 系统中实现流媒体的直播和点播。

相对于常见的流媒体直播协议,HLS 直播最大的不同在于,直播客户端获取到的并不是一个完整的数据流,HLS协议在服务器端将直播数据流存储为连续的、很短时长的媒体文件(MPEG-TS格式),而客户端则不断下载并播放这些小文件。因为服务器总是会将最新的直播数据生成新的小文件,这样客户端只要不停地按顺序播放从服务器获取到的文件,就实现了直播。

由此可见,HLS 是以点播的技术实现直播。由于数据通过 HTTP 协议传输,所以完全不用考虑防火墙或者代理的问题,而且分段文件的时长很短,客户端可以很快的选择和切换码率,以适应不同带宽条件下的播放。不过HLS 的这种技术特点,决定了它的延迟一般总是会高于普通的流媒体直播协议。

2、RTP 与 RTCP

RTP(Real-time Transport Protocol,实时传输协议)是互联网上针对多媒体数据流的一种实时传输协议。RTP 由紧密连接的两个部分组成:

  • RTP 协议:传送具有实时属性的数据;
  • RTP 控制协议(简称 RTCP):监控服务质量并传送正在进行的会话参与者的相关信息。

RTP 协议详细说明了在互联网上传输音频和视频的标准数据包格式,常用于流媒体系统(配合 RTSP 协议,下面会介绍这个协议)、视频会议和视频电话系统(配合 H.263 或 SIP)。

RTP 协议是建立在 UDP 协议之上的,因此本身并没有提供按时发送机制或其他服务质量(QoS)保证,它依赖于底层服务去实现这一过程。RTCP 协议则是 RTP 协议的一个姐妹协议,它会定期在流媒体会话参加者之间传输控制数据,用来为 RTP 所提供的服务质量提供反馈。RTCP 协议会收集相关媒体连接的统计信息,如传输字节数、传输分组数、丢失分组数、时延抖动、单向和双向网络延迟等等,网络应用程序可以利用 RTCP 所提供的信息提高服务质量,比如限制信息流量或改用压缩比较小的编解码器。RTCP 协议本身不提供数据加密或身份认证,其伴生协议 SRTCP(安全的实时传输控制协议)则可用于此类用途。

3、RTSP

RTSP(Real Time Streaming Protocol,实时流协议)协议是最早的视频传输协议,定义了一对多应用程序如何有效通过 IP 网络传输多媒体数据。RTSP 在体系结构上位于 RTP 和 RTCP 之上,是一种双向实时数据传输协议,它允许客户端向服务器端发送请求,如回放、快进、倒退等操作。RTSP 可基于 RTP 来传送数据,还可以选择 TCP、UDP、组播 UDP 等通道来发送数据,具有很好的扩展性。

RTSP 协议的优势在于可以控制到视频帧,因此可以承载实时性很高的应用,这个优点也是相对于 HTTP 传输方式的最大优点。不过 iOS 系统不支持该协议,Andriod 系统原生支持。

4、RSVP

RSVP 即资源预订协议,使用 RSVP 预留一部分网络资源(即带宽),能在一定程度上为流媒体的传输提供 QoS。RSVP、RTSP 与 RTP 协议工作在不同的层次,如下图所示:

5、RTMP

RTMP(Real Time Messaging Protocol,实时消息传输协议)是 Adobe 公司为 Flash 播放器和服务器之间音频、视频和数据传输开发的流媒体协议。它有以下三种变种:

  • 工作在 TCP 之上的明文协议,使用端口 1935;
  • RTMPT 封装在 HTTP 请求之中,可穿越防火墙;
  • RTMPS 类似 RTMPT,但使用的是 HTTPS 连接。

RTMP 协议采用实时的流式传输,所以不会缓存文件到客户端,因此用户想下载 RTMP 协议下的视频是比较难的,该协议下的视频流可以随便拖动,可以从任意时间点向服务器发送请求进行播放,并不需要视频有关键帧。相比而言,HTTP 协议下视频需要有关键帧才可以拖动。RTMP 协议可以支持点播、回放和直播。

因为该协议是 Adobe 公司开发的,所以最初服务器端架设的环境是 FMS(Flash Media Server),该软件为收费软件,价格昂贵。后来,开源软件 red5 的推出使支持 RTMP 协议的服务器架设成本大大缩小,但是在性能方面不如 FMS 稳定。

6、MMS

MMS(Microsoft Media Server Protocol,微软媒体服务协议)是用来访问并流式接收 Windows 媒体服务器中 .asf 文件的一种协议。MMS 协议用于访问 Windows Media 发布点上的单播内容,是连接Windows Media 单播服务的默认方法。如果用户在 Windows Media Player 中键入一个 URL 以连接内容,而不是通过超链接,则必须使用 MMS 协议引用该流。

小结

综上,在 iOS 中我们可以基于 HLS 实现流媒体传输,在非 iOS 系统可以基于 RTSP 实现流媒体传输,RTMP 则适用于所有系统,而且时延小,尤其适用于直播实现,是目前比较主流的直播流媒体协议,视频点播的主流协议则是 HTTP,对于性能要求不高的直播系统,也可以使用 HTTP 协议,毕竟服务器不需要做任何额外配置即可支持,简单,成本低。

如何基于 RTMP 协议实现视频直播


我们以视频直播的主流协议 RTMP 为例,介绍如何基于 RTMP 协议实现视频直播过程中视频流的网络传输,为了便于理解,我们还是参照整个直播过程的流程图进行讲解。

主播在客户端采集视频后,照例客户端软件会对视频进行编码以压缩视频,然后通过 RTMP 协议将这个二进制的视频流打包成网络包发送给服务器,这个过程对应上述流程图中的推流(在实际开发中,通常通过 FFmpeg 进行推流)。

RTMP 是基于 TCP 的,因而双方需要建立一个 TCP 连接,在 TCP 连接的基础上,还需要建立一个 RTMP 连接,对应在程序里面,你需要调用 RTMP 类库的 Connect 函数,显示创建一个连接。

之所以要建立单独的 RTMP 连接,是因为客户端与服务器需要商量一些事情,以保证后续的传输能正常进行。主要是两个事情,一个是 RTMP 协议的版本号,如果客户端、服务器的版本号不一致,则不能工作;另一个就是时间戳,视频播放中,时间是很重要的,后面的数据流互通的时候,经常要带上时间戳的差值,因而一开始双方就要知道对方的时间戳。下面我们简单来介绍下 RTMP 连接的建立和数据传输的细节。

首先,客户端发送 C0 表示自己的版本号,不必等对方的回复,然后发送 C1 表示自己的时间戳。服务器只有在收到 C0 的时候,才会返回 S0,表明自己的版本号,如果版本不匹配,可以断开连接。服务器发送完 S0 后,也不用等什么,就直接发送自己的时间戳 S1。客户端收到 S1 的时候,发一个知道了对方时间戳的 ACK C2。同理服务器收到 C1 的时候,发一个知道了对方时间戳的 ACK S2。于是,握手完成,连接建立成功。

握手之后,双方需要互相传递一些控制信息,例如 Chunk 块的大小、窗口大小等。真正传输数据的时候,还需要创建一个 Stream,然后通过这个 Stream 来推流。前面我们讲推流之前会将视频编码,编码后的视频会变成由一个个称之为 NALU 单元构成的二进制流,推流的过程,就是将这些 NALU 放到 Message 报文里发送。

在收发数据的时候,和 HTTP 类似,RTMP 还会将 Message 报文拆分成 Chunk 进行发送,Chunk 的发送是有序的,一个 Chunk 发送完成之后,才能开始下一个 Chunk 的发送。每个 Chunk 中都带有 Message ID,表示属于哪个 Message,接收端也会按照这个 ID 将 Chunk 组装成 Message。前面连接建立之后,设置的 Chunk 块大小指的就是这个 Chunk,这样做的好处是将大的消息变为小的块发送,以便在低带宽的情况下,减少网络拥塞。

二进制视频流数据就是这样源源不断到达流媒体服务器。主播客户端推送的时序图如下:

服务器接收主播推送视频流的环节叫做接流,获取到视频流后还要对视频流进行处理,以适配不同客户端的各种协议,从而方便观看直播的观众拉取到本地观看,这个过程就是流处理。

观看直播的观众同样可以通过 RTMP 协议从流媒体服务器上拉取视频流(当然也可以通过上篇分享介绍的其它流媒体协议拉取),这个过程叫做拉流,但是如果同时观看直播的观众很多,都去同一个地方拉取,还是视频这种很耗带宽的资源,服务器压力会很大,也会导致时延比较长(观众直观的感受就是卡),所以需要通过 CDN(分发网络) 提升直播流畅度,关于视频直播的 CDN 实现方案,我们放到下一篇分享详细介绍。

观众的客户端拉取服务器的视频流与主播推送视频流类似,先要建立 RTMP 连接,然后创建一个 Stream 用于拉流,拉流的时候,会获取到解码参数以及由 NALU 组成的一个个帧,将解码之后的帧交给播放器播放,就可以看到直播视频画面了。

观众客户端拉流的时序图如下:

至此,我们就大致介绍完了从主播客户端推流到服务器处理,再到观众客户端拉流的视频直播整体技术实现方案。

流媒体协议的 CDN 实现方案及防盗链问题

CDN 支持流媒体协议,例如前面讲过的 RTMP 协议。

流媒体 CDN 的实现

多数情况下,CDN 相当于一个代理,从上一级缓存读取内容,然后转发给用户。

对于普通的静态资源(HTML、CSS、JavaScript、图片等小文件)来讲,内容的分发往往采取拉取的方式,当发现未命中的时候,再去上一级进行拉取。但是,流媒体(视频、音频等大文件)数据量大,如果出现回源,压力会比较大,所以往往采取主动推送的模式,将热点数据主动推送到边缘节点。具体而言,以直播为例,主播在开始直播时,就会将视频推送到就近 CDN 节点缓存,然后观众观看直播的时候,也会就近从 CDN 边缘节点拉取视频,如果该节点没有资源,会从其它 CDN 节点同步再返回给观众。看直播往往是有时延的,这个时延就是从主播端采集视频到观众端开始播放相应应视频的时间差。

对于流媒体来说,很多 CDN 还会提供预处理服务,即文件在分发之前,经过一定的处理。例如将视频转换为不同的码流,以适应不同的网络带宽的用户需求;再如对视频进行分片,降低存储压力,也使得客户端可以选择使用不同的码率加载不同的分片(对客户端而言就是标清、高清、超清等不同的清晰度)。

以七牛云提供的 CDN 解决方案为例,基本上涵盖上面提到的点:

当然,对直播而言,基本原理差不多,但技术方案要更加复杂一些,以保证首播时间和卡顿率,所以一般云服务提供商会专门提供针对直播场景的解决方案。

防盗链问题

对于流媒体 CDN 来讲,有个关键的问题是防盗链问题。因为视频是要花大价钱买版权的,为了挣点钱,收点广告费,如果流媒体被其他的网站盗走,在人家的网站播放,那损失可就大了。

最常用也最简单的方法就是 HTTP 头的 Referer 字段,当浏览器发送请求的时候,一般会带上 Referer,告诉服务器是从哪个页面链接过来的,如果不是来自本站,就阻止访问或者跳到其它链接,比如以学院在使用的七牛云 CDN 为例,Referer 防盗链配置界面如下:

Referer 的机制相对比较容易破解,所以还需要配合其他的机制。一种常用的机制是时间戳防盗链,使用 CDN 的管理员可以在配置界面上,和 CDN 厂商约定一个加密字符串(KEY):

客户端取出当前的时间戳,要访问的资源及其路径,连同加密字符串通过签名算法得到一个字符串,然后生成一个下载链接,带上这个签名字符串和截止时间戳去访问 CDN。

在 CDN 服务端,根据取出的过期时间,和当前 CDN 节点时间进行比较,确认请求是否过期。然后 CDN 服务端有了资源及路径,时间戳,以及约定的加密字符串,根据相同的签名算法计算签名,如果匹配则一致,访问合法,才会将资源返回给客户。

除此之外,还有一些其它的防盗链方式:

原文地址:https://www.cnblogs.com/stringarray/p/13027230.html