#define ENABLE_LOG #define DEBUG /* * Copyright (c) 2014 - 2022 t_saki@serenegiant.com */ using AOT; using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using UnityEngine; #if UNITY_ANDROID && UNITY_2018_3_OR_NEWER using UnityEngine.Android; #endif using UnityEngine.Events; namespace SLAMUVC { public class UVCManager : MonoBehaviour { private const string TAG = "UVCManager#"; //-------------------------------------------------------------------------------- public Int32 DefaultWidth = 1280; public Int32 DefaultHeight = 720; protected UVCInterface _interface; /** * 保持正在使用的相机信息 */ public class CameraInfo { //internal readonly UVCDevice device; internal UVCInterface uvcInterface; internal Texture previewTexture; internal int frameType; internal volatile Int32 activeId; private Int32 currentWidth; private Int32 currentHeight; //校准时候使用的分辨率 Vector2 CalibrationResolution = new Vector2(1280, 720);//"1280x720"; //识别的最高分辨率 Vector2 HighResolution = new Vector2(320, 240);//"320x240"; //识别的最低分辨率 Vector2 LowResolution = new Vector2(160, 120);// "160x120"; //摄像机参数 private Dictionary ctrlInfos = new Dictionary(); //当前摄像机分辨率 private Dictionary resolutionInfos = new Dictionary(); //PC测试用 internal CameraInfo(Texture texture) { // this.device = null; activeId = 1; previewTexture = texture; SetSize(texture.width, texture.height); } internal CameraInfo(UVCInterface _uvcInterface) { this.uvcInterface = _uvcInterface; } /** * 是否正在获取图像 */ public bool IsPreviewing { get { return (activeId != 0) && (previewTexture != null); } } /** * 当前分辨率(宽度) * 如果不在预览中则为0 */ public Int32 CurrentWidth { get { return currentWidth; } } /** * 当前分辨率(高度) * 如果不在预览中则为0 */ public Int32 CurrentHeight { get { return currentHeight; } } /** * 返回一个尺寸 */ public Vector2 Size => new Vector2(currentWidth, currentHeight); public Vector2Int IndexToCoord(int i) { var y = i / currentWidth; var x = i % currentWidth; return new Vector2Int(x, y); } public int CoordToIndex(int x, int y) { return y * currentWidth + x; } /** * 修改当前分辨率 * @param width * @param height */ internal bool SetSize(Int32 width, Int32 height) { bool bChange = false; if (width != currentWidth || height != currentHeight) { bChange = true; currentWidth = width; currentHeight = height; } Debug.Log("CameraInfo设置SetSize,大小变化:" + bChange + ",Size:[" + width + "," + height + "]"); return bChange; } /** * 当前默认分辨率 */ public Vector2 CurrentCalibrationResolution { get { return CalibrationResolution; } } /** * 当前默认校准时候高分辨率 */ public Vector2 CurrentHighResolution { get { return HighResolution; } } /** * 当前默认最低分辨率 */ public Vector2 CurrentLowResolution { get { return LowResolution; } } /** * 修改相机的分辨率,相机分辨率修改成功回调后才修改 本地分辨率 * @param width * @param height */ internal bool SetCameraSize(Int32 width, Int32 height) { bool bChange = false; if (width != currentWidth || height != currentHeight) { bChange = true; uvcInterface.ChangeCameraInfo(width, height); } return bChange; } /** * 更新支持的分辨率 */ public void UpdateResolution() { string[] resolutions = uvcInterface.GetSupportedResolutions(); if (resolutions == null || resolutions.Length == 0) { Debug.LogError("[Error] 获取到的分辨率列表为空!"); return; } resolutionInfos.Clear(); //resolutions 数组是从大到小 //for (int i = 0; i < resolutions.Length; i++) //{ // string resolution = resolutions[i]; // string[] res = resolution.ToString().Split('x'); // resolutionInfos.Add(resolution, new Vector2(int.Parse(res[0]), int.Parse(res[1]))); //} for (int i = 0; i < resolutions.Length; i++) { string resolution = resolutions[i]; // 1. 先检查是否为空或格式不对 if (string.IsNullOrEmpty(resolution) || !resolution.Contains("x")) { Debug.LogWarning($"[Warning] 无效的分辨率数据: {resolution}"); continue; } // 2. 尝试拆分 string[] res = resolution.Split('x'); if (res.Length != 2) { Debug.LogError($"[Error] 解析失败,分辨率格式错误: {resolution}"); continue; } // 3. 解析成整数 if (!int.TryParse(res[0], out int width) || !int.TryParse(res[1], out int height)) { Debug.LogError($"[Error] 解析整数失败: {resolution}"); continue; } // 4. 添加到列表 resolutionInfos.Add(resolution, new Vector2(width, height)); //Debug.Log($"[Debug] 添加分辨率: {width}x{height}"); } } /** * 获取分辨率的key: 1280 * 720 */ public List GetResolutionsStrs() { return new List(resolutionInfos.Keys); } /** * 获取分辨率的values:Vector2(1280,720) */ public List GetResolutionsVec2s() { return new List(resolutionInfos.Values); } /** * 是否存在分辨率 */ public bool ContainsResulutionKey(string type) { return resolutionInfos.ContainsKey(type); } /** * 更新支持的 UVC 控制/处理功能信息 */ public void UpdateCtrls() { //uvcInterface.GetUvcCtrlList(); //ctrlInfos.Clear(); //foreach (UVCCtrl ctrl in uvcInterface.UVCCtrls) //{ // // Debug.Log($"name:{ctrl.name}, isAuto: {ctrl.isAuto}, isEnable: {ctrl.isEnable}, limit: {string.Join(", ", ctrl.limit)}, value: {ctrl.value}"); // ctrlInfos.Add(ctrl.name, // new UVCCtrlInfo // { // name = ctrl.name, // current = ctrl.value, // min = ctrl.limit != null && ctrl.limit.Length > 0 ? ctrl.limit[0] : 0, // max = ctrl.limit != null && ctrl.limit.Length > 1 ? ctrl.limit[1] : 0, // def = ctrl.limit != null && ctrl.limit.Length > 2 ? ctrl.limit[2] : 0 // }); //} // 获取 UVC 控制列表 uvcInterface.GetUvcCtrlList(); if (uvcInterface.UVCCtrls == null || uvcInterface.UVCCtrls.Length == 0) { Debug.LogError("[Error] 获取到的 UVC 控制列表为空!"); return; } // 清空旧数据 ctrlInfos.Clear(); foreach (UVCCtrl ctrl in uvcInterface.UVCCtrls) { if (ctrl == null) { Debug.LogError("[Error] 发现无效的 UVC 控制项 (null)"); continue; } if (string.IsNullOrEmpty(ctrl.name)) { Debug.LogWarning("[Warning] 发现无效的控制项,名称为空"); continue; } // 记录每个控制项的数据 //Debug.Log($"[Debug] 解析 UVC 控制项: name={ctrl.name}, isAuto={ctrl.isAuto}, isEnable={ctrl.isEnable}, value={ctrl.value}, " + // $"limit=[{(ctrl.limit != null ? string.Join(", ", ctrl.limit) : "null")}]"); ctrlInfos.Add(ctrl.name, new UVCCtrlInfo { name = ctrl.name, current = ctrl.value, min = ctrl.limit != null && ctrl.limit.Length > 0 ? ctrl.limit[0] : 0, max = ctrl.limit != null && ctrl.limit.Length > 1 ? ctrl.limit[1] : 0, def = ctrl.limit != null && ctrl.limit.Length > 2 ? ctrl.limit[2] : 0 }); } } /** * 获取支持的 UVC 控制/处理功能的类型列表 */ public List GetCtrls() { return new List(ctrlInfos.Keys); } /** * 获取指定 UVC 控制/处理功能的信息 * @param type * @return UVCCtrlInfo * @throws ArgumentOutOfRangeException */ public UVCCtrlInfo GetInfo(string type) { if (ctrlInfos.ContainsKey(type)) { return ctrlInfos.GetValueOrDefault(type, new UVCCtrlInfo()); } else { throw new ArgumentOutOfRangeException($"不支持的控制类型{type:X}"); } } public bool ContainsKey(string type) { return ctrlInfos.ContainsKey(type); } /** * 获取 UVC 控制/处理功能的设置值 * @param type * @return 变更后的值 * @throws ArgumentOutOfRangeException * @throws Exception */ public Int32 GetValue(string type) { if (ctrlInfos.ContainsKey(type)) { var r = ctrlInfos.GetValueOrDefault(type, new UVCCtrlInfo()); if (r.name != null) { return r.current; } else { throw new Exception($"获取控制值失败,type={type},err={r}"); } } else { throw new ArgumentOutOfRangeException($"不支持的控制类型{type:X}"); } } /** * 修改 UVC 控制/处理功能的设置 * @param type * @param value * @return 变更后的值 * @throws ArgumentOutOfRangeException * @throws Exception */ public Int32 SetValue(string type, Int32 value) { if (ctrlInfos.ContainsKey(type)) { var r = uvcInterface.SetCtrlValue(type, value); if (r == 0) { UpdateCtrls(); // 同步刷列表 var info = ctrlInfos.GetValueOrDefault(type, new UVCCtrlInfo()); info.current = value; ctrlInfos[type] = info; return value; } else { Debug.LogError($"设置控制值失败,type={type},err={r}"); } } else { Debug.LogError($"不支持的控制类型{type:X}"); } return 0; } public override string ToString() { return $"{base.ToString()}({currentWidth}x{currentHeight},activeId={activeId},IsPreviewing={IsPreviewing})"; } } // CameraInfo /** * 获取映像中的 UVC 设备映射 */ private CameraInfo cameraInfo; /// /// 开始事件 /// [HideInInspector] public UnityEvent startUVCManager; /// /// 更新事件 /// [HideInInspector] public UnityEvent updateUVCManager; private bool bInit = false; private void Awake() { // _interface = GetComponent(); #if UNITY_IOS _interface = gameObject.AddComponent(); #elif UNITY_ANDROID _interface = gameObject.AddComponent(); #else Debug.LogError("Unsupported platform!"); #endif _interface.systemCameraPermissionHandle += () => { //授权系统相机之后,初始化红外相机 initUVCManagerCamera(); }; } private void Start() { //initUVCManagerCamera(); } /// /// 初始化相机系统 /// public void initUVCManagerCamera() { _interface.cameraTextureHandle += () => { Debug.Log("cameraTextureHandle"); if (_interface.CameraTexture == null) { Debug.LogError("[Error] CameraTexture is NULL!"); return; } var info = GetCamera(); if (info == null) { Debug.LogError("[Error] GetCamera() returned NULL!"); return; } //bChange反馈是否变化宽高 bool bChange = info.SetSize(_interface.CameraTexture.width, _interface.CameraTexture.height); info.previewTexture = _interface.CameraTexture; info.activeId = 1; Debug.Log("info.previewTexture:" + (info.previewTexture != null ? info.previewTexture.GetNativeTexturePtr().ToString() : "null") + " == bInit:" + bInit); if (bInit) { //之后的触发的重新创建纹理更新 updateUVCManager?.Invoke(bChange); } else { /** * 第一次更新触发初始化 */ info.UpdateCtrls();//获取摄像机参数 info.UpdateResolution();//获取摄像机分辨率 if (startUVCManager == null) Debug.LogWarning("[Warning] startUVCManager 为空,回调不会执行"); startUVCManager?.Invoke(info); // StartCoroutine(DelayGetInfo(info)); } bInit = true; }; //初始化相机,连接设备时候自动开启渲染 _interface.InitCamera(DefaultWidth, DefaultHeight); } /// /// 延迟一下获取操作参数 /// /// /// //IEnumerator DelayGetInfo(CameraInfo info) //{ // yield return new WaitForSecondsRealtime(0.5f); //} /// /// 开启渲染 /// public void onStartPreview() { _interface.OpenCamera(); } /// /// 停止渲染 /// public void onStopPreview() { _interface.CloseCamera(); //重置cameraInfo的参数 var info = GetCamera(); info.SetSize(0, 0); info.previewTexture = null; info.activeId = 0; } /** * 获取与指定的 UVC 识别字符串对应的 CameraInfo * @param device * @return 如果已注册,则返回 CameraInfo;如果未注册,则返回 New CameraInfo */ /*Nullable*/ private CameraInfo GetCamera() { if (cameraInfo == null) cameraInfo = new CameraInfo(_interface); return cameraInfo; } } }