package com.netsdk.lib.callback.impl; import com.netsdk.lib.NetSDKLib; import com.netsdk.lib.callback.BasicVideoStatHeatMapCallBack; import com.netsdk.lib.callback.fVideoStatHeatMapCallBack; import com.netsdk.lib.enumeration.EM_HEATMAP_TYPE; import com.netsdk.module.HeatMapModule; import com.netsdk.module.entity.HeatMapData; import com.netsdk.module.entity.HeatMapGrayData; import com.sun.jna.Pointer; import java.util.concurrent.ConcurrentHashMap; /** * @author 47081 * @version 1.0 * @description 热度图回调函数的默认实现, 回调函数建议写成单例模式, 不然容易导致sdk出现意想不到的错误 * @date 2020/9/24 */ public class DefaultVideoStatHeatMapCallBack extends BasicVideoStatHeatMapCallBack { private HeatMapModule module; /** 由于热度图数据是分多次发送,需要判断数据接收完整再处理 */ private ConcurrentHashMap binDatas; /** 用于外部获取灰度图数据 */ public static ConcurrentHashMap grayDatas = new ConcurrentHashMap(); private static DefaultVideoStatHeatMapCallBack instance; private DefaultVideoStatHeatMapCallBack() { this.module = new HeatMapModule(); this.binDatas = new ConcurrentHashMap(); } public static fVideoStatHeatMapCallBack getInstance() { if (instance == null) { instance = new DefaultVideoStatHeatMapCallBack(); } return instance; } /** * 解析数据 * * @param attachHandle 订阅句柄 * @param nToken 获取数据的句柄,即调用{@link * com.netsdk.lib.NetSDKLib#CLIENT_GetVideoStatHeatMap(NetSDKLib.LLong, Pointer, Pointer, * int)} 对应其出参的nToken字段{@link com.netsdk.lib.structure.NET_OUT_GET_VIDEOSTAT_HEATMAP#nToken} * @param type 热度图类型 * @param binData 热度图字节数据 */ @Override public void parseData(long attachHandle, int nToken, EM_HEATMAP_TYPE type, byte[] binData) { System.out.println( "receive heatmap data. attachHandle:" + attachHandle + ",nToken:" + nToken + ",type:" + type.getType() + "," + type.getDesc() + " data length:" + binData.length); // 协议描述:每个getHeatMap请求的结果分多个包来发送,每个包的大小在 “4~7此次数据总长度”中描述,每个包的 “8~11 // 总行数(总轨迹条数)”相同,每个包的“12~15本次行数(本次轨迹条数)”表示本包的数据数量,最后一个包的“12~15本次行数(本次轨迹条数)”值为0,表示数据发送完毕。 // 当总行数(或者总轨迹条数)和本次行数(或者本次轨迹条数)都为0时,表示没有数据。 // 当总行数(或者总轨迹条数)不为0,而本次行数(或者本次轨迹条数)为0时表示,数据已经传完 // 对binData进行过滤 byte[] temp = new byte[4]; System.arraycopy(binData, 7, temp, 0, 4); // 总行数 int totalLine = byte2Int(temp); System.arraycopy(binData, 11, temp, 0, 4); // 本次行数 int currentLine = byte2Int(temp); if (totalLine == 0 && currentLine == 0) { System.out.println("token:" + nToken + ",本次没有数据"); return; } // 总行数和本次行数都不为0时,说明数据有效 if (totalLine != 0 && currentLine != 0) { HeatMapData heatMapData = binDatas.get(nToken); // 获取宽高,宽16-17位,高18-19位 int width = ((binData[16] & 0xFF)) | ((binData[17] & 0xFF) << 8); int height = ((binData[18] & 0xFF)) | ((binData[19] & 0xFF) << 8); if (heatMapData == null) { heatMapData = new HeatMapData(width, height, binData); } else { /** 目前设备端处理是一个完整数据包和一个结束包,以下代码基本不会被执行到, 先按协议进行多包数据拼接处理 */ // 获取已保存数据的数据行数 System.arraycopy(heatMapData.getData(), 11, temp, 0, 4); int savedLine = byte2Int(temp); // 合并后的本次行数 int currentTotal = savedLine + currentLine; byte[] bytes = int2ByteArr(currentTotal); System.arraycopy(bytes, 0, heatMapData.getData(), 11, bytes.length); // 去掉数据头,数据头为32位 byte[] data = new byte[binData.length - 32]; System.arraycopy(binData, 32, data, 0, data.length); // 追加到完整数据包中 heatMapData.addData(data); } // 将数据存到map中 binDatas.put(nToken, heatMapData); } // 数据接收完成 if (totalLine != 0 && currentLine == 0) { // 将数据取出 HeatMapData heatMapData = binDatas.get(nToken); if (heatMapData != null) { System.out.println( "width:" + heatMapData.getWidth() + ",height:" + heatMapData.getHeight() + ",data length:" + heatMapData.getData().length); // 热度图数据转灰度图 byte[] grayData = module.transferGray( heatMapData.getData(), heatMapData.getWidth(), heatMapData.getHeight()); // 销毁binData数据 binDatas.remove(nToken); // 保存灰度图数据 grayDatas.put( nToken, new HeatMapGrayData(heatMapData.getWidth(), heatMapData.getHeight(), grayData)); } } } /** * 将byte[4]转成int * * @param src * @return */ private int byte2Int(byte[] src) { int value; value = (int) ((src[0] & 0xFF) | ((src[1] & 0xFF) << 8) | ((src[2] & 0xFF) << 16) | ((src[3] & 0xFF) << 24)); return value; } /** * int转成byte[],长度为4 * * @param value * @return */ private byte[] int2ByteArr(int value) { byte[] bytes = new byte[4]; bytes[3] = (byte) (value >> 24); bytes[2] = (byte) (value >> 16); bytes[1] = (byte) (value >> 8); bytes[0] = (byte) (value); return bytes; } }