UVCManager.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. #define ENABLE_LOG
  2. #define DEBUG
  3. /*
  4. * Copyright (c) 2014 - 2022 t_saki@serenegiant.com
  5. */
  6. using AOT;
  7. using System;
  8. using System.Collections;
  9. using System.Collections.Generic;
  10. using System.Runtime.CompilerServices;
  11. using System.Runtime.InteropServices;
  12. using System.Threading;
  13. using UnityEngine;
  14. #if UNITY_ANDROID && UNITY_2018_3_OR_NEWER
  15. using UnityEngine.Android;
  16. #endif
  17. using UnityEngine.Events;
  18. namespace SLAMUVC
  19. {
  20. public class UVCManager : MonoBehaviour
  21. {
  22. private const string TAG = "UVCManager#";
  23. //--------------------------------------------------------------------------------
  24. public Int32 DefaultWidth = 1280;
  25. public Int32 DefaultHeight = 720;
  26. protected UVCInterface _interface;
  27. /**
  28. * 保持正在使用的相机信息
  29. */
  30. public class CameraInfo
  31. {
  32. //internal readonly UVCDevice device;
  33. internal UVCInterface uvcInterface;
  34. internal Texture previewTexture;
  35. internal int frameType;
  36. internal volatile Int32 activeId;
  37. private Int32 currentWidth;
  38. private Int32 currentHeight;
  39. //校准时候使用的分辨率
  40. Vector2 CalibrationResolution = new Vector2(1280, 720);//"1280x720";
  41. //识别的最高分辨率
  42. Vector2 HighResolution = new Vector2(320, 240);//"320x240";
  43. //识别的最低分辨率
  44. Vector2 LowResolution = new Vector2(160, 120);// "160x120";
  45. //摄像机参数
  46. private Dictionary<string, UVCCtrlInfo> ctrlInfos = new Dictionary<string, UVCCtrlInfo>();
  47. //当前摄像机分辨率
  48. private Dictionary<string, Vector2> resolutionInfos = new Dictionary<string, Vector2>();
  49. //PC测试用
  50. internal CameraInfo(Texture texture)
  51. {
  52. // this.device = null;
  53. activeId = 1;
  54. previewTexture = texture;
  55. SetSize(texture.width, texture.height);
  56. }
  57. internal CameraInfo(UVCInterface _uvcInterface)
  58. {
  59. this.uvcInterface = _uvcInterface;
  60. }
  61. /**
  62. * 是否正在获取图像
  63. */
  64. public bool IsPreviewing
  65. {
  66. get { return (activeId != 0) && (previewTexture != null); }
  67. }
  68. /**
  69. * 当前分辨率(宽度)
  70. * 如果不在预览中则为0
  71. */
  72. public Int32 CurrentWidth
  73. {
  74. get { return currentWidth; }
  75. }
  76. /**
  77. * 当前分辨率(高度)
  78. * 如果不在预览中则为0
  79. */
  80. public Int32 CurrentHeight
  81. {
  82. get { return currentHeight; }
  83. }
  84. /**
  85. * 返回一个尺寸
  86. */
  87. public Vector2 Size => new Vector2(currentWidth, currentHeight);
  88. public Vector2Int IndexToCoord(int i)
  89. {
  90. var y = i / currentWidth;
  91. var x = i % currentWidth;
  92. return new Vector2Int(x, y);
  93. }
  94. public int CoordToIndex(int x, int y)
  95. {
  96. return y * currentWidth + x;
  97. }
  98. /**
  99. * 修改当前分辨率
  100. * @param width
  101. * @param height
  102. */
  103. internal bool SetSize(Int32 width, Int32 height)
  104. {
  105. bool bChange = false;
  106. if (width != currentWidth || height != currentHeight)
  107. {
  108. bChange = true;
  109. currentWidth = width;
  110. currentHeight = height;
  111. }
  112. Debug.Log("CameraInfo设置SetSize,大小变化:" + bChange + ",Size:[" + width + "," + height + "]");
  113. return bChange;
  114. }
  115. /**
  116. * 当前默认分辨率
  117. */
  118. public Vector2 CurrentCalibrationResolution
  119. {
  120. get { return CalibrationResolution; }
  121. }
  122. /**
  123. * 当前默认校准时候高分辨率
  124. */
  125. public Vector2 CurrentHighResolution
  126. {
  127. get { return HighResolution; }
  128. }
  129. /**
  130. * 当前默认最低分辨率
  131. */
  132. public Vector2 CurrentLowResolution
  133. {
  134. get { return LowResolution; }
  135. }
  136. /**
  137. * 修改相机的分辨率,相机分辨率修改成功回调后才修改 本地分辨率
  138. * @param width
  139. * @param height
  140. */
  141. internal bool SetCameraSize(Int32 width, Int32 height)
  142. {
  143. bool bChange = false;
  144. if (width != currentWidth || height != currentHeight)
  145. {
  146. bChange = true;
  147. uvcInterface.ChangeCameraInfo(width, height);
  148. }
  149. return bChange;
  150. }
  151. /**
  152. * 更新支持的分辨率
  153. */
  154. public void UpdateResolution()
  155. {
  156. string[] resolutions = uvcInterface.GetSupportedResolutions();
  157. if (resolutions == null || resolutions.Length == 0)
  158. {
  159. Debug.LogError("[Error] 获取到的分辨率列表为空!");
  160. return;
  161. }
  162. resolutionInfos.Clear();
  163. //resolutions 数组是从大到小
  164. //for (int i = 0; i < resolutions.Length; i++)
  165. //{
  166. // string resolution = resolutions[i];
  167. // string[] res = resolution.ToString().Split('x');
  168. // resolutionInfos.Add(resolution, new Vector2(int.Parse(res[0]), int.Parse(res[1])));
  169. //}
  170. for (int i = 0; i < resolutions.Length; i++)
  171. {
  172. string resolution = resolutions[i];
  173. // 1. 先检查是否为空或格式不对
  174. if (string.IsNullOrEmpty(resolution) || !resolution.Contains("x"))
  175. {
  176. Debug.LogWarning($"[Warning] 无效的分辨率数据: {resolution}");
  177. continue;
  178. }
  179. // 2. 尝试拆分
  180. string[] res = resolution.Split('x');
  181. if (res.Length != 2)
  182. {
  183. Debug.LogError($"[Error] 解析失败,分辨率格式错误: {resolution}");
  184. continue;
  185. }
  186. // 3. 解析成整数
  187. if (!int.TryParse(res[0], out int width) || !int.TryParse(res[1], out int height))
  188. {
  189. Debug.LogError($"[Error] 解析整数失败: {resolution}");
  190. continue;
  191. }
  192. // 4. 添加到列表
  193. resolutionInfos.Add(resolution, new Vector2(width, height));
  194. //Debug.Log($"[Debug] 添加分辨率: {width}x{height}");
  195. }
  196. }
  197. /**
  198. * 获取分辨率的key: 1280 * 720
  199. */
  200. public List<string> GetResolutionsStrs()
  201. {
  202. return new List<string>(resolutionInfos.Keys);
  203. }
  204. /**
  205. * 获取分辨率的values:Vector2(1280,720)
  206. */
  207. public List<Vector2> GetResolutionsVec2s()
  208. {
  209. return new List<Vector2>(resolutionInfos.Values);
  210. }
  211. /**
  212. * 是否存在分辨率
  213. */
  214. public bool ContainsResulutionKey(string type)
  215. {
  216. return resolutionInfos.ContainsKey(type);
  217. }
  218. /**
  219. * 更新支持的 UVC 控制/处理功能信息
  220. */
  221. public void UpdateCtrls()
  222. {
  223. //uvcInterface.GetUvcCtrlList();
  224. //ctrlInfos.Clear();
  225. //foreach (UVCCtrl ctrl in uvcInterface.UVCCtrls)
  226. //{
  227. // // Debug.Log($"name:{ctrl.name}, isAuto: {ctrl.isAuto}, isEnable: {ctrl.isEnable}, limit: {string.Join(", ", ctrl.limit)}, value: {ctrl.value}");
  228. // ctrlInfos.Add(ctrl.name,
  229. // new UVCCtrlInfo
  230. // {
  231. // name = ctrl.name,
  232. // current = ctrl.value,
  233. // min = ctrl.limit != null && ctrl.limit.Length > 0 ? ctrl.limit[0] : 0,
  234. // max = ctrl.limit != null && ctrl.limit.Length > 1 ? ctrl.limit[1] : 0,
  235. // def = ctrl.limit != null && ctrl.limit.Length > 2 ? ctrl.limit[2] : 0
  236. // });
  237. //}
  238. // 获取 UVC 控制列表
  239. uvcInterface.GetUvcCtrlList();
  240. if (uvcInterface.UVCCtrls == null || uvcInterface.UVCCtrls.Length == 0)
  241. {
  242. Debug.LogError("[Error] 获取到的 UVC 控制列表为空!");
  243. return;
  244. }
  245. // 清空旧数据
  246. ctrlInfos.Clear();
  247. foreach (UVCCtrl ctrl in uvcInterface.UVCCtrls)
  248. {
  249. if (ctrl == null)
  250. {
  251. Debug.LogError("[Error] 发现无效的 UVC 控制项 (null)");
  252. continue;
  253. }
  254. if (string.IsNullOrEmpty(ctrl.name))
  255. {
  256. Debug.LogWarning("[Warning] 发现无效的控制项,名称为空");
  257. continue;
  258. }
  259. // 记录每个控制项的数据
  260. //Debug.Log($"[Debug] 解析 UVC 控制项: name={ctrl.name}, isAuto={ctrl.isAuto}, isEnable={ctrl.isEnable}, value={ctrl.value}, " +
  261. // $"limit=[{(ctrl.limit != null ? string.Join(", ", ctrl.limit) : "null")}]");
  262. ctrlInfos.Add(ctrl.name,
  263. new UVCCtrlInfo
  264. {
  265. name = ctrl.name,
  266. current = ctrl.value,
  267. min = ctrl.limit != null && ctrl.limit.Length > 0 ? ctrl.limit[0] : 0,
  268. max = ctrl.limit != null && ctrl.limit.Length > 1 ? ctrl.limit[1] : 0,
  269. def = ctrl.limit != null && ctrl.limit.Length > 2 ? ctrl.limit[2] : 0
  270. });
  271. }
  272. }
  273. /**
  274. * 获取支持的 UVC 控制/处理功能的类型列表
  275. */
  276. public List<string> GetCtrls()
  277. {
  278. return new List<string>(ctrlInfos.Keys);
  279. }
  280. /**
  281. * 获取指定 UVC 控制/处理功能的信息
  282. * @param type
  283. * @return UVCCtrlInfo
  284. * @throws ArgumentOutOfRangeException
  285. */
  286. public UVCCtrlInfo GetInfo(string type)
  287. {
  288. if (ctrlInfos.ContainsKey(type))
  289. {
  290. return ctrlInfos.GetValueOrDefault(type, new UVCCtrlInfo());
  291. }
  292. else
  293. {
  294. throw new ArgumentOutOfRangeException($"不支持的控制类型{type:X}");
  295. }
  296. }
  297. public bool ContainsKey(string type)
  298. {
  299. return ctrlInfos.ContainsKey(type);
  300. }
  301. /**
  302. * 获取 UVC 控制/处理功能的设置值
  303. * @param type
  304. * @return 变更后的值
  305. * @throws ArgumentOutOfRangeException
  306. * @throws Exception
  307. */
  308. public Int32 GetValue(string type)
  309. {
  310. if (ctrlInfos.ContainsKey(type))
  311. {
  312. var r = ctrlInfos.GetValueOrDefault(type, new UVCCtrlInfo());
  313. if (r.name != null)
  314. {
  315. return r.current;
  316. }
  317. else
  318. {
  319. throw new Exception($"获取控制值失败,type={type},err={r}");
  320. }
  321. }
  322. else
  323. {
  324. throw new ArgumentOutOfRangeException($"不支持的控制类型{type:X}");
  325. }
  326. }
  327. /**
  328. * 修改 UVC 控制/处理功能的设置
  329. * @param type
  330. * @param value
  331. * @return 变更后的值
  332. * @throws ArgumentOutOfRangeException
  333. * @throws Exception
  334. */
  335. public Int32 SetValue(string type, Int32 value)
  336. {
  337. if (ctrlInfos.ContainsKey(type))
  338. {
  339. var r = uvcInterface.SetCtrlValue(type, value);
  340. if (r == 0)
  341. {
  342. UpdateCtrls(); // 同步刷列表
  343. var info = ctrlInfos.GetValueOrDefault(type, new UVCCtrlInfo());
  344. info.current = value;
  345. ctrlInfos[type] = info;
  346. return value;
  347. }
  348. else
  349. {
  350. Debug.LogError($"设置控制值失败,type={type},err={r}");
  351. }
  352. }
  353. else
  354. {
  355. Debug.LogError($"不支持的控制类型{type:X}");
  356. }
  357. return 0;
  358. }
  359. public override string ToString()
  360. {
  361. return $"{base.ToString()}({currentWidth}x{currentHeight},activeId={activeId},IsPreviewing={IsPreviewing})";
  362. }
  363. } // CameraInfo
  364. /**
  365. * 获取映像中的 UVC 设备映射
  366. */
  367. private CameraInfo cameraInfo;
  368. /// <summary>
  369. /// 开始事件
  370. /// </summary>
  371. [HideInInspector]
  372. public UnityEvent<CameraInfo> startUVCManager;
  373. /// <summary>
  374. /// 更新事件
  375. /// </summary>
  376. [HideInInspector]
  377. public UnityEvent<bool> updateUVCManager;
  378. private bool bInit = false;
  379. private void Awake()
  380. {
  381. // _interface = GetComponent<UVCInterface>();
  382. #if UNITY_IOS
  383. _interface = gameObject.AddComponent<UVCInterface_IOS>();
  384. #elif UNITY_ANDROID
  385. _interface = gameObject.AddComponent<UVCInterface_Android>();
  386. #else
  387. Debug.LogError("Unsupported platform!");
  388. #endif
  389. _interface.systemCameraPermissionHandle += () =>
  390. {
  391. //授权系统相机之后,初始化红外相机
  392. initUVCManagerCamera();
  393. };
  394. }
  395. private void Start()
  396. {
  397. //initUVCManagerCamera();
  398. }
  399. /// <summary>
  400. /// 初始化相机系统
  401. /// </summary>
  402. public void initUVCManagerCamera()
  403. {
  404. _interface.cameraTextureHandle += () =>
  405. {
  406. Debug.Log("cameraTextureHandle");
  407. if (_interface.CameraTexture == null)
  408. {
  409. Debug.LogError("[Error] CameraTexture is NULL!");
  410. return;
  411. }
  412. var info = GetCamera();
  413. if (info == null)
  414. {
  415. Debug.LogError("[Error] GetCamera() returned NULL!");
  416. return;
  417. }
  418. //bChange反馈是否变化宽高
  419. bool bChange = info.SetSize(_interface.CameraTexture.width, _interface.CameraTexture.height);
  420. info.previewTexture = _interface.CameraTexture;
  421. info.activeId = 1;
  422. Debug.Log("info.previewTexture:" + (info.previewTexture != null ? info.previewTexture.GetNativeTexturePtr().ToString() : "null") + " == bInit:" + bInit);
  423. if (bInit)
  424. {
  425. //之后的触发的重新创建纹理更新
  426. updateUVCManager?.Invoke(bChange);
  427. }
  428. else
  429. {
  430. /**
  431. * 第一次更新触发初始化
  432. */
  433. info.UpdateCtrls();//获取摄像机参数
  434. info.UpdateResolution();//获取摄像机分辨率
  435. if (startUVCManager == null)
  436. Debug.LogWarning("[Warning] startUVCManager 为空,回调不会执行");
  437. startUVCManager?.Invoke(info);
  438. // StartCoroutine(DelayGetInfo(info));
  439. }
  440. bInit = true;
  441. };
  442. //初始化相机,连接设备时候自动开启渲染
  443. _interface.InitCamera(DefaultWidth, DefaultHeight);
  444. }
  445. /// <summary>
  446. /// 延迟一下获取操作参数
  447. /// </summary>
  448. /// <param name="info"></param>
  449. /// <returns></returns>
  450. //IEnumerator DelayGetInfo(CameraInfo info)
  451. //{
  452. // yield return new WaitForSecondsRealtime(0.5f);
  453. //}
  454. /// <summary>
  455. /// 开启渲染
  456. /// </summary>
  457. public void onStartPreview()
  458. {
  459. _interface.OpenCamera();
  460. }
  461. /// <summary>
  462. /// 停止渲染
  463. /// </summary>
  464. public void onStopPreview()
  465. {
  466. _interface.CloseCamera();
  467. //重置cameraInfo的参数
  468. var info = GetCamera();
  469. info.SetSize(0, 0);
  470. info.previewTexture = null;
  471. info.activeId = 0;
  472. }
  473. /**
  474. * 获取与指定的 UVC 识别字符串对应的 CameraInfo
  475. * @param device
  476. * @return 如果已注册,则返回 CameraInfo;如果未注册,则返回 New CameraInfo
  477. */
  478. /*Nullable*/
  479. private CameraInfo GetCamera()
  480. {
  481. if (cameraInfo == null)
  482. cameraInfo = new CameraInfo(_interface);
  483. return cameraInfo;
  484. }
  485. }
  486. }