‘liusuyi’
2023-12-28 8e384e65b3fc9b0c9116cf2ec2c11e3ad3bc361e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
package com.ard.utils.sdk.hiksdk.service;
 
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ard.alarm.camera.domain.ArdCameras;
import com.ard.alarm.camera.domain.CameraCmd;
import com.ard.alarm.camera.service.impl.ArdCamerasServiceImpl;
import com.ard.alarm.external.domain.ArdEquipExternal;
import com.ard.alarm.external.service.impl.ArdEquipExternalServiceImpl;
import com.ard.utils.sdk.hiksdk.domain.*;
import com.ard.utils.minio.MinioUtil;
import com.ard.utils.sdk.hiksdk.domain.isapi.IsapiAlarm;
import com.ard.utils.util.ByteUtils;
import com.ard.utils.sdk.hiksdk.common.GlobalVariable;
import com.ard.utils.sdk.hiksdk.util.hikSdkUtil.HCNetSDK;
import com.ard.utils.util.DateUtils;
import com.ard.utils.mqtt.MqttProducer;
import com.ard.utils.util.IdUtils;
import com.sun.jna.Pointer;
import lombok.extern.slf4j.Slf4j;
 
import java.io.*;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Optional;
 
import static com.ard.utils.sdk.hiksdk.util.hikSdkUtil.HCNetSDK.*;
 
/**
 * @ClassName: FMSGCallBack
 * @Description:
 * @Author: Administrator
 * @Date: 2023年02月15日 12:16
 * @Version: 1.0
 **/
@Slf4j(topic = "hikSdk")
public class FMSGCallBack implements HCNetSDK.FMSGCallBack_V31 {
 
