H5 直播系统开发之原理概述

1. 系统开发目的

实验室需求,需要接入实验室的海康摄像头,通过 web 播放摄像头的视频流,在网页端对实验室的同学进行拍照,截取头像,发送给后台人脸识别系统进行人脸特征提取更新,以便我们的人脸识别系统可以识别实验室同学。当然每个同学都拍几张照片直接录入到我们的人脸识别系统也是可以的,但是相对来说要麻烦很多,直接在网页端通过各种摄像头进行录入人脸应用则更加广泛,也更方便。

2. 开发思路及使用框架

整个系统看起来更像是直播系统,所以当初的设计思路就是按照直播系统来设计的,直播系统可以分成三个部分:推流、视频流服务器、前端播放。

  • 前端播放器播放: 使用 vue.js+element 前端开发框架进行开发
  • 配置视频流服务器: 使用 Nginx 服务器配置成视频流服务器
  • 推流:使用 ffmpeg 进行后台推流

中间遇到了很多坑,整个过程也是经历了各种问题,最后终于完成了自己比较满意的结果,接下来会详细记录下。

在这篇文章中简单介绍下 视频流,视频推流,视频流服务器和视频流播放 相关的理论知识,具体的实践操作,写在另外的博客中,这样看起来好组织。

先来简单说下直播工作原理吧。

3. 直播工作原理

完整的直播包括:

  1. 视频录制端
    电脑上的音视频输入设备或者手机端的摄像头或者麦克风。

  2. 视频播放端
    可以是电脑上的播放器,手机端的 Native 播放器,还有 H5 的 video 标签等。

  3. 流媒体服务器端
    用来接受视频录制端提供的视频源,同时提供给视频播放端流服务。目前开源的流媒体有RED5,CRTMPD,NGINX-RTMP,SRS。

直播原理就如上图所示,真正的直播是比较复杂的,我做的这个其实还是太简单了,少了视频采集、压缩编码、字幕叠加,CDN 等步骤,只是一个简单推流播放功能,功能虽小,但是也可以从某一方面一窥直播的究竟。

4. 视频流相关知识

封装格式 的主要作用是把视频码流和音频码流按照一定的格式存储在一个文件中。

为什么要分封装格式和视频编码格式呢?
这个其实跟网络分七层模型一个原理。解耦和,降低依赖,底层给上层提供基础功能,底层和上层都可以单独扩展,可以以多种方案组合编码与封装,比如MP4与H264、MP4与MPEG、TS与H264等等。比如编码就只负责将最原始的音频和视频数据就行压缩,而压缩完的数据要怎么组织就拜托给上层的封装,封装接到视频音频数据负责给数据编号,指定同步协议,加入字幕等操作。经过封装后,得到的就是可以播放的上面提到的视频文件MP4或者MKV等等。把这个过程反过来就是上图描述的视频播放的过程。

4.1 封装

FLV(Flash Video)是Adobe公司设计开发的一种流行的流媒体格式,FLV可以使用Flash Player进行播放,FLV封装格式的文件后缀通常为“.flv”。总体上看,FLV包括文件头(File Header)和文件体(File Body)两部分,其中文件体由一系列的Tag组成。

特点:视频文件体积轻巧、封装简单

4.2 相关协议

直播领域使用最多的三种协议是:

  1. HLS 协议
  2. RTMP 协议
  3. HTTP-FLV 协议

HLS 协议

HLS 协议即 Http Live Streaming,是由苹果提出基于HTTP的流媒体传输协议。HLS有一个非常大的优点:HTML5可以直接打开播放;这个意味着可以把一个直播链接通过微信等转发分享,不需要安装任何独立的APP,有浏览器即可,所以流行度很高。社交直播APP,HLS可以说是刚需 。HLS 主要是一个 m3u8 的文件,每个文件都是一些 ts 小片段组合在一起。

  • 测试 HLS 协议
    直接在 safari 浏览器中输入以下地址就可以播放了

http://live.streamingfast.net/osmflivech1.m3u8
http://live.streamingfast.net/osmflivech4.m3u8
http://live.streamingfast.net/osmflivech5.m3u8

对于H5视频播放,可以使用 HLS(HTTP Live Streaming)协议播放直播流,iOS和 Android 都天然支持这种协议,配置简单,直接使用 video 标签即可。

使用 video在移动客户端上播放直播视频:

<video controls autoplay>
    <source src="xxx.m3u8" type="application/mpegurl"/>
</video>

HLS是一个由苹果公司提出的基于HTTP的流媒体网络传输协议。

HLS直播最大的不同在于,直播客户端获取到的,并不是一个完整的数据流。

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

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

每一个 .m3u8 文件,分别对应若干个 ts 文件,这些 ts 文件才是真正存放视频的数据,m3u8 文件只是存放了一些 ts 文件的配置信息和相关路径,当视频播放时,.m3u8 是动态改变的,video 标签会解析这个文件,并找到对应的 ts 文件来播放,所以一般为了加快速度,.m3u8 放在 Web 服务器上,ts 文件放在 CDN 上。

