项目中需要在浏览器中播放Camera的监控视频,之前对视频监控不太了解,以为只要是Ip camera出来的视频流通过H5的Video控件就能直接播放,实际测试时发现不是那么容易,网上也有很多种方法,但大多都是介绍性的内容,而且很多代码也会因为各种原因无法运行,比如框架库的更新,代码不全等导致很多编译和运行错误,因此在深入的分析和验证了每个方法的可行性的基础上,总结出这篇文章,希望对有类似需求的人有所帮助。在实现这个需求前,首先需要脑补一下与视频相关的知识。
背景知识
主流的视频传输协议
Http Live Streaming(HLS)
是苹果公司实现的基于Http的流媒体传输协议,可实现流媒体的直播以及点播,HLS传输协议与其他传输协议的不同在于客户端获取到的并不是一个完整的数据流,而是将数据流存储为连续的、短时长的媒体文件,即MPEG-TS格式的文件,客户端这是通过不断的下载这些小文件,然后进行按顺序的播放从服务器那边获取到的文件,就实现了视频的直播效果 。而且数据是通过Http来传输的,就不用担心防火墙或者代理的问题,唯一的缺点就是延迟会比其他传输协议大一些。
Real Time Messaging Protocol(RTMP)
主要采用TCP传输,如果互联网的环境较差,采用RTMP可以保证视频的传输质量,但是延迟还是相对来说有点高。使用RTMP有个特点,就是使用 Flash Player 作为播放器客户端,而Flash Player 现在已经安装在了全世界将近99%的PC上,因此一般情况下收看RTMP流媒体系统的视音频是不需要安装插件的。实时视频采用RTMP作为流媒体传输协议,FLV作为封装格式,直播服务器可以选择Nginx+rtmp实现,客户端采用librtmp进行推流,FFmpeg负责编解码,查看视频采用VLC即可。
Real Time Serial Protocol(RTSP)
由Real network 和 Netscape共同提出的如何有效地在IP网络上传输流媒体数据的应用层协议,相对于其余两种协议来说实时性是比较高的,并且易于扩展,新的一些方法和参数都是比较容易加入RTSP, 独立于传输 RTSP传输通道,可使用不可靠数据包协议(UDP)或可靠数据包协议(RDP)。RTSP还是一种双向实时数据传输协议,它允许客户端向服务器端发送请求,如回放、快进、倒退等操作。
常见IP Camera传输协议
RTSP/H.264: 这类型的摄像头通常用于安防场合。它们使用RTSP协议来建立一个RTP媒体会话。换句话说,媒体传输时通过RTSP发生的信令基于plain(简单的)RTP。不同的摄像头厂商可能支持不同的RTP规格,但是就我看到的大部分摄像头而言,AVP是唯一可用的选项。在这些摄像头中,同样典型的,H.264是编解码器唯一的选项。
HTTP/MJPEG: 这类型摄像头使用HTTP流来signaling,传输,将一系列的JPEG图像编码为视频。这些摄像头的硬件相对更简单,只需要很少的资源来操作。这就是为什么他们被更多用在电池功耗或者在意负载的场合(如机器人,无人机等)。不足的是,它们的视频质量显著下降。
海康,大华,霍尼等安防领域的摄像头目前都支持是RTSP传输协议。
HTML5 Video支持的格式
有了上面的知识后,就发现直接在浏览器中播放当前主流IP Camera的视频是不太可能,因为Ip camera出来的视频流不被H5支持。在网上收集了很多的方案,认为以下几个方案可行性比较高,所以就列举出以下的方案分别验证。
常见方案汇总
商业流媒体代理服务
Streamedian
H5Stream
浏览器插件
VLC插件
VXG插件
开源的WebRTC服务
Kurnto
WebRTCStreamer
基于Ffmpeg搭建流媒体服务
Transcode from RTSP to HLS
商业流媒体服务
零视技术(H5Stream)
现在有很多这种流媒体云服务,包括阿里云也提供了视频流解决方案,我收集了两个出现频率比较高的流媒体云服务,一个是国内一家公司,叫零视技术的物联网视频解决方案。它支持RTSP/RTMP拉流/RTMP推流/GB28181 摄像机NVR集成,支持HLS/RTSP/RTMP/WS/RTC 服务,并且在不转码的情况下支持H.264。参考产品官网:
https://www.linkingvision.cn/product/h5stream
Streamedian
它提供了对RTSP流进行转换为MP4文件,并提供了一个Javascript库来实时播放视频流。功能应该没有H5Stream强大,支持的格式也比较少。下面是它的架构图和官网:
https://streamedian.com/
小结
如果要求支持所有的视频流和协议格式比较多,建议使用H5Stream,搭建云流媒体服务。
如果是仅支持有限格式的视频流和协议,建议使用Streamedian,它提供了免费的license,只支持部署一个ip或域名,两个浏览器同时浏览。
浏览器插件
有两种浏览器插件,VLC和VXG两个插件可以直接播放RTSP和RTMP的视频流,我们也可以使用这两个工具来测试RTSP和RTMP的视频流。
VLC视频播放软件下载:
https://www.videolan.org/vlc/index.zh_TW.html
VXG视频播放软件下载:
https://www.chromefor.com/vxg-media-player_v1-8-44/
VLC插件
安装 VLC 客户端,直接在浏览器中调用 VLC 的视频控件,通过监控视频 RTSP 串流进行预览。该方式调用时比较方便,在360安全浏览器的极速模式下是可运行的,但是在谷歌和Firefox等浏览器依旧因为插件的原因不能预览。具体参考这篇文章可以验证:
https://videoconverter.wondershare.com/vlc/vlc-web-plugins-for-top-browsers.html#part1
VXG插件
VXG插件的播放方式,首先在chrome里搜索VXG,安装Chrome VXG插件,然后下载Github上的代码
https://github.com/aitexiaoy/rtsp_chrome_demo
就可以通过VXG插件来播放RTSP视频流。
小结
通过插件方式来播放视频流,对用户不够友好,需要安装插件,特别是在国内还无法在线安装Chrome插件,只能离线安装,比较麻烦,而且随时有被Chrome disable的风险。
VLC插件只能适用于360浏览器,不适用于Chrome和Firefox浏览器
VXG插件会在视频中出现VXG三个字样的水印,影响使用,如果需要去除水印,需要付费
VXG只支持HTTP
优点就是开发比较简单,不需要搭建流媒体服务,适合于快速Demo视频流这种场景
开源的WebRTC服务
WebRTC,即Web Real-Time Communication, web实时通信技术。简单地说就是在web浏览器里面引入实时通信,包括音视频通话等。WebRTC实现了基于网页的语音对话或视频通话,目的是无插件实现web端的实时通信的能力。
WebRTC提供了视频会议的核心技术,包括音视频的采集、编解码、网络传输、展示等功能,并且还支持跨平台,包括linux、windows、mac、android等。虽然WebRTC主要用于在Chrome中视频聊天,但我们也可以利用它来进行视频转换,将视频流转成WebRTC协议,然后可以在支持WebRTC协议的浏览器上直接播放。我验证了两个WebRTC技术,webrtc-streamer和kurento。
webrtc-streamer
WebRTC-streamer是一个将RTSP流转成WebRTC的开源demo,它提供了restful service来视频转换请求,并使用Ajax在前端发起视频转换请求和播放视频。使用Docker进行部署。官网:
https://github.com/mpromonet/webrtc-streamer
提供的api如下:
/api/call : send offer and get answer
/api/hangup : close a call
/api/addIceCandidate : add a candidate/api/getIceCandidate : get the list of candidates
Kurento
Kurento 是一个开源的WebRTC媒体服务,它提供了一系列的Client API,使得在移动和浏览器上开发视频应用变得简单。它可以进行分组视频通讯,视频转码,录像,广播等功能,是一个功能比较强大的视频流媒体服务。但是它提供的Demo程序因为版本不兼容的问题,没有测试成功。git网址:
https://github.com/Kurento
我测试的方法是使用它提供的Kurento javascript util库来实现,实现方式参考开源demo:
https://github.com/lulop-k/kurento-rtsp2webrtc
测试没有任何错误抛出,但无法显示视频页面,可能是因为服务器版本和此demo程序版本不匹配导致,demo的代码比较久远。但kurento自身库中提供的demo样例有明显的语法错误,因为demo代码还没来得及更新,使用的js库在代码中不能找到,期望以后更新再进行测试。
小结
对比了这两种开源的WebRTC技术,Kurento开源社区更活跃,WebRTC-Streamer相比之下功能比较简单,但WebRTC更加适合的场景是多人视频聊天,技术也相当复杂,对于IP Camera的实时播放有点大材小用的味道。
基于Ffmpeg视频流媒体服务
这种开发方式是当前大部分网站推荐的视频实时播放方法,实现方式的步骤可以参考以下博客,很多文章中都给出的是此方法,但没有一个完整的实例
https://blog.csdn.net/weixin_41774153/article/details/98082280
自己部署比较麻烦,现在docker技术已经可以完全简化部署,因此推荐使用docker部署,比较简单。我使用下面的docker部署方式,并针对ffmpeg的新版本做了脚本更新,并且在镜像中增加了一个测试实例。更新的脚步部分下面会详细给出脚本代码,其他参考git上的脚本,下面是我部署后的架构图。
https://github.com/gihad/streamer
1)Dockerfile
在docker file里更新了ffmpeg版本,创建了一个网站目录,来部署html网站。
FROM alpine:3.12
# Install nginx and ffmpeg
RUN apk add --update nginx ffmpeg && rm -rf /var/cache/apk/* && mkdir /tmp/stream && mkdir /tmp/examples
COPY nginx/nginx.conf /etc/nginx/nginx.conf
COPY examples /tmp/examples
COPY ./startup.sh /
COPY ./create_ffmpeg_cmd.sh /
RUN ["chmod", "+x", "/startup.sh"]
RUN ["chmod", "+x", "/create_ffmpeg_cmd.sh"]
CMD ["/startup.sh"]
2)ffmpeg命令
为了防止生成的ts文件重名,因此使用时间戳的方式来命名ts文件,保证部署多个ip camera摄像头下不会出现重名。此外,新增了一个参数在忽略网络连接引起的错误。-hls_start_number_source datetime -ignore_io_errors 1
#!/bin/sh
OUTPUT_PATH=/tmp/stream/
DEFAULT_AUDIO="copy"
DEFAULT_VIDEO="copy"
LACKING_AUDIO=""
IS_RTSP=""
INPUT=$1
OUTPUT=$2
# Check if codecs are already in the format supported by Chromecast devices (aac for audio and h264 for video)
AUDIO_RESULT="$(ffprobe -v error -select_streams a:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 $INPUT)"
VIDEO_RESULT="$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 $INPUT)"
if [ "$AUDIO_RESULT" != "aac" ]; then
DEFAULT_AUDIO=aac
fi
# Check if it's empty to add silent dummy stream
if [ -z "$AUDIO_RESULT"]; then
LACKING_AUDIO="-f lavfi -i aevalsrc=0"
fi
if [ "$VIDEO_RESULT" != "h264" ]; then
DEFAULT_VIDEO=h264
fi
if [ "$INPUT" == rtsp://* ]; then
IS_RTSP="-rtsp_transport tcp"
fi
FFMPEG_CMD="ffmpeg -rtsp_transport tcp -i ${INPUT} ${LACKING_AUDIO} -acodec ${DEFAULT_AUDIO} -vcodec ${DEFAULT_VIDEO} -hls_start_number_source datetime -ignore_io_errors 1 -hls_list_size 2 -hls_init_time 1 -hls_time 1 -hls_flags delete_segments ${OUTPUT_PATH}${OUTPUT}.m3u8"
echo "${FFMPEG_CMD}"
3)Nginx的配置
在原有的Nginx配置下,新增了一个测试网站来测试视频的播放。网站代码放在/tmp/examples目录下。
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
sendfile off;
tcp_nopush on;
directio 512;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
server {
listen 80;
location / {
# Disable cache
add_header 'Cache-Control' 'no-cache';
# CORS setup
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length';
# allow CORS preflight requests
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
types {
application/dash+xml mpd;
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /tmp/stream;
}
location /examples {
root /tmp/;
}
location ~ \.css {
default_type text/css;
root /tmp/;
}
location ~ \.js {
default_type application/x-javascript;
root /tmp/;
}
}
}
4)部署测试程序
在Chrome下播放HLS协议的视频需要使用开源库video js和h5 video控件,video.js是一个通用的在网页上嵌入视频播放器的javascript库,Video.js会自动检测浏览器对html5的支持情况,如果不支持html5则自动使用Flash播放器。
https://videojs.com/getting-started/
这是官网,使用Safari不需要使用videojs,只需要使用h5 video控件。
5)NPM安装video js
npm install --save-dev video.js
6)测试网页
<!DOCTYPE html>
<html lang="en">
<head>
<title>Video.js | HTML5 Video Player</title>
<link href="../node_modules/video.js/dist/video-js.min.css" rel="stylesheet">
<script src="../node_modules/video.js/dist/video.min.js"></script>
</head>
<body>
<video muted="muted" id="example_video_1" class="video-js" controls width="640" height="264"
data-setup='{ "autoplay": true, "preload": "auto","loadingSpinner": false }'>
<source src="http://your ip address:8089/hello1.m3u8" type="application/x-mpegURL">
</video>
</body>
</html>
注意chrome中不支持视频自动播放,如果需要自动播放,需要设置muted,因此在video中设置muted为"muted"。
7)Build docker镜像
docker build . -t gihad/streamer
8)运行docker容器
docker run -e PARAMETERS='rtsp://username:password@192.168.1.55:554/cam/realmonitor?channel=1&subtype=0 hello' -v /tmp/stream:/tmp/stream -v /home/deploy/streamer-master/examples:/tmp/examples -v /home/deploy/streamer-master/nginx/nginx.conf:/etc/nginx/nginx.conf -p 8089:80 gihad/streamer
为了便于调试,我把测试网页源码和nginx配置文件和生成的m3u8路径都外挂到宿主机的/home/deploy/streamer-master文件夹下,192.168.1.55是IP camera的地址,username和password是IP Camera的用户名和密码,tmp/stream是转换的m3u8和ts文件的路径。
9)运行测试网站
使用Chrome打开http://your server ip:8089/examples/index.html,即可以实时播放IP Camera视频。
写在最后
随着视频直播技术的迅猛发展,在浏览器中无插件播放视频未来肯定会越来越简单,Webrtc技术肯定会成为未来的发展趋势。但现阶段成本最低的播放方式应该是基于浏览器插件的播放方式,不需要搭建流媒体服务。而纵观整个视频相关技术,视频播放只是其中一个很小的部分,视频实时通讯(RTC)从功能流程上来说,包含采集、编码、前后处理、传输、解码、缓冲、渲染等很多环节。每一个细分环节,还有更细分的技术模块。