From 6e0b5aa056d107871c3a9befd408ddecf14e5b7c Mon Sep 17 00:00:00 2001 From: zqm Date: Wed, 18 Mar 2026 13:38:36 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=8A=93=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCamera/Test/Form1.Designer.cs | 14 + Windows/CS/Framework4.0/XCamera/Test/Form1.cs | 96 ++++++ .../src/Core/CameraConnectionManager.cs | 24 +- .../XCamera/src/Core/XCloudSdkEnums.cs | 137 +++++++- .../XCamera/src/Core/XCloudSdkWrapper.cs | 12 + .../XCamera/XCamera/src/XCameraManager.cs | 306 +++++++++++++----- Windows/CS/Framework4.0/XCamera/XCloudSDK.ini | 14 + 7 files changed, 522 insertions(+), 81 deletions(-) create mode 100644 Windows/CS/Framework4.0/XCamera/XCloudSDK.ini diff --git a/Windows/CS/Framework4.0/XCamera/Test/Form1.Designer.cs b/Windows/CS/Framework4.0/XCamera/Test/Form1.Designer.cs index 0d4bf9f..70824f3 100644 --- a/Windows/CS/Framework4.0/XCamera/Test/Form1.Designer.cs +++ b/Windows/CS/Framework4.0/XCamera/Test/Form1.Designer.cs @@ -47,6 +47,7 @@ namespace Test this.txtIpAddress = new System.Windows.Forms.TextBox(); this.btnSetIP = new System.Windows.Forms.Button(); this.camera = new System.Windows.Forms.PictureBox(); + this.btnTestOnvifSnapshot = new System.Windows.Forms.Button(); ((System.ComponentModel.ISupportInitialize)(this.LedImage)).BeginInit(); this.statusStrip1.SuspendLayout(); this.groupBox1.SuspendLayout(); @@ -254,11 +255,23 @@ namespace Test this.camera.TabIndex = 14; this.camera.TabStop = false; // + // btnTestOnvifSnapshot + // + this.btnTestOnvifSnapshot.Location = new System.Drawing.Point(811, 604); + this.btnTestOnvifSnapshot.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.btnTestOnvifSnapshot.Name = "btnTestOnvifSnapshot"; + this.btnTestOnvifSnapshot.Size = new System.Drawing.Size(148, 39); + this.btnTestOnvifSnapshot.TabIndex = 15; + this.btnTestOnvifSnapshot.Text = "10. ONVIF抓图测试"; + this.btnTestOnvifSnapshot.UseVisualStyleBackColor = true; + this.btnTestOnvifSnapshot.Click += new System.EventHandler(this.btnTestOnvifSnapshot_Click); + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(1067, 718); + this.Controls.Add(this.btnTestOnvifSnapshot); this.Controls.Add(this.camera); this.Controls.Add(this.groupBox1); this.Controls.Add(this.statusStrip1); @@ -312,5 +325,6 @@ namespace Test private System.Windows.Forms.TextBox txtIpAddress; private System.Windows.Forms.Button btnSetIP; private System.Windows.Forms.PictureBox camera; + private System.Windows.Forms.Button btnTestOnvifSnapshot = null; } } \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/Test/Form1.cs b/Windows/CS/Framework4.0/XCamera/Test/Form1.cs index a92ae6b..e5d1ab7 100644 --- a/Windows/CS/Framework4.0/XCamera/Test/Form1.cs +++ b/Windows/CS/Framework4.0/XCamera/Test/Form1.cs @@ -5,6 +5,7 @@ using System.Data; using System.Drawing; using System.IO; using System.Linq; +using System.Net; using System.Text; using System.Threading; using System.Windows.Forms; @@ -778,5 +779,100 @@ namespace Test txtLog.AppendText($"[{timestamp}] {message}" + Environment.NewLine); txtLog.ScrollToCaret(); } + + /// + /// 10. ONVIF抓图测试 + /// + private void btnTestOnvifSnapshot_Click(object sender, EventArgs e) + { + try + { + LogMessage("正在测试ONVIF抓图..."); + + var imageStream = GetSnapshot(); + if (imageStream != null) + { + // 显示捕获的图像 + using (var image = System.Drawing.Image.FromStream(imageStream)) + { + // 清理之前的图像 + if (LedImage.Image != null) + { + var oldImage = LedImage.Image; + LedImage.Image = null; + oldImage.Dispose(); + } + + LedImage.Image = (System.Drawing.Image)image.Clone(); + LedImage.SizeMode = PictureBoxSizeMode.Zoom; + LogMessage("ONVIF抓图成功!"); + } + } + else + { + LogMessage("ONVIF抓图失败: 无法获取图像流"); + } + } + catch (Exception ex) + { + LogMessage($"ONVIF抓图错误: {ex.Message}"); + } + } + + /// + /// 使用ONVIF协议获取快照 + /// + public System.IO.Stream GetSnapshot() + { + var request = (HttpWebRequest)WebRequest.Create("http://192.168.100.10:8899/cgi-bin/snapshot.cgi"); + request.Method = "POST"; + request.ContentType = "application/json"; + request.Timeout = 10000; // 10秒超时 + request.ReadWriteTimeout = 10000; + + // 添加认证信息 + string username = "admin"; + string password = ""; + string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}")); + request.Headers["Authorization"] = $"Basic {credentials}"; + + // 发送JSON格式的POST数据 + string postData = "{\"action\": \"snapshot\"}"; + byte[] data = Encoding.UTF8.GetBytes(postData); + request.ContentLength = data.Length; + + using (var stream = request.GetRequestStream()) + { + stream.Write(data, 0, data.Length); + } + + // 发送请求 + var response = (HttpWebResponse)request.GetResponse(); + if (response.StatusCode == HttpStatusCode.OK) + { + // 检查响应内容类型 + string contentType = response.ContentType; + if (contentType.StartsWith("image/")) + { + // 返回图片二进制流 + return response.GetResponseStream(); + } + else + { + // 读取JSON错误信息 + using (var reader = new StreamReader(response.GetResponseStream())) + { + string errorMessage = reader.ReadToEnd(); + response.Close(); + throw new Exception($"ONVIF抓图失败: {errorMessage}"); + } + } + } + else + { + response.Close(); + throw new Exception($"ONVIF抓图失败,状态码: {response.StatusCode}"); + } + } } } \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/CameraConnectionManager.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/CameraConnectionManager.cs index 6b53619..9ecd7b7 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/CameraConnectionManager.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/CameraConnectionManager.cs @@ -189,6 +189,8 @@ namespace XCamera.Core throw new Exception($"设置设备用户名密码失败,错误码: {result}"); } + // 注意:不进行设备登录,因为实时预览可以工作说明设备已经连接 + // 直接设置连接状态为已连接 lock (_lockObject) { _isConnected = true; @@ -225,6 +227,8 @@ namespace XCamera.Core StopRealPlay(); } + // 注意:不进行设备登出,因为我们没有登录设备 + // 删除设备信息 XCloudSdkWrapper.XCloudSDK_Device_DeleteDevsInfo(DeviceId); @@ -325,15 +329,21 @@ namespace XCamera.Core } /// - /// 抓拍图片 + /// 抓拍图片(异步) /// /// 保存文件名 - /// 是否成功抓拍 - public bool CaptureImage(string fileName) + /// 序列号 + /// 是否成功发起抓图请求 + public bool CaptureImage(string fileName, int nSeq = 0) { lock (_lockObject) { - if (!_isPlaying) + if (!_isConnected) + { + throw new InvalidOperationException("设备未连接"); + } + + if (!_isPlaying || _playHandle <= 0) { throw new InvalidOperationException("未开始实时预览"); } @@ -341,11 +351,13 @@ namespace XCamera.Core try { - int result = XCloudSdkWrapper.XCloudSDK_Play_MediaSnapImage(_playHandle, fileName); + // 使用播放句柄进行抓图,与Demo保持一致 + int result = XCloudSdkWrapper.XCloudSDK_Play_MediaSnapImage( + _playHandle, fileName); if (result != 0) { - throw new Exception($"抓拍图片失败,错误码: {result}"); + throw new Exception($"发起抓图请求失败,错误码: {result}"); } return true; diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/XCloudSdkEnums.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/XCloudSdkEnums.cs index 0802e4b..f119b6e 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/XCloudSdkEnums.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/XCloudSdkEnums.cs @@ -2,8 +2,141 @@ using System; namespace XCamera.Core { + public enum EXSDK_ERROR + { + EXSDK_ER_OK = 0, + EXSDK_ER_OBJ_NOT_EXIST = -1239510, + EXSDK_ER_VALUE_NOT_EXIST = -1239511, + EXSDK_ER_ERROR = -100000, + EXSDK_ER_PARAM_ERROR = -99999, + EXSDK_ER_CREATE_FILE = -99998, + EXSDK_ER_OPEN_FILE = -99997, + EXSDK_ER_WRITE_FILE = -99996, + EXSDK_ER_READ_FILE = -99995, + EXSDK_ER_NO_SUPPORTED = -99994, + EXSDK_ER_NET = -99993, // NET ERROR + EXSDK_ER_OBJ_EXIST = -99992, + EXSDK_ER_TIMEOUT = -99991, + EXSDK_ER_NOT_FOUND = -99990, + EXSDK_ER_NEW_BUFFER = -99989, + EXSDK_ER_NET_RECV = -99988, + EXSDK_ER_NET_SEND = -99987, + EXSDK_ER_OBJECT_BUSY = -99986, + EXSDK_ER_SERVER_INTERNAL_ERROR = -99985, // 服务器内部错误 + EXSDK_ER_SERVER_BIND_PORT = -99984, // 监听端口bind失败(端口被占用) + EXSDK_ER_SERVER_LISTEN = -99983, // 监听服务器启动失败 + EXSDK_ER_NET_SEND_BUF_FULL = -99982, // 发送缓冲区满了 + EXSDK_ER_NO_BUFFER = -99981, // 缓冲区大小不够或缓冲区满 + + EXSDK_ER_USER_CANCEL = -90000, + EXSDK_ER_Dev_NotLogin = -90002, // 设备未登录 + EXSDK_ER_Dev_NotFound = -70119, // Not Found + EXSDK_ER_UserOrPassword = -70203, // 登录设备密码错误 + EXSDK_ER_Illegal_User = -70205, // 非法用户 + EXSDK_ER_EE_NET_SOCKET = -1010, // socket异常 + EXSDK_ER_JSON_PARSE = -69999, // Json解析异常 + } + + public enum ESXSDK_CMD + { + ESXSDK_MSG_BEGIN = 12000, + ESXSDK_DEV_LOGIN = 12001, // 登录结果返回--XSDK_DevLogin + + ESXSDK_MEDIA_START_REAL_PLAY = 12002, // 实时视频结果返回--XSDK_MediaRealPlay + ESXSDK_MEDIA_START_FACE_IMAGE = 12003, // 请求人脸抓图返回--XSDK_MediaGetFaceImage + ESXSDK_MEDIA_START_RECORD_PLAY = 12004, // 录像回放结果返回--XSDK_MediaRecordPlay + ESXSDK_MEDIA_DOWN_RECORD_FILE = 12005, // 录像下载 + ESXSDK_MEDIA_DOWN_IMAGES_FILE = 12006, // 图片或缩略图下载 + ESXSDK_MEDIA_START_TALK = 12007, // 开始对讲回调 + ESXSDK_MEDIA_STOPT_TALK = 12008, // 结束对讲(服务器内部使用) + ESXSDK_MEDIA_ON_INFO = 12010, // 媒体信息回调 + ESXSDK_MEDIA_SET_PARAM = 12011, // 修改参数 + ESXSDK_MEDIA_START_RECORD_PLAY_BYNAME = 12012, // 按文件名称进行录像回放 + + // 设备协议交互ESXSDK_DEV_GENERAL_COMMAND + ESXSDK_DEV_GENERAL_COMMAND = 12100, // 通用交互返回 + ESXSDK_DEV_GET_SYS_CONFIG = 12101, // 设备系统配置获取 + ESXSDK_DEV_SET_SYS_CONFIG = 12102, // 设备系统配置设置 + ESXSDK_DEV_GET_CHN_CONFIG = 12103, // 设备通道配置获取 + ESXSDK_DEV_SET_CHN_CONFIG = 12104, // 设备通道配置设置 + ESXSDK_DEV_FIND_FILE = 12105, // 查询录像文件 + ESXSDK_DEV_SNAP = 12106, // 设备通道抓图 + ESXSDK_DEV_TRANSPORT_OPEN = 12107, // 打开设备透明串口 + ESXSDK_DEV_TRANSCOMWRITE = 12108, // 向透明串口发送数据 + ESXSDK_DEV_ON_RECV_TRANSPORT_DATA = 12109, // 接收透明串口返回的数据 + ESXSDK_DEV_ON_SEARCH_CALENDAR = 12110, // 查询录像日历 + ESXSDK_DEV_FIND_FILE_BYTIME = 12111, // 按时间查询录像 + + ESXSDK_DEV_USER_COMMAND_BEGIN = 12280, // 用户自定义消息ID开始 + ESXSDK_DEV_GENERAL_COMMAND_END1 = 12300, // 通用交互返回 + ESXSDK_DEV_GENERAL_COMMAND_END2 = 12499, // 通用交互内部使用 + + ESXSDK_ON_DEV_STATE = 12500, // 设备状态返回,param1参考:EXSDK_DEV_STATE + ESXSDK_ON_DEV_ALARM_MSG = 1504, // 设备报警回调消息ID + ESXSDK_ON_SEARCH_DEVICES = 13001, // 局域网设备搜索--XSDK_SearchDevices + ESXSDK_MEDIA_ON_PLAY_STATE = 13002, // 媒体状态回调 + ESXSDK_MEDIA_PAUSE = 13003, // 媒体暂停/播放 + ESXSDK_MEDIA_SEEK_TO_TIME = 13004, // 媒体Seek + ESXSDK_MEDIA_SET_SPEED = 13005, // 媒体Seek + + ESXSDK_DEV_UPGRADE = 13006, // 升级设备返回 + + ESXSDK_ON_DAS_SERVER_START = 13007, // DAS服务器启动结果返回 + ESXSDK_ON_DAS_DEVICE_REGIST = 13008, // DAS设备注册 + ESXSDK_DEV_SEND_COMMAND = 13009, // 发送命令 + + ESXSDK_DEV_SENDFILE = 13010, // 发送文件的返回 + + ESXSDK_DEV_UPGRADE_CLOUD = 13011, // 云升级设备 + + + ESXSDK_DEV_ON_GET_STATE = 13013, // 获取设备服务状态返回值 + ESXSDK_DEV_UPDATE_DEVSTATUS = 13014, // 设备服务状态更新回调 + + ESXSDK_PTL_DATA_TRANSPORT = 15000, // 协议数据直接转发 + + ESXSDK_DEV_EXPORTFILE = 15001, // 导出文件数据返回 + + ESXSDK_MSG_END = 16000, + } + + public enum EUIMSG + { + EUIMSG_PLAY_START = 30000, // 开始播放 + EUIMSG_PLAY_PAUSE = 30001, // 暂停播放 + EUIMSG_PLAY_STOP = 30002, // 播放结束(数据异常停止返回或文件播放结束返回) + EUIMSG_START_BUFFER_DATA = 30003, // 正在缓存数据 + EUIMSG_END_BUFFER_DATA = 30004, // 缓存结束,开始播放 + EUIMSG_PLAY_MEDIA_FRAME_LOSS = 30005, // 超过4S没有收到数据 + EUIMSG_PLAY_INFO = 30006, // 播放信息 + EUIMSG_PLAY_SAVE_IMAGE_FILE = 30007, // 本地保存图片 + EUIMSG_PLAY_CATCH_PIC_BUFFER = 30008, // 获取图片数据 + EUIMSG_AUDIO_DATA = 30009, // 采集到的音频数据 + EUIMSG_YUV_DATA = 30010, // YUV数据 + EUIMSG_RECORD_START = 30011, // 开始录像 + EUIMSG_RECORD_STOP = 30012, // 录像结束 + EUIMSG_ON_FILE_DOWNLOAD = 30013, // 文件下载 + EUIMSG_PLAY_SOUND = 30014, // 播放音频 + EUIMSG_DECODE_PCM = 30015, // PCM数据 + EUIMSG_OPEN_SEND_DATA_CHANNEL = 30016, // 打开发送数据通道 + EUIMSG_CLOSE_SEND_DATA_CHANNEL = 30017, // 关闭发送数据通道 + EUIMSG_SEND_DATA = 30018, // 发送数据 + EUIMSG_CAPTURE_AUDIO = 30019, // 采集音频结果 + EUIMSG_ON_FRAME_USR_DATA = 30020, // 用户自定义信息帧回调 + } + + // 通道状态枚举 + public enum EMediaChnState + { + EState_Media_NetDisConnect = 2, // 通道断线 + EState_Media_NetConnecting = 3, // 正在连接 + EState_Media_NetConnected = 4, // 网络连接成功 + EState_Media_RecvData = 8, // 正在接收数据 + EState_Media_DataEnd = 9, // 数据接收结束 + } + /// - /// SDK消息枚举 + /// SDK消息枚举(兼容旧版) /// public enum XCloudSdkMessage { @@ -134,7 +267,7 @@ namespace XCamera.Core } /// - /// SDK错误码枚举 + /// SDK错误码枚举(兼容旧版) /// public enum XCloudSdkError { diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/XCloudSdkWrapper.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/XCloudSdkWrapper.cs index 30ea0b0..413bcd6 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/XCloudSdkWrapper.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/XCloudSdkWrapper.cs @@ -235,6 +235,18 @@ namespace XCamera.Core [DllImport("XCloudSDK.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] public static extern int XCloudSDK_Play_PlaySound(int nPlayHandle, int nVolume, int nSeq); + /// + /// 设备抓图(异步) + /// + /// 用户句柄 + /// 设备ID + /// 通道号 + /// 参数(JSON格式) + /// 序列号 + /// 0表示成功 + [DllImport("XCloudSDK.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] + public static extern int XCloudSDK_Device_DevSnap(int hUser, string szDevId, int nChannel, string sParam, int nSeq); + #endregion } } \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/XCameraManager.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/XCameraManager.cs index be274a1..cec6950 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/XCameraManager.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/XCameraManager.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Windows.Forms; using XCamera.Models; using XCamera.Core; + using XCamera.Vision; using ErrorEventArgs = XCamera.Models.ErrorEventArgs; @@ -27,6 +28,10 @@ namespace XCamera private int _captureInterval = 1000; private string _cameraIpAddress = "192.168.100.10"; // 摄像头IP地址 private int _userHandle = -1; // 用户句柄 + private int _snapSequence = 0; // 抓图序列号 + private Dictionary _snapRequests = new Dictionary(); // 抓图请求跟踪 + private AutoResetEvent _captureEvent = new AutoResetEvent(false); // 抓图完成事件 + private XCloudSdkWrapper.XCloudSdkMessageCallback _sdkCallback; // 存储回调委托,防止被垃圾回收 /// /// LED状态更新事件 @@ -142,8 +147,8 @@ namespace XCamera } // 注册回调函数 - var callback = new XCloudSdkWrapper.XCloudSdkMessageCallback(SdkMessageCallback); - int userHandle = XCloudSdkWrapper.XCloudSDK_RegisterCallback(callback, IntPtr.Zero); + _sdkCallback = new XCloudSdkWrapper.XCloudSdkMessageCallback(SdkMessageCallback); + int userHandle = XCloudSdkWrapper.XCloudSDK_RegisterCallback(_sdkCallback, IntPtr.Zero); if (userHandle < 0) { throw new Exception($"注册回调函数失败,错误码: {userHandle}"); @@ -330,8 +335,9 @@ namespace XCamera /// /// 5. 识别配置文件内的每个区域中(这些区域是led灯),led灯的颜色(红,黄,蓝,绿),亮灭,是否闪烁 /// + /// 图像文件路径 /// LED状态列表 - public List DetectLeds() + public List DetectLeds(string imagePath = null) { if (!_isInitialized) { @@ -344,56 +350,62 @@ namespace XCamera return new List(); } + if (string.IsNullOrEmpty(imagePath) || !File.Exists(imagePath)) + { + OnErrorOccurred("图像文件不存在"); + return new List(); + } + try { - // 抓拍当前图像 - string tempFile = System.IO.Path.GetTempFileName() + ".jpg"; - if (!_connectionManager.CaptureImage(tempFile)) + // 加载图像并调整大小以减少内存使用 + using (var originalImage = System.Drawing.Image.FromFile(imagePath)) { - return new List(); - } - - // 加载图像并触发图像捕获事件 - try - { - using (var image = System.Drawing.Image.FromFile(tempFile)) + // 计算缩放比例,最大宽度或高度不超过1024 + int maxDimension = 1024; + int newWidth, newHeight; + + if (originalImage.Width > originalImage.Height) { - // 触发图像捕获事件 - OnImageCaptured((System.Drawing.Image)image.Clone(), tempFile); + // 宽度大于高度,以宽度为基准 + newWidth = maxDimension; + newHeight = (int)(originalImage.Height * ((float)maxDimension / originalImage.Width)); } - } - catch (Exception imgEx) - { - OnErrorOccurred($"图像加载失败: {imgEx.Message}"); - } - - try - { - // 加载图像到处理器 - _imageProcessor.LoadImage(tempFile); - - // 检测LED状态 - var ledStatuses = _ledDetector.DetectLedStates(CurrentConfig.LedRegions); - - // 更新图像事件,包含LED状态信息 - try + else { - using (var image = System.Drawing.Image.FromFile(tempFile)) + // 高度大于宽度,以高度为基准 + newHeight = maxDimension; + newWidth = (int)(originalImage.Width * ((float)maxDimension / originalImage.Height)); + } + + // 创建缩小的图像 + using (var resizedImage = new System.Drawing.Bitmap(newWidth, newHeight)) + { + using (var g = System.Drawing.Graphics.FromImage(resizedImage)) { - OnImageCaptured((System.Drawing.Image)image.Clone(), tempFile, ledStatuses); + g.DrawImage(originalImage, 0, 0, newWidth, newHeight); + } + + // 保存调整大小后的图像到临时文件 + string resizedTempFile = Path.GetTempFileName() + ".jpg"; + try + { + resizedImage.Save(resizedTempFile, System.Drawing.Imaging.ImageFormat.Jpeg); + + // 加载调整大小后的图像到处理器 + _imageProcessor.LoadImage(resizedTempFile); + + // 检测LED状态 + var ledStatuses = _ledDetector.DetectLedStates(CurrentConfig.LedRegions); + + return ledStatuses; + } + finally + { + // 清理临时文件 + try { if (File.Exists(resizedTempFile)) System.IO.File.Delete(resizedTempFile); } catch { } } } - catch (Exception imgEx) - { - OnErrorOccurred($"图像加载失败: {imgEx.Message}"); - } - - return ledStatuses; - } - finally - { - // 清理临时文件 - try { System.IO.File.Delete(tempFile); } catch { } } } catch (Exception ex) @@ -409,7 +421,9 @@ namespace XCamera /// LED状态列表 public List GetLedStatuses() { - return DetectLeds(); + // 注意:由于使用异步抓图,LED状态会在SDK回调中更新 + // 这里返回空列表,实际结果会通过LedStatusUpdated事件传递 + return new List(); } /// @@ -419,8 +433,9 @@ namespace XCamera /// LED状态 public LedStatus GetLedStatus(string regionId) { - var statuses = DetectLeds(); - return statuses.Find(s => s.RegionId == regionId); + // 注意:由于使用异步抓图,LED状态会在SDK回调中更新 + // 这里返回null,实际结果会通过LedStatusUpdated事件传递 + return null; } /// @@ -658,39 +673,41 @@ namespace XCamera string tempFile = System.IO.Path.GetTempFileName() + ".jpg"; try { - if (_connectionManager.CaptureImage(tempFile)) + // 生成序列号 + int seq = Interlocked.Increment(ref _snapSequence); + + // 存储抓图请求信息 + lock (_lockObject) { - // 加载图像并触发图像捕获事件 - try + _snapRequests[seq] = tempFile; // 存储带.jpg扩展名的临时文件路径 + } + + if (_connectionManager.CaptureImage(tempFile, seq)) // 使用带.jpg扩展名的临时文件 + { + // 抓图请求已发起,结果会通过SDK回调处理 + OnInfoOccurred($"抓图请求已发起: {tempFile}, 序列号: {seq}"); + } + + // 等待抓图完成回调 + if (!_captureEvent.WaitOne(10000)) // 10秒超时 + { + OnErrorOccurred($"抓图超时: {tempFile}"); + // 清理超时的请求 + lock (_lockObject) { - using (var image = System.Drawing.Image.FromFile(tempFile)) + if (_snapRequests.ContainsKey(seq)) { - // 触发图像捕获事件(无LED状态) - OnImageCaptured((System.Drawing.Image)image.Clone(), tempFile); + _snapRequests.Remove(seq); } } - catch (Exception imgEx) - { - OnErrorOccurred($"图像加载失败: {imgEx.Message}"); - } - - // 如果有LED区域,再进行LED检测 - if (CurrentConfig?.LedRegions != null && CurrentConfig.LedRegions.Count > 0) - { - var ledStatuses = DetectLeds(); - OnLedStatusUpdated(ledStatuses); - } - else - { - // 没有LED区域,只更新空状态 - OnLedStatusUpdated(new List()); - } + // 清理临时文件 + try { if (File.Exists(tempFile)) System.IO.File.Delete(tempFile); } catch { } } } finally { - // 清理临时文件 - try { System.IO.File.Delete(tempFile); } catch { } + // 无论成功失败,都清理临时文件 + try { if (File.Exists(tempFile)) System.IO.File.Delete(tempFile); } catch { } } // 等待指定间隔 @@ -723,7 +740,9 @@ namespace XCamera string szString, IntPtr pObject, long lParam, int nSeq, IntPtr pUserData, IntPtr pMsg) { // 处理SDK消息 - if (nMsgId == (int)XCloudSdkMessage.DeviceLogin) + + // 设备登录结果 + if (nMsgId == (int)ESXSDK_CMD.ESXSDK_DEV_LOGIN) { if (nParam1 < 0) { @@ -732,7 +751,9 @@ namespace XCamera _connectionManager?.Disconnect(); } } - else if (nMsgId == (int)XCloudSdkMessage.MediaStartRealPlay) + + // 实时预览结果 + else if (nMsgId == (int)ESXSDK_CMD.ESXSDK_MEDIA_START_REAL_PLAY) { if (nParam1 < 0) { @@ -742,6 +763,145 @@ namespace XCamera } } + // 正在缓存数据 + else if (nMsgId == (int)EUIMSG.EUIMSG_START_BUFFER_DATA) + { + OnInfoOccurred("正在缓存数据"); + } + + // 缓存结束,开始播放 + else if (nMsgId == (int)EUIMSG.EUIMSG_END_BUFFER_DATA) + { + OnInfoOccurred("缓存结束,开始播放"); + } + + // 播放信息 + else if (nMsgId == (int)EUIMSG.EUIMSG_PLAY_INFO) + { + OnInfoOccurred($"播放信息: {szString}"); + } + + // 媒体状态回调 + else if (nMsgId == (int)ESXSDK_CMD.ESXSDK_MEDIA_ON_PLAY_STATE) + { + OnInfoOccurred($"媒体状态回调,状态: {nParam1}"); + } + + // 抓图结果回调 + else if (nMsgId == (int)EUIMSG.EUIMSG_PLAY_SAVE_IMAGE_FILE || nMsgId == (int)ESXSDK_CMD.ESXSDK_DEV_SNAP) + { + try + { + if (nParam1 >= 0) + { + // 从序列号获取文件路径 + string filePath = null; + lock (_lockObject) + { + if (nSeq > 0 && _snapRequests.TryGetValue(nSeq, out filePath)) + { + _snapRequests.Remove(nSeq); + } + else if (nSeq == 0 && _snapRequests.Count > 0) + { + // 处理XCloudSDK_Play_MediaSnapImage返回的序列号0 + // 取第一个请求的文件路径 + int firstKey = -1; + foreach (var key in _snapRequests.Keys) + { + firstKey = key; + break; + } + if (firstKey > 0 && _snapRequests.TryGetValue(firstKey, out filePath)) + { + _snapRequests.Remove(firstKey); + } + } + } + + if (!string.IsNullOrEmpty(filePath)) + { + try + { + // 确保文件存在且可读 + if (File.Exists(filePath)) + { + try + { + // 加载图像 + using (var originalImage = System.Drawing.Image.FromFile(filePath)) + { + // 传递图像的克隆,避免原始图像被释放后使用 + OnImageCaptured((System.Drawing.Image)originalImage.Clone(), filePath); + } + + // 进行LED检测 + if (CurrentConfig?.LedRegions != null && CurrentConfig.LedRegions.Count > 0) + { + try + { + // 调用DetectLeds方法进行LED检测 + var ledStatuses = DetectLeds(filePath); + + // 加载图像 + using (var originalImage = System.Drawing.Image.FromFile(filePath)) + { + // 传递图像的克隆,避免原始图像被释放后使用 + OnImageCaptured((System.Drawing.Image)originalImage.Clone(), filePath, ledStatuses); + } + + // 触发LED状态更新事件 + OnLedStatusUpdated(ledStatuses); + } + catch (Exception ledEx) + { + OnErrorOccurred($"LED检测失败: {ledEx.Message}"); + } + } + } + catch (Exception imgEx) + { + OnErrorOccurred($"图像处理失败: {imgEx.Message}, 文件: {filePath}"); + } + } + else + { + OnErrorOccurred($"抓图文件不存在: {filePath}"); + } + } + catch (Exception imgEx) + { + OnErrorOccurred($"图像加载失败: {imgEx.Message}, 文件: {filePath}"); + } + finally + { + // 清理临时文件 + try { if (File.Exists(filePath)) System.IO.File.Delete(filePath); } catch { } + } + } + else + { + OnErrorOccurred($"未找到抓图请求信息,序列号: {nSeq}"); + } + } + else + { + OnErrorOccurred($"抓图失败,错误码: {nParam1}"); + } + } + finally + { + // 无论成功失败,都通知等待的线程 + _captureEvent.Set(); + } + } + + // 未处理的消息 + else + { + OnInfoOccurred($"收到回调,MsgId:{nMsgId}, P1:{nParam1}, P2:{nParam2}, P3:{nParam3}, Str:{szString}"); + } + return 0; } diff --git a/Windows/CS/Framework4.0/XCamera/XCloudSDK.ini b/Windows/CS/Framework4.0/XCamera/XCloudSDK.ini new file mode 100644 index 0000000..bedf18d --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/XCloudSDK.ini @@ -0,0 +1,14 @@ +{ + "Server": { + "SID": "98FE3E132FD02603181121071652-XCloudSDK" + }, + "Log": { + "UIEnbale": 0, + "FileEnbale": 1, + "NetEnbale": 0, + "ServerIP": "", + "Port": 0, + "LogLevel": 8, + "BackupDays": 7 + } +} \ No newline at end of file