package com.netsdk.demo.accessControl.accessFaceQuality;
|
|
import com.netsdk.demo.util.CaseMenu;
|
import com.netsdk.lib.NativeString;
|
import com.netsdk.lib.NetSDKLib;
|
import com.netsdk.lib.ToolKits;
|
import com.sun.jna.Memory;
|
|
import java.io.File;
|
import java.io.UnsupportedEncodingException;
|
import java.util.Scanner;
|
|
import static com.netsdk.lib.Utils.getOsPrefix;
|
|
/**
|
* @author : 47040
|
* @since : Created in 2020/8/26 20:29
|
*/
|
public class FaceQualityDemo {
|
|
// The constant net sdk
|
public static final NetSDKLib netsdk = NetSDKLib.NETSDK_INSTANCE;
|
|
// The constant config sdk.
|
public static NetSDKLib configsdk = NetSDKLib.CONFIG_INSTANCE;
|
|
public static String encode; // 编码格式
|
|
static {
|
String osPrefix = getOsPrefix();
|
if (osPrefix.toLowerCase().startsWith("win32-amd64")) {
|
encode = "GBK";
|
} else if (osPrefix.toLowerCase().startsWith("linux-amd64")) {
|
encode = "UTF-8";
|
}
|
}
|
|
////////////////////////////////////// 登录相关 ///////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
|
private NetSDKLib.NET_DEVICEINFO_Ex deviceInfo = new NetSDKLib.NET_DEVICEINFO_Ex(); // 设备信息
|
|
private NetSDKLib.LLong m_hLoginHandle = new NetSDKLib.LLong(0); // 登录句柄
|
|
/**
|
* login with high level 高安全级别登陆
|
*/
|
public void loginWithHighLevel() {
|
|
NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY pstInParam =
|
new NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY(); // 输入结构体参数
|
System.arraycopy(m_strIpAddr.getBytes(), 0, pstInParam.szIP, 0, m_strIpAddr.length());
|
pstInParam.nPort = m_nPort;
|
System.arraycopy(m_strUser.getBytes(), 0, pstInParam.szUserName, 0, m_strUser.length());
|
System.arraycopy(m_strPassword.getBytes(), 0, pstInParam.szPassword, 0, m_strPassword.length());
|
|
NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY pstOutParam =
|
new NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY(); // 输结构体参数
|
|
// 登录并获取句柄
|
m_hLoginHandle = netsdk.CLIENT_LoginWithHighLevelSecurity(pstInParam, pstOutParam);
|
|
if (m_hLoginHandle.longValue() == 0) {
|
System.err.printf("Login Device[%s] Port[%d]Failed. %s\n", m_strIpAddr, m_nPort, ToolKits.getErrorCode());
|
} else {
|
deviceInfo = pstOutParam.stuDeviceInfo; // 获取设备信息
|
System.out.println("登录成功 句柄: " + m_hLoginHandle);
|
System.out.println("设备地址:" + m_strIpAddr);
|
System.out.println("设备包含:" + deviceInfo.byChanNum + "个通道");
|
}
|
}
|
|
/**
|
* logout 退出
|
*/
|
public void logOut() {
|
if (m_hLoginHandle.longValue() != 0) {
|
netsdk.CLIENT_Logout(m_hLoginHandle);
|
System.out.println("退出登录成功");
|
}
|
}
|
|
//////////////////////////////////////// 智能事件 订阅/退订 //////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
private NetSDKLib.LLong m_IVSAttachHandle = new NetSDKLib.LLong(0); // 智能订阅句柄
|
|
private final NetSDKLib.fAnalyzerDataCallBack analyzerDataCB = FaceQualityAnalyzerCallBack.getSingleInstance();
|
|
private int channel = 0;
|
|
public void setChannelID() {
|
Scanner sc = new Scanner(System.in);
|
System.out.println("请输入通道号:");
|
this.channel = sc.nextInt();
|
}
|
|
public void AttachEventRealLoadPic() {
|
|
this.DetachEventRealLoadPic(); // 先退订,部分设备不会对重复订阅作校验,重复订阅后会有重复的事件返回
|
|
int bNeedPicture = 1; // 需要图片
|
|
// Demo里只模拟了一个通道的订阅所以把订阅句柄写成了全局, 如果订阅多个通道, 每个通道订阅后返回的句柄都不一样,请一一对应妥善保存
|
m_IVSAttachHandle = netsdk.CLIENT_RealLoadPictureEx(m_hLoginHandle, channel, NetSDKLib.EVENT_IVS_ALL, bNeedPicture, analyzerDataCB, null, null);
|
if (m_IVSAttachHandle.longValue() != 0) {
|
System.out.printf("Channel [%d] CLIENT_RealLoadPictureEx Success\n", channel);
|
} else {
|
System.out.printf("Channel [%d] CLIENT_RealLoadPictureEx Failed!LastError = %s\n", channel, ToolKits.getErrorCode());
|
}
|
}
|
|
/**
|
* 停止侦听智能事件
|
*/
|
public void DetachEventRealLoadPic() {
|
if (m_IVSAttachHandle.longValue() != 0) {
|
netsdk.CLIENT_StopLoadPic(m_IVSAttachHandle);
|
}
|
}
|
|
//////////////////////////////////////// 报警事件 订阅/退订 //////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
private final NetSDKLib.fMessCallBackEx1 messCallBackEx1 = FaceQualityMessageCallBack.getSingleInstance();
|
|
/**
|
* 订阅任务, start listen
|
*/
|
public void AttachEventStartListen() {
|
boolean bRet = netsdk.CLIENT_StartListenEx(m_hLoginHandle);
|
if (bRet) {
|
System.out.println("CLIENT_StartListenEx success.");
|
} else {
|
System.out.printf("CLIENT_StartListenEx fail, error:%s\n", ToolKits.getErrorCode());
|
}
|
}
|
|
/**
|
* 退订任务, stop listen
|
*/
|
public void DetachEventStopListen() {
|
boolean bRet = netsdk.CLIENT_StopListen(m_hLoginHandle);
|
if (bRet) {
|
System.out.println("CLIENT_StopListen success");
|
} else {
|
System.out.printf("CLIENT_StopListen fail, error:%s\n", ToolKits.getErrorCode());
|
}
|
}
|
|
//////////////////////////////////////// 记录查询 ///////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
/**
|
* 按卡号查询 刷卡记录 注意并不是所有设备都支持此条件查询
|
*/
|
public void TestQueryRecordByNo() {
|
final NetSDKLib.FIND_RECORD_ACCESSCTLCARDREC_CONDITION_EX queryCondition = new NetSDKLib.FIND_RECORD_ACCESSCTLCARDREC_CONDITION_EX();
|
queryCondition.bCardNoEnable = 1;
|
|
Scanner sc = new Scanner(System.in);
|
System.out.println("请输入查询的卡号: ");
|
final String cardNo = sc.next().trim();
|
|
System.arraycopy(cardNo.getBytes(), 0, queryCondition.szCardNo, 0, cardNo.length());
|
|
queryAccessRecord(queryCondition);
|
}
|
|
/**
|
* 按时间查询刷卡记录 注意并不是所有设备都支持此条件查询
|
*/
|
public void TestQueryRecordByTime() {
|
final NetSDKLib.FIND_RECORD_ACCESSCTLCARDREC_CONDITION_EX queryCondition = new NetSDKLib.FIND_RECORD_ACCESSCTLCARDREC_CONDITION_EX();
|
queryCondition.bTimeEnable = 1;
|
|
Scanner sc = new Scanner(System.in);
|
|
System.out.println("请输入起始时间(空格隔开): 年 月 日 时 分 秒");
|
queryCondition.stStartTime.setTime(sc.nextInt(), sc.nextInt(), sc.nextInt(), sc.nextInt(), sc.nextInt(), sc.nextInt());
|
|
System.out.println("请输入结束时间(空格隔开): 年 月 日 时 分 秒");
|
queryCondition.stEndTime.setTime(sc.nextInt(), sc.nextInt(), sc.nextInt(), sc.nextInt(), sc.nextInt(), sc.nextInt());
|
|
queryAccessRecord(queryCondition);
|
}
|
|
/**
|
* 不按时间或卡号查询刷卡记录 即查询全部
|
*/
|
public void TestQueryAllRecords() {
|
|
final NetSDKLib.FIND_RECORD_ACCESSCTLCARDREC_CONDITION_EX queryCondition = new NetSDKLib.FIND_RECORD_ACCESSCTLCARDREC_CONDITION_EX();
|
queryAccessRecord(queryCondition);
|
|
}
|
|
/**
|
* 查询门禁刷卡记录
|
*/
|
public void queryAccessRecord(NetSDKLib.FIND_RECORD_ACCESSCTLCARDREC_CONDITION_EX queryCondition) {
|
|
if (queryCondition == null) {
|
queryCondition = new NetSDKLib.FIND_RECORD_ACCESSCTLCARDREC_CONDITION_EX();
|
}
|
|
///////////////////////////////////// FindRecord ///////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// CLIENT_FindRecord 入参
|
NetSDKLib.NET_IN_FIND_RECORD_PARAM findRecordIn = new NetSDKLib.NET_IN_FIND_RECORD_PARAM();
|
findRecordIn.emType = NetSDKLib.EM_NET_RECORD_TYPE.NET_RECORD_ACCESSCTLCARDREC_EX; // 指定类型
|
findRecordIn.pQueryCondition = queryCondition.getPointer(); // 这里写入搜索条件
|
|
///CLIENT_FindRecord出参
|
NetSDKLib.NET_OUT_FIND_RECORD_PARAM findRecordOut = new NetSDKLib.NET_OUT_FIND_RECORD_PARAM();
|
|
// 指针类型在调用前必须 write
|
queryCondition.write();
|
findRecordIn.write();
|
findRecordOut.write();
|
boolean success = netsdk.CLIENT_FindRecord(m_hLoginHandle, findRecordIn, findRecordOut, 5000);
|
// 获取后指针类型需要 read
|
findRecordOut.read();
|
findRecordIn.read();
|
queryCondition.read();
|
|
if (!success) {
|
System.err.println("Find Record failed: " + ToolKits.getErrorCode());
|
return;
|
}
|
System.out.println("Find Record Succeed" + "\n" + "FindHandle :" + findRecordOut.lFindeHandle);
|
|
///////////////////////////////////// GetCount ///////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
int totalRecord = GetTotalRecordCount(findRecordOut.lFindeHandle);
|
System.out.println("Total Record Count: " + totalRecord);
|
|
if(totalRecord <= 0) {
|
System.out.println("No Record Found.");
|
FindRecordClose(findRecordOut.lFindeHandle);
|
return;
|
}
|
|
///////////////////////////////////// 是否展示数据 /////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
Scanner sc = new Scanner(System.in);
|
while (true) {
|
System.out.println("是否查看记录? Y/N");
|
String input = sc.next();
|
|
if (input.toUpperCase().equals("Y"))
|
break;
|
else if (input.toUpperCase().equals("N")) {
|
FindRecordClose(findRecordOut.lFindeHandle);
|
return;
|
} else {
|
System.out.println("输入不合法");
|
}
|
}
|
|
///////////////////////////////////// 如何展示数据 /////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
System.out.println("单次获取记录数量?( 小于等于0或大于总记录数 表示默认值 10)");
|
int singleFetch = sc.nextInt();
|
final int nRecordCount = (singleFetch > 0 && singleFetch <= totalRecord) ? singleFetch : 10; // 单次获取数量
|
|
int maxFetchTimes = (totalRecord / nRecordCount) + 1; // 最大获取次数
|
System.out.println("最多获取几次数据?( 小于等于0或大于最大获取次数 表示不限次数全部获取)");
|
int totalTimes = sc.nextInt();
|
final int nFetchCount = (totalTimes > 0 && totalTimes <= maxFetchTimes) ? totalTimes : maxFetchTimes; // 总的获取数量
|
|
///门禁刷卡记录记录集信息
|
NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC[] records = new NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC[nRecordCount];
|
for (int i = 0; i < nRecordCount; i++) {
|
records[i] = new NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC();
|
}
|
|
///CLIENT_FindNextRecord 入参
|
NetSDKLib.NET_IN_FIND_NEXT_RECORD_PARAM findNextRecordIn = new NetSDKLib.NET_IN_FIND_NEXT_RECORD_PARAM();
|
findNextRecordIn.lFindeHandle = findRecordOut.lFindeHandle;
|
findNextRecordIn.nFileCount = nRecordCount; //想查询的记录条数
|
|
///CLIENT_FindNextRecord 出参
|
NetSDKLib.NET_OUT_FIND_NEXT_RECORD_PARAM findNextRecordOut = new NetSDKLib.NET_OUT_FIND_NEXT_RECORD_PARAM();
|
findNextRecordOut.nMaxRecordNum = nRecordCount;
|
findNextRecordOut.pRecordList = new Memory(records[0].dwSize * nRecordCount);
|
findNextRecordOut.pRecordList.clear(records[0].dwSize * nRecordCount);
|
|
// 将 native 数据初始化
|
ToolKits.SetStructArrToPointerData(records, findNextRecordOut.pRecordList);
|
|
int count = 0; //循环的次数
|
int recordIndex = 0;
|
|
while (count < nFetchCount) { //循环查询
|
|
if (!netsdk.CLIENT_FindNextRecord(findNextRecordIn, findNextRecordOut, 5000)) {
|
System.err.println("FindNextRecord Failed: " + ToolKits.getErrorCode());
|
break;
|
}
|
|
/// 将 native 数据转为 java 数据
|
ToolKits.GetPointerDataToStructArr(findNextRecordOut.pRecordList, records);
|
for (int i = 0; i < findNextRecordOut.nRetRecordNum; i++) {
|
recordIndex = i + count * nRecordCount + 1;
|
|
StringBuilder builder = new StringBuilder();
|
try {
|
builder.append("<<----------------[").append(recordIndex).append("]---------------->>\n")
|
.append("刷卡时间:").append(records[i].stuTime.toStringTime()).append("\n")
|
.append("卡号:").append(new String(records[i].szCardNo).trim()).append("\n")
|
.append("卡类型:").append(records[i].emCardType).append("\n")
|
.append("门号:").append(records[i].nDoor).append("\n")
|
.append("密码:").append(new String(records[i].szPwd).trim()).append("\n")
|
.append("开门方式:").append(records[i].emMethod).append("\n")
|
.append("开门结果:").append(records[i].bStatus == 1 ? "成功" : "失败").append("\n")
|
.append("开门用户: ").append(new String(records[i].szUserID, encode).trim()).append("\n")
|
.append("开门失败原因错误码: ").append(records[i].nErrorCode).append("\n")
|
.append("考勤状态: ").append(records[i].emAttendanceState).append("\n")
|
.append("卡命名: ").append(new String(records[i].szCardName, encode).trim()).append("\n")
|
.append("证件号: ").append(new String(records[i].szCitizenIDNo, encode).trim()).append("\n")
|
.append("人证比对结果: ").append(records[i].bCitizenIDResult == 0 ? "失败" : "成功").append("\n")
|
.append("性别: ").append((records[i].emSex == 1) ? "男" : (records[i].emSex == 2 ? "女" : "未知或未说明")).append("\n")
|
.append("姓名: ").append(new String(records[i].szCitizenIDName, encode).trim()).append("\n")
|
.append("住址:").append(new String(records[i].szCitizenIDAddress, encode).trim()).append("\n")
|
.append("签发机关: ").append(new String(records[i].szCitizenIDAuthority, encode).trim()).append("\n")
|
.append("起始日期: ").append(records[i].stuCitizenIDStart.toStringTime()).append("\n");
|
|
if (records[i].bIsEndless != 0) { // 是否长期有效
|
builder.append("截止日期: ").append("永久").append("\n");
|
} else {
|
builder.append("截止日期: ").append(records[i].stuCitizenIDEnd.toStringTime()).append("\n");
|
}
|
builder.append("人脸质量: ").append(records[i].nScore).append("\n")
|
.append("人脸图片地址: ").append(new String(records[i].szSnapFaceURL, encode).trim()).append("\n")
|
.append("证件图片地址: ").append(new String(records[i].szCitizenPictureURL, encode).trim());
|
} catch (UnsupportedEncodingException e) {
|
e.printStackTrace();
|
}
|
System.out.println(builder.toString());
|
}
|
// 当 nRetRecordNum < nRecordCount 时说明已获取到最后一个批次
|
if (findNextRecordOut.nRetRecordNum < nRecordCount || recordIndex == totalRecord) {
|
break;
|
}
|
count++;
|
}
|
FindRecordClose(findRecordOut.lFindeHandle);
|
}
|
|
/**
|
* 结束查找记录
|
*
|
* @param m_lFindHandle 查询句柄
|
*/
|
private static void FindRecordClose(NetSDKLib.LLong m_lFindHandle) {
|
boolean success;
|
success = netsdk.CLIENT_FindRecordClose(m_lFindHandle);
|
if (!success) {
|
System.err.println("Failed to Close: " + String.format("0x%x", netsdk.CLIENT_GetLastError()));
|
}
|
}
|
|
/**
|
* 获取查询总记录条数
|
*
|
* @param findHandle 查询句柄
|
* @return 记录数目
|
*/
|
public static int GetTotalRecordCount(NetSDKLib.LLong findHandle) {
|
// 入参
|
NetSDKLib.NET_IN_QUEYT_RECORD_COUNT_PARAM paramIn = new NetSDKLib.NET_IN_QUEYT_RECORD_COUNT_PARAM();
|
paramIn.lFindeHandle.setValue(findHandle.longValue());
|
// 出参
|
NetSDKLib.NET_OUT_QUEYT_RECORD_COUNT_PARAM paramOut = new NetSDKLib.NET_OUT_QUEYT_RECORD_COUNT_PARAM();
|
|
boolean bRet = netsdk.CLIENT_QueryRecordCount(paramIn, paramOut, 3000);
|
if (!bRet) {
|
System.err.println("Can't FindNextRecord" + ToolKits.getErrorCode());
|
return -1;
|
}
|
return paramOut.nRecordCount;
|
}
|
|
// 从远程下载图片
|
public void DownloadRemotePic() {
|
|
Scanner sc = new Scanner(System.in);
|
System.out.println("远程地址:");
|
String remotePath = sc.next();
|
System.out.println("文件名: ");
|
String saveName = sc.next();
|
|
File path = new File("AccessFacePic/RemoteFile");
|
if (!path.exists()) path.mkdir();
|
|
NetSDKLib.NET_IN_DOWNLOAD_REMOTE_FILE pInParam = new NetSDKLib.NET_IN_DOWNLOAD_REMOTE_FILE();
|
pInParam.pszFileName = new NativeString(remotePath).getPointer();
|
pInParam.pszFileDst = new NativeString(path + "/" + saveName).getPointer();
|
|
NetSDKLib.NET_OUT_DOWNLOAD_REMOTE_FILE pOutParam = new NetSDKLib.NET_OUT_DOWNLOAD_REMOTE_FILE();
|
|
if (!netsdk.CLIENT_DownloadRemoteFile(m_hLoginHandle, pInParam, pOutParam, 3000)) {
|
System.err.printf("CLIENT_DownloadRemoteFile failed, ErrCode=%s\n", ToolKits.getErrorCode());
|
} else {
|
System.out.println("CLIENT_DownloadRemoteFile success");
|
}
|
}
|
|
|
/////////////////////////////////////// 简易控制台 ///////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
// 初始化测试
|
public void InitTest() {
|
|
FaceQualityUtils.Init(); // 初始化SDK库
|
netsdk.CLIENT_SetDVRMessCallBackEx1(messCallBackEx1, null); // 注册一般事件回调函数
|
this.loginWithHighLevel(); // 高安全登录
|
}
|
|
/**
|
* 加载测试内容
|
*/
|
public void RunTest() {
|
|
CaseMenu menu = new CaseMenu();
|
menu.addItem(new CaseMenu.Item(this, "智能事件订阅", "AttachEventRealLoadPic"));
|
menu.addItem(new CaseMenu.Item(this, "智能事件退订", "DetachEventRealLoadPic"));
|
menu.addItem(new CaseMenu.Item(this, "选择通道", "setChannelID"));
|
// menu.addItem(new CaseMenu.Item(this, "报警事件订阅", "AttachEventStartListen"));
|
// menu.addItem(new CaseMenu.Item(this, "报警事件退订", "DetachEventStopListen"));
|
menu.addItem(new CaseMenu.Item(this, "按卡号查询刷卡记录", "TestQueryRecordByNo"));
|
menu.addItem(new CaseMenu.Item(this, "按时间查询刷卡记录", "TestQueryRecordByTime"));
|
menu.addItem(new CaseMenu.Item(this, "查询全部刷卡记录", "TestQueryAllRecords"));
|
menu.addItem(new CaseMenu.Item(this, "下载设备图片", "DownloadRemotePic"));
|
menu.run();
|
|
}
|
|
/**
|
* 结束测试
|
*/
|
public void EndTest() {
|
|
System.out.println("End Test");
|
this.logOut(); // 退出
|
|
System.out.println("See You...");
|
FaceQualityUtils.cleanAndExit(); // 清理资源并退出
|
}
|
|
/////////////// 配置登陆地址,端口,用户名,密码 ////////////////////////
|
// private String m_strIpAddr = "10.34.3.63";
|
private String m_strIpAddr = "172.5.9.98";
|
private int m_nPort = 37777;
|
private String m_strUser = "admin";
|
private String m_strPassword = "admin123";
|
// private String m_strPassword = "admin";
|
//////////////////////////////////////////////////////////////////////
|
|
public static void main(String[] args) {
|
/**
|
* 本次需求要求增加的 “人脸质量” 字段涉及到 2个事件组和1个查询接口,分别是:
|
* 门禁事件(智能)、认证比对事件(智能)、门禁记录查询。
|
* Demo中 “智能事件订阅/退订” 包含 “门禁”、“认证比对” 的智能事件,由于是按通道订阅,所以还提供了 "选择通道" 菜单项。
|
* Demo中 “按卡号/按时间/全部 查询” 包含了 “门禁记录查询” 的三种主要查询方式。
|
* Demo 最后还提供了一个下载远程图片的接口,用于查看查询记录中的图片信息。
|
*
|
* 注意:sdk对普通 “门禁” 和 “人证比对” 事件(无图事件)也扩充了 “人脸质量” 字段,但这次的需求中并不涉及所以设备暂不支持。
|
* Demo 中这一部分相关示例请见 RunTest()中被注释的部分,以后如果有需要可以参考。
|
*/
|
FaceQualityDemo demo = new FaceQualityDemo();
|
|
if (args.length == 4) {
|
demo.m_strIpAddr = args[0];
|
demo.m_nPort = Integer.parseInt(args[1]);
|
demo.m_strUser = args[2];
|
demo.m_strPassword = args[3];
|
}
|
|
demo.InitTest();
|
demo.RunTest();
|
demo.EndTest();
|
}
|
|
}
|