首页 / 资讯中心 / 文章详情

海康威视Java SDK二次开发实战:JNA加载DLL实现实时流、录像下载与云台控制

海康威视Java SDK二次开发实战:JNA加载DLL实现实时流、录像下载与云台控制 ★ FEATURED ARTICLE
简介面向需要对接海康威视网络摄像机与NVR录像机的Java工程师这份资源围绕SDK二次开发整理覆盖实时流与历史流推流、抓图、录像下载、云台控制等核心功能可帮助解决设备接入、协议配置与Java环境集成中的常见问题。包体内共256个文件约39.25MB以Java源码、XML配置、DLL/SO动态库及相关JAR包为主同时包含YML脚本、SQL与说明文档各类文件对应SDK调用示例、依赖库和部署配置便于直接对照学习。资源目前已吸引1163人学习具有一定参考价值。内容从海康威视SDK接口讲解出发到RTSP/HLS推流流程、录像按时间段检索与下载、JPEG抓图以及云台指令控制均有分模块梳理配套的Java工程文件与库文件可帮助读者快速搭建测试环境减少重复踩坑适合正在做安防平台或视频接入项目的开发者参考。1. 海康威视Java SDK二次开发先弄明白这套资源到底能干什么做Java后端的人第一次接触海康威视SDK基本都会被一堆DLL和官方文档吓住以为这种设备二次开发只能靠C#或C去调。实际上海康威视的HCNetSDK动态库不止给C/C用Java通过JNA完全可以直调实时流、历史流推流、抓图、录像下载、云台控制这些功能都能在Java工程里落地。这套资源就是把海康威视网络摄像机和NVR录像机的Java SDK二次开发流程完整跑通最后能稳定实现实时流与历史流的推流、抓图、录像下载和云台控制。适合谁Java后端工程师、视频平台开发者、做安防集成或者企业监控系统的人。你已经会拉RTSP流还不够很多业务能力不在RTSP这一层设备激活、登录鉴权、按时间段检索录像、回放历史流、控制球机转动这些必须走SDK。这篇笔记把项目里的DLL依赖关系、JNA加载顺序、几个最容易翻车的参数一次性讲清楚你照着步骤复现即可。2. Java工程搭建与SDK初始化JNA加载DLL的细节和依赖顺序2.1 资源包里的文件哪些必须保留解压这套资源后你会看到很多文件HCNetSDK.dll、PlayCtrl.dll、HCCore.dll、SuperRender.dll、AudioIntercom.dll、HCGeneralCfgMgr.dll还有几个让人摸不着头脑的libcrypto.so.1.0.0、libeay32.dll、libopenal.so.1以及一个start.bat启动脚本。先说结论Java工程里真正运行期必须加载的核心DLL只有两个——HCNetSDK.dll和PlayCtrl.dll。HCNetSDK负责设备登录、实时取流、录像检索、云台控制、录像下载这些主功能PlayCtrl负责解码、播放和抓图相关的接口回放历史流、YUV数据转换基本都要它。HCCore.dll是HCNetSDK内部的强依赖缺了它HCNetSDK.dll会直接加载失败所以必须放在同一个目录。其余那些DLL我的经验是做纯Java后端服务时SuperRender.dll、AudioIntercom.dll、HCGeneralCfgMgr.dll这些不一定被主动调用放不放都能跑。libeay32.dll和libcrypto.so.1.0.0是OpenSSL加密依赖某些老版本SDK在登录和下载时会用到建议保留但不用管它。libopenal.so.1是音频库只看视频不碰音频可以忽略。start.bat是Windows下的启动环境变量样本我一般照着它写一套在IDE里的启动配置后面加载DLL时会用到。这里有个常见认知误区网上很多教程只说「把jar包引入项目」没说DLL怎么摆。实际上海康SDK的Java调用是JNA动态加载的DLL必须能被JNA找到否则代码写得再对也一样报UnsatisfiedLinkError。我一般把整个资源包的DLL按系统架构放到项目的native/win32-x64目录下再在启动参数里指定java.library.path这样开发环境、测试环境不会互相污染。2.2 用JNA定义HCNetSDK接口并按顺序加载Java调海康SDK标准姿势是JNA不推荐用JNI手写头文件。JNA最大的好处是动态库换了Linux版本只需要把加载的库名和结构体对齐Java代码基本不用重写。海康官方其实也提供了Java SDK包里面头文件和结构体都定义好了但很多二次开发不是从官方最新包来的而是网上流传的老包这时候自己用JNA补几个结构体反而更快。先定义最核心的接口import com.sun.jna.Library; import com.sun.jna.Native; public interface HCNetSDK extends Library { HCNetSDK INSTANCE Native.load(HCNetSDK, HCNetSDK.class); boolean NET_DVR_Init(); boolean NET_DVR_Cleanup(); int NET_DVR_GetLastError(); boolean NET_DVR_SetConnectTime(int dwWaitTime, int dwTryTimes); boolean NET_DVR_SetReconnect(int dwInterval, int bEnableRecon); }这段代码是整个项目的地基。Native.load(HCNetSDK, HCNetSDK.class)会按顺序在java.library.path、当前工作目录、系统PATH里查找HCNetSDK.dll。NET_DVR_Init()是初始化SDK必须在任何接口之前调用进程结束前要调NET_DVR_Cleanup()释放全局资源。NET_DVR_GetLastError()用于拿最近一次操作的错误码几乎所有失败排查都要依赖它。连接参数这块容易被忽略。NET_DVR_SetConnectTime(int dwWaitTime, int dwTryTimes)第一个参数是连接超时毫秒数第二个是重试次数。我实测过局域网内设3000毫秒、重试2次足够跨公网访问NVR时最好设5000毫秒、重试3次否则设备一慢就误报登录失败。NET_DVR_SetReconnect是断线自动重连第一个参数是重连间隔毫秒第二个参数填1开启线上服务建议开启。JNA结构体是第二个大坑。海康的登录接口NET_DVR_Login_V40需要一个NET_DVR_DEVICEINFO_V40结构体接收设备信息这个结构体字段极多。我刚开始自己手写经常因为少一个setFieldOrder字段导致返回的设备通道数乱七八糟。后来就老老实实用官方SDK包里定义好的类或者从资源包的Java demo里直接复制结构体import com.sun.jna.Structure; import java.util.Arrays; import java.util.List; public static class NET_DVR_DEVICEINFO_V40 extends Structure { public byte[] sSerialNumber new byte[48]; public byte byAlarmInPortNum; public byte byAlarmOutPortNum; public byte byDiskNum; public byte byDVRType; public byte byChanNum; public byte byStartChan; public byte byAudioChanNum; public byte byIPChanNum; public byte byZeroChanNum; public byte byMainChanNum; public byte bySpareChanNum; public byte bySupport; public byte bySupport1; public byte bySupport2; public short wDevType; public byte byChanType; public byte byIOServerNum; public byte byExtendChanNum; Override protected ListString getFieldOrder() { return Arrays.asList( sSerialNumber, byAlarmInPortNum, byAlarmOutPortNum, byDiskNum, byDVRType, byChanNum, byStartChan, byAudioChanNum, byIPChanNum, byZeroChanNum, byMainChanNum, bySpareChanNum, bySupport, bySupport1, bySupport2, wDevType, byChanType, byIOServerNum, byExtendChanNum ); } }getFieldOrder必须跟C结构体内存布局完全一致漏一个字段或者顺序不对后面读出的通道数、起始通道号全是错的。这是JNA调C动态库最典型的坑我见过有人因为这个排查了一整天最后发现byChanNum和byStartChan顺序写反了。登录调用NET_DVR_DEVICEINFO_V40 deviceInfo new NET_DVR_DEVICEINFO_V40(); int userId hcNetSdk.NET_DVR_Login_V40( 192.168.1.64, 8000, admin, yourpassword, deviceInfo); if (userId -1) { System.out.println(登录失败错误码 hcNetSdk.NET_DVR_GetLastError()); } else { System.out.println(登录成功 userId userId 起始通道 deviceInfo.byStartChan 通道数 deviceInfo.byChanNum); }注意登录端口默认是8000不是RTSP的554。userId是后续所有业务操作的登录ID相当于会话凭证。byStartChan这个字段特别重要NVR接入多路IPC时通道号是从这个起始值开始偏的不是固定从1开始。你后面做抓图、回放、云台控制如果写死1多通道NVR上必然错。2.3 日志和错误码定位把SDK黑匣子打开海康SDK最让人痛苦的就是黑匣子调用返回0或-1但完全不知道内部发生了什么。官方其实留了日志接口没有比打开日志更快的定位方式。我一般在初始化后马上开启日志boolean logRet hcNetSdk.NET_DVR_SetLogToFile(3, D:/hik_sdk_log/, false);第一个参数是日志级别3是错误级能把关键错误和关键调用写下来正式环境够用第二个是日志目录目录必须事先存在否则接口返回false第三个参数false表示不写调试信息调二级联调时改成true能看到每次调用的参数明细。界面反正是丑了点但出问题翻日志比拿错误码问同事高效得多。错误码定位也有技巧。NET_DVR_GetLastError()返回值在官方文档里有对照表我记得最常见的几个17是网络不可达或者端口不对29是用户名或密码错误1070是请求超时。线上服务要加一个统一的错误码日志过滤器每次调用失败都打上操作名和错误码这样客户报「下载不了」的时候你一眼就能看出是登录错误还是查询超时。还有一个容易被忽略的点SDK在同一个进程中只能初始化一次。如果是web应用不要每次请求都Init/Cleanup否则到第二次就偶发登录失败。正确做法是进程启动时Init一次应用关闭时Cleanup并发控制用连接池或信号量。3. 实时流与抓图把摄像头画面变成JPEG和可推送的码流3.1 实时预览取流NET_DVR_RealPlay_V40是第一步实时流推流的第一步不是拉RTSP而是通过SDK建立实时预览会话。NET_DVR_RealPlay_V40返回一个播放句柄后续抓图、回调、基于SDK的推流都依赖它。NET_DVR_PREVIEWINFO previewInfo new NET_DVR_PREVIEWINFO(); previewInfo.lChannel 1; previewInfo.dwStreamType 0; // 0主码流1子码流 previewInfo.dwLinkMode 1; // 1 TCP2 UDP previewInfo.bBlocked 1; // 1阻塞0非阻塞 int playHandle hcNetSdk.NET_DVR_RealPlay_V40( userId, previewInfo, null, null, 0); if (playHandle -1) { System.out.println(取流失败错误码 hcNetSdk.NET_DVR_GetLastError()); }lChannel传设备通道号NVR上必须用设备信息里的实际通道。dwStreamType选主码流还是子码流做预览画面或推流上墙用主码流分辨率高但带宽占用大做抓小图、AI分析建议用子码流流量小很多。dwLinkMode我在局域网用TCPUDP模式在公网上丢包会花屏。bBlocked这个参数要解释一下填1表示阻塞式取流SDK内部会等第一帧画面出来才返回句柄好处是好做同步逻辑坏处是如果在断网环境下调用可能卡好几秒。填0是非阻塞配合后面的回调线程独立收数据业务代码不阻塞但句柄返回时可能画面还没准备好。线上服务我更愿意用0配合一个「取流状态」检查初始化超时兜底。这里顺便说一个普遍误解很多人以为实时流推流应该直接让摄像头推RTSP到服务器海康威视网络摄像头设置rtsp地址确实可以做rtsp://admin:passwordip:554/Streaming/Channels/101这种地址拉流也没毛病。但RTSP拿不到SDK里的设备状态、录像检索、云台控制、报警信息。真正做平台一定是用SDK建立会话再把码流交给推流组件。RTSP适合快速demoSDK适合正式产品。3.2 抓图实现JPEG落盘的两种路径抓图有两种路径要看业务场景。第一种是定时抓图直接用SDK的NET_DVR_CaptureJPEGPicture接口一行代码出文件第二种是事件触发抓帧在实时预览回调里截取YUV帧再编码。下面先说第一种NET_DVR_JPEGPARA jpegPara new NET_DVR_JPEGPARA(); jpegPara.wPicSize 0; // 0表示原图尺寸不缩放 jpegPara.wPicQuality 90; // JPEG质量 0-100越高越清晰 boolean captureRet hcNetSdk.NET_DVR_CaptureJPEGPicture( userId, 1, jpegPara, D:/capture/20240601_101530.jpg); if (!captureRet) { System.out.println(抓图失败错误码 hcNetSdk.NET_DVR_GetLastError()); }NET_DVR_JPEGPARA在主流SDK版本里是wPicSize和wPicQuality两个字段但不同版本可能字段有差异以你实际拿到的头文件为准。wPicSize填0最常见表示按摄像头当前分辨率出图填非0值可以强制缩放到某个规格。wPicQuality我一般填90低于70画质明显发糊高于95文件变大但视觉提升有限。第二种抓帧路径更灵活在实时预览回调里拿码流。海康的码流是PS封装格式里面是H.264或H.265数据要得到JPEG需要先解码再编码。用JavaCV的话流程是PS流 - FFmpeg解码 - YUV - JPEGCPU开销大。如果只需要偶尔抓图第一种接口完全够用如果要做连续抓帧建议直接用海康的PlayCtrl.dll解码回调效率高得多。抓图还有一个常见需求抓「当前正在回放的历史画面」。这里不能直接调NET_DVR_CaptureJPEGPicture因为抓图接口默认走实时通道。历史回放抓图要在回放句柄上操作用PlayCtrl的PlayM4_GetJPEG接口传入回放句柄。资源包里的PlayCtrl.dll正好是干这个的。3.3 推流到RTMP/RTSPSDK取流后交给FFmpeg或JavaCV转封装海康SDK本身不直接推RTMP也没有现成的「一键推流」方法。实时流推流的通用架构是SDK实时预览回调拿码流然后交给FFmpeg或JavaCV做转封装推到SRS、Nginx-RTMP或云平台。这里的核心决策是「转封装」还是「转码」。如果只是把海康的H.264裸流包装成FLV或RTSP格式推出去属于转封装CPU占用很低几路并发不心疼。如果下游要H.265转H.264或者要做分辨率缩放就属于转码CPU会飙升。我一般优先转封装只有客户端播放兼容性有问题时才转码。JavaCV示意的推流骨架FFmpegFrameRecorder recorder new FFmpegFrameRecorder( rtmp://192.168.1.100/live/hik01, 1920, 1080); recorder.setVideoCodecName(h264); recorder.setFormat(flv); recorder.start(); // 在SDK实时回调里 // VideoFrame frame decodeToYuv(psPacket); // 解码得到YUV // recorder.record(frame);这不是完整可运行版本真正要做的事情是在NET_DVR_RealPlay_V40的回调参数NET_DVR_STREAMFRAME_CALLBACK里接收码流先解析PS流里的每个视频帧再喂给recorder。如果直接走RTSP拉流给JavaCV也行但那样就绕过了SDK的设备管控。推流不稳定是高频问题尤其是SRS推流不稳定时多半不是SRS的问题。排查顺序先看码流类型是不是主码流导致带宽打满再检查TCP连接数是否超过设备限制最后用Wireshark抓包确认有没有大量重传。海康设备对单路取流的连接数限制严格别在同一个线程里既预览又回放很容易触发设备侧的流数量上限。4. 历史流与录像下载回放取流、时间轴检索和文件落盘4.1 录像检索按时间和类型查记录做历史流推流和录像下载之前先把录像文件查出来。海康SDK的查询流程是建立查找条件 - 获取查找句柄 - 循环取记录。NET_DVR_FIND_RECORD_PARAM findParam new NET_DVR_FIND_RECORD_PARAM(); findParam.lChannel 1; findParam.dwRecordFileType 0; // 0定时录像1报警2移动侦测 NET_DVR_TIME startTime new NET_DVR_TIME(); startTime.dwYear 2024; startTime.dwMonth 6; startTime.dwDay 1; startTime.dwHour 0; startTime.dwMinute 0; startTime.dwSecond 0; NET_DVR_TIME stopTime new NET_DVR_TIME(); stopTime.dwYear 2024; stopTime.dwMonth 6; stopTime.dwDay 2; stopTime.dwHour 0; stopTime.dwMinute 0; stopTime.dwSecond 0; findParam.pStartTime startTime; findParam.pStopTime stopTime; int findHandle hcNetSdk.NET_DVR_FindRecord_V30(userId, findParam); if (findHandle -1) { System.out.println(录像查找失败错误码 hcNetSdk.NET_DVR_GetLastError()); }找到句柄后用NET_DVR_FindNextRecord_V30循环拉取NET_DVR_FINDDATA_V30结构体每条记录里有文件名、开始时间、结束时间、文件大小。这里有一个细节dwRecordFileType按录像类型区分定时录像和报警录像要分开查再合并结果。很多做视频平台的同事在这里踩坑只查了定时录像报警录像全部漏掉用户回放时找不到关键画面。时间范围设置也有讲究。录像文件在设备端是按「录像段」存储的不是按秒。你查1小时可能返回好几个段每段几分钟到几十分钟不等。所以在业务层要做一个「时间段合并」逻辑把相邻的记录段合并展示不然用户看到时间轴断断续续。4.2 历史流回放按时间点开始回放检索到录像记录后回放历史流用NET_DVR_PlayBackByTime。接口返回回放句柄然后通过回调接收码流。核心参数是起始时间和结束时间以及流类型。NET_DVR_PLAYBACK_PARAM_V40 playbackParam new NET_DVR_PLAYBACK_PARAM_V40(); playbackParam.lChannel 1; playbackParam.pStartTime startTime; playbackParam.pStopTime stopTime; playbackParam.dwStreamType 0; // 0主码流1子码流 playbackParam.dwLinkMode 1; // 1 TCP2 UDP int playbackHandle hcNetSdk.NET_DVR_PlayBackByTime( userId, playbackParam); if (playbackHandle -1) { System.out.println(回放失败错误码 hcNetSdk.NET_DVR_GetLastError()); }回放历史流的dwStreamType我建议用子码流。历史录像如果只是给客户端预览子码流完全够用流量小、回放启动快。要做录像剪辑下载才用主码流保证画质。NET_DVR_PLAYBACK_PARAM_V40在旧版本SDK里对应NET_DVR_PLAYBACK_PARAM字段名字可能是lChannel加pStartTime等JNA结构体别搞混。回放句柄必须显式停止。很多人以为播放完了SDK会自动释放实际上要调NET_DVR_StopPlayBack(playbackHandle)否则句柄泄漏一路一路地占最后设备侧拒绝新会话。回调里也要做结束标志SDK会通知码流播放结束收到结束事件后再调Stop。关于时间戳如果你想实现真正的按帧回放海康有NET_DVR_PlayBackByTime配合NET_DVR_PlayBackByFrame或者NET_DVR_SetPlayBackMode把回放模式切成按帧回放支持暂停在某一帧。这个功能在视频取证场景很实用。注意按帧回放模式下单帧步进要控制频率太快了设备端跟不上会丢帧。4.3 录像下载单文件下载和断点续传的替代方案录像下载是安防平台最基础也最容易出问题的功能。海康SDK提供NET_DVR_StartDownload接口指定通道、文件类型、起止时间、本地路径SDK会去设备端拉录像文件。int downloadHandle hcNetSdk.NET_DVR_StartDownload( userId, 1, 0, startTime, stopTime, D:/record/segment1.mp4); if (downloadHandle -1) { System.out.println(下载失败错误码 hcNetSdk.NET_DVR_GetLastError()); }这个接口在多数SDK版本里是异步的意思是它先返回一个下载句柄实际下载在后台进行需要通过下载进度回调判断进度。不能简单地认为「函数返回了就下载完了」。回调里有总大小和已下载大小现场通常会做一个进度条。下载完成后关闭句柄再打开文件校验。断点续传是真正的痛点。海康SDK的下载接口没有公开的可续传参数断网后重新调用只能从头传。我的做法是分段下载把一个小时的目标时间段切成10分钟一段分别调用下载接口文件落到临时目录全部完成后再合并。这种分段方案还有个额外好处可以并发。NVR对同一个登录ID的并发下载会话有限制我实测6路左右一般能跑再多会报资源不足。所以我会控制并发数一次最多5段同时下载。每段下载完成后校验文件大小是否为0以及大小和录像记录中的文件大小是否接近小于预期说明下载出错触发重跑这一小段。实际交付时用户可以感知的是「进度条是10分钟一段地跳」比一个大文件卡在99%体验好得多。还有一个合并问题。下载下来的录像段是H.264裸流文件不能简单拼接后直接改后缀为mp4。常见做法是用FFmpeg做一次转封装合并命令级别不复杂但要注意时间戳连续性。用JavaCV也一样把每个段的帧依次读出来写入同一个recorder最后输出一个可播放的mp4。5. 云台控制与预置点PTZ指令、缩放和协议边界5.1 PTZ控制方向、缩放与速度参数云台控制用于调整摄像头角度海康SDK提供的核心接口是NET_DVR_PTZControlWithSpeed它同时支持方向控制、变倍和聚焦。// 向左持续转 boolean startRet hcNetSdk.NET_DVR_PTZControlWithSpeed( userId, 1, NET_DVR_PAN_LEFT, 0, 3); Thread.sleep(800); // 转动持续800ms // 停止 boolean stopRet hcNetSdk.NET_DVR_PTZControlWithSpeed( userId, 1, NET_DVR_PAN_LEFT, 1, 3);参数含义第二个参数是通道号第三个是PTZ命令包括NET_DVR_PAN_LEFT左转、NET_DVR_PAN_RIGHT右转、NET_DVR_TILT_UP上仰、NET_DVR_TILT_DOWN下俯、NET_DVR_ZOOM_IN变倍放大、NET_DVR_ZOOM_OUT变倍缩小、NET_DVR_FOCUS_NEAR/FAR聚焦第四个参数是停止标志0表示开始1表示停止第五个是速度范围1-7。这里最容易翻车的点是停止时必须再发一次相同命令把停止标志置1。很多人只发开始命令云台转起来了但停不下来因为没发停止指令。我见过有人用重新登录来紧急停止纯属暴力。正确做法是把「开始」和「停止」封装成一对操作停止指令最好放到finally里防止异常导致云台一直转。速度参数不是越大越好。1-7等级里3级适合精确微调5级以上启动和制动的冲击很大容易过冲。如果你发现用低速转动但方向根本不响应先检查设备是否支持调速有些半球机只支持固定速。这时要改成不带速度的控制接口。转动持续时间我一般控制在500到1000毫秒再配合一次轻微的停止反冲能显著减少定位过冲。5.2 预置点设置、调用与巡航预置点对巡检场景很重要海康SDK提供三个基本接口设置预置点、调用预置点、删除预置点。// 把当前云台位置设为第1号预置点 boolean setRet hcNetSdk.NET_DVR_PTZPreset_Set(userId, 1, 1); if (!setRet) { System.out.println(设置预置点失败错误码 hcNetSdk.NET_DVR_GetLastError()); } // 调用第1号预置点 boolean callRet hcNetSdk.NET_DVR_PTZPreset_Call(userId, 1, 1); if (!callRet) { System.out.println(调用预置点失败错误码 hcNetSdk.NET_DVR_GetLastError()); }第三个参数是预置点编号设备不同支持的范围不同常见是1到64。设置预置点前云台必须先移动到目标位置并完成聚焦。调用预置点是异步过程设备转向需要时间不能立刻执行下一个预置点操作。我一般会在调用后轮询设备状态或者做一个至少2秒的延迟否则连续调用会失败一大半。预置点的巡航是更进阶的用法海康SDK还有巡航扫描接口可以设置巡航路线。但巡航配置在不同设备上参数差异很大有的要在设备网页端配置SDK只负责触发。如果你的项目需要自动巡航建议先把预置点设置和调用的基础打牢再用官方客户端的「巡航路径」配置确认设备行为最后才引入SDK的巡航控制否则调试成本很高。5.3 协议边界不是所有指令都通用这里要泼一盆冷水。海康SDK的云台指令走的是海康私有协议但你的项目里有可能接入了非海康的球机或是通过ONVIF接入的第三方设备。这种情况下SDK的PTZ指令可能部分失效或者完全不响应。遇到云台控制无效我的排查顺序是先用海康官方客户端手动测试这台设备确认云台本身能转动再用SDK自带的C demo或Java demo试同一通道同一条命令如果demo有效而你的代码无效查JNA结构体和停止指令是否成对如果demo也无效说明设备对海康私有PTZ协议兼容不完整这个通道不能走SDK的PTZ接口。此时更可靠的方案是走ONVIF的PTZ控制。ONVIF协议里有一套标准的ContinuousMove和AbsoluteMove接口对大多数支持ONVIF的球机都通用。代价是要引入ONVIF客户端库认证复杂度更高。很多项目是海康SDK管录像和取流ONVIF管云台两条链路并存这是被兼容性逼出来的常见架构。还有一类问题不是协议而是机械限制。球机的机械限位、隐私遮蔽、自动翻转模式都会影响PTZ指令。比如云台转到某个角度就不动了不一定是代码问题去设备配置里查「水平限位」和「垂直限位」。资源包里的HCGeneralCfgMgr.dll、HCIndustry.dll这些配置模块正是用SDK读写这种设备配置项的碰到特殊设备时能用上。6. 常见问题排查与避坑指南从加载失败到花屏的实战记录6.1 UnsatisfiedLinkErrorDLL位数与JDK不一致现象Native.load(HCNetSDK, HCNetSDK.class)直接抛UnsatisfiedLinkError或者提示找不到依赖库。原因这套资源里的HCNetSDK.dll是32位环境编译的而你的JDK是64位。Windows下32位进程不能加载64位DLLJava也一样。解决先用java -version确认JDK架构。如果是64位JDK要么换32位JDK要么去海康官网下载对应64位的HCNetSDK包。换完JDK后把HCNetSDK.dll、HCCore.dll、PlayCtrl.dll、libeay32.dll全部放在同一个目录缺OpenSSL也会报加载失败。6.2 登录失败错误码17网络能ping通但SDK连不上现象设备能ping通浏览器也能打开登录页但SDK登录返回-1错误码17。原因海康设备默认SDK端口是8000有人下意识用RTSP的554端口去登录或者防火墙只放通了80端口。解决登录端口固定用8000。跨网段登录时把连接超时调到5000毫秒以上再检查链路防火墙是否放通了TCP 8000端口。如果需要公网访问优先用海康提供的隧道或安全网关不要直接把8000端口裸奔到公网。6.3 实时预览黑屏或花屏主码流太大或UDP丢包现象预览句柄返回正常但画面黑屏、花屏或卡死。原因主码流分辨率太高超出了本机解码能力或者链路用的是UDP公网下丢包严重。解决先降级到子码流测试。dwStreamType改成1dwLinkMode改成1用TCP模式。如果子码流正常再逐级切回主码流。只做抓图的话压根不用走预览直接NET_DVR_CaptureJPEGPicture出图就行。6.4 回放失败录像查得到但回放起不来现象NET_DVR_FindRecord_V30能查到录像记录但NET_DVR_PlayBackByTime返回-1错误码多为1070或时间无效。原因起始时间或结束时间格式不对或者回放时间范围没有落在录像段内。NVR跨时区时设备本地时间和服务器时间差几小时查询到的时间点对应不到录像。解决先取设备本地时间校准不要拿服务器当前时间直接查。回放请求的结束时间在录像段基础上加30秒余量。如果失败抓包看设备返回的错误码是「时间无效」就优先查时区。6.5 录像下载卡住或文件损坏不知道下载是异步的现象下载接口返回了句柄函数也执行完了但本地文件不完整或损坏。原因下载是异步的必须在回调里判断完成状态不能只看接口返回值。直接按同步方式处理句柄可能都还没开始拉数据。解决为下载句柄设置进度回调判断已下载大小等于总大小且状态成功后再关闭。或者采用我前面说的分段下载方案每段下载完校验文件大小再决定是否重下。从那以后我每次做海康对接都强制先跑一遍官方demo确认DLL位数和登录正常再动业务确认单路抓图和回放通再推全量功能。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站