支持的视频流编码为H.264,音频流编码为AAC。

简单讲就是把整个流分成一个个小的,基于 HTTP 的文件来下载,每次只下载一些,前面提到了用于 H5 播放直播视频时引入的一个 .m3u8 的文件,这个文件就是基于 HLS 协议,存放视频流元数据的文件。

HLS的分段策略,基本上推荐是10秒一个分片,当然,具体时间还要根据分好后的分片的实际时长做标注

为了缓存等方面的原因,在索引文件中会保留最新的三个分片地址,以“滑动窗口”的形式进行刷新。

.m3u8 文件,其实就是以 UTF-8 编码的 m3u 文件,这个文件本身不能播放,只是存放了播放信息的文本文件。
打开之后就是这个样子:

#EXTM3U                     m3u文件头,必须放在第一行
#EXT-X-MEDIA-SEQUENCE       第一个TS分片的序列号
#EXT-X-TARGETDURATION       每个分片TS的最大的时长
#EXT-X-ALLOW-CACHE          是否允许cache
#EXT-X-ENDLIST              m3u8文件结束符
#EXTINF                     extra info,分片TS的信息,如时长,带宽等
#EXTM3U
#EXT-X-TARGETDURATION:11#EXT-X-VERSION:3#EXT-X-MEDIA-SEQUENCE:0#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:10.133333,
fileSequence0.ts
#EXTINF:10.000666,
fileSequence1.ts
#EXTINF:10.667334,
fileSequence2.ts
#EXTINF:9.686001,
fileSequence3.ts
#EXTINF:9.768665,
fileSequence4.ts
#EXTINF:10.000000,
fileSequence5.ts
#EXT-X-ENDLIST

ts 文件,就是存放视频的文件:

HLS只请求基本的HTTP报文,与实时传输协议(RTP)不同,HLS可以穿过任何允许HTTP数据通过的防火墙或者代理服务器。它也很容易使用内容分发网络来传输媒体流。

HLS 的请求播放流程:

  1. HTTP 请求 m3u8 的 url。

  2. 服务端返回一个 m3u8 的播放列表,这个播放列表是实时更新的,一般一次给出5段数据的 url。

  3. 客户端解析 m3u8 的播放列表,再按序请求每一段的 url,获取 ts 数据流。

HLS直播延时:

我们知道 hls 协议是将直播流分成一段一段的小段视频去下载播放的,所以假设列表里面的包含5个 ts 文件,每个 TS 文件包含5秒的视频内容,那么整体的延迟就是25秒。因为当你看到这些视频时,主播已经将视频录制好上传上去了,所以是这样产生的延迟。当然可以缩短列表的长度和单个 ts 文件的大小来降低延迟,极致来说可以缩减列表长度为1,并且 ts 的时长为1s,但是这样会造成请求次数增加,增大服务器压力,当网速慢时回造成更多的缓冲,所以苹果官方推荐的 ts 时长时10s,所以这样就会大改有30s的延迟。所以服务器接收流,转码,保存,切块,再分发给客户端,这里就是延时的根本原因。

更多关于延迟的问题可以参考苹果官方地址:
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StreamingMediaGuide/FrequentlyAskedQuestions/FrequentlyAskedQuestions.html

HLS优势:

但是 H5 直播视频却有一些不可替代的优势:

  1. 传播性好,利于分享等操作。

  2. 可以动态发布,有利于实时迭代产品需求并迅速上线。

  3. 不用安装 App,直接打开浏览器即可。

不过现在看来使用 HTTP-FLV 既有 HLS 的优势延时也低。

RTMP 协议

Real Time Messaging Protocol是 Macromedia 开发的一套视频直播协议,现在属于 Adobe。

使用RTMP技术的流媒体系统有一个非常明显的特点:使用 Flash Player 作为播放器客户端,而Flash Player 现在已经安装在了全世界将近99%的PC上,因此一般情况下收看RTMP流媒体系统的视音频是不需要安装插件的。用户只需要打开网页,就可以直接收看流媒体。

和 HLS 一样都可以应用于视频直播,区别是 RTMP 基于 flash 无法在 iOS 的浏览器里播放,但是实时性比 HLS 要好。所以一般使用这种协议来上传视频流,也就是视频流推送到服务器。

rtmp 现在大部分国外的CDN已不支持,在国内流行度很高。原因有几个方面:

  1. 开源软件和开源库的支持稳定完整。如斗鱼主播常用的OBS软件,开源的librtmp库,服务端有nginx-rtmp插件。

  2. 播放端安装率高。只要浏览器支持FlashPlayer就能播放RTMP的直播。相对其他协议而言,RTMP协议初次建立连接的时候握手过程过于复杂(RTMP协议本身的交互是基于TCP),视不同的网络状况会带来100ms以上的延迟。基于RTMP延迟在2~5秒。

HTTP-FLV 协议

