前言
前一段时间项目中遇到了网页播放摄像头实时画面的需求,最开始的设计是:
1. 拿到摄像头的rtsp流地址;
2. 通过ffmpeg插件将rtsp流转码为rtmp流,并借助nginx推流;
3. 网页中利用ckplayer.js解析nginx推过来的rtmp流进行展示;
但是由于ckplayer解析rtmp流后要求需要使用Adobe Flash插件才能展示画面,不幸的是Chrome等主流浏览器从2020年12月31日往后就不再支持Adobe Flash。。。。(时间卡的真好),查资料加一顿捣鼓后发现flv.js+nginx-http-flv可以实现相同功能,下面进行一波总结
一.nginx-http-flv配置
下载地址:nginx-http-flv 简单说几点:
1. 我的操作系统环境:windows server 2012
2. 在基于ckplayer.js开发时,只需要rtmp模块足够,但使用flv.js则需要nginx的http-flv模块并配置http服务
3. 注意!!!如果你需要同时展示6个以上画面,建议配多个http服务
我在http模块中配置了两个服务,分别监听8038端口和8039端口,正常来说一个服务足够,但由于浏览器同源策略,同源请求(就是协议,端口(如果有指定)和域名都相同的请求)在Chrome的一个网页中最多存在6个(网站升级为HTTP2.0的略过),后面的会阻塞,因此如果网页中需要同时直播6个以上画面的话(我的需要8个),可以按我的方法配置两个服务分别推流即可
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#error_log logs/error.log debug;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
# 添加RTMP服务
rtmp {
server {
listen 1935;
chunk_size 4000;
application live {
live on;
gop_cache on;
}
}
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 8038;
server_name 127.0.0.1;
location /live {
flv_live on;
chunked_transfer_encoding on; #open 'Transfer-Encoding: chunked' response
add_header 'Access-Control-Allow-Credentials' 'true'; #add additional HTTP header
add_header 'Access-Control-Allow-Origin' '*'; #add additional HTTP header
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
add_header 'Cache-Control' 'no-cache';
}
}
server {
listen 8039;
server_name 127.0.0.1;
location /live {
flv_live on;
chunked_transfer_encoding on; #open 'Transfer-Encoding: chunked' response
add_header 'Access-Control-Allow-Credentials' 'true'; #add additional HTTP header
add_header 'Access-Control-Allow-Origin' '*'; #add additional HTTP header
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
add_header 'Cache-Control' 'no-cache';
}
}
}
配置文件配好后,双击nginx.exe
二.ffmpeg插件推流
ffmpeg插件的推流办法,网上资料已有很多,本地测试时使用cmd命令即可
D:\\Program Files\\ffmpeg-20200831-4a11a6f-win64-static\\bin\\ffmpeg -thread_queue_size 100000 -i rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov -vcodec libx264 -preset:v medium -tune:v zerolatency -profile:v main -acodec copy -f flv -s 420*260 -an rtmp://127.0.0.1:1935/live/test2
其中:rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov为视频的rtsp流地址(这里引用的是公网上的一个可用测试地址),420*260为我需要的视频尺寸大小,rtmp://127.0.0.1:1935/live/test2为rtmp流地址,D:\Program Files\ffmpeg-20200831-4a11a6f-win64-static\bin\ffmpeg为ffmpeg.exe的路径,这四处在使用时替换为实际需要的即可。
如果项目里需要动态推流,则使用代码动态执行上面命令生成进程,java里执行代码为
try {
Process process = Runtime.getRuntime().exec("D:\\Program Files\\ffmpeg-20200831-4a11a6f-win64-static\\bin\\ffmpeg -thread_queue_size 100000 -i rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov -vcodec libx264 -preset:v medium -tune:v zerolatency -profile:v main -acodec copy -f flv -s 420*260 -an rtmp://127.0.0.1:1935/live/test2");
} catch (IOException e) {
e.printStackTrace();
}
可以对process进行监听,获取ffmpeg进程的实时状态来进行异常中断后的重新推流等后续操作。
三.flv.js解析流
前端只需要引入flv.min.js,代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>flv.js test</title>
<link rel="stylesheet" href="dplayer.css"/>
<script src="flv.min.js"></script>
</head>
<body>
<video muted id="videoElement1" width="420" height="260"></video>
<video muted id="videoElement2" width="420" height="260"></video>
<video muted id="videoElement3" width="420" height="260"></video>
<video muted id="videoElement4" width="420" height="260"></video>
<video muted id="videoElement5" width="420" height="260"></video>
<video muted id="videoElement6" width="420" height="260"></video>
<video muted id="videoElement7" width="420" height="260"></video>
<video muted id="videoElement8" width="420" height="260"></video>
<script>
//flvjs.LoggingControl.enableAll = false;
for(var i = 1;i < 9;i++){
var videoElement1 = document.getElementById('videoElement'+i);
//前6个解析8038端口推过来的流,后两个使用8039端口
var port = 8038;
if(i < 7){
port = 8039;
}
var flvPlayer = flvjs.createPlayer({
type: 'flv',
isLive: true,
url: 'http://localhost:'+port+'/live?port=1935&app=live&stream=test2'
});
flvPlayer.attachMediaElement(videoElement1);
flvPlayer.load();
flvPlayer.play();
}
</script>
</body>
</html>
其中后两个视频画面是对8039端口的流解析渲染而成,实际浏览器效果如下图