海康威视4G球机对接萤石云平台实现实时预览、云台控制 ----- java完整demo
程序员文章站
2022-03-25 13:16:49
...
前言:上一篇博文已经分享了如何获取直播列表,本篇博文是在上一篇博文的基础上做了完善,实现了实时预览和云台控制。因此,部分代码会有重复。
步骤一:在 萤石云开发平台 注册开发者并添加球机设备
步骤二:获取accessToken和直播列表请参考上一篇博文 海康威视4G球机对接萤石云平台获取直播视频列表
步骤三:云台控制
后端代码:action类
package com.jk.action;
import com.jk.comm.action.BaseAction;
import com.jiankong.util.HttpRequest;
import com.jiankong.util.TokenThread;
public class JianKongAction extends BaseAction{
private String device; //设备***,存在英文字母的设备***,字母需为大写
private Integer channelNo; //通道号
private Integer direction; //操作命令:0-上,1-下,2-左,3-右,4-左上,5-左下,6-右上,7-右下,8-放大,9-缩小,10-近焦距,11-远焦距
private Integer speed; //云台速度:0-慢,1-适中,2-快,海康设备参数不可为0
public String getDevice() {
return device;
}
public void setDevice(String device) {
this.device = device;
}
public Integer getChannelNo() {
return channelNo;
}
public void setChannelNo(Integer channelNo) {
this.channelNo = channelNo;
}
public Integer getDirection() {
return direction;
}
public void setDirection(Integer direction) {
this.direction = direction;
}
public Integer getSpeed() {
return speed;
}
public void setSpeed(Integer speed) {
this.speed = speed;
}
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* 获取直播列表
*/
public void getList(){
String accessToken = MyHttpRequest.getAccessToken("https://open.ys7.com/api/lapp/token/get?appKey=xxxxxxxxxxxxxxxx&appSecret=xxxxxxxxxxxxxxxxx");
//获取直播列表
String list = HttpRequest.getList("https://open.ys7.com/api/lapp/live/video/list?accessToken="+accessToken+"&pageStart=0&pageSize=3");
printJsonString(list);
}
/**
* 云台控制
* 开始云台控制之后必须先调用停止云台控制接口才能进行其他操作,包括其他方向的云台转动
*/
public void setCloudControl(){
String accessToken = MyHttpRequest.getAccessToken("https://open.ys7.com/api/lapp/token/get?appKey=xxxxxxxxxxxxxxxx&appSecret=xxxxxxxxxxxxxxxxx");
String start = "accessToken="+accessToken+"&deviceSerial="+device+"&channelNo="+channelNo+"&direction="+direction+"&speed="+speed;
String stop = "accessToken="+accessToken+"&deviceSerial="+device+"&channelNo="+channelNo+"&direction="+direction;
jsonMsg = HttpRequest.setStartCloudControl("https://open.ys7.com/api/lapp/device/ptz/start?"+start);
if(jsonMsg.equals("开始云台控制成功")){
HttpRequest.setStopCloudControl("https://open.ys7.com/api/lapp/device/ptz/stop?"+stop);
}
printJsonString(jsonMsg);
}
}
action父类:
public class BaseAction extends ActionSupport {
protected int page = 1; //当前第几页
protected int rows = 10; // 每页数量
protected String jsonMsg = "";
/**
* 打印Json字符串返回给客户
* @param jsonString
* @Description:
*/
protected void printJsonString ( String jsonString ) {
PrintWriter out = null;
try {
HttpServletResponse response = getResponse();
response.setCharacterEncoding ( "UTF-8" );
response.setContentType("text/html;charset=UTF-8");
out = response.getWriter ();
out.print ( jsonString );
}
catch (IOException e) {
e.printStackTrace ();
}
finally {
out.close ();
}
}
}
util类
package com.jiankong.util;
import java.util.HashMap;
import java.util.Map;
import net.sf.json.JSONObject;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
public class HttpRequest {
/**
* 获取监控应用的 accessToken
* @param url
* @return
*/
public static String getAccessToken(String url) {
DefaultHttpClient client = new DefaultHttpClient();
client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS,true);
HttpPost httpost = getPostMethod(url);
String accessToken = "";
try {
try {
HttpResponse response = client.execute(httpost);
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println("jsonStr:"+jsonStr);
JSONObject jsStr = JSONObject.fromObject(jsonStr);
System.out.println("jsStr:"+jsStr);
String code = String.valueOf(jsStr.get("code"));
if(code.equals("200")){
String data = jsStr.getString("data");
JSONObject dataJson = JSONObject.fromObject(data);
accessToken = dataJson.getString("accessToken");
return accessToken;
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(!httpost.isAborted()){
httpost.abort();
}
client.getConnectionManager().shutdown();
}
return accessToken;
}
/**
* 获取直播视频列表
* @param url
* @return
*/
public static String getList(String url) {
DefaultHttpClient client = new DefaultHttpClient();
client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS,true);
HttpPost httpost = getPostMethod(url);
String list = "";
try {
try {
HttpResponse response = client.execute(httpost);
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println("jsonStr:"+jsonStr);
JSONObject jsStr = JSONObject.fromObject(jsonStr);
String code = jsStr.getString("code");
if(code.equals("200")){
list = jsStr.getString("data");
return list;
}else if(code.equals("10002")){ //accessToken过期或异常
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(!httpost.isAborted()){
httpost.abort();
}
client.getConnectionManager().shutdown();
}
return list;
}
public static String setStartCloudControl(String url){
DefaultHttpClient client = new DefaultHttpClient();
client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS,true);
HttpPost httpost = getPostMethod(url);
String msg = "";
try {
try {
HttpResponse response = client.execute(httpost);
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println("jsonStr:"+jsonStr);
JSONObject jsStr = JSONObject.fromObject(jsonStr);
String code = jsStr.getString("code");
if(code.equals("200")){
msg = "开始云台控制成功";
}else{
msg = "开始云台控制失败";
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(!httpost.isAborted()){
httpost.abort();
}
client.getConnectionManager().shutdown();
}
return msg;
}
public static String setStopCloudControl(String url){
DefaultHttpClient client = new DefaultHttpClient();
client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS,true);
HttpPost httpost = getPostMethod(url);
String msg = "";
try {
try {
HttpResponse response = client.execute(httpost);
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println("jsonStr:"+jsonStr);
JSONObject jsStr = JSONObject.fromObject(jsonStr);
String code = jsStr.getString("code");
if(code.equals("200")){
msg = "停止云台控制成功";
}else{
msg = "停止云台控制失败";
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(!httpost.isAborted()){
httpost.abort();
}
client.getConnectionManager().shutdown();
}
return msg;
}
/**
* 模拟浏览器post提交
*
* @param url
* @return
*/
public static HttpPost getPostMethod(String url) {
HttpPost pmethod = new HttpPost(url); // 设置响应头信息
pmethod.addHeader("Connection", "keep-alive");
pmethod.addHeader("Accept", "*/*");
pmethod.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
pmethod.addHeader("Host", "open.ys7.com");
pmethod.addHeader("X-Requested-With", "XMLHttpRequest");
pmethod.addHeader("Cache-Control", "max-age=0");
pmethod.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
return pmethod;
}
}
前端页面:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>监控网点</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<link href="${basePath}static/css/jiankong.css" rel="stylesheet" type="text/css"/>
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
<style type="text/css">
body{margin:0;}
#myPlayer{max-width: 600px;width: 100%;display: inline;}
#myPlayer1{max-width: 600px;width: 100%;display: inline;}
#myPlayer2{max-width: 600px;width: 100%;display: inline;}
.num{
max-width: 600px;
display: inline;
}
.head{
display: inline-grid;
width: 600px;
}
</style>
<script src="${basePath}static/js/hontek/jiankong/ezuikit.js" type="text/javascript"></script>
<script src="${basePath}static/js/jquery/jquery-1.8.0.min.js" type="text/javascript"></script>
<script src="${basePath}static/js/layer/layer.js" type="text/javascript"></script>
</head>
<body>
<div class="head">
<div class="num">1号监控点</div>
<video id="myPlayer" controls playsInline webkit-playsinline autoplay>
<source id="playVideo0" src="" type="rtmp/flv" />
</video>
</div>
<div class="head">
<div class="num">2号监控点</div>
<video id="myPlayer1" controls playsInline webkit-playsinline autoplay>
<source id="playVideo1" src="" type="rtmp/flv" />
</video>
</div>
<div class="head">
<div class="num">3号监控点</div>
<video id="myPlayer2" controls playsInline webkit-playsinline autoplay>
<source id="playVideo2" src="" type="rtmp/flv" />
</video>
</div>
<div class="head">
<fieldset class="ptz" style="position: absolute;margin-top: 80px;margin-left: 60px;">
<legend>云台控制</legend>
<table cellpadding="0" cellspacing="3" border="0" class="left">
<tr>
<td>
<input type="button" class="btn" value="左上" onclick="cloudControl(4)" />
<input type="button" class="btn" value="上" onclick="cloudControl(0)"/>
<input type="button" class="btn" value="右上" onclick="cloudControl(6)" />
</td>
</tr>
<tr>
<td>
<input type="button" class="btn" value="左" onclick="cloudControl(2)"/>
<input type="button" class="btn" value="自动" onclick="" style="display:none"/>
<input type="button" class="btn" value="右" onclick="cloudControl(3)" style="position: unset;margin-left: 49px;"/>
</td>
</tr>
<tr>
<td>
<input type="button" class="btn" value="左下" onclick="cloudControl(5)" />
<input type="button" class="btn" value="下" onclick="cloudControl(1)"/>
<input type="button" class="btn" value="右下" onclick="cloudControl(7)"/>
</td>
</tr>
</table>
<table cellpadding="0" cellspacing="3" border="0" class="left">
<tr>
<td class="tt">云台速度</td>
<td>
<select id="ptzspeed" class="sel">
<option value="1" >适中</option>
<option value="2">快</option>
</select>
</td>
</tr>
<tr>
<td class="tt">监控点</td>
<td id="jkd">
</td>
</tr>
</table>
<table cellpadding="0" cellspacing="3" border="0" class="left">
<tr>
<td class="tt"><input type="button" class="btn2" value="变倍+" onclick="cloudControl(8)"></td>
<td><input type="button" class="btn2" value="变倍-" onclick="cloudControl(9)"></td>
</tr>
<tr style="position: absolute;margin-top: 20px;margin-left: -2px;">
<td class="tt"><input type="button" class="btn2" value="变焦+" onclick="cloudControl(10)"></td>
<td><input type="button" class="btn2" value="变焦-" onclick="cloudControl(11)"></td>
</tr>
</table>
</fieldset>
</div>
<script>
$.post('jiankong_getList.action','',function(res){
if(res.length>0){
var myJkd = "<select id='direction' class='sel'>";
for(var i=0;i<res.length;i++){
var rtmp = res[i].rtmp;
$("#playVideo"+i).attr('src',rtmp);
myJkd+="<option value='"+res[i].deviceSerial+"'>"+(i+1)+"号监控点</option>";
}
myJkd+=" </select>";
$("#jkd").html(myJkd);
var player = new EZuikit.EZUIPlayer('myPlayer');
var player1 = new EZuikit.EZUIPlayer('myPlayer1');
}else{
alert("获取失败");
}
},'json');
function cloudControl(direction){
layer.load(2);
var jkd = $("#jkd option:selected").val();//选中的值
var speed = $("#ptzspeed option:selected").val();//选中的值
var data ={
"device":jkd,
"channelNo":1,
"direction":direction,
"speed":speed
};
$.post('jiankong_setCloudControl.action',data,function(res){
layer.closeAll('loading');
},'text');
}
</script>
</body>
</html>
jiankong.css文件
@charset "utf-8";
*
{
margin:0;
padding:0;
}
html
{
width:100%;
height:100%;
font-size:12px;
font-family:Arial, Helvetica, sans-serif;
-webkit-text-size-adjust:none;
background:#FFFFFF;
}
body
{
padding:5px;
}
select
{
height:20px;
line-height:20px;
}
.left
{
float:left;
}
.freeze
{
position:absolute;
text-align:center;
background:#343434;
color:#FFFFFF;
font-size:26px;
font-weight:bold;
filter:alpha(opacity=60);
opacity:0.6;
}
.vtop
{
vertical-align:middle;
margin-top:-1px;
}
/*插件*/
.plugin
{
width:800px;
height:600px;
top:10px;
}
object
{
width:800px !important ;
height:600px !important;
}
fieldset
{
display:block;
}
/*本地配置*/
.localconfig
{
width:480px;
padding:10px;
border:1px solid #7F9DB9;
}
.localconfig .tt
{
width:125px;
}
.localconfig .txt
{
width:310px;
}
.localconfig .txt2
{
width:300px;
}
.localconfig .btn
{
width:45px;
height:22px;
line-height:18px;
}
.localconfig .sel
{
width:120px;
}
/*登录*/
.login
{
width:480px;
padding:10px;
border:1px solid #7F9DB9;
}
.login .tt
{
width:100px;
}
.login .txt
{
width:130px;
}
.login .btn
{
width:45px;
height:22px;
line-height:18px;
}
.login .btn2
{
width:100px;
height:22px;
line-height:18px;
}
.login .sel
{
width:130px;
}
.login .sel2
{
width:65px;
}
/*数字通道*/
.ipchannel
{
width:480px;
padding:10px;
border:1px solid #7F9DB9;
}
.ipchannel .btn
{
width:130px;
height:22px;
line-height:18px;
}
.ipchannel .digitaltdiv
{
height:100px;
overflow:hidden;
overflow-y:auto;
border:1px solid #7F9DB9;
font-size:11px;
}
.ipchannel .digitalchannellist th, .ipchannel .digitalchannellist td
{
padding:2px;
border:1px solid #7F9DB9;
border-collapse:collapse;
white-space:nowrap;
}
/*预览*/
.preview
{
width:450px;
padding:10px;
padding-top:0;
margin-left:10px;
border:1px solid #7F9DB9;
}
.preview .tt
{
width:60px;
}
.preview .txt
{
width:30px;
}
.preview .btn
{
width:70px;
height:22px;
line-height:18px;
}
.preview .btn2
{
width:90px;
height:22px;
line-height:18px;
}
.preview .sel
{
width:105px;
}
/*云台*/
.ptz
{
width:450px;
padding:10px;
margin-left:10px;
border:1px solid #7F9DB9;
}
.ptz .tt
{
width:60px;
}
.ptz .txt
{
width:60px;
}
.ptz .btn
{
width:45px;
height:22px;
line-height:18px;
}
.ptz .btn2
{
width:60px;
height:22px;
line-height:18px;
}
.ptz .sel
{
width:100px;
}
/*视频参数*/
.videoparam
{
width:450px;
padding:10px;
margin-left:10px;
border:1px solid #7F9DB9;
}
.videoparam .tt
{
width:60px;
}
.videoparam .txt
{
width:60px;
}
.videoparam .btn
{
width:45px;
height:22px;
line-height:18px;
}
.videoparam .sel
{
width:65px;
}
/*回放*/
.playback
{
width:450px;
padding:10px;
margin-left:10px;
border:1px solid #7F9DB9;
}
.playback .tt
{
width:60px;
}
.playback .txt
{
width:140px;
}
.playback .btn
{
width:45px;
height:22px;
line-height:18px;
}
.playback .btn2
{
width:70px;
height:22px;
line-height:18px;
}
.playback .sel
{
width:142px;
}
.playback .searchdiv
{
height:100px;
overflow:hidden;
overflow-y:auto;
border:1px solid #7F9DB9;
font-size:11px;
}
.playback .searchlist th, .playback .searchlist td
{
padding:2px;
border:1px solid #7F9DB9;
border-collapse:collapse;
white-space:nowrap;
}
/*系统维护*/
.maintain
{
width:450px;
padding:10px;
margin-left:10px;
border:1px solid #7F9DB9;
}
.maintain .tt
{
width:60px;
}
.maintain .txt
{
width:280px;
}
.maintain .btn
{
width:45px;
height:22px;
line-height:18px;
}
.maintain .btn2
{
width:100px;
height:22px;
line-height:18px;
}
.maintain .sel
{
width:65px;
}
/*操作信息*/
.operate
{
width:450px;
padding:10px;
margin-left:10px;
border:1px solid #7F9DB9;
}
.operate .opinfo
{
height:150px;
border:1px solid #7F9DB9;
overflow:auto;
}
/*事件回调*/
.callback
{
width:450px;
padding:10px;
margin-left:10px;
border:1px solid #7F9DB9;
}
.callback .cbinfo
{
height:114px;
border:1px solid #7F9DB9;
overflow:auto;
}
/*IP解析*/
.ipparse
{
width:450px;
padding:10px;
margin-left:10px;
border:1px solid #7F9DB9;
}
.ipparse .tt
{
width:85px;
}
.ipparse .txt
{
width:130px;
}
.ipparse .btn
{
width:90px;
height:22px;
line-height:18px;
}
.ipparse .sel
{
width:130px;
}
/*绘图*/
.draw
{
width:450px;
padding:10px;
padding-top:0;
margin-left:10px;
border:1px solid #7F9DB9;
}
.draw .tt
{
width:60px;
}
.draw .txt
{
width:140px;
}
.draw .btn
{
width:70px;
height:22px;
line-height:18px;
}
.draw .btn2
{
width:100px;
height:22px;
line-height:18px;
}
.draw .sel
{
width:105px;
}
注:ezuikit.js文件可在萤石云开发平台下载
最终效果如下:
有两台设备,不过此时只一台设备接通了电源。
上一篇: (一) easyopen介绍
下一篇: MSR 分区有什么用