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