ARTICLE DETAIL

资讯详情

深耕网站SEO优化与搜索引擎排名提升的一线实战洞察。

Unity集成海康威视摄像头SDK:云台控制与视频流接入实战指南

Unity集成海康威视摄像头SDK:云台控制与视频流接入实战指南 1. 项目概述当Unity遇见海康威视如果你正在开发一个虚拟仿真、数字孪生或者安防监控培训系统需要把真实世界的摄像头画面无缝接入到Unity的3D场景里那么海康威视的摄像头大概率是你的首选硬件。但当你兴冲冲地打开海康的SDK开发包准备在Unity里大干一场时迎面而来的很可能是一连串的“坑”DLL加载失败、登录错误码看不懂、云台控制指令发了没反应最头疼的是运行一段时间后Unity编辑器直接崩溃闪退。这些问题我几乎全踩过一遍。这个项目就是要把这些坑一个个填平。核心目标很简单在Unity里通过一个精心设计的C#脚本稳定、高效地控制海康威视摄像头的云台上下左右转动、变倍、聚焦等并确保整个集成过程清晰、可复现。这不仅仅是调用几个API那么简单它涉及到Unity特殊的运行时环境、跨平台兼容性、内存管理以及海康SDK自身的一些“特性”。接下来我会把从环境搭建、SDK适配、核心功能实现到性能优化和异常处理的全过程毫无保留地拆解给你看。2. 环境准备与SDK的“正确打开方式”很多人第一步就错了。不是简单地把SDK文件拖进Unity工程就万事大吉这里面有很多细节决定了后续开发的成败。2.1 SDK获取与关键文件识别首先你需要从海康威视官方下载“设备网络SDK”。注意要选择Windows开发包因为Unity在Editor模式下和在Windows平台打包后本质上是一个Windows应用程序。下载后解压你会看到一堆文件夹和文件。对于我们的云台控制项目核心文件只有以下几个HCNetSDK.dll最核心的库文件所有主要API都在这里。HCNetSDKCom文件夹这个文件夹必须原封不动地保留里面包含了HCAudioAlarm.dll、HCGeneralTrackM.dll等辅助组件缺少它们某些功能会异常。CHCNetSDK.csC#的封装类文件提供了所有SDK函数的C#声明。这是我们需要重点修改的文件。2.2 Unity工程中的文件部署“玄学”在Unity项目中创建Assets/Plugins文件夹如果不存在。这里的部署结构有严格讲究Assets/ └── Plugins/ ├── HCNetSDK.dll ├── HCNetSDKCom/ │ ├── HCAudioAlarm.dll │ ├── HCGeneralTrackM.dll │ └── ... (其他所有dll) └── CHCNetSDK.cs关键操作1设置DLL平台兼容性选中HCNetSDK.dll在Unity Inspector面板中进行如下设置Platform Settings 确保Any Platform被取消勾选。Include Platforms 只勾选Editor和Standalone如果你只发布Windows桌面应用。对于Editor选择x86_64对于Standalone选择x86_6464位系统或x8632位系统但建议统一用64位。HCNetSDKCom文件夹内的所有DLL 按照同样的规则设置。这一步至关重要否则在打包或某些编辑器操作时会因架构不匹配导致加载失败。关键操作2修改CHCNetSDK.cs源文件海康提供的原始C#封装文件是为传统.NET Framework控制台或WinForm程序设计的在Unity的Mono或IL2CPP环境下直接使用会出问题。必须进行两处修改修改DllImport路径 找到文件中所有类似[DllImport(HCNetSDK.dll)]的行将其中的.dll扩展名去掉。因为Unity在不同平台下对库文件的扩展名处理方式不同。// 修改前 [DllImport(HCNetSDK.dll)] public static extern int NET_DVR_Init(); // 修改后 [DllImport(HCNetSDK)] public static extern int NET_DVR_Init();处理字符串编码 海康SDK大量使用ANSI编码的字符串C中的char*。在原始C#封装中常用CharSet CharSet.Ansi来声明。但在Unity的跨平台环境下尤其是非Windows平台这可能导致封送处理Marshaling错误。一个更稳妥的做法是在调用函数时自己手动将C#的string转换为字节数组。不过对于基本的登录函数我们可以先采用一个兼容性更好的声明方式尽管不完全准确但对多数基础函数有效// 原始声明可能包含CharSet.Ansi我们可以先尝试移除它让Unity/Mono使用默认行为。 // 如果后续调用出现乱码或失败再考虑更复杂的手动编码转换。 [DllImport(HCNetSDK)] public static extern int NET_DVR_Login_V30( string sDVRIP, ushort wDVRPort, string sUserName, string sPassword, ref NET_DVR_DEVICEINFO_V30 lpDeviceInfo ); // 注意如果登录后设备信息乱码问题可能出在这里需要更精细的编码处理。这是第一个潜在的“坑点”。2.3 SDK初始化与清理在Unity中SDK的初始化和清理必须与游戏的生命周期严格绑定。我推荐使用一个单例管理器类来负责。using UnityEngine; using System.Runtime.InteropServices; public class HikvisionSDKManager : MonoBehaviour { public static HikvisionSDKManager Instance { get; private set; } private bool isSDKInitialized false; void Awake() { if (Instance ! null Instance ! this) { Destroy(this.gameObject); return; } Instance this; DontDestroyOnLoad(this.gameObject); // 跨场景不销毁 InitializeSDK(); } void InitializeSDK() { // 1. 初始化SDK if (!CHCNetSDK.NET_DVR_Init()) { Debug.LogError(海康SDK初始化失败); int errorCode CHCNetSDK.NET_DVR_GetLastError(); Debug.LogError($错误代码: {errorCode}); return; } // 2. 设置连接超时和重连参数非常重要 CHCNetSDK.NET_DVR_SetConnectTime(2000, 1); // 连接超时2秒 CHCNetSDK.NET_DVR_SetReconnect(10000, true); // 重连间隔10秒 isSDKInitialized true; Debug.Log(海康SDK初始化成功。); } void OnApplicationQuit() { CleanupSDK(); } void OnDestroy() { if (Instance this) { CleanupSDK(); } } void CleanupSDK() { if (isSDKInitialized) { // 注意必须在停止所有预览、报警布防等操作后再清理SDK Debug.Log(正在清理海康SDK资源...); if (!CHCNetSDK.NET_DVR_Cleanup()) { Debug.LogWarning(SDK清理过程中报告错误但进程即将结束。); } isSDKInitialized false; } } public bool IsSDKReady() { return isSDKInitialized; } }注意OnApplicationQuit和OnDestroy中的清理是安全底线。在实际项目中你还需要确保在切换场景或退出功能模块时主动注销登录和停止预览而不是等到程序完全退出。3. 设备登录破解错误码迷局登录是后续所有操作的基础。海康SDK的登录函数会返回一个用户IDint类型如果为负值则表示失败并通过NET_DVR_GetLastError()获取错误码。这些错误码是排查问题的关键。3.1 实现一个健壮的登录方法我设计了一个带重试和错误处理的协程登录方法它更适应Unity的帧循环和非阻塞操作。using System.Collections; using System.Text; public class CameraController : MonoBehaviour { private int m_userId -1; // 登录成功后返回的用户ID后续操作都依赖它 private int m_deviceChannel 1; // 默认操作通道通常是1 public string deviceIp 192.168.1.64; public ushort devicePort 8000; public string username admin; public string password your_password; public IEnumerator LoginToDevice() { if (!HikvisionSDKManager.Instance.IsSDKReady()) { Debug.LogError(SDK未初始化无法登录。); yield break; } int retryCount 0; const int maxRetries 3; while (retryCount maxRetries m_userId 0) { CHCNetSDK.NET_DVR_DEVICEINFO_V30 deviceInfo new CHCNetSDK.NET_DVR_DEVICEINFO_V30(); // 调用登录接口 m_userId CHCNetSDK.NET_DVR_Login_V30(deviceIp, devicePort, username, password, ref deviceInfo); if (m_userId 0) { // 登录成功 string deviceType Encoding.UTF8.GetString(deviceInfo.sDeviceType).TrimEnd(\0); Debug.Log($登录成功用户ID: {m_userId}, 设备型号: {deviceType}); // 可以在这里触发登录成功的事件 yield break; } else { // 登录失败获取错误码 uint errorCode CHCNetSDK.NET_DVR_GetLastError(); string errorMsg GetErrorMessage(errorCode); Debug.LogWarning($第{retryCount 1}次登录失败. 错误码: {errorCode}, 信息: {errorMsg}); // 根据错误码决定是否重试及如何重试 switch (errorCode) { case 1: // 用户名或密码错误 case 7: // 用户名或密码错误 (不同版本SDK错误码可能有差异) Debug.LogError(用户名或密码错误请检查。); yield break; // 密码错误无需重试 case 3: // 用户被锁定 Debug.LogError(用户已被锁定请等待15分钟或重启设备。); yield break; case 10: // 通道数达到上限 Debug.LogError(设备通道数已满请检查NVR或设备授权。); yield break; case 2: // 设备不在线 case 4: // 网络连接失败 default: // 网络类错误等待后重试 retryCount; if (retryCount maxRetries) { Debug.Log($等待2秒后重试...); yield return new WaitForSeconds(2.0f); } break; } } } if (m_userId 0) { Debug.LogError($经过{maxRetries}次尝试后设备登录仍然失败。); } } // 一个简单的错误码翻译函数 private string GetErrorMessage(uint errorCode) { // 这里只列举常见错误完整列表需参考海康官方文档 switch (errorCode) { case 1: return 用户名或密码错误; case 2: return 设备不在线; case 3: return 用户被锁定; case 4: return 网络连接失败; case 5: return 设备忙; case 6: return 设备不支持此操作; case 7: return 用户名或密码错误(另一版本); case 8: return 设备未初始化; case 9: return 通道号错误; case 10: return 通道数达到上限; default: return $未知错误 ({errorCode}); } } void OnDisable() { LogoutDevice(); } private void LogoutDevice() { if (m_userId 0) { if (!CHCNetSDK.NET_DVR_Logout(m_userId)) { Debug.LogWarning($注销用户 {m_userId} 时发生错误。); } else { Debug.Log($用户 {m_userId} 已注销。); } m_userId -1; } } }3.2 登录环节的避坑要点字符串编码问题前面提到如果登录后从deviceInfo里读出的设备型号、版本等信息是乱码说明字符串编码转换有问题。这时需要修改CHCNetSDK.cs中涉及字符串参数和结构体的声明使用Marshal.PtrToStringAnsi手动转换。这是一个进阶话题如果基础功能正常可以暂不处理。多设备登录如果你需要同时控制多个摄像头每个设备都需要单独调用NET_DVR_Login_V30获取独立的userId。务必管理好这些ID在不需要时及时注销。心跳与超时SDK有默认的心跳机制但在网络不稳定的环境下建议自己实现一个心跳检测定期检查连接状态并在断线时尝试重连。4. 云台控制核心从原理到稳定实现云台控制PTZ: Pan, Tilt, Zoom是本文的核心。海康SDK提供了多种云台控制函数我们选择最常用且支持速度控制的NET_DVR_PTZControlWithSpeed_Other。4.1 云台控制命令与参数解析这个函数的原型通常如下[DllImport(HCNetSDK)] public static extern bool NET_DVR_PTZControlWithSpeed_Other( int lUserID, // 登录返回的用户ID uint lChannel, // 通道号 uint dwPTZCommand, // 控制命令如上下左右 uint dwStop, // 0:开始, 1:停止 uint dwSpeed // 速度 (1-7) );关键参数详解dwPTZCommand 控制指令。这是核心每个动作对应一个魔法数字。例如11 上仰 (TILT_UP)12 下俯 (TILT_DOWN)13 左转 (PAN_LEFT)14 右转 (PAN_RIGHT)15 左上 (UP_LEFT)16 右上 (UP_RIGHT)17 左下 (DOWN_LEFT)18 右下 (DOWN_RIGHT)9 焦距拉近 (ZOOM_IN)10 焦距拉远 (ZOOM_OUT)5 焦点前调 (FOCUS_NEAR)6 焦点后调 (FOCUS_FAR)等等。务必查阅你所用SDK版本的头文件HCNetSDK.h或文档中的PTZ_Control_Command枚举定义不同版本或设备型号可能有细微差别。dwStop这是最容易出错的地方0表示开始连续运动1表示停止运动。你必须为每一个开始命令配对发送一个停止命令否则摄像机会一直运动直到达到物理限位或收到停止指令。dwSpeed 速度等级范围通常是1-71最慢7最快。具体效果因设备而异。4.2 实现一个可靠的云台控制器在Unity中我们不能简单地用一个Button的OnClick事件来触发开始和停止因为我们需要“按下持续控制松开停止”的效果。这里采用EventTrigger组件来监听PointerDown和PointerUp事件。首先创建一个核心的云台控制类public class PTZController : MonoBehaviour { private int m_userId -1; private uint m_channel 1; private uint m_currentSpeed 3; // 默认速度 // 当前正在执行的控制命令用于停止操作 private uint m_currentActiveCommand 0; private bool m_isPTZActive false; public void Setup(int userId, uint channel 1) { m_userId userId; m_channel channel; if (m_userId 0) { Debug.LogError(PTZController: 无效的用户ID请先登录设备。); } } // 开始云台控制 public void StartPTZControl(uint ptzCommand) { if (m_userId 0) return; // 如果已有其他命令在执行先停止它 if (m_isPTZActive m_currentActiveCommand ! ptzCommand) { StopCurrentPTZControl(); } if (!m_isPTZActive) { bool success CHCNetSDK.NET_DVR_PTZControlWithSpeed_Other( m_userId, m_channel, ptzCommand, 0, // 开始 m_currentSpeed ); if (success) { m_currentActiveCommand ptzCommand; m_isPTZActive true; // Debug.Log($开始PTZ控制: {ptzCommand}); } else { uint error CHCNetSDK.NET_DVR_GetLastError(); Debug.LogError($开始PTZ控制失败 (命令:{ptzCommand})错误码: {error}); } } } // 停止当前的云台控制 public void StopCurrentPTZControl() { if (m_isPTZActive m_userId 0) { bool success CHCNetSDK.NET_DVR_PTZControlWithSpeed_Other( m_userId, m_channel, m_currentActiveCommand, 1, // 停止 m_currentSpeed ); if (!success) { uint error CHCNetSDK.NET_DVR_GetLastError(); Debug.LogWarning($停止PTZ控制失败 (命令:{m_currentActiveCommand})错误码: {error}); } m_isPTZActive false; m_currentActiveCommand 0; // Debug.Log(停止PTZ控制。); } } // 设置速度 public void SetSpeed(uint speed) { if (speed 1 speed 7) { m_currentSpeed speed; } else { Debug.LogWarning(速度值应在1-7之间。); } } void OnDisable() { // 当脚本被禁用或物体被销毁时确保停止所有云台动作 StopCurrentPTZControl(); } }然后在Unity Editor中为UI按钮绑定事件在场景中创建UI Button例如一个向左的箭头。移除Button自带的OnClick()监听。为Button GameObject添加EventTrigger组件。在EventTrigger组件中添加两个EventEvent Type:PointerDown(当鼠标按下或触摸开始时)调用PTZController.StartPTZControl(13)(13代表左转)。Event Type:PointerUp(当鼠标松开或触摸结束时)调用PTZController.StopCurrentPTZControl()。为上下右等其他方向按钮重复此操作只需改变命令参数即可11-上12-下14-右。4.3 高级控制预置点与巡航除了方向控制高级云台功能同样重要。调用预置点// 假设预置点编号为1 uint presetIndex 1; bool success CHCNetSDK.NET_DVR_PTZPreset_Other(m_userId, m_channel, 8, presetIndex); // 命令8 (GOTO_PRESET) 表示跳转到预置点 if (!success) { /* 处理错误 */ }设置预置点// 将摄像头当前位置保存为预置点1 bool success CHCNetSDK.NET_DVR_PTZPreset_Other(m_userId, m_channel, 3, presetIndex); // 命令3 (SET_PRESET) 表示设置预置点开始/停止巡航// 开始巡航路径1 uint cruisePath 1; bool success CHCNetSDK.NET_DVR_PTZCruise_Other(m_userId, m_channel, 2, cruisePath, 0); // 命令2 (START_CRUISE) 表示开始巡航 // 停止巡航 success CHCNetSDK.NET_DVR_PTZCruise_Other(m_userId, m_channel, 3, cruisePath, 0); // 命令3 (STOP_CRUISE) 表示停止巡航注意预置点和巡航功能需要摄像头硬件支持且通常需要在摄像头的Web界面或客户端软件中预先设置好预置点和巡航路径SDK只是调用它们。5. 视频流预览低延迟渲染方案虽然标题聚焦云台控制但视频预览往往是配套需求。在Unity中显示摄像头画面核心是将SDK回调的视频数据流转换并渲染到Texture2D上再赋值给RawImage或Material。5.1 初始化预览与回调设置海康SDK通过NET_DVR_RealPlay_V40函数启动预览并需要一个回调函数来接收视频帧。using System; using UnityEngine.UI; public class CameraPreview : MonoBehaviour { public RawImage previewImage; // UI上的RawImage组件 private Texture2D m_previewTexture; private int m_previewHandle -1; // 预览句柄 private int m_userId -1; private uint m_channel 1; // 定义海康SDK需要的回调委托 private CHCNetSDK.REALDATACALLBACK m_realDataCallback; public void StartPreview(int userId, uint channel 1) { if (userId 0) return; m_userId userId; m_channel channel; StopPreview(); // 开始新的预览前先停止旧的 // 初始化回调委托实例 m_realDataCallback new CHCNetSDK.REALDATACALLBACK(RealDataCallback); CHCNetSDK.NET_DVR_PREVIEWINFO previewInfo new CHCNetSDK.NET_DVR_PREVIEWINFO(); previewInfo.hPlayWnd IntPtr.Zero; // Unity中不需要窗口句柄填0 previewInfo.lChannel m_channel; previewInfo.dwStreamType 0; // 0-主码流1-子码流 previewInfo.dwLinkMode 0; // 0-TCP1-UDP previewInfo.bBlocked 1; // 阻塞取流0-非阻塞 // 启动预览 m_previewHandle CHCNetSDK.NET_DVR_RealPlay_V40(m_userId, ref previewInfo, m_realDataCallback, IntPtr.Zero); if (m_previewHandle 0) { uint error CHCNetSDK.NET_DVR_GetLastError(); Debug.LogError($启动预览失败错误码: {error}); } else { Debug.Log($预览启动成功句柄: {m_previewHandle}); // 创建纹理初始尺寸可以设小一点回调中会根据实际帧大小调整 if (m_previewTexture null) { m_previewTexture new Texture2D(1920, 1080, TextureFormat.BGRA32, false); // 常见格式为BGRA } if (previewImage ! null) { previewImage.texture m_previewTexture; } } } // 视频数据回调函数 private void RealDataCallback(int lRealHandle, uint dwDataType, IntPtr pBuffer, uint dwBufSize, IntPtr pUser) { // 只处理视频帧数据 if (dwDataType CHCNetSDK.NET_DVR_STREAMDATA) // 通常视频流类型 { // 注意此回调不在Unity主线程中执行 // 我们不能直接在这里操作Texture2D或UnityEngine.Object。 // 需要将数据传递到主线程处理。 // 这里使用一个线程安全的队列或Action lock (m_frameDataQueue) { // 简单示例这里应该将pBuffer的数据拷贝到字节数组并放入队列 // 实际项目中为了性能可以考虑使用环形缓冲区或直接操作NativeArray byte[] frameData new byte[dwBufSize]; System.Runtime.InteropServices.Marshal.Copy(pBuffer, frameData, 0, (int)dwBufSize); // ... 将frameData和尺寸信息放入待处理队列 } } } void Update() { // 在主线程的Update中从队列取出数据并更新纹理 lock (m_frameDataQueue) { if (/* 队列中有数据 */) { // 1. 检查帧尺寸如果变化则重新创建Texture2D // 2. 使用 m_previewTexture.LoadRawTextureData(frameDataByteArray); // 3. 调用 m_previewTexture.Apply(); } } } public void StopPreview() { if (m_previewHandle 0) { if (!CHCNetSDK.NET_DVR_StopRealPlay(m_previewHandle)) { Debug.LogWarning($停止预览失败句柄: {m_previewHandle}); } m_previewHandle -1; } m_realDataCallback null; } void OnDisable() { StopPreview(); } }5.2 视频预览的避坑指南与性能优化线程安全RealDataCallback运行在SDK的内部线程绝对不能在回调中直接调用任何Unity API如Texture2D.LoadRawTextureData否则会导致崩溃。必须通过线程安全的方式如ConcurrentQueue、Action队列将数据和指令传递到主线程如Update函数处理。纹理格式海康摄像头输出的常见视频格式是YUV而Unity的Texture2D常用RGB或RGBA格式。你需要进行颜色空间转换。有些SDK版本或设置下可以直接输出RGB数据。最直接的方法是使用FFmpeg或libyuv库在C插件层完成转换或者寻找海康SDK是否提供直接获取RGB数据的接口如NET_DVR_SetRealDataCallBackEx。这是一个性能瓶颈和复杂点。内存与性能频繁创建byte[]数组和Texture2D会导致GC垃圾回收压力。最佳实践是使用固定大小的环形缓冲区Circular Buffer。使用Unity.Collections.NativeArraybyte配合Unity.Jobs系统进行高效的内存操作和颜色转换。仅在视频分辨率改变时重新创建Texture2D。延迟控制设置previewInfo.dwLinkMode 0(TCP) 比UDP更稳定但可能延迟稍高。对于实时性要求极高的场景如VR可以尝试UDP模式(1)但要自己处理丢包和乱序。bBlocked 1(阻塞)通常更简单可靠。6. 实战避坑与疑难杂症排查即使按照上述步骤操作在实际项目中你仍可能遇到各种奇怪问题。以下是我总结的“血泪”经验。6.1 常见错误代码速查与应对错误码可能原因排查步骤1, 7用户名/密码错误1. 确认密码。2. 检查密码中是否有特殊字符尝试用Web界面登录验证。3. 某些设备需要确认用户是否有云台控制权限。2设备不在线1. Ping设备IP确认网络连通性。2. 检查设备供电和网络线。3. 确认设备IP地址是否正确。3用户被锁定连续输错密码导致。等待15-30分钟自动解锁或重启设备。10通道数超限1. 设备如NVR的授权通道数已满。2. 登录的是NVR但指定的通道号超出范围。29预览句柄错误1. 预览未成功启动。2.m_previewHandle无效。检查StartPreview返回值。32云台控制命令不支持1. 摄像头不支持云台功能可能是固定镜头。2. 命令码dwPTZCommand填写错误。核对SDK头文件。未知崩溃内存/线程问题1. 检查所有回调函数是否加了[MonoPInvokeCallback]属性。2. 确保在OnApplicationQuit中正确顺序清理先停预览再注销最后清理SDK。3. 检查是否在主线程外调用了Unity API。6.2 稳定性与内存管理黄金法则“谁创建谁销毁”每一个NET_DVR_Login_V30都必须对应一个NET_DVR_Logout。每一个NET_DVR_RealPlay_V40都必须对应一个NET_DVR_StopRealPlay。在Unity的OnDisable、OnDestroy或场景切换时必须严格按顺序执行销毁逻辑。单例管理SDK生命周期强烈建议使用前面提到的HikvisionSDKManager这样的单例来管理NET_DVR_Init和NET_DVR_Cleanup。整个应用程序生命周期只初始化一次退出时清理一次。异步操作与协程登录、设备搜索等耗时操作务必放在协程IEnumerator中并使用yield return new WaitForSeconds进行延时重试避免阻塞主线程导致界面卡死。异常捕获在所有关键的SDK调用周围使用try-catch块并将异常信息记录下来。海康SDK的某些错误可能导致托管代码异常。6.3 跨平台注意事项如WebGL如果你想发布到WebGL很遗憾海康官方的Windows SDK DLL方案是行不通的。WebGL运行在浏览器沙箱中无法直接调用本地DLL。替代方案有海康威视EHome/ISUP协议通过设备自带的Web服务HTTP/HTTPS发送云台控制指令GET/POST请求视频流则通过RTSP/RTMP/HLS拉取在Unity中使用视频播放插件如AVPro Video、Unity VideoPlayer配合转码服务来显示。这是WebGL的主流方案但功能可能没有SDK全面。后端转发构建一个后端服务器如C# ASP.NET Core在服务器上运行海康SDK。Unity WebGL前端通过WebSocket或HTTP API与后端通信由后端服务器转发控制指令和转发视频流如转成WebRTC。架构复杂但功能最完整。7. 封装与复用打造你的“一个脚本”最后我们将上述所有功能模块整合到一个相对完整、易于使用的脚本中虽然“一个脚本”是理想化的说法但我们可以创建一个核心管理器。// HikvisionCameraManager.cs - 核心管理器 public class HikvisionCameraManager : MonoBehaviour { // 单例模式 // SDK初始化状态 // 设备登录信息列表支持多摄像头 // PTZController实例池 // CameraPreview实例池 // 公共方法 // - InitializeSDK() // - LoginDevice(string ip, ...) // - GetPTZController(int deviceIndex) // - StartPreview(int deviceIndex, RawImage display) // - StopAllAndCleanup() // 内部事件 // - OnDeviceLoginSuccess // - OnDeviceLogout // - OnPreviewStarted // - OnErrorOccurred } // 使用时在场景中创建一个空物体挂载此管理器。 // 其他UI按钮只需调用 HikvisionCameraManager.Instance.GetPTZController(0).StartPTZControl(11);这个管理器负责生命周期的协调、资源的分配和错误的统一处理。对于简单的单摄像头控制场景你甚至可以将登录、预览、PTZ控制逻辑进一步精简全部放在一个脚本里挂在负责显示视频的UI Canvas或某个空物体上。经过以上步骤从SDK部署、设备登录、云台精确控制到视频预览和全方位避坑你应该能在Unity中相对稳健地驾驭海康威视摄像头了。记住与硬件打交道总是充满不确定性耐心查阅官方文档尽管它可能不那么友好善用错误码并始终牢记内存和线程安全的原则是项目成功的关键。在实际开发中建议先用一个最基础的Demo打通全流程然后再逐步将功能模块化、健壮化集成到你的大型项目中。
返回列表