UVCInterface_IOS.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. using System;
  2. using UnityEngine;
  3. using System.Runtime.InteropServices;
  4. using System.Collections;
  5. using UnityEngine.Rendering;
  6. using AOT;
  7. using System.Collections.Generic;
  8. using UnityEngine.Events;
  9. namespace SLAMUVC
  10. {
  11. //public class MonoPInvokeCallbackAttribute : Attribute { }
  12. //UVC������
  13. public class UVCInterface_IOS : UVCInterface
  14. {
  15. // 导入iOS插件中的方法
  16. [DllImport("__Internal")]
  17. private static extern void Lib_InitCamera(int w, int h, [MarshalAs(UnmanagedType.LPStr)] string format, [MarshalAs(UnmanagedType.LPStr)] string mirror);
  18. [DllImport("__Internal")]
  19. static extern IntPtr GetTextureUpdateCallback();
  20. [DllImport("__Internal")]
  21. private static extern void Lib_OpenCamera();
  22. [DllImport("__Internal")]
  23. private static extern void Lib_CloseCamera();
  24. [DllImport("__Internal")]
  25. private static extern void Lib_SetCameraMirror([MarshalAs(UnmanagedType.LPStr)] string mirror);
  26. [DllImport("__Internal")]
  27. private static extern void Lib_SetBrightness(float brightness);
  28. [DllImport("__Internal")]
  29. private static extern void Lib_SetContrast(float contrast);
  30. [DllImport("__Internal")]
  31. private static extern void Lib_SetSaturation(float saturation);
  32. [DllImport("__Internal")]
  33. private static extern void Lib_ResetControlParams();
  34. [DllImport("__Internal")]
  35. private static extern IntPtr Lib_GetUvcCtrlList();
  36. [DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
  37. private static extern IntPtr Lib_GetSupportedResolutions(out int count);
  38. [DllImport("__Internal")]
  39. private static extern void Lib_FreeResolutions(IntPtr resArray, int count);
  40. [DllImport("__Internal")]
  41. private static extern void Lib_ChangeCameraInfo(int width, int height, [MarshalAs(UnmanagedType.LPStr)] string format);
  42. [DllImport("__Internal")]
  43. private static extern bool Lib_GetIsPreviewing();
  44. // 定义 C# 回调函数委托
  45. [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  46. public delegate void CameraCallback(int id, int status);
  47. // 用于存储 UVC 接口实例
  48. private static Dictionary<int, UVCInterface> mUVCInterfaces = new Dictionary<int, UVCInterface>();
  49. // 用于持有回调,防止 GC 清理
  50. private static CameraCallback CameraCallbackDelegate;
  51. // ✅ 确保 C# 代码和 iOS 端方法匹配
  52. [DllImport("__Internal")]
  53. private static extern void RegisterCameraCallback(int id, CameraCallback callback);
  54. [DllImport("__Internal")]
  55. private static extern void UnregisterCameraCallback(int id);
  56. public static void Add(UVCInterface myUVCInterface)
  57. {
  58. int id = myUVCInterface.GetHashCode();
  59. if (mUVCInterfaces.ContainsKey(id)) return;
  60. mUVCInterfaces.Add(id, myUVCInterface);
  61. // ✅ 这里要存储委托,防止 GC 清理
  62. CameraCallbackDelegate = OnCameraStatusChanged;
  63. RegisterCameraCallback(id, CameraCallbackDelegate);
  64. }
  65. public static void Remove(UVCInterface myUVCInterface)
  66. {
  67. int id = myUVCInterface.GetHashCode();
  68. if (!mUVCInterfaces.ContainsKey(id)) return;
  69. UnregisterCameraCallback(id);
  70. mUVCInterfaces.Remove(id);
  71. }
  72. // ✅ 添加 MonoPInvokeCallback,防止崩溃
  73. [MonoPInvokeCallback(typeof(CameraCallback))]
  74. private static void OnCameraStatusChanged(int id, int status)
  75. {
  76. if (mUVCInterfaces.TryGetValue(id, out UVCInterface myUVCInterface))
  77. {
  78. CameraStatus cameraStatus = (CameraStatus)status;
  79. switch (cameraStatus)
  80. {
  81. case CameraStatus.Active:
  82. Debug.Log($"[Unity] 摄像头状态更新: {cameraStatus}");
  83. myUVCInterface.GetUvcCtrlList();
  84. myUVCInterface.GetSupportedResolutions();
  85. myUVCInterface.OnCameraTextureUpdated();
  86. break;
  87. case CameraStatus.ResolutionChanged:
  88. Debug.Log($"[Unity] 摄像头状态更新: {cameraStatus}");
  89. myUVCInterface.ChangeCameraInfoCallback(myUVCInterface.tempCameraSize[0], myUVCInterface.tempCameraSize[1]);
  90. break;
  91. case CameraStatus.RenderUpdate:
  92. myUVCInterface.OnTextureUpdate(myUVCInterface.tempCameraSize[0], myUVCInterface.tempCameraSize[1], true);
  93. break;
  94. }
  95. }
  96. }
  97. Texture2D _cameraTexture;
  98. public override Texture2D CameraTexture => _cameraTexture;
  99. private UVCCtrl[] uvcCtrls;
  100. public override UVCCtrl[] UVCCtrls => uvcCtrls;
  101. //修改时候的分辨率
  102. int[] tempSize = new int[2] { 1280, 720 };
  103. public override int[] tempCameraSize => tempSize;
  104. CommandBuffer _command;
  105. CameraFormat mCameraFormat = CameraFormat.MJPEG;
  106. CameraMirror mCameraMirror = CameraMirror.NONE;
  107. public UnityEvent<bool> updateUVCManager;
  108. /// <summary>
  109. /// 更新纹理
  110. /// </summary>
  111. /// <param name="newWidth"></param>
  112. /// <param name="newHeight"></param>
  113. /// <param name="isInit"></param>
  114. void UpdateCameraTexture(int newWidth, int newHeight, bool isInit = true)
  115. {
  116. // 销毁旧纹理
  117. if (_cameraTexture != null)
  118. {
  119. Destroy(_cameraTexture);
  120. _cameraTexture = null;
  121. }
  122. // 重新创建新的纹理
  123. _cameraTexture = new Texture2D(newWidth, newHeight, TextureFormat.BGRA32, false);
  124. _cameraTexture.filterMode = FilterMode.Point;
  125. _cameraTexture.Apply();
  126. if (isInit)
  127. {
  128. tempSize = new int[2] { newWidth, newHeight };
  129. Debug.Log($"[Unity] 重新获取 " + tempSize[0] + "=" + tempSize[1]);
  130. // 重新初始化 Camera
  131. string format = mCameraFormat == CameraFormat.MJPEG ? "MJPEG" : "YUV";
  132. string mirror = mCameraMirror == CameraMirror.NONE ? "NONE" :
  133. mCameraMirror == CameraMirror.HORIZONTAL ? "HORIZONTAL" : "VERTICAL";
  134. Lib_InitCamera(_cameraTexture.width, _cameraTexture.height, format, mirror);
  135. }
  136. }
  137. private void Awake()
  138. {
  139. Add(this);
  140. }
  141. private void Start()
  142. {
  143. OnCameraPermissionGranted();
  144. }
  145. void OnDestroy()
  146. {
  147. Remove(this);
  148. if (_command != null)
  149. {
  150. _command.Dispose();
  151. _command = null;
  152. }
  153. if (_cameraTexture != null)
  154. {
  155. Destroy(_cameraTexture);
  156. _cameraTexture = null;
  157. }
  158. }
  159. public override void InitCamera(int width, int height)
  160. {
  161. Debug.Log($"[Unity] InitCamera Texture1 : " + width + "=" + height);
  162. if (_command == null) _command = new CommandBuffer();
  163. UpdateCameraTexture(width, height);
  164. Debug.LogWarning("初始化 texture 成功!.");
  165. }
  166. public override void OpenCamera()
  167. {
  168. Lib_OpenCamera();
  169. }
  170. public override void CloseCamera()
  171. {
  172. Lib_CloseCamera();
  173. }
  174. public override void ChangeCameraInfo(int width, int height)
  175. {
  176. string format = mCameraFormat == CameraFormat.MJPEG ? "MJPEG" : "YUV";
  177. tempSize = new int[2] { width, height };
  178. Debug.Log($"[Unity] ChangeCameraInfo:" + tempSize[0] + "=" + tempSize[1]);
  179. Lib_ChangeCameraInfo(width, height, format);
  180. }
  181. public override void ChangeCameraInfoCallback(int width, int height)
  182. {
  183. Debug.Log($"[Unity] ChangeCameraInfoCallback Texture1 : " + width + "=" + height);
  184. if (_command == null) _command = new CommandBuffer();
  185. UpdateCameraTexture(width, height, false);
  186. OnCameraTextureUpdated();
  187. }
  188. public override string[] GetSupportedResolutions()
  189. {
  190. int count = 0;
  191. IntPtr resPtr = Lib_GetSupportedResolutions(out count);
  192. if (count == 0 || resPtr == IntPtr.Zero)
  193. {
  194. Debug.LogError("[Unity] GetSupportedResolutions 失败: count=0 或 resPtr 为 null");
  195. return new string[0];
  196. }
  197. string[] resolutions = new string[count];
  198. IntPtr[] ptrArray = new IntPtr[count];
  199. Marshal.Copy(resPtr, ptrArray, 0, count);
  200. for (int i = 0; i < count; i++)
  201. {
  202. resolutions[i] = Marshal.PtrToStringAnsi(ptrArray[i]);
  203. }
  204. // 释放 C 端内存
  205. Lib_FreeResolutions(resPtr, count);
  206. Debug.Log("[Unity] UVC支持的分辨率列表: " + string.Join(", ", resolutions));
  207. return resolutions;
  208. }
  209. public override string GetUvcCtrlList()
  210. {
  211. IntPtr ptr = Lib_GetUvcCtrlList();
  212. if (ptr == IntPtr.Zero)
  213. {
  214. Debug.LogError("[Unity] Lib_GetUvcCtrlList 返回空指针");
  215. return string.Empty;
  216. }
  217. string json = Marshal.PtrToStringAnsi(ptr); // 读取完就好,绝对不能 FreeHGlobal
  218. // 解析 JSON 并包裹在 wrapper 里
  219. try
  220. {
  221. UVCCtrlWrapper wrapper = JsonUtility.FromJson<UVCCtrlWrapper>("{\"uvcCtrls\":" + json + "}");
  222. if (wrapper != null && wrapper.uvcCtrls != null)
  223. {
  224. uvcCtrls = wrapper.uvcCtrls;
  225. }
  226. else
  227. {
  228. Debug.LogError("[Unity] JSON 解析失败,UVC 控制列表为空!");
  229. }
  230. }
  231. catch (Exception e)
  232. {
  233. Debug.LogError("[Unity] 解析 JSON 出错: " + e.Message);
  234. }
  235. return json;
  236. }
  237. public override void SetBrightness(int value)
  238. {
  239. Lib_SetBrightness(value);
  240. }
  241. public override void SetContrast(int value)
  242. {
  243. Lib_SetContrast(value);
  244. }
  245. public override void FlipHorizontally()
  246. {
  247. mCameraMirror = CameraMirror.HORIZONTAL;
  248. Lib_SetCameraMirror("HORIZONTAL");
  249. }
  250. public override void FlipVertically()
  251. {
  252. mCameraMirror = CameraMirror.VERTICAL;
  253. Lib_SetCameraMirror("VERTICAL");
  254. }
  255. public override void resetControlParams()
  256. {
  257. Lib_ResetControlParams();
  258. }
  259. public override bool GetIsPreviewing()
  260. {
  261. return Lib_GetIsPreviewing();
  262. }
  263. public override int SetCtrlValue(string type, int value)
  264. {
  265. int result = -1;
  266. if (type == "PU_BRIGHTNESS")
  267. {
  268. Lib_SetBrightness(value);
  269. result = 0;
  270. }
  271. else if (type == "PU_CONTRAST")
  272. {
  273. Lib_SetContrast(value);
  274. result = 0;
  275. }
  276. return result;
  277. }
  278. public override void OnTextureUpdate(int width, int height, bool bUpdate)
  279. {
  280. if (_cameraTexture == null) return;
  281. if (!GetIsPreviewing()) return;
  282. _command.IssuePluginCustomTextureUpdateV2(
  283. GetTextureUpdateCallback(), _cameraTexture, (uint)(Time.time * 60)
  284. );
  285. Graphics.ExecuteCommandBuffer(_command);
  286. _command.Clear();
  287. }
  288. }
  289. }