场景: 在页面上选择摄像头,弹出窗口展示摄像头的监控视频
思路:在点选摄像头时根据选中的摄像头id,去数据库中读取rtsp地址,调用ffmpeg命令转换成hls格式,返回hls地址给前端,通过videojs进行播放
首先来搭建环境
环境说明:
1. 视频服务器(linux,java8,nginx 1.16.1)
2. 开发机 win10 ,影响不大
服务搭建部分参考
搭建视频服务需要用到nginx的nginx-rtmp-module
wget和unzip通过yum安装
yum install wget
yum install unzip
# mkdir module // 创建下载module的文件夹
# cd module
# wget https://github.com/arut/nginx-rtmp-module/archive/master.zip //下载模块
# unzip master.zip // 解压
# yum -y install pcre-devel openssl openssl-devel //安装依赖
# wget http://nginx.org/download/nginx-1.12.2.tar.gz //下载nginx包
# tar -zxvf nginx-1.12.2.tar.gz
# ./configure --prefix=/opt/nginx-1.9.5 --add-module=/root/module/nginx-rtmp-module-master --with-http_ssl_module // 编译安装nginx到/opt/nginx-1.9.5
# make
# make install
rtmp{
server {
listen 1935;
application myapp{
live on;
record off;
allow play all;
}
application hls{
live on;
hls on;
hls_path /tmp/hls;
hls_fragment 10s;
hls_playlist_length 3s;
record off;
}
}
}
注意:rtmp协议和http协议不同,需要写在http外面
由于使用hls播放,需要在http中添加支持, 因为服务在8002端口 所以在nginx监听的8002端口下添加配置 /hls 部分,并添加跨域处理
server {
listen 8002;
server_name server_name;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
allow 172.30.17.243;
deny all;
}
location / {
root /opt/vue/well/dist;
index index.html;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept";
add_header Access-Control-Methods "GET, POST, OPTIONS";
}
location /hls/ {
types {
application/vnd.apple.mpegusr m3u8;
video/mp2t ts;
}
root html;
add_header Cache-Control no-cache;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept";
add_header Access-Control-Methods "GET, POST, OPTIONS";
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
nginx安装完后如果想直接运行,还需要将nginx配置到环境变量中,此处不多介绍
# nginx -s reload
# yum install yasm -y
# git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg //下载ffmpeg
# cd ffmpeg
# ./configure --prefix=/usr/local/ffmpeg
# make
# make install
# ls /usr/local/ffmpeg/
bin include lib share
# cp /usr/local/ffmpeg/bin/* /usr/bin/
测试通过vlc进行测试
ffmpeg -rtsp_transport tcp -i rtsp://admin:[email protected]/8000 -acodec aac -strict experimental -ar 44100 -ac 2 -b:a 96k -r 25 -b:v 500k -s 640*480 -f flv rtmp://xxx.xx.xx.xxx:1935/myapp/23
成功之后下面会出来一堆东西 一跳一跳的,
之后打开VLC->右键打开媒体->打开网络->输入你的rtmp地址进行测试
此时ffmpeg的命令使用,将在html文件夹生成test.m3u8文件
ffmpeg -f rtsp -rtsp_transport tcp -i rtsp://admin:[email protected]/8000 -c copy -f hls -hls_time 2.0 -hls_list_size 1 -hls_wrap 15 /usr/local/nginx/html/hls/test.m3u8
在VLC中通过 http://视频服务ip:8002/hls/test.m3u8进行访问
注:8002是 nginx中 /hls 所在监听端口
在java调用ffmpeg命令时愁了好久,后来找到了git上的一个项目,帮助很大
http://github.com/eguid/FFCH4J,将其引入到项目ffmpeg目录中
遇到的坑:
部分代码如下
controller部分
@Autowired
CommandManager manager;
/**
* start
* @param id
* @return
* @throws Exception
*/
@RequestMapping(value = "toHls2", method = RequestMethod.GET)
@CrossOrigin
public void toHls(@RequestParam String id) throws Exception
{
// 省略查询路径部分 实体-> result
manager.stop(id); // 先停止视频
manager.start(id, CommandBuidlerFactory.createBuidler()
.add("ffmpeg").add("-f","rtsp")
.add("-rtsp_transport","tcp")
.add("-i", result.getVideoUrl()) // 取videoUrl
.add("-c", "copy")
.add("-f", "hls")
.add("-hls_time", "2.0")
.add("-hls_list_size", "1")
.add("-hls_wrap","15")
.add("/usr/local/nginx/html/hls/" + id + ".m3u8"));
return "视频路径"
}
停止转换部分如果不删除m3u8文件,videojs会直接调用之前停止时的m3u8文件,里面有终止符,导致视频无法继续播放
@Autowired
CommandManager manager;
/**
* stop
* @param id
* @return
* @throws Exception
*/
@RequestMapping(value = "stop", method = RequestMethod.GET)
@CrossOrigin
public ObjectRestResponse stop(@RequestParam String id) throws Exception
{
ObjectRestResponse objectRestResponse = new ObjectRestResponse();
manager.stop(id);
manager.start(id, CommandBuidlerFactory.createBuidler()
.add("rm -rf","/usr/local/nginx/html/hls/"+ id + ".m3u8"));
objectRestResponse.setData("");
return objectRestResponse;
}
思路:调用接口返回地址成功后给video的src重新赋值
var player = videojs('my-video');
player.src([
{type:"application/x-mpegURL", src: res.data}
])
this.player.load();
this.player.play();
}, 3000);