package com.netsdk.demo.customize;
|
|
import static com.netsdk.lib.Utils.getOsPrefix;
|
|
import java.io.File;
|
import java.io.UnsupportedEncodingException;
|
import java.util.Objects;
|
import java.util.Scanner;
|
|
import com.netsdk.demo.util.CaseMenu;
|
import com.netsdk.lib.NetSDKLib;
|
import com.netsdk.lib.NetSDKLib.*;
|
import com.netsdk.lib.enumeration.EM_EVENT_IVS_TYPE;
|
import com.netsdk.lib.structure.CFG_INTELLI_SHELF_INFO;
|
import com.netsdk.lib.structure.CFG_IVS_MAN_NUM_DETECTION_INFO;
|
import com.netsdk.lib.structure.CFG_NUMBERSTAT_INFO;
|
import com.netsdk.lib.structure.DEV_EVENT_INTELLI_SHELF_INFO;
|
import com.netsdk.lib.ToolKits;
|
import com.sun.jna.Memory;
|
import com.sun.jna.Pointer;
|
import com.sun.jna.ptr.IntByReference;
|
|
|
/**
|
* 视频统计摘要信息
|
* 进出数量统计
|
* @author 29779
|
*
|
*/
|
public class VideoStatistic {
|
|
static NetSDKLib netsdkApi = NetSDKLib.NETSDK_INSTANCE;
|
static NetSDKLib configApi = NetSDKLib.CONFIG_INSTANCE;
|
|
private NetSDKLib.NET_DEVICEINFO_Ex deviceInfo = new NetSDKLib.NET_DEVICEINFO_Ex();
|
// 登录句柄
|
private static LLong loginHandle = new LLong(0);
|
|
public static String encode;
|
|
static {
|
String osPrefix = getOsPrefix();
|
if (osPrefix.toLowerCase().startsWith("win32")) {
|
encode = "GBK";
|
} else if (osPrefix.toLowerCase().startsWith("linux")) {
|
encode = "UTF-8";
|
}
|
}
|
// 智能订阅句柄
|
private LLong attachHandle = new NetSDKLib.LLong(0);
|
|
String address = "172.27.1.173";
|
int port = 37777;
|
String username = "admin";
|
String password = "admin123";
|
//
|
|
private static class DisconnectCallback implements NetSDKLib.fDisConnect {
|
private static DisconnectCallback instance = new DisconnectCallback();
|
private DisconnectCallback() {}
|
public static DisconnectCallback getInstance() {
|
return instance;
|
}
|
|
public void invoke(LLong lLoginID, String pchDVRIP, int nDVRPort, Pointer dwUser){
|
System.out.printf("Device[%s:%d] Disconnect!\n" , pchDVRIP , nDVRPort);
|
}
|
}
|
|
private static class HaveReconnectCallback implements NetSDKLib.fHaveReConnect {
|
private static HaveReconnectCallback instance = new HaveReconnectCallback();
|
private HaveReconnectCallback() {}
|
public static HaveReconnectCallback getInstance() {
|
return instance;
|
}
|
|
public void invoke(LLong lLoginID, String pchDVRIP, int nDVRPort, Pointer dwUser){
|
System.out.printf("Device[%s:%d] HaveReconnected!\n" , pchDVRIP , nDVRPort);
|
}
|
}
|
|
|
|
|
public void EndTest() {
|
System.out.println("End Test");
|
if( loginHandle.longValue() != 0) {
|
netsdkApi.CLIENT_Logout(loginHandle);
|
}
|
System.out.println("See You...");
|
|
netsdkApi.CLIENT_Cleanup(); // 进程关闭时调用一次
|
System.exit(0);
|
}
|
|
public void InitTest() {
|
//初始化SDK库
|
netsdkApi.CLIENT_Init(DisconnectCallback.getInstance(), null); // 进程启动时调用一次
|
|
//设置断线自动重练功能
|
netsdkApi.CLIENT_SetAutoReconnect(HaveReconnectCallback.getInstance(), null);
|
|
// 向设备登入
|
final int nSpecCap = 0; /// login device by TCP
|
final IntByReference error = new IntByReference();
|
|
loginHandle = netsdkApi.CLIENT_LoginEx2(address, (short)port, username,
|
password, nSpecCap, null, deviceInfo, error);
|
|
if(loginHandle.longValue() == 0) {
|
System.err.printf("Login Device [%s:%d] Failed ! Last Error[%x]\n", address, port, netsdkApi.CLIENT_GetLastError());
|
return;
|
}
|
|
System.out.printf("Login Device [%s:%d] Success. \n", address, port);
|
}
|
|
private static class VideoStatSumCallback implements NetSDKLib.fVideoStatSumCallBack {
|
private static VideoStatSumCallback instance = new VideoStatSumCallback();
|
private VideoStatSumCallback() {}
|
public static VideoStatSumCallback getInstance() {
|
return instance;
|
}
|
|
public void invoke(LLong lAttachHandle, NET_VIDEOSTAT_SUMMARY stVideoState, int dwBufLen, Pointer dwUser){
|
/**
|
* 回调函数使用注意(防止卡回调)
|
* 1.不能再回调进行耗时操作,建议将数据、图片流、视频流等通过中间件和多线程抛出处理
|
* 2.不能再回调调用netsdk的其他接口
|
*/
|
System.out.printf("Channel[%d] GetTime[%s]\n" +
|
"People In Information[Total[%d] Hour[%d] Today[%d]]\n" +
|
"People Out Information[Total[%d] Hour[%d] Today[%d]]\n",
|
stVideoState.nChannelID , stVideoState.stuTime.toStringTime() ,
|
stVideoState.stuEnteredSubtotal.nToday ,
|
stVideoState.stuEnteredSubtotal.nHour ,
|
stVideoState.stuEnteredSubtotal.nTotal ,
|
stVideoState.stuExitedSubtotal.nToday ,
|
stVideoState.stuExitedSubtotal.nHour ,
|
stVideoState.stuExitedSubtotal.nTotal );
|
|
try {
|
/**
|
* 方案:通过上报的规则类型名称 和区域ID值 去智能规则配置关系获取自定义的规则名称
|
* 一.规则类型名称
|
* 输出字符串
|
* 1."ManNumDetection" 对应 智能规则配置枚举 EVENT_IVS_MAN_NUM_DETECTION(立体视觉区域内人数统计事件)
|
* 2."NumberStat" 对应 智能规则配置枚举 EVENT_IVS_NUMBERSTAT(数量统计事件)对应的规则配置
|
*
|
* 二、区域ID
|
* 输出区域ID值 对应智能规则字段nAreaID的值
|
*/
|
System.out.println("规则类型名称:"+new String(stVideoState.szRuleName,encode));
|
System.out.println("区域ID:"+stVideoState.nAreaID);
|
|
} catch (UnsupportedEncodingException e) {
|
e.printStackTrace();
|
}
|
}
|
}
|
|
|
|
/**
|
* 查询智能规则配置信息
|
*/
|
public void getCongigRuleInfo() {
|
int channel = 0; // 通道号
|
String command = NetSDKLib.CFG_CMD_ANALYSERULE;
|
|
int ruleCount = 10; // 事件规则个数
|
CFG_RULE_INFO[] ruleInfo = new CFG_RULE_INFO[ruleCount];
|
for (int i = 0; i < ruleCount; i++) {
|
ruleInfo[i] = new CFG_RULE_INFO();
|
}
|
|
CFG_ANALYSERULES_INFO analyse = new CFG_ANALYSERULES_INFO();
|
analyse.nRuleLen = 1024 * 1024 * 40;
|
analyse.pRuleBuf = new Memory(1024 * 1024 * 40); // 申请内存
|
analyse.pRuleBuf.clear(1024 * 1024 * 40);
|
|
// 查询
|
if (ToolKits.GetDevConfig(loginHandle, channel, command, analyse)) {
|
int offset = 0;
|
System.out.println("设备返回的事件规则个数:" + analyse.nRuleCount);
|
int count = analyse.nRuleCount < ruleCount ? analyse.nRuleCount : ruleCount;
|
for (int i = 0; i < count; i++) {
|
// 每个视频输入通道对应的所有事件规则:缓冲区pRuleBuf填充多个事件规则信息,每个事件规则信息内容为 CFG_RULE_INFO + 事件类型对应的规则配置结构体。
|
ToolKits.GetPointerDataToStruct(analyse.pRuleBuf, offset, ruleInfo[i]);
|
|
offset += ruleInfo[0].size(); // 智能规则偏移量
|
|
switch (ruleInfo[i].dwRuleType) {
|
case NetSDKLib.EVENT_IVS_CROSSLINEDETECTION: { //事件类型 EVENT_IVS_CROSSLINEDETECTION (警戒线事件)对应的规则配置CFG_CROSSLINE_INFO
|
//System.out.println("警戒线配置----------------------------");
|
break;
|
}
|
case NetSDKLib.EVENT_IVS_CROSSREGIONDETECTION: {//事件类型EVENT_IVS_CROSSREGIONDETECTION(警戒区事件)对应的规则配置CFG_CROSSREGION_INFO
|
//System.out.println("警戒区配置-----------------------------");
|
break;
|
}
|
case NetSDKLib.EVENT_IVS_NUMBERSTAT: { //事件类型EVENT_IVS_NUMBERSTAT(数量统计事件)对应的规则配置 CFG_NUMBERSTAT_INFO
|
// #define EVENT_IVS_NUMBERSTAT = 0x00000010
|
System.out.println("数量统计-----------------------------");
|
System.out.println("数量统计的枚举值:"+NetSDKLib.EVENT_IVS_NUMBERSTAT+" 对应规则类型名称字符串'NumberStat'");
|
CFG_NUMBERSTAT_INFO msg = new CFG_NUMBERSTAT_INFO();
|
ToolKits.GetPointerDataToStruct(analyse.pRuleBuf, offset, msg);
|
try {
|
System.out.println("自定义规则名称:"+ new String(msg.szRuleName,encode)); // 用户需要的名称
|
System.out.println("区域ID:"+ msg.nAreaID);
|
} catch (UnsupportedEncodingException e) {
|
e.printStackTrace();
|
}
|
break;
|
}
|
case NetSDKLib.EVENT_IVS_MAN_NUM_DETECTION: { //事件类型EVENT_IVS_MAN_NUM_DETECTION(立体视觉区域内人数统计事件)对应的规则配置 CFG_IVS_MAN_NUM_DETECTION_INFO
|
//#define EVENT_IVS_MAN_NUM_DETECTION = 0x0000020E
|
System.out.println("区域内人数统计-----------------------------");
|
System.out.println("区域内人数统计的枚举值:"+NetSDKLib.EVENT_IVS_MAN_NUM_DETECTION+" 对应规则类型名称字符串'ManNumDetection'");
|
CFG_IVS_MAN_NUM_DETECTION_INFO msg = new CFG_IVS_MAN_NUM_DETECTION_INFO();
|
ToolKits.GetPointerDataToStruct(analyse.pRuleBuf, offset, msg);
|
try {
|
System.out.println("自定义规则名称:"+ new String(msg.szRuleName,encode)); // 用户需要的名称
|
System.out.println("区域ID:"+ msg.nAreaID);
|
} catch (UnsupportedEncodingException e) {
|
e.printStackTrace();
|
}
|
break;
|
}
|
case NetSDKLib.EVENT_IVS_INTELLI_SHELF: { //事件类型EVENT_IVS_INTELLI_SHELF(智能补货事件)对应的规则配置 CFG_INTELLI_SHELF_INFO
|
//#define EVENT_IVS_INTELLI_SHELF = 0x00000277
|
System.out.println("智能补货事件-----------------------------");
|
System.out.println("智能补货事件的枚举值:"+NetSDKLib.EVENT_IVS_INTELLI_SHELF+" 对应规则类型名称字符串'IntelliShelf'");
|
CFG_INTELLI_SHELF_INFO msg = new CFG_INTELLI_SHELF_INFO();
|
ToolKits.GetPointerDataToStruct(analyse.pRuleBuf, offset, msg);
|
try {
|
System.out.println("自定义规则名称:"+ new String(msg.szRuleName,encode)); // 用户需要的名称
|
System.out.println("区域ID:"+ msg.nAreaID);
|
} catch (UnsupportedEncodingException e) {
|
e.printStackTrace();
|
}
|
break;
|
}
|
default:
|
break;
|
}
|
offset += ruleInfo[i].nRuleSize; // 智能事件偏移量
|
}
|
} else {
|
System.err.println("查询智能事件规则信息失败!" + ToolKits.getErrorCode());
|
}
|
}
|
|
|
|
/** 订阅视频统计 句柄*/
|
private LLong videoStatHandle = new LLong(0);
|
|
/**
|
* 订阅
|
*/
|
public void attachVideoStatSummary() {
|
if (loginHandle.longValue() == 0) {
|
return;
|
}
|
|
NET_IN_ATTACH_VIDEOSTAT_SUM videoStatIn = new NET_IN_ATTACH_VIDEOSTAT_SUM();
|
videoStatIn.nChannel = 0;
|
videoStatIn.cbVideoStatSum = VideoStatSumCallback.getInstance();
|
|
NET_OUT_ATTACH_VIDEOSTAT_SUM videoStatOut = new NET_OUT_ATTACH_VIDEOSTAT_SUM();
|
|
videoStatHandle = netsdkApi.CLIENT_AttachVideoStatSummary(loginHandle, videoStatIn, videoStatOut, 5000);
|
if( videoStatHandle.longValue() == 0 ) {
|
System.err.printf("Attach Failed!LastError = %x\n", netsdkApi.CLIENT_GetLastError());
|
return;
|
}
|
|
System.out.printf("Attach Success!Wait Device Notify Information\n");
|
}
|
|
/**
|
* 退订
|
*/
|
public void detachVideoStatSummary() {
|
if (videoStatHandle.longValue() != 0) {
|
netsdkApi.CLIENT_DetachVideoStatSummary(videoStatHandle);
|
videoStatHandle.setValue(0);
|
}
|
}
|
|
private LLong findHandle = new LLong(0); // 查询句柄
|
|
public void startFindNumberStat() {
|
NetSDKLib.NET_IN_FINDNUMBERSTAT inParam = new NetSDKLib.NET_IN_FINDNUMBERSTAT();
|
inParam.nChannelID = 0; // 通道号
|
|
inParam.stStartTime.dwYear = 2016;// 开始时间
|
inParam.stStartTime.dwMonth = 6;
|
inParam.stStartTime.dwDay = 20;
|
inParam.stStartTime.dwHour = 0;
|
|
inParam.stEndTime.dwYear = 2016;// 结束时间
|
inParam.stEndTime.dwMonth = 6;
|
inParam.stEndTime.dwDay = 21;
|
inParam.stEndTime.dwHour = 23;
|
|
inParam.nGranularityType = 1;// 颗粒度
|
inParam.nWaittime = 5000; // 接口超时时间5s
|
|
NetSDKLib.NET_OUT_FINDNUMBERSTAT outParam = new NetSDKLib.NET_OUT_FINDNUMBERSTAT();
|
|
/// 获取查询句柄
|
findHandle = netsdkApi.CLIENT_StartFindNumberStat(loginHandle, inParam, outParam);
|
if (findHandle.longValue() == 0) {
|
System.err.printf("StartFindNumberStat Failed! LastError = 0x%x\n", netsdkApi.CLIENT_GetLastError() );
|
return;
|
}
|
|
System.out.println("dwTotalCount: " + outParam.dwTotalCount);
|
/// 查询
|
NetSDKLib.NET_IN_DOFINDNUMBERSTAT inDoFind = new NetSDKLib.NET_IN_DOFINDNUMBERSTAT();
|
inDoFind.nBeginNumber = 0; // 从0开始查询
|
inDoFind.nCount = 10; // 每次查询10条
|
inDoFind.nWaittime = 5000; //接口超时时间 5s
|
|
NetSDKLib.NET_OUT_DOFINDNUMBERSTAT outDofind = new NetSDKLib.NET_OUT_DOFINDNUMBERSTAT();
|
NetSDKLib.NET_NUMBERSTAT[] numberstat = (NetSDKLib.NET_NUMBERSTAT[])new NetSDKLib.NET_NUMBERSTAT().toArray(inDoFind.nCount);
|
|
for (int i = 0 ;i < numberstat.length; i ++) {
|
numberstat[i].dwSize = numberstat[0].dwSize;
|
}
|
|
outDofind.nBufferLen = inDoFind.nCount * numberstat[0].dwSize;
|
outDofind.pstuNumberStat = new Memory(outDofind.nBufferLen);
|
outDofind.pstuNumberStat.clear(outDofind.nBufferLen);
|
// Note: 初始化内存中 dwSize 字段的值,否则查询的结果为空
|
ToolKits.SetStructArrToPointerData(numberstat, outDofind.pstuNumberStat);
|
|
int bFound = 0;
|
int index = 1;
|
do {
|
bFound = netsdkApi.CLIENT_DoFindNumberStat(findHandle, inDoFind, outDofind);
|
if (0 == bFound) {
|
System.err.printf("DoFindNumberStat Failed! LastError = 0x%x\n", netsdkApi.CLIENT_GetLastError() );
|
return;
|
}
|
|
// 查询结果
|
ToolKits.GetPointerDataToStructArr(outDofind.pstuNumberStat, numberstat);
|
for(int i = 0; i < outDofind.nCount; i++, index ++) {
|
System.out.println("Index = " + index +
|
" Start Time: " + numberstat[i].stuStartTime.toStringTime() +
|
" Stop Time: " + numberstat[i].stuEndTime.toStringTime() +
|
" Enter Total: " + numberstat[i].nEnteredSubTotal +
|
" Exit Total: " + numberstat[i].nExitedSubtotal + "\n"
|
);
|
}
|
|
// 查询下一次
|
inDoFind.nBeginNumber += inDoFind.nCount; // 从上一次结束地方开始查询
|
}while(outDofind.nCount >= inDoFind.nCount);
|
}
|
|
public void stopFindNumberStat() {
|
if (findHandle.longValue() != 0 ) {
|
netsdkApi.CLIENT_StopFindNumberStat(findHandle);
|
System.out.println("stop Find Number Stat Success. ");
|
findHandle.setValue(0);
|
}
|
}
|
|
|
|
/**
|
* 选择通道
|
*/
|
private int channel = 0;
|
|
public void setChannelID() {
|
System.out.println("请输入通道,从0开始计数,-1表示全部");
|
Scanner sc = new Scanner(System.in);
|
this.channel = sc.nextInt();
|
}
|
|
/**
|
* 订阅智能事件
|
*/
|
public void AttachEventRealLoadPic() {
|
// 先退订,设备不会对重复订阅作校验,重复订阅后会有重复的事件返回
|
this.DetachEventRealLoadPic();
|
// 需要图片
|
int bNeedPicture = 1;
|
attachHandle = netsdkApi.CLIENT_RealLoadPictureEx(loginHandle, channel, NetSDKLib.EVENT_IVS_ALL, bNeedPicture,
|
AnalyzerDataCB.getInstance(), null, null);
|
if (attachHandle.longValue() != 0) {
|
System.out.printf("Chn[%d] CLIENT_RealLoadPictureEx Success\n", channel);
|
} else {
|
System.out.printf("Ch[%d] CLIENT_RealLoadPictureEx Failed!LastError = %s\n", channel,
|
ToolKits.getErrorCode());
|
}
|
}
|
|
/**
|
* 智能事件回调
|
*/
|
private static class AnalyzerDataCB implements NetSDKLib.fAnalyzerDataCallBack {
|
private final File picturePath;
|
private static AnalyzerDataCB instance;
|
|
private AnalyzerDataCB() {
|
picturePath = new File("./AnalyzerPicture/");
|
if (!picturePath.exists()) {
|
picturePath.mkdirs();
|
}
|
}
|
|
public static AnalyzerDataCB getInstance() {
|
if (instance == null) {
|
synchronized (AnalyzerDataCB.class) {
|
if (instance == null) {
|
instance = new AnalyzerDataCB();
|
}
|
}
|
}
|
return instance;
|
}
|
|
public int invoke(LLong lAnalyzerHandle, int dwAlarmType, Pointer pAlarmInfo, Pointer pBuffer, int dwBufSize,
|
Pointer dwUser, int nSequence, Pointer reserved) {
|
if (lAnalyzerHandle == null || lAnalyzerHandle.longValue() == 0) {
|
return -1;
|
}
|
System.out.println("dwAlarmType:"+dwAlarmType);
|
switch (Objects.requireNonNull(EM_EVENT_IVS_TYPE.getEventType(dwAlarmType))) {
|
case EVENT_IVS_INTELLI_SHELF: {// 智能补货事件(对应 DEV_EVENT_INTELLI_SHELF_INFO)
|
DEV_EVENT_INTELLI_SHELF_INFO msg = new DEV_EVENT_INTELLI_SHELF_INFO();
|
ToolKits.GetPointerData(pAlarmInfo, msg);
|
System.out.println(" 智能补货事件 时间(UTC):" + msg.UTC
|
+ " 通道号:" + msg.nChannelID
|
+" 事件ID:" + msg.nEventID
|
+" 事件名称:" +new String(msg.szName).trim() // 规则类型名称
|
+" 区域ID(从1开始), 0为单区域:" +msg.nAreaID // 区域ID
|
+" 事件触发的预置点号,从1开始:" +msg.nPresetID
|
+" 表示货架上剩余货物的百分比:" +msg.nPercent
|
);
|
/**
|
* 回调函数使用注意(防止卡回调)
|
* 1.不能再回调进行耗时操作,建议将数据、图片流、视频流等通过中间件和多线程抛出处理
|
* 2.不能再回调调用netsdk的其他接口
|
*/
|
// 全图
|
String Picture = picturePath + "\\" + "EVENT_IVS_INTELLI_SHELF" + System.currentTimeMillis()
|
+ ".jpg";
|
if (dwBufSize > 0) {
|
ToolKits.savePicture(pBuffer, 0, dwBufSize, Picture);
|
}
|
// 全景大图
|
if (msg.stuSceneImage != null && msg.stuSceneImage.nLength > 0) {
|
String bigPicture = picturePath + "\\" + "big" + System.currentTimeMillis()
|
+ ".jpg";
|
ToolKits.savePicture(pBuffer, msg.stuSceneImage.nOffSet, msg.stuSceneImage.nLength, bigPicture);
|
}
|
|
break;
|
}
|
default:
|
System.out.println("其他事件--------------------" + dwAlarmType);
|
break;
|
}
|
return 0;
|
}
|
|
}
|
|
/**
|
* 停止侦听智能事件
|
*/
|
public void DetachEventRealLoadPic() {
|
if (attachHandle.longValue() != 0) {
|
netsdkApi.CLIENT_StopLoadPic(attachHandle);
|
}
|
}
|
|
|
public void RunTest() {
|
System.out.println("Run Test");
|
|
CaseMenu menu = new CaseMenu();
|
menu.addItem(new CaseMenu.Item(this, "查询智能规则配置信息", "getCongigRuleInfo"));
|
menu.addItem(new CaseMenu.Item(this, "订阅", "attachVideoStatSummary"));
|
menu.addItem(new CaseMenu.Item(this, "退订", "detachVideoStatSummary"));
|
|
//menu.addItem(new CaseMenu.Item(this, "开始查询", "startFindNumberStat"));
|
//menu.addItem(new CaseMenu.Item(this, "停止查询", "stopFindNumberStat"));
|
|
menu.addItem(new CaseMenu.Item(this, "选择通道", "setChannelID"));
|
menu.addItem(new CaseMenu.Item(this, "订阅智能事件", "AttachEventRealLoadPic"));
|
menu.addItem(new CaseMenu.Item(this, "停止侦听智能事件", "DetachEventRealLoadPic"));
|
|
menu.run();
|
}
|
|
public static void main(String[]args)
|
{
|
VideoStatistic demo = new VideoStatistic();
|
demo.InitTest();
|
demo.RunTest();
|
demo.EndTest();
|
}
|
}
|