实现抓图

This commit is contained in:
zqm
2026-03-18 13:38:36 +08:00
parent 47733146ac
commit 6e0b5aa056
7 changed files with 522 additions and 81 deletions

View File

@@ -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;
}
}

View File

@@ -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();
}
/// <summary>
/// 10. ONVIF抓图测试
/// </summary>
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}");
}
}
/// <summary>
/// 使用ONVIF协议获取快照
/// </summary>
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}");
}
}
}
}

View File

@@ -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
}
/// <summary>
/// 抓拍图片
/// 抓拍图片(异步)
/// </summary>
/// <param name="fileName">保存文件名</param>
/// <returns>是否成功抓拍</returns>
public bool CaptureImage(string fileName)
/// <param name="nSeq">序列号</param>
/// <returns>是否成功发起抓图请求</returns>
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;

View File

@@ -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, // 数据接收结束
}
/// <summary>
/// SDK消息枚举
/// SDK消息枚举(兼容旧版)
/// </summary>
public enum XCloudSdkMessage
{
@@ -134,7 +267,7 @@ namespace XCamera.Core
}
/// <summary>
/// SDK错误码枚举
/// SDK错误码枚举(兼容旧版)
/// </summary>
public enum XCloudSdkError
{

View File

@@ -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);
/// <summary>
/// 设备抓图(异步)
/// </summary>
/// <param name="hUser">用户句柄</param>
/// <param name="szDevId">设备ID</param>
/// <param name="nChannel">通道号</param>
/// <param name="sParam">参数JSON格式</param>
/// <param name="nSeq">序列号</param>
/// <returns>0表示成功</returns>
[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
}
}

View File

@@ -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<int, string> _snapRequests = new Dictionary<int, string>(); // 抓图请求跟踪
private AutoResetEvent _captureEvent = new AutoResetEvent(false); // 抓图完成事件
private XCloudSdkWrapper.XCloudSdkMessageCallback _sdkCallback; // 存储回调委托,防止被垃圾回收
/// <summary>
/// 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
/// <summary>
/// 5. 识别配置文件内的每个区域中这些区域是led灯led灯的颜色绿亮灭是否闪烁
/// </summary>
/// <param name="imagePath">图像文件路径</param>
/// <returns>LED状态列表</returns>
public List<LedStatus> DetectLeds()
public List<LedStatus> DetectLeds(string imagePath = null)
{
if (!_isInitialized)
{
@@ -344,56 +350,62 @@ namespace XCamera
return new List<LedStatus>();
}
if (string.IsNullOrEmpty(imagePath) || !File.Exists(imagePath))
{
OnErrorOccurred("图像文件不存在");
return new List<LedStatus>();
}
try
{
// 抓拍当前图像
string tempFile = System.IO.Path.GetTempFileName() + ".jpg";
if (!_connectionManager.CaptureImage(tempFile))
// 加载图像并调整大小以减少内存使用
using (var originalImage = System.Drawing.Image.FromFile(imagePath))
{
return new List<LedStatus>();
}
// 加载图像并触发图像捕获事件
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
/// <returns>LED状态列表</returns>
public List<LedStatus> GetLedStatuses()
{
return DetectLeds();
// 注意由于使用异步抓图LED状态会在SDK回调中更新
// 这里返回空列表实际结果会通过LedStatusUpdated事件传递
return new List<LedStatus>();
}
/// <summary>
@@ -419,8 +433,9 @@ namespace XCamera
/// <returns>LED状态</returns>
public LedStatus GetLedStatus(string regionId)
{
var statuses = DetectLeds();
return statuses.Find(s => s.RegionId == regionId);
// 注意由于使用异步抓图LED状态会在SDK回调中更新
// 这里返回null实际结果会通过LedStatusUpdated事件传递
return null;
}
/// <summary>
@@ -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<LedStatus>());
}
// 清理临时文件
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;
}

View File

@@ -0,0 +1,14 @@
{
"Server": {
"SID": "98FE3E132FD02603181121071652-XCloudSDK"
},
"Log": {
"UIEnbale": 0,
"FileEnbale": 1,
"NetEnbale": 0,
"ServerIP": "",
"Port": 0,
"LogLevel": 8,
"BackupDays": 7
}
}