    /**
     * 报警信息回调函数
     *
     * @param lCommand   上传消息类型
     * @param pAlarmer   报警设备信息
     * @param pAlarmInfo 报警信息
     * @param dwBufLen   报警信息缓存大小
     * @param pUser      用户数据
     */
    @Override
    public boolean invoke(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser) {
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String sDeviceIP = ByteUtils.bytesToStringZh(pAlarmer.sDeviceIP).trim();//设备IP地址
        int wLinkPort = pAlarmer.wLinkPort;//设备通讯端口
        //通过ip和端口查询设备
        Optional<ArdCameras> foundCamera = findArdCameraByIpAndPort(sDeviceIP, wLinkPort);
        Optional<ArdEquipExternal> foundExternal = findArdEquipExternalByIpAndPort(sDeviceIP, wLinkPort);
        ArdCameras camera = null;
        ArdEquipExternal ardEquipExternal = null;
        if (foundCamera.isPresent()) {
            camera = foundCamera.get();
        } else {
            if (foundExternal.isPresent()) {
                ardEquipExternal = foundExternal.get();
            }
        }
        //如果没有找到设备,直接返回
        if (camera == null && ardEquipExternal == null) {
            return false;
        }
        String alarmName = "";//报警名称
        String alarmTime;//事件时间
        String alarmType = "";//报警类型
        String picUrl = "";//事件图片
        String facePicUrl = "";//人脸抓拍图片
        int dwPicDataLen;//图片数据长度
        int chanNo = 0;//通道号
        //lCommand是传的报警类型
        log.debug("【" + sDeviceIP + ":" + wLinkPort + "】报警事件类型:lCommand:" + Integer.toHexString(lCommand));
        switch (lCommand) {
            case COMM_ALARM_V30:
                log.debug("移动侦测信息上报");
                //region 移动侦测、视频丢失、遮挡、IO信号量等报警信息(V3.0以上版本支持的设备)
                HCNetSDK.NET_DVR_ALARMINFO_V30 netDvrAlarminfoV30 = new HCNetSDK.NET_DVR_ALARMINFO_V30();
                netDvrAlarminfoV30.write();
                Pointer pNDAInfo = netDvrAlarminfoV30.getPointer();
                pNDAInfo.write(0, pAlarmInfo.getByteArray(0, netDvrAlarminfoV30.size()), 0, netDvrAlarminfoV30.size());
                netDvrAlarminfoV30.read();
                switch (netDvrAlarminfoV30.dwAlarmType) {
                    case 3:
                        if (camera != null) {
                            for (byte b : netDvrAlarminfoV30.byChannel) {
                                if (b == 1) {
                                    chanNo = b;
                                    switch (camera.getGdType()) {
                                        case "0":
                                            cameraEventHandler(camera, chanNo, "移动侦测", "移动侦测报警", fmt.format(new Date()), picUrl, "");
                                            break;
                                    }
                                }
                            }
                        }
                        break;
                }
                //endregion
                break;
            case COMM_VCA_ALARM:
                log.debug("智能检测通用信息上报(暂不解析)");
            case COMM_ALARM_RULE:
                log.debug("异常行为识别信息上报");
                //region 异常行为识别信息
                HCNetSDK.NET_VCA_RULE_ALARM strVcaAlarm = new HCNetSDK.NET_VCA_RULE_ALARM();
                strVcaAlarm.write();
                Pointer pVCAInfo = strVcaAlarm.getPointer();
                pVCAInfo.write(0, pAlarmInfo.getByteArray(0, strVcaAlarm.size()), 0, strVcaAlarm.size());
                strVcaAlarm.read();
                Integer ruleID = Integer.valueOf(strVcaAlarm.struRuleInfo.byRuleID);
                alarmTime = DateUtils.parseTime(strVcaAlarm.dwAbsTime);//事件时间
                chanNo = Integer.valueOf(strVcaAlarm.struDevInfo.byChannel);//通道
                switch (strVcaAlarm.struRuleInfo.wEventTypeEx) {
                    case 1: //region穿越警戒面 (越界侦测)
                        alarmType = "越界侦测报警";
                        //endregion
                        break;
                    case 2: //region 目标进入区域
                        alarmType = "目标进入区域报警";
                        //endregion
                        break;
                    case 3: //region 目标离开区域
                        alarmType = "目标离开区域报警";
                        //strVcaAlarm.struRuleInfo.uEventParam.setType(HCNetSDK.NET_VCA_AREA.class);
                        //endregion
                        break;
                    case 4: //region 周界入侵
                        alarmType = "周界入侵报警";
                        //endregion
                        break;
                    case 5: //region 徘徊
                        alarmType = "徘徊事件报警";
                        //endregion
                        break;
                    case 8: //region 快速移动(奔跑)
                        alarmType = "快速移动报警";
                        //endregion
                        break;
                    case 9: //region 人员聚集报警
                        alarmType = "人员聚集报警";
                        //endregion
                        break;
                    case 13: //region 物品遗留事件
                        alarmType = "物品遗留事件报警";
                        //endregion
                        break;
                    case 14: //region 物品拿取事件
                        alarmType = "物品拿取事件报警";
                        //endregion
                        break;
                    case 15: //region 离岗事件
                        strVcaAlarm.struRuleInfo.uEventParam.setType(HCNetSDK.NET_VCA_LEAVE_POSITION.class);
                        int byMode = strVcaAlarm.struRuleInfo.uEventParam.struLeavePos.byMode;
                        switch (byMode) {
                            case 0:
                                alarmType = "离岗事件报警";
                                break;
                            case 1:
                                alarmType = "睡岗事件报警";
                                break;
                        }
                        //endregion
                        break;
                    case 20: //region 倒地检测
                        alarmType = "倒地检测事件报警";
                        //endregion
                        break;
                    case 35: //region 人数变化事件报警
                        alarmType = "人数变化事件报警";
                        //endregion
                        break;
                    case 41: //region 滞留检测
                        alarmType = "滞留检测事件报警";
                        //endregion
                        break;
                    case 44: //region 玩手机
                        alarmType = "玩手机事件报警";
                        //endregion
                        break;
                    default:
                        log.debug("未知异常行为事件类型:" + strVcaAlarm.struRuleInfo.wEventTypeEx);
                        break;
                }
                //图片接收
                int byPicType = strVcaAlarm.byPicType;
                dwPicDataLen = strVcaAlarm.dwPicDataLen;
                int byPicTransType = strVcaAlarm.byPicTransType;
                if (dwPicDataLen > 0 && strVcaAlarm.pImage != null && byPicTransType == 0) {
                    picUrl = saveBinPicToMinio(strVcaAlarm.pImage, dwPicDataLen);
                }
                if (camera != null) {
                    alarmName = "异常行为识别";
                    switch (camera.getGdType()) {
                        case "0":
                            cameraEventHandler(camera, chanNo, alarmName, alarmType, alarmTime, picUrl, "");
                            break;
                        case "3":
                            superBrainEventHandler(camera, chanNo, alarmName, alarmType, alarmTime, picUrl, "");
                            break;
                    }
                }
                //endregion
                break;
            case COMM_UPLOAD_FACESNAP_RESULT:
                log.debug("人脸抓拍报警信息上报");
                //region 人脸抓拍报警信息
                HCNetSDK.NET_VCA_FACESNAP_RESULT struFaceSnap = new HCNetSDK.NET_VCA_FACESNAP_RESULT();
                struFaceSnap.write();
                Pointer vcaInfo = struFaceSnap.getPointer();
                vcaInfo.write(0, pAlarmInfo.getByteArray(0, struFaceSnap.size()), 0, struFaceSnap.size());
                struFaceSnap.read();
                alarmTime = DateUtils.parseTime(struFaceSnap.dwAbsTime);
                String facePicTyp;
                chanNo = struFaceSnap.struDevInfo.byChannel;
                switch (struFaceSnap.byUploadEventDataType) {
                    case 0:
                        facePicTyp = "二进制数据";
                        break;
                    case 1:
                        facePicTyp = "URL";
                        break;
                    default:
                        facePicTyp = "";
                        break;
                }
                if (struFaceSnap.dwFacePicLen > 0 && struFaceSnap.pBuffer1 != null) {
                    facePicUrl = saveBinPicToMinio(struFaceSnap.pBuffer1, struFaceSnap.dwFacePicLen);
                }
                if (struFaceSnap.dwBackgroundPicLen > 0 && struFaceSnap.pBuffer2 != null) {
                    picUrl = saveBinPicToMinio(struFaceSnap.pBuffer2, struFaceSnap.dwBackgroundPicLen);
                }
                //log.debug("【人脸抓拍报警信息】: alarmTime:" + alarmTime + " picUrl:" + picUrl + " facePicType:" + facePicTyp + " facePicUrl:" + facePicUrl);
                if (camera != null) {
                    alarmName = "人脸抓拍检测";
                    alarmType = "人脸抓拍报警";
                    switch (camera.getGdType()) {
                        case "0":
                            cameraEventHandler(camera, chanNo, alarmName, alarmType, alarmTime, "", "");
                            break;
                        case "3":
                            superBrainEventHandler(camera, chanNo, alarmName, alarmType, alarmTime, picUrl, facePicUrl);
                            break;
                    }
                }
                //endregion
                break;
            case COMM_SNAP_MATCH_ALARM:
                log.debug("人脸比对报警信息上报");
                //region 人脸比对报警信息
                HCNetSDK.NET_VCA_FACESNAP_MATCH_ALARM struFaceMatchAlarm = new HCNetSDK.NET_VCA_FACESNAP_MATCH_ALARM();
                struFaceMatchAlarm.write();
                Pointer fmaInfo = struFaceMatchAlarm.getPointer();
                fmaInfo.write(0, pAlarmInfo.getByteArray(0, struFaceMatchAlarm.size()), 0, struFaceMatchAlarm.size());
                struFaceMatchAlarm.read();
                alarmTime = DateUtils.parseTime(struFaceMatchAlarm.struSnapInfo.dwAbsTime);//报警时间
                chanNo = struFaceMatchAlarm.struSnapInfo.struDevInfo.byChannel;
                int byMatchPicNum = struFaceMatchAlarm.byMatchPicNum;//匹配图片数量
                int picTransType = struFaceMatchAlarm.byPicTransType;////图片数据传输方式: 0-二进制;1-url
                String contrastStatus = "";
                switch (struFaceMatchAlarm.byContrastStatus) {
                    case 1:
                        contrastStatus = "比对成功";
                        break;
                    case 2:
                        contrastStatus = "比对失败";
                        break;
                    default:
                        contrastStatus = "未知";
                        break;
                }
                String BlockType = "";
                switch (struFaceMatchAlarm.struBlockListInfo.struBlockListInfo.byType) {
                    case 1:
                        BlockType = "陌生人报警";
                        break;
                    case 2:
                        BlockType = "人脸比对报警";
                        break;
                    default:
                        BlockType = "未知";
                        break;
                }
                //人脸比对报警图片保存,图片格式URL格式
                if ((struFaceMatchAlarm.dwSnapPicLen > 0) && (struFaceMatchAlarm.byPicTransType == 1)) {
 
                    long offset = 0;
                    ByteBuffer buffers = struFaceMatchAlarm.pSnapPicBuffer.getByteBuffer(offset, struFaceMatchAlarm.dwSnapPicLen);
                    byte[] bytes = new byte[struFaceMatchAlarm.dwSnapPicLen];
                    buffers.rewind();
                    buffers.get(bytes);
                    picUrl = new String(bytes);
                    //log.debug("抓拍图URL:" + picUrl);
                }
                if ((struFaceMatchAlarm.struSnapInfo.dwSnapFacePicLen > 0) && (struFaceMatchAlarm.byPicTransType == 1)) {
 
                    long offset = 0;
                    ByteBuffer buffers = struFaceMatchAlarm.struSnapInfo.pBuffer1.getByteBuffer(offset, struFaceMatchAlarm.struSnapInfo.dwSnapFacePicLen);
                    byte[] bytes = new byte[struFaceMatchAlarm.struSnapInfo.dwSnapFacePicLen];
                    buffers.rewind();
                    buffers.get(bytes);
                    facePicUrl = new String(bytes);
                    //System.out.println("抓拍人脸子图URL:" + SnapPicUrl);
                }
                if ((struFaceMatchAlarm.struBlockListInfo.dwBlockListPicLen > 0) && (struFaceMatchAlarm.byPicTransType == 1)) {
 
                    long offset = 0;
                    ByteBuffer buffers = struFaceMatchAlarm.struBlockListInfo.pBuffer1.getByteBuffer(offset, struFaceMatchAlarm.struBlockListInfo.dwBlockListPicLen);
                    byte[] bytes = new byte[struFaceMatchAlarm.struBlockListInfo.dwBlockListPicLen];
                    buffers.rewind();
                    buffers.get(bytes);
                    String faceLibUrl = new String(bytes);
                    //System.out.println("人脸库人脸图的URL:" + SnapPicUrl);
                }
                //人脸比对报警图片保存,图片格式二进制
                //if ((struFaceMatchAlarm.dwSnapPicLen > 0) && (struFaceMatchAlarm.byPicTransType == 0)) {
                //    picUrl = saveBinPicToMinio(struFaceMatchAlarm.pSnapPicBuffer, struFaceMatchAlarm.dwSnapPicLen);
                //}
                //if ((struFaceMatchAlarm.struSnapInfo.dwSnapFacePicLen > 0) && (struFaceMatchAlarm.byPicTransType == 0)) {
                //    facePicUrl = saveBinPicToMinio(struFaceMatchAlarm.struSnapInfo.pBuffer1, struFaceMatchAlarm.struSnapInfo.dwSnapFacePicLen);
                //}
                //if ((struFaceMatchAlarm.struBlockListInfo.dwBlockListPicLen > 0) && (struFaceMatchAlarm.byPicTransType == 0)) {
                //    //String faceBlockPicUrl = saveBinPicToMinio(struFaceMatchAlarm.struBlockListInfo.pBuffer1, struFaceMatchAlarm.struBlockListInfo.dwBlockListPicLen);
                //}
                if (camera != null) {
                    alarmName = "人脸比对检测";
                    alarmType = BlockType + "[" + contrastStatus + "]";
                    switch (camera.getGdType()) {
                        case "0":
                            cameraEventHandler(camera, chanNo, alarmName, alarmType, alarmTime, "", "");
                            break;
                        case "3":
                            superBrainEventHandler(camera, chanNo, alarmName, alarmType, alarmTime, picUrl, facePicUrl);
                            break;
                    }
                }
                //endregion
                break;
            case COMM_UPLOAD_AIOP_VIDEO:
                log.debug("AI视频检测报警上传");
                //region AI开放平台接入视频检测
                HCNetSDK.NET_AIOP_VIDEO_HEAD struAIOPVideo = new HCNetSDK.NET_AIOP_VIDEO_HEAD();
                struAIOPVideo.write();
                Pointer pAIOPVideo = struAIOPVideo.getPointer();
                pAIOPVideo.write(0, pAlarmInfo.getByteArray(0, struAIOPVideo.size()), 0, struAIOPVideo.size());
                struAIOPVideo.read();
                log.debug("视频任务ID" + new String(struAIOPVideo.szTaskID).trim());
                log.debug("通道号:" + struAIOPVideo.dwChannel);
                String szMPID = new String(struAIOPVideo.szMPID).trim();//检测模型包ID
                log.debug("检测模型包ID" + szMPID);
                alarmTime = String.format("%04d", struAIOPVideo.struTime.wYear) + "-" +
                        String.format("%02d", struAIOPVideo.struTime.wMonth) + "-" +
                        String.format("%02d", struAIOPVideo.struTime.wDay) + " " +
                        String.format("%02d", struAIOPVideo.struTime.wHour) + ":" +
                        String.format("%02d", struAIOPVideo.struTime.wMinute) + ":" +
                        String.format("%02d", struAIOPVideo.struTime.wSecond);
                // + "." + String.format("%03d", struAIOPVideo.struTime.wMilliSec);
                chanNo = struAIOPVideo.dwChannel;
                switch (szMPID) {
                    case "H930_MODEL_SPD":
                        alarmType = "抽烟打电话";
                        break;
                }
                //图片数据保存
                if (struAIOPVideo.dwPictureSize > 0) {
                    picUrl = saveBinPicToMinio(struAIOPVideo.pBufferPicture, struAIOPVideo.dwPictureSize);
                }
                if (camera != null) {
                    alarmName = "AI视频检测";
                    switch (camera.getGdType()) {
                        case "3":
                            superBrainEventHandler(camera, chanNo, alarmName, alarmType, alarmTime, picUrl, facePicUrl);
                            break;
                    }
                }
                //endregion
                break;
            case COMM_ISAPI_ALARM://ISAPI协议报警信息
                log.debug("ISAPI协议报警信息上报");
                //region ISAPI协议报警信息
                HCNetSDK.NET_DVR_ALARM_ISAPI_INFO struEventISAPI = new HCNetSDK.NET_DVR_ALARM_ISAPI_INFO();
                struEventISAPI.write();
                Pointer pEventISAPI = struEventISAPI.getPointer();
                pEventISAPI.write(0, pAlarmInfo.getByteArray(0, struEventISAPI.size()), 0, struEventISAPI.size());
                struEventISAPI.read();
                int dwAlarmDataLen = struEventISAPI.dwAlarmDataLen;// 报警数据长度
                int byDataType = struEventISAPI.byDataType;// 0-invalid,1-xml,2-json
                int byPicturesNumber = struEventISAPI.byPicturesNumber;// 图片数量
                if (dwAlarmDataLen > 0) {//报警数据打印
                    HCNetSDK.BYTE_ARRAY m_strISAPIData = new HCNetSDK.BYTE_ARRAY(struEventISAPI.dwAlarmDataLen);
                    m_strISAPIData.write();
                    Pointer pPlateInfo = m_strISAPIData.getPointer();
                    pPlateInfo.write(0, struEventISAPI.pAlarmData.getByteArray(0, m_strISAPIData.size()), 0, m_strISAPIData.size());
                    m_strISAPIData.read();
                    String json = new String(m_strISAPIData.byValue).trim();
                    // log.debug(new String(m_strISAPIData.byValue).trim() + "\n");
                    //解析JSON数据
                    if (byDataType == 2) {
                        IsapiAlarm isapiAlarm = JSONObject.parseObject(json, IsapiAlarm.class);
                        alarmName = "ISAPI协议信息检测";
                        switch (isapiAlarm.getEventType()) {
                            //case "HFPD":
                            //chanNo = isapiAlarm.getChannelID();
                            //alarmType = "高频人员事件报警";
                            //picUrl = isapiAlarm.getFaceCapture().get(0).getTargetAttrs().getBkgUrl();
                            //facePicUrl = isapiAlarm.getFaceCapture().get(0).getFaces().get(0).getURL();
                            // break;
                            case "safetyHelmetDetection":
                                chanNo = isapiAlarm.getChannelID();
                                alarmType = "安全帽事件报警";
                                alarmTime = fmt.format(isapiAlarm.getDateTime());
                                //图片保存
                                for (int i = 0; i < struEventISAPI.byPicturesNumber; i++) {
                                    HCNetSDK.NET_DVR_ALARM_ISAPI_PICDATA struPicData = new HCNetSDK.NET_DVR_ALARM_ISAPI_PICDATA();
                                    struPicData.write();
                                    Pointer pPicData = struPicData.getPointer();
                                    pPicData.write(0, struEventISAPI.pPicPackData.getByteArray(i * struPicData.size(), struPicData.size()), 0, struPicData.size());
                                    struPicData.read();
                                    switch (i) {
                                        case 0:
                                            picUrl = saveBinPicToMinio(struPicData.pPicData, struPicData.dwPicLen);
                                            break;
                                        case 1:
                                            facePicUrl = saveBinPicToMinio(struPicData.pPicData, struPicData.dwPicLen);
                                            break;
                                    }
                                }
                                if (camera != null) {
                                    switch (camera.getGdType()) {
                                        case "3":
                                            superBrainEventHandler(camera, chanNo, alarmName, alarmType, alarmTime, picUrl, facePicUrl);
                                            break;
                                    }
                                }
                                break;
                        }
 
                    }
                }
                //endregion
                break;
            case COMM_GISINFO_UPLOAD:
                log.debug("GPS报警信息上报(暂不解析)");
                break;
            case COMM_ALARMHOST_CID_ALARM:
                log.debug("报警主机CID报告信息上报");
                //region 报警主机报警处理
                HCNetSDK.NET_DVR_CID_ALARM netDvrCidAlarm = new HCNetSDK.NET_DVR_CID_ALARM();
                netDvrCidAlarm.write();
                Pointer pCIDInfo = netDvrCidAlarm.getPointer();
                pCIDInfo.write(0, pAlarmInfo.getByteArray(0, netDvrCidAlarm.size()), 0, netDvrCidAlarm.size());
                netDvrCidAlarm.read();
                //CID事件名
                String sCIDCode = ByteUtils.bytesToStringZh(netDvrCidAlarm.sCIDCode);//CID事件名
                //CID事件名
                //String sCIDDescribe = ByteUtils.bytesToStringZh(netDvrCidAlarm.sCIDDescribe);//CID事件名
                int position = ByteUtils.findIndexOfDoubleZero(netDvrCidAlarm.sCIDDescribe);
                String sCIDDescribe;
                if (position != -1) {
                    byte[] result = new byte[position];
                    System.arraycopy(netDvrCidAlarm.sCIDDescribe, 0, result, 0, position);
                    sCIDDescribe = ByteUtils.bytesToStringZh(result);
                } else {
                    sCIDDescribe = ByteUtils.bytesToStringZh(netDvrCidAlarm.sCIDDescribe);
                }
                //触发报警的时间点
                String struTriggerTime = DateUtils.convertDate(parseAlarmTime(netDvrCidAlarm.struTriggerTime), "yyyy-M-d H:m:s");
                //上传报警的时间点
                String struUploadTime = DateUtils.convertDate(parseAlarmTime(netDvrCidAlarm.struUploadTime), "yyyy-M-d H:m:s");
                //报告类型
                String byReportType = "";
                switch (netDvrCidAlarm.byReportType) {
                    case 1:
                        byReportType = "防区报警";
                        break;
                    case 2:
                        byReportType = "视频报警";
                        break;
                    case 3:
                        byReportType = "软防区报警";
                        break;
                    case 4:
                        byReportType = "挟持报警";
                        break;
                    case 5:
                        byReportType = "防拆报警 ";
                        break;
                    case 6:
                        byReportType = "操作报告 ";
                        break;
                    case 7:
                        byReportType = "异常报告 ";
                        break;
                }
                //子系统号
                Integer bySubSysNo = Integer.valueOf(netDvrCidAlarm.bySubSysNo);
                //防区号 起始0
                Integer wDefenceNo = Integer.valueOf(netDvrCidAlarm.wDefenceNo);
                //防区名称
                String wDefenceName = "";
                if (!bySubSysNo.equals(-1)) {
                    CameraCmd cmd = new CameraCmd();
                    cmd.setCameraId(ardEquipExternal.getId());
                    cmd.setWZoneIndex(wDefenceNo);
                    wDefenceName = HikClientUtil.getDefenseZoneName(cmd);
                }
                if (sCIDDescribe.contains("恢复")) {
                    return true;
                }
 
                ExternalAlarmEventInfo externalAlarmEventInfo = new ExternalAlarmEventInfo();
                externalAlarmEventInfo.setAlarmId(sCIDCode);
                externalAlarmEventInfo.setAlarmName(sCIDDescribe);
                externalAlarmEventInfo.setDefenseId((wDefenceNo + 1));
                externalAlarmEventInfo.setDefenseName(wDefenceName);
                externalAlarmEventInfo.setSubSysNo(bySubSysNo);
                externalAlarmEventInfo.setAlarmType(byReportType);
                externalAlarmEventInfo.setAlarmTime(struTriggerTime);
                externalAlarmEventInfo.setAlarmHostId(ardEquipExternal.getId());
                publishMqtt(externalAlarmEventInfo, "external");
                //endregion
                break;
            case HCNetSDK.COMM_ALARM_ACS:
                log.debug("门禁主机信息上报");
                //region 门禁主机报警处理
                HCNetSDK.NET_DVR_ACS_ALARM_INFO strACSInfo = new HCNetSDK.NET_DVR_ACS_ALARM_INFO();
                strACSInfo.write();
                Pointer acsInfo = strACSInfo.getPointer();
                acsInfo.write(0, pAlarmInfo.getByteArray(0, strACSInfo.size()), 0, strACSInfo.size());
                strACSInfo.read();
                int dwMajor = strACSInfo.dwMajor;
                if (dwMajor != 5) {
                    //只获取事件
                    // log.debug("非事件报警数据上报(暂不解析)");
                    break;
                }
                int dwMinor = strACSInfo.dwMinor;
                if (dwMinor != 80 && dwMinor != 104) {
                    //只解析真人检测失败和人脸抓拍失败的次类型事件
                    break;
                }
 
                switch (dwMinor) {
                    case 104:
                        alarmType = "真人检测失败";
                        break;
                    case 80:
                        alarmType = "人脸抓拍失败";
                        break;
                }
                log.debug("门禁主机报警上传:" + alarmType);
                alarmTime = DateUtils.convertDate(parseAlarmTime(strACSInfo.struTime), "yyyy-M-d H:m:s");
 
                //事件图片处理
                dwPicDataLen = strACSInfo.dwPicDataLen;
                if (dwPicDataLen > 0) {
                    picUrl = saveBinPicToMinio(strACSInfo.pPicData, strACSInfo.dwPicDataLen);
                }
                HCNetSDK.NET_DVR_ACS_EVENT_INFO struAcsEventInfo = strACSInfo.struAcsEventInfo;
                int byType = struAcsEventInfo.byType;
                String defenseType = "";
                switch (byType) {
                    case 0:
                        defenseType = "即时防区";
                        break;
                    case 1:
                        defenseType = "24小时防区";
                        break;
                    case 2:
                        defenseType = "延时防区";
                        break;
                    case 3:
                        defenseType = "内部防区";
                        break;
                    case 4:
                        defenseType = "钥匙防区";
                        break;
                    case 5:
                        defenseType = "火警防区";
                        break;
                    case 6:
                        defenseType = "周界防区";
                        break;
                    case 7:
                        defenseType = "24小时无声防区";
                        break;
                    case 8:
                        defenseType = "24小时辅助防区";
                        break;
                    case 9:
                        defenseType = "24小时震动防区";
                        break;
                    case 10:
                        defenseType = "门禁紧急开门防区";
                        break;
                    case 11:
                        defenseType = "门禁紧急关门防区";
                        break;
                    default:
                        defenseType = "无";
                        break;
                }
                AccessControlHostEventInfo accessControlHostEventInfo = new AccessControlHostEventInfo();
                accessControlHostEventInfo.setSerialNo(struAcsEventInfo.dwSerialNo);
                accessControlHostEventInfo.setAlarmType(alarmType);
                accessControlHostEventInfo.setDoorNo(struAcsEventInfo.dwDoorNo);
                accessControlHostEventInfo.setDefenseType(defenseType);
                accessControlHostEventInfo.setAlarmTime(alarmTime);
                accessControlHostEventInfo.setPicUrl(picUrl);
                accessControlHostEventInfo.setAcsId(ardEquipExternal.getId());
                publishMqtt(accessControlHostEventInfo, "accessControl");
                //endregion
                break;
            case COMM_FIREDETECTION_ALARM: //火点检测报警
                log.debug("火点检测信息上报");
                //region 火点检测报警
                HCNetSDK.NET_DVR_FIREDETECTION_ALARM struFireDecAlarm = new HCNetSDK.NET_DVR_FIREDETECTION_ALARM();
                struFireDecAlarm.write();
                Pointer pFireDecAlarm = struFireDecAlarm.getPointer();
                pFireDecAlarm.write(0, pAlarmInfo.getByteArray(0, struFireDecAlarm.size()), 0, struFireDecAlarm.size());
                struFireDecAlarm.read();
                switch (struFireDecAlarm.byAlarmSubType) {
                    case 0:
                        alarmType = "火点检测报警";
                        break;
                    case 1:
                        alarmType = "烟雾检测报警";
                        break;
                    case 2:
                        alarmType = "烟火报警 ";
                        break;
                }
                //String sFireDecAlarmInfo = "绝对时间:" + struFireDecAlarm.dwAbsTime + ",报警子类型:" + struFireDecAlarm.byAlarmSubType + ",火点最高温度 :" +
                //        struFireDecAlarm.wFireMaxTemperature + ",火点目标距离:" + struFireDecAlarm.wTargetDistance;
                //System.out.println(sFireDecAlarmInfo);
                //图片保存
                if ((struFireDecAlarm.dwPicDataLen > 0) && (struFireDecAlarm.byPicTransType == 0)) {
                    picUrl = saveBinPicToMinio(struFireDecAlarm.pBuffer, struFireDecAlarm.dwPicDataLen);
                }
                chanNo = struFireDecAlarm.dwVisibleChannel;
                alarmTime = DateUtils.parseTime(struFireDecAlarm.dwAbsTime);//报警时间
                if (camera != null) {
                    alarmName = "火焰检测信息上报";
                    switch (camera.getGdType()) {
                        case "3":
                            superBrainEventHandler(camera, chanNo, alarmName, alarmType, alarmTime, picUrl, facePicUrl);
                            break;
                    }
                }
                //endregion
                break;
            case COMM_ITS_PLATE_RESULT://交通抓拍的终端图片上传
                log.debug("交通抓拍的终端图片上报(暂不解析)");
                break;
            default:
                log.debug("未知报警事件类型:lCommand:" + Integer.toHexString(lCommand));
                break;
 
        }
        return true;
    }
 
