一、准备工作
1、前言
最近在项目中需要在网页和手机app端进行视频预览和控制,本文就如何搭建视频流媒体服务、海康视频推流和拉流播放(rtsp流转rtmp流)、云台控制等功能进行讲解。
软件环境:服务器为windows2016,jdk1.8,tomcat9,mysql8.0,Springboot1.5。
2、业务分析
1.使用海康威视的官方SDK访问摄像头,获取摄像头可用通道号,组装rtsp地址,获取摄像头的实时rtsp视频流。
2.使用FFmpeg将rtsp流转换成rtmp流供网页显示。(注:rtsp流不可以直接用网页播放)
-注1:FFmpeg支持转mp4,webm,ogg等多种前言音视频文件的格式转换;
-注2:本文使用rtmp流,有其他需求的小伙伴可以使用FFmpeg转成其他格式;
3.服务器搭建集成nginx-rtmp插件的nginx服务,将转换的rtmp流推送至nginx制定代理地址,实现外网访问。
4.前端页面使用免费的前端H5插件video.js实现实时预览
-注1:video.js支持mp4,webm,ogg三种格式的文件的播放。
-注2:rtmp流属于flv格式只能用flash播放,故需要flash插件支持;(谷歌浏览器从2020年12月31日后不再支持flash(目前2020年12月15日还能播放),可以使用360浏览器播放)
-注3:video.js只有一些版本支持flash,故要选好版本(本文使用的是v5.20.5);–v6、7版本不支持flash
二、环境安装
第一步:安装VLC播放器,测试摄像头是否正常。
(文章最后的下载链接中有地址,注意区分是32位还是64位,我用的是vlc-3.0.6-win64.exe)
vlc–打开媒体–网络–输入以下url–下拉中选择播放,即可预览视频。
rtsp://admin:a123456@10.192.44.101:554/h264/ch1/main/av_stream
解释说明:
admin:设备登录账号;
a123456:设备登录密码;
10.192.44.101:设备的内网IP地址:
554:默认端口(注:不要变,这是取rtsp流的默认端口);
h264:是视频流编码格式;
ch1:通道号;
第二步:下载FFempg(多媒体处理程序),并配置环境变量
下载地址:https://ffmpeg.zeranoe.com/builds/ 我们选择static版本,下载之后,将压缩包解压到你想安装的地方然后复制ffmpeg.exe文件所在路径,添加至系统环境变量;
在项目的pom文件中需要引入jar文件(将rtsp流转换成rtmp流就是用这个jar包结合ffmpeg程序和海康dll进行操作)
第三步:下载Nginx
1.下载已经集成nginx-rtmp插件的nginx。
传送门:https://github.com/illuspas/nginx-rtmp-win32,解压到指定文件夹,打开conf/nginx.conf文件,这里的live就是上边代码中的rtmp://localhost:1935/live/中的live,可以自己定义。
2.启动nginx
双击nginx.exe即可启动,在“任务管理器”中可以看到启动后的进程。
推流就是将rtsp流转为rtmp流并推送至nginx中。而产生的rtmp流地址为:rtmp://xxx.xxx.xxx.xxx:1935/live/appName,这里的xxx.xxx.xxx.xxx是流媒体所在服务器的外网ip;
三、编码
1.在海康官网下载海康威视的最新SDK,选择适合自己环境的SDK下载。
https://www.hikvision.com/cn/download_61.html
2.下载之后解压,目录如下:
Demo示例中的是几种开发语言的demo,其中java的是用swing写客户端(亲测可用),C/S架构的,可以参考。库文件中是需要使用的dll运行库;是需要引进项目中的。那个txt文件里说了,有几个文件和文件夹是必须的:HCNetSDK.dll、HCCore.dll、PlayCtrl.dll、SuperRender.dll、AudioRender.dll、HCNetSDKCom文件夹。以下是我在项目中放的目录位置:
– 以下(4、5、6、7)为具体的Java代码,我会打包放在资源下载中,见文章最后的下载链接,无需自己手敲代码,除非项目中需要改动代码进行一些自定义的操作或者配置。
主要代码见下图:
4.然后在一个全局工具类里写了一个静态方法获取webapp的路径以获取dll文件的路径;
5.根据SDK压缩包里的那个txt文件所说,修改SDK文件的路径:
6.编写工具类的各种方法,初始化,注册设备,获取通道:
6.1初始化环境:
6.2注册设备:
6.3获取通道:
6.4:整体调用获取通道号:(关键的地方)
/**
* 开始推流并获取推流进程名称
* @param videoBasic 设备信息
* @param appName 进程名命名
* @return 返回结果集{msg:"",tasker:""}
*/
public Map<String,String> startTranscodeAndGetTasker(VideoBasic videoBasic, String appName){
Map<String,String> result = new HashMap<>();
int code = 0;
String[] resultNames = {
"成功","初始化失败","注册前请关闭预览","注册失败","通道获取失败"};
if(hcTool.initDevices() == 1) code = 1;//初始化失败
System.out.println("初始化设备(0-成功),code:"+code);
int regSuc = hcTool.deviceRegist(videoBasic.getUser_name(),videoBasic.getPwd(),videoBasic.getIp(),videoBasic.getPort());
if(regSuc != 0) code = regSuc;//注册失败
int channelNumber = hcTool.getChannelNumber();
if(channelNumber == -1) code = 4;
if(code == 0) {
String tasker = VideoUtil.startTranscoding(appName,videoBasic.getUser_name(),videoBasic.getPwd(),videoBasic.getIp(),channelNumber);
System.out.println("推流进程********tasker:"+tasker);
result.put("tasker", (StringUtils.isNotEmpty(tasker)) ? tasker : appName);
}else{
result.put("msg",resultNames[code])</