即使用HTTP协议传输流媒体内容。相对于RTMP,HTTP更简单和广为人知,而且不担心被Adobe的专利绑架。内容延迟同样可以做到2~5秒,打开速度更快,因为HTTP本身没有复杂的状态交互。所以从延迟角度来看,HTTP-FLV要优于RTMP。

不同协议的延时问题

HLS的优点是显而易见的:移动端无需安装APP,使用兼容HTML5的浏览器打开即可观看,所有主流的移动端浏览器基本都支持HTML5,在直播的传播和体验上有巨大的优势。

但是 HLS 最大的问题是延时太高,我在实验室测试播放延时大概在 35 秒左右,这对于我们需要录入人脸数据简直是不能忍受的,一个人站在摄像头之前,等待 35 秒之后才能看到他的图像,这对于谁来说都是在挑战耐心极限。

下面是 HTTP-FLV、HLS 、 RTMP 的对比:

协议 传输层协议 逻辑单元 延时 优点
RTMP TCP RTMP消息 2s 延时低
HTTP-FLV HTTP http报文 2s 延时低
HLS HTTP m3u8文件 10s-30s 跨平台

我们来具体看一下,下图是我在实验室对比测试的图:

上面这张图是 HLS,RTMP,RTSP 之间的对比图, HLS 的延时很明显在 36秒 左右。

上面这张图是 HTTP-FLV,RTMP,RTSP 之间的对比图, HTTP-FLV 的延时和 RTMP 是一样的。

5. 搭建视频流服务器

了解了有关视频流的相关知识,我们接下来实现一个简单的直播系统。直播系统需要三部分:

  1. 推流
  2. 视频流服务器
  3. 视频流播放

这里先讲一下怎么搭建一个推流服务器,因为只有先搭建好了推流服务器才能进行推流,所以这是第一步。

如何搭建一个推流服务器?

简单的推流服务器搭建,服务器需要支持 RTMP ,大概需要以下几个步骤:

  1. 安装一台 nginx 服务器。

  2. 安装 nginx 的 RTMP 扩展,目前使用比较多的是 https://github.com/arut/nginx-rtmp-module 和 https://github.com/winshining/nginx-http-flv-module

  3. 配置 nginx 的 conf 文件

  4. 重启 nginx,将 RTMP 的推流地址写为 rtmp://ip:1935/hls/mystream,mysteam 表示一个实例,这个自己可以随便设置一个

下面是 nginx 的配置文件:
其中 hls_path 表示生成的 .m3u8 和 ts 文件所存放的地址,hls_fragment 表示切片时长,更多配置可以参考:https://github.com/arut/nginx-rtmp-module/wiki/

rtmp {
    server {
        listen 1935;
        chunk_size 4096;

        application live {
            live on;
            max_connections 1024;
        }

        application hls {
            live on;
            hls on;  
            hls_path /etc/nginx/temp/hls;  // 这个路径一定要写绝对路径,不要使用相对路径,否则可能获取不到视频数据,我一开始写的 './temp/hls',结果找了半天问题,很坑,窃注意。
            hls_fragment 5s; 
        }
    }
}

更多详细内容请看我的另一篇博客:H5 直播系统开发之搭建视频流服务器 Nginx

6. 视频推流

所谓推流,就是将我们已经编码好的音视频数据发往视频流服务器中。

视频推流具体操作请看另一篇博客:H5 直播系统开发之搭建视频流服务器 Nginx

7. 播放直播视频

直播视频的参数指标:
码率:影响体积,与体积成正比:码率越大,体积越大;码率越小,体积越小。
帧率:影响画面流畅度,与画面流畅度成正比:帧率越大,画面越流畅;帧率越小,画面越有跳动感。如果码率为变量,则帧率也会影响体积,帧率越高,每秒钟经过的画面越多,需要的码率也越高,体积也越大。
分辨率:影响图像大小,与图像大小成正比:分辨率越高,图像越大;分辨率越低,图像越小。

在 H5 上播放视频流,有很多开源的播放器可以使用,比如

  1. flv.js(B站开源)
  2. ksplayer.js(金山云开源)
  3. vue-video-player(基于vue的)
  4. chimee.js(奇舞团开源)
  5. cyberplayer(百度开源)

以上播放器我都使用过,他们支持不同的协议,可以根据自己的需要进行选择,比如我使用 vue 开发前端页面并需要进行网页截图,有要求延时低,所以我选择了低延时的HTTP-FLV协议,支持这个协议的上面的只有 flv.js 了,所以最终选择了它。

8. 总结

踩了几个月的坑,终于弄好了整好了系统,然后就是把学到的东西记录下来,分享出来,这样可以共同学习交流。实际操作之后会发现其实很简单,需要自己做的并不是很多,但是之前不懂会觉得很难,不断学习不断进步真的是人生常态。


关注微信公众号『极客技术之路

第一时间了解最新动态
关注博主不迷路~

极客技术之路:站内收集的部分资源来源于网络,若侵犯了您的合法权益,请联系我们删除!
分享到:
赞(0)

文章评论

0点赞 0评论 收藏 QQ分享 微博分享

极客技术之路

极客技术之路