    /**
     * 相机事件处理
     * 刘苏义
     * 2023/12/5 12:56:47
     */
    public void cameraEventHandler(ArdCameras camera, Integer chanNo, String alarmName, String alarmType, String alarmTime, String picUrl, String faceUrl) {
        CameraEventInfo cameraEventInfo = new CameraEventInfo();
        cameraEventInfo.setAlarmName(alarmName);
        cameraEventInfo.setAlarmTime(alarmTime);
        cameraEventInfo.setCameraName(camera.getName());
        cameraEventInfo.setCameraId(camera.getId());
        cameraEventInfo.setCameraIp(camera.getIp());
        cameraEventInfo.setCameraPort(camera.getPort());
        cameraEventInfo.setCameraType(camera.getGdType());
        cameraEventInfo.setCameraChannel(chanNo);
        cameraEventInfo.setLongitude(camera.getLongitude());
        cameraEventInfo.setLatitude(camera.getLatitude());
        cameraEventInfo.setAlarmType(alarmType);
        //图片存入minio
        if (picUrl.equals("")) {
            picUrl = snapPicture(cameraEventInfo);
        }
        cameraEventInfo.setPicUrl(picUrl);
        log.debug("处理通用光电事件报警:【Name】" + alarmName + "【Type】" + alarmType + "【Time】" + alarmTime + "【Device】" + camera.getName() + "【Url】" + picUrl);
        publishMqtt(cameraEventInfo, "camera");
    }
 
