直播在互联网中已经成为一个必不可少的东西,话说各大直播平台 bilibili,虎牙,斗鱼都准备上市了。javascript
富途证券做为了一家互联证券公司直播固然也少不了的。目前直播在富途牛牛软件(如下简称:牛牛)中主要功能是教育跟宣传做用。css
富途牛牛为领先的港股美股交易软件。html
目前牛牛支持状况:java
移动牛牛(安卓、IOS)主播端只支持摄像头直播,观众端支持展现nginx
PC牛牛主播端支持摄像头直播、录屏直播、摄像头+录屏直播,观众端支持展现git
MAC牛牛跟web端主播端不支持,观众端支持展现github
视频直播能够分为采集,前处理,编码,传输,解码,渲染 这几个环节。web
通常是由客户端(IOS、安卓、PC或其它工具,如OBS)完成的,iOS是比较简单的,Android则要作些机型适配工做,PC最麻烦各类奇葩摄像头驱动,固然这些问题,腾讯云已经帮咱们处理好了,呵呵。算法
主要是处理直播美颜,美颜算法须要用到GPU编程,须要懂图像处理算法的人,没有好的开源实现,要本身参考论文去研究。难点不在于美颜效果,而在于GPU占用和美颜效果之间找平衡。chrome
确定要采用硬编码,软编码720p彻底没但愿,勉强能编码也会致使CPU过热烫到摄像头。编码要在分辨率,帧率,码率,GOP等参数设计上找到最佳平衡点。
通常交给了CDN服务商。
是对以前编码的操做,进行解码,在web里须要解码是HLS。
主要用播放器来解决,web中经常使用到的播放器有 video.js ,目前咱们使用是腾讯云播放器。
其实一个完成直播,远远不上面这几个环节,下面是腾讯云直播方案的整个流程图:
目前互联网上web作直播,主要是展现,主流web展现的话可能涉及到HLS跟RTMP这两个东西,如今咱们重点讲解hls跟RTMP协议。
HLS(HTTP Live Streaming全称)是一个基于HTTP的视频流协议,由Apple公司实现,Mac OS上的QuickTime、Safari 以及iOS上的 Safari都能很好的支持 HLS,高版本 Android 也增长了对 HLS 的支持。
一些常见的客户端如:MPlayerX、VLC 也都支持HLS协议,若是须要在chrome上播放,须要使用 videojs-contrib-hls.js 解析。
HLS工做流程图
HLS的服务器组件负责获取的媒体输入流 , 而后Media编码后 MPEG-4(H.264 video 和 AAC audio)格式而后用硬件打包到 MPEG-2 (MPEG-2 transport stream)的传输流中。图中显示,传输流会通过stream segmenter, 这里的工做是MPEG-2传输流会被分散为小片断而后保存为一个或多个系列的 .ts 格式的媒体文件。这个过程须要借助编码工具来完成,好比 Apple stream segmenter。 (视频类是.ts文件,纯音频会被编码为一些音频小片断,一般为 ADTS头的AAC、MP三、或者 AC-3格式。) 服务端能够采用硬件编码和软件编码两种形式,其功能都是按照上文描述的规则对现有的媒体文件进行切片并使用索引文件进行管理。而软件切片一般会使用 Apple 公司提供的工具或者第三方的集成工具。
同时上面提到的那个切片器(segmenter)也会建立一个索引文件,一般会包含这些媒体文件的一个列表,也能包含元数据。它通常都是一个个.M38U的列表。列表元素会关联一个 URL 用于客户端访问。而后按序去请求这些 URL。
索引文件结构图
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=409037,RESOLUTION=416x234,CODECS="mp4a.40.2, avc1.42001e"
Gear1/prog_index.m3u8
复制代码
第一行:#EXTM3U
每一个M3U文件第一行必须是这个tag,起标示做用
第二行:#EXT-X-STREAM-INF
标签的属性列表中直接指明当前流是VIDEO仍是AUDIO
包含属性 :
#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
复制代码
#EXTM3U m3u文件头,必须放在第一行。
#EXT-X-TARGETDURATION 每一个分片TS的最大的时长。
#EXT-X-VERSION 用以标示协议版本。
#EXT-X-MEDIA-SEQUENCE TS分片的序列号。
#EXT-X-PLAYLIST-TYPE 提供关于PlayList的可变性的信息, 这个对整个PlayList文件有效,是可选的。
#EXTINF extra info,分片TS的信息,如时长,带宽等。
分配组件由标准的网络服务器。他们负责接受Client客户端请求并提供相关联的资源给客户端。
videojs-contrib-hls.js解析图
HLS简单讲就是把整个流分红一个个小的片断,基于 HTTP 的文件来下载,每次只下载一小部分。
前面提到了用于 H5 播放直播视频时引入的一个 .m3u8 的文件,这个文件就是基于 HLS 协议,存放视频流元数据的文件。
每个 .m3u8 文件,分别对应若干个 ts 文件,这些 ts 文件才是真正存放视频的数据,m3u8 文件只是存放了一些 ts 文件的配置信息和相关路径,当视频播放时,.m3u8 是动态改变的,再经过解析器(videojs-contrib-hls.js)解析这个文件,并找到对应的 ts 文件来播放,因此通常为了加快速度,.m3u8 放在 web 服务器上,ts 文件放在 cdn 上。
Real Time Messaging Protocol(简称 RTMP)是 Macromedia 开发的一套视频直播协议,如今属于 Adobe。这套方案须要搭建专门的 RTMP 流媒体服务如 Adobe Media Server,而且在浏览器中只能使用 Flash 实现播放器。它的实时性很是好,延迟很小,但没法支持移动端 WEB 播放是它的硬伤。
浏览器端,HTML5 video标签没法播放 RTMP 协议的视频,能够经过 video.js
来实现。
<link href="http://vjs.zencdn.net/5.8.8/video-js.css" rel="stylesheet">
<video id="example_video_1" class="video-js vjs-default-skin" controls preload="auto" width="640" height="264" loop="loop" webkit-playsinline>
<source src="rtmp://10.14.221.17:1935/rtmplive/home" type='rtmp/flv'>
</video>
<script src="http://vjs.zencdn.net/5.8.8/video.js"></script>
<script> videojs.options.flash.swf = 'video.swf'; videojs('example_video_1').ready(function() { this.play(); }); </script>
复制代码
协议 | 原理 | 延时 | 优势 | 缺点 | 使用场景 |
---|---|---|---|---|---|
HLS(http) | 集合一段时间数据生成ts切片文件更m3u8文件 | 10s-30s | 跨平台 | 延时性高 | 移动端 |
RTMP(TCP) | 每一个时刻的数据收到后当即发送 | 2s | 延时低、实时性好 | 跨平台差 | PC+直播+实时性要求高+互动性强 |
brew install nginx
复制代码
brew install nginx-full --with-rtmp-module
复制代码
而后安装FFmpeg(是一个集录制、转换、音/视频编码解码功能 为一体的完整的开源工具,咱们下面用它来作推流跟切片)。
brew install ffmpeg
复制代码
查找到nginx.conf配置文件(/usr/local/etc/nginx/nginx.conf),并配置相应的直播流配置。
rtmp {
server {
#监听的端口
listen 1935;
# RTMP 直播流配置
application rtmplive {
live on;
#为 rtmp 引擎设置最大链接数。默认为 off
max_connections 1024;
}
# HLS 直播流配置
application hls{
live on;
hls on;
hls_path /Users/youname/Documents/notes/live/public/hls; #这里的路径切片须要保存的路径
hls_fragment 1s;
}
}
}
复制代码
在http中添加 HLS 的配置:
location /hls {
# Serve HLS fragments
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /Users/youname/Documents/notes/live/public;#切片的路径
#add_header Cache-Controll no-cache;
expires -1;
}
复制代码
sudo nginx -s reload
复制代码
netstat -an | grep 1935
复制代码
若是显示以下,显示已经启用。
http端口同理。
到如今咱们已经完成了,服务的搭建。
咱们以推流MP4文件为例,个人视频文件地址:/Users/youname/Desktop/w01661pl9vw.p702.1.mp4
RTMP 协议推流命令:
ffmpeg -re -i /Users/youname/Desktop/w01661pl9vw.p702.1.mp4 -vcodec libx264 -acodec aac -f flv rtmp://127.0.0.1:1935/rtmplive/home
复制代码
HLS 协议推流命令:
ffmpeg -re -i /Users/youname/Desktop/w01661pl9vw.p702.1.mp4 -vcodec libx264 -vprofile baseline -acodec aac -ar 44100 -strict -2 -ac 1 -f flv -q 10 rtmp://127.0.0.1:1935/hls/test
复制代码
参数:
上面的命令操做后,命令行出现了以下图,表示已经成功了。
关于FFmpeg功能命令可参考:FFmpeg功能命令集合
两种推流方式播放的话,咱们都使用video.js播放器播放(牛牛里使用的是腾讯云播放器)
须要注意的是src中的地址填的是RTMP推流地址。播放时,若是出现“当前系统环境不支持播放该视频格式”,浏览器须要启用flash,才能正常播放。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link href="http://vjs.zencdn.net/5.19/video-js.min.css" rel="stylesheet">
<script src="http://vjs.zencdn.net/5.19/video.min.js"></script>
</head>
<body>
<video id="my-player" class="video-js" controls preload="auto" data-setup='{}'>
<source src='rtmp://127.0.0.1/rtmplive/home' type='rtmp/flv'/>
</p>
</video>
<script type="text/javascript"> var player = videojs('my-player'); var options = {}; var player = videojs('my-player', options, function onPlayerReady() { videojs.log('Your player is ready!'); // In this context, `this` is the player that was created by Video.js. this.play(); // How about an event listener? this.on('ended', function() { videojs.log('Awww...over so soon?!'); }); }); </script>
</body>
</html>
复制代码
下面的src填的是切片地址。
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>videojs-contrib-hls embed</title>
<link href="https://unpkg.com/video.js/dist/video-js.css" rel="stylesheet">
<script src="https://unpkg.com/video.js/dist/video.js"></script>
<script src="https://unpkg.com/videojs-contrib-hls/dist/videojs-contrib-hls.js"></script>
</head>
<body>
<video id="my_video_1" class="video-js vjs-default-skin" controls preload="auto" width="640" height="268" data-setup='{}'>
<source src="http://www.tony.com/hls/test.m3u8" type="application/x-mpegURL">
</video>
</body>
</html>
复制代码
咱们来看看真正的效果如何。
RTMP效果图
HLS效果
ts和m3u8文件
在X5内核浏览器里必须使用触发touchend、click、doubleclick或keydown事件等标准的事件才能触发。
安卓下不少浏览器把video标签替换成了原生自带播放器样式跟行为,很难控制其行为跟样式。
目前使用的是weinre调试,但weinre调试看不到在native实际效果,好比web调用native,须要native反馈一种效果,weinre是看不到效果。
schema跟jsBridge,schema只能作到web调用native,并且作不到native调用web;jsBridge虽然能够作native调用web,但在iframe没加载完的状况下,也是通知不到web的;
整个直播是一个很是复杂的过程,实现过程当中会遇到不少性能问题,须要在性能跟即时性作一个权衡,ts跟m3u8尽可能作到缓存,浏览器里尽可能使用推流。
欢迎你们关注富途web开发团队,原文连接