    /**
     * 超脑事件处理
     * 刘苏义
     * 2023/12/5 12:56:47
     */
    public void superBrainEventHandler(ArdCameras camera, Integer chanNo, String alarmName, String alarmType, String alarmTime, String picUrl, String faceUrl) {
 
        SuperBrainEventInfo superBrainEventInfo = new SuperBrainEventInfo();
        superBrainEventInfo.setAlarmName(alarmName);
        superBrainEventInfo.setAlarmType(alarmType);
        superBrainEventInfo.setAlarmTime(alarmTime);
        List<ChannelInfo> channelInfoList = GlobalVariable.deviceChanMap.get(camera.getId());//获取超脑的通道集合
        if (channelInfoList.size() > 0) {
            if (chanNo > 0) {
                ChannelInfo channelInfo = channelInfoList.get(chanNo - 1);//根据通道号获取通道信息
                if (channelInfo != null) {
                    Optional<ArdCameras> foundCamera = findArdCameraByIpAndPort(channelInfo.getIp(), channelInfo.getPort());
                    if (foundCamera.isPresent()) {
                        camera = foundCamera.get();
                        superBrainEventInfo.setDeviceId(camera.getId());
                        superBrainEventInfo.setDeviceName(camera.getName());
                        superBrainEventInfo.setLongitude(camera.getLongitude());
                        superBrainEventInfo.setLatitude(camera.getLatitude());
                        superBrainEventInfo.setAltitude(camera.getAltitude());
                    }
                }
            }
        }
        superBrainEventInfo.setChanNo(chanNo);
        superBrainEventInfo.setPicUrl(picUrl);
        superBrainEventInfo.setFaceUrl(faceUrl);
        log.debug("处理超脑事件报警:【Name】" + alarmName + "【Type】" + alarmType + "【Time】" + alarmTime + "【Device】" + camera.getName() + "【Url】" + picUrl + "【faceUrl】" + faceUrl);
        publishMqtt(superBrainEventInfo, "superBrain");
    }
 
    /**
     * 根据给定的IP地址和端口查找ArdEquipExternal对象
     *
     * @param ip   IP地址
     * @param port 端口
     * @return ArdEquipExternal对象的Optional,如果找到则有值,否则为空
     */
    public static Optional<ArdEquipExternal> findArdEquipExternalByIpAndPort(String ip, int port) {
        return ArdEquipExternalServiceImpl.ardEquipExternalList.stream()
                .filter(equip -> equip.getIp().equals(ip) && equip.getPort() == port)
                .findFirst();
    }
 
    /**
     * 根据IP地址和端口查找ArdCamera对象。
     *
     * @param ip   IP地址
     * @param port 端口
     * @return ArdCamera对象的Optional,如果找不到则为空
     */
    public static Optional<ArdCameras> findArdCameraByIpAndPort(String ip, int port) {
        return ArdCamerasServiceImpl.ardCameraList.stream()
                .filter(camera -> camera.getIp().equals(ip) && camera.getPort() == port)
                .findFirst();
    }
 
    /**
     * 相机截图
     */
    private String snapPicture(CameraEventInfo info) {
        CameraCmd cmd = new CameraCmd();
        String key = info.getCameraIp() + ":" + info.getCameraPort();
        ArdCameras Cameras = GlobalVariable.cameraMap.get(key);
        if (Cameras == null) {
            return "";
        }
        cmd.setCameraId(Cameras.getId());
        cmd.setChannelNum(info.getCameraChannel());
        cmd.setBucketName("pic");
        String filename = "alarm" + "/" + IdUtils.simpleUUID() + ".jpg";
        cmd.setObjectName(filename);
        String url = HikClientUtil.picCutCate(cmd);
        return url;
    }
 
    /**
     * 打印通用光电日志
     */
    private void printLog(CameraEventInfo info) {
        log.debug("【规则】" + info.getAlarmName() + "【规则id】" + info.getRuleId() + "【类型】" + info.getAlarmType() +
                "【时间】" + info.getAlarmTime() + "【相机id】" + info.getCameraId() + "【相机】" + info.getCameraName() +
                "【IP】" + info.getCameraIp() + "【通道】" + info.getCameraChannel() + "【型号】" + info.getCameraType() +
                "【图片】" + info.getPicUrl() + "【坐标】" + info.getLongitude() + "," + info.getLatitude());
    }
 
    /**
     * 打印报警主机事件日志
     */
    private void printLog(ExternalAlarmEventInfo info) {
        log.debug("【报警ID】" + info.getAlarmId() + "【报警名称】" + info.getAlarmName() +
                "【防区ID】" + info.getDefenseId() + "【防区名称】" + info.getDefenseName() + "【类型】" + info.getAlarmType() +
                "【时间】" + info.getAlarmTime() + "【报警主机ID】" + info.getAlarmHostId());
    }
 
    /**
     * 打印门禁事件日志
     */
    private void printLog(AccessControlHostEventInfo info) {
        log.debug("【报警ID】" + info.getSerialNo() + "【设备编号】" +
                "【门编号】" + info.getDoorNo() + "【事件类型】" + info.getAlarmType() +
                "【防区类型】" + info.getDefenseType() + "【时间】" + info.getAlarmTime() +
                "【门禁主机ID】" + info.getAcsId());
    }
 
    /**
     * 发布MQTT消息
     *
     * @param info  消息内容
     * @param topic 主题
     */
    private <T> void publishMqtt(T info, String topic) {
        MqttProducer.publish(2, false, topic, JSON.toJSONString(info));
    }
 
    /**
     * 时间格式化
     */
    private String parseAlarmTime(HCNetSDK.NET_DVR_TIME_EX netDvrTimeEx) {
        short wYear = netDvrTimeEx.wYear;
        byte byMonth = netDvrTimeEx.byMonth;
        byte byDay = netDvrTimeEx.byDay;
        byte byHour = netDvrTimeEx.byHour;
        byte byMinute = netDvrTimeEx.byMinute;
        byte bySecond = netDvrTimeEx.bySecond;
        return wYear + "-" + byMonth + "-" + byDay + " " + byHour + ":" + byMinute + ":" + bySecond;
    }
 
    /**
     * 时间格式化
     */
    private String parseAlarmTime(HCNetSDK.NET_DVR_TIME netDvrTimeEx) {
        int wYear = netDvrTimeEx.dwYear;
        int byMonth = netDvrTimeEx.dwMonth;
        int byDay = netDvrTimeEx.dwDay;
        int byHour = netDvrTimeEx.dwHour;
        int byMinute = netDvrTimeEx.dwMinute;
        int bySecond = netDvrTimeEx.dwSecond;
        return wYear + "-" + byMonth + "-" + byDay + " " + byHour + ":" + byMinute + ":" + bySecond;
    }
 
    //二进制图片接收写入minio返回url
    private String saveBinPicToMinio(Pointer picData, int picDataLen) {
        String picUrl = "";
        try {
            //将字节写入文件
            long offset = 0;
            ByteBuffer buffers = picData.getByteBuffer(offset, picDataLen);
            byte[] bytes = new byte[picDataLen];
            buffers.rewind();
            buffers.get(bytes);
            InputStream input = new ByteArrayInputStream(bytes);
            String bucketName = "pic";
            String objectName = "alarm/" + IdUtils.simpleUUID() + ".jpeg";
            boolean uploadObject = MinioUtil.uploadObject(bucketName, objectName, input, picDataLen, "image/JPEG");
            if (uploadObject) {
                picUrl = MinioUtil.getBucketObjectUrl(bucketName, objectName);
                //log.debug("上传文件成功!" + picUrl);
            }
        } catch (Exception e) {
            log.error("图片保存失败:" + e.getMessage());
        }
        return picUrl;
    }
 
}