using System; using UnityEngine; using System.Runtime.InteropServices; using System.Collections; using UnityEngine.Rendering; using AOT; using System.Collections.Generic; using UnityEngine.Events; namespace SLAMUVC { //public class MonoPInvokeCallbackAttribute : Attribute { } //UVC�Ĺ����� public class UVCInterface_IOS : UVCInterface { // 导入iOS插件中的方法 [DllImport("__Internal")] private static extern void Lib_InitCamera(int w, int h, [MarshalAs(UnmanagedType.LPStr)] string format, [MarshalAs(UnmanagedType.LPStr)] string mirror); [DllImport("__Internal")] static extern IntPtr GetTextureUpdateCallback(); [DllImport("__Internal")] private static extern void Lib_OpenCamera(); [DllImport("__Internal")] private static extern void Lib_CloseCamera(); [DllImport("__Internal")] private static extern void Lib_SetCameraMirror([MarshalAs(UnmanagedType.LPStr)] string mirror); [DllImport("__Internal")] private static extern void Lib_SetBrightness(float brightness); [DllImport("__Internal")] private static extern void Lib_SetContrast(float contrast); [DllImport("__Internal")] private static extern void Lib_SetSaturation(float saturation); [DllImport("__Internal")] private static extern void Lib_ResetControlParams(); [DllImport("__Internal")] private static extern IntPtr Lib_GetUvcCtrlList(); [DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr Lib_GetSupportedResolutions(out int count); [DllImport("__Internal")] private static extern void Lib_FreeResolutions(IntPtr resArray, int count); [DllImport("__Internal")] private static extern void Lib_ChangeCameraInfo(int width, int height, [MarshalAs(UnmanagedType.LPStr)] string format); [DllImport("__Internal")] private static extern bool Lib_GetIsPreviewing(); // 定义 C# 回调函数委托 [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void CameraCallback(int id, int status); // 用于存储 UVC 接口实例 private static Dictionary mUVCInterfaces = new Dictionary(); // 用于持有回调,防止 GC 清理 private static CameraCallback CameraCallbackDelegate; // ✅ 确保 C# 代码和 iOS 端方法匹配 [DllImport("__Internal")] private static extern void RegisterCameraCallback(int id, CameraCallback callback); [DllImport("__Internal")] private static extern void UnregisterCameraCallback(int id); public static void Add(UVCInterface myUVCInterface) { int id = myUVCInterface.GetHashCode(); if (mUVCInterfaces.ContainsKey(id)) return; mUVCInterfaces.Add(id, myUVCInterface); // ✅ 这里要存储委托,防止 GC 清理 CameraCallbackDelegate = OnCameraStatusChanged; RegisterCameraCallback(id, CameraCallbackDelegate); } public static void Remove(UVCInterface myUVCInterface) { int id = myUVCInterface.GetHashCode(); if (!mUVCInterfaces.ContainsKey(id)) return; UnregisterCameraCallback(id); mUVCInterfaces.Remove(id); } // ✅ 添加 MonoPInvokeCallback,防止崩溃 [MonoPInvokeCallback(typeof(CameraCallback))] private static void OnCameraStatusChanged(int id, int status) { if (mUVCInterfaces.TryGetValue(id, out UVCInterface myUVCInterface)) { CameraStatus cameraStatus = (CameraStatus)status; switch (cameraStatus) { case CameraStatus.Active: Debug.Log($"[Unity] 摄像头状态更新: {cameraStatus}"); myUVCInterface.GetUvcCtrlList(); myUVCInterface.GetSupportedResolutions(); myUVCInterface.OnCameraTextureUpdated(); break; case CameraStatus.ResolutionChanged: Debug.Log($"[Unity] 摄像头状态更新: {cameraStatus}"); myUVCInterface.ChangeCameraInfoCallback(myUVCInterface.tempCameraSize[0], myUVCInterface.tempCameraSize[1]); break; case CameraStatus.RenderUpdate: myUVCInterface.OnTextureUpdate(myUVCInterface.tempCameraSize[0], myUVCInterface.tempCameraSize[1], true); break; } } } Texture2D _cameraTexture; public override Texture2D CameraTexture => _cameraTexture; private UVCCtrl[] uvcCtrls; public override UVCCtrl[] UVCCtrls => uvcCtrls; //修改时候的分辨率 int[] tempSize = new int[2] { 1280, 720 }; public override int[] tempCameraSize => tempSize; CommandBuffer _command; CameraFormat mCameraFormat = CameraFormat.MJPEG; CameraMirror mCameraMirror = CameraMirror.NONE; public UnityEvent updateUVCManager; /// /// 更新纹理 /// /// /// /// void UpdateCameraTexture(int newWidth, int newHeight, bool isInit = true) { // 销毁旧纹理 if (_cameraTexture != null) { Destroy(_cameraTexture); _cameraTexture = null; } // 重新创建新的纹理 _cameraTexture = new Texture2D(newWidth, newHeight, TextureFormat.BGRA32, false); _cameraTexture.filterMode = FilterMode.Point; _cameraTexture.Apply(); if (isInit) { tempSize = new int[2] { newWidth, newHeight }; Debug.Log($"[Unity] 重新获取 " + tempSize[0] + "=" + tempSize[1]); // 重新初始化 Camera string format = mCameraFormat == CameraFormat.MJPEG ? "MJPEG" : "YUV"; string mirror = mCameraMirror == CameraMirror.NONE ? "NONE" : mCameraMirror == CameraMirror.HORIZONTAL ? "HORIZONTAL" : "VERTICAL"; Lib_InitCamera(_cameraTexture.width, _cameraTexture.height, format, mirror); } } private void Awake() { Add(this); } private void Start() { OnCameraPermissionGranted(); } void OnDestroy() { Remove(this); if (_command != null) { _command.Dispose(); _command = null; } if (_cameraTexture != null) { Destroy(_cameraTexture); _cameraTexture = null; } } public override void InitCamera(int width, int height) { Debug.Log($"[Unity] InitCamera Texture1 : " + width + "=" + height); if (_command == null) _command = new CommandBuffer(); UpdateCameraTexture(width, height); Debug.LogWarning("初始化 texture 成功!."); } public override void OpenCamera() { Lib_OpenCamera(); } public override void CloseCamera() { Lib_CloseCamera(); } public override void ChangeCameraInfo(int width, int height) { string format = mCameraFormat == CameraFormat.MJPEG ? "MJPEG" : "YUV"; tempSize = new int[2] { width, height }; Debug.Log($"[Unity] ChangeCameraInfo:" + tempSize[0] + "=" + tempSize[1]); Lib_ChangeCameraInfo(width, height, format); } public override void ChangeCameraInfoCallback(int width, int height) { Debug.Log($"[Unity] ChangeCameraInfoCallback Texture1 : " + width + "=" + height); if (_command == null) _command = new CommandBuffer(); UpdateCameraTexture(width, height, false); OnCameraTextureUpdated(); } public override string[] GetSupportedResolutions() { int count = 0; IntPtr resPtr = Lib_GetSupportedResolutions(out count); if (count == 0 || resPtr == IntPtr.Zero) { Debug.LogError("[Unity] GetSupportedResolutions 失败: count=0 或 resPtr 为 null"); return new string[0]; } string[] resolutions = new string[count]; IntPtr[] ptrArray = new IntPtr[count]; Marshal.Copy(resPtr, ptrArray, 0, count); for (int i = 0; i < count; i++) { resolutions[i] = Marshal.PtrToStringAnsi(ptrArray[i]); } // 释放 C 端内存 Lib_FreeResolutions(resPtr, count); Debug.Log("[Unity] UVC支持的分辨率列表: " + string.Join(", ", resolutions)); return resolutions; } public override string GetUvcCtrlList() { IntPtr ptr = Lib_GetUvcCtrlList(); if (ptr == IntPtr.Zero) { Debug.LogError("[Unity] Lib_GetUvcCtrlList 返回空指针"); return string.Empty; } string json = Marshal.PtrToStringAnsi(ptr); // 读取完就好,绝对不能 FreeHGlobal // 解析 JSON 并包裹在 wrapper 里 try { UVCCtrlWrapper wrapper = JsonUtility.FromJson("{\"uvcCtrls\":" + json + "}"); if (wrapper != null && wrapper.uvcCtrls != null) { uvcCtrls = wrapper.uvcCtrls; } else { Debug.LogError("[Unity] JSON 解析失败,UVC 控制列表为空!"); } } catch (Exception e) { Debug.LogError("[Unity] 解析 JSON 出错: " + e.Message); } return json; } public override void SetBrightness(int value) { Lib_SetBrightness(value); } public override void SetContrast(int value) { Lib_SetContrast(value); } public override void FlipHorizontally() { mCameraMirror = CameraMirror.HORIZONTAL; Lib_SetCameraMirror("HORIZONTAL"); } public override void FlipVertically() { mCameraMirror = CameraMirror.VERTICAL; Lib_SetCameraMirror("VERTICAL"); } public override void resetControlParams() { Lib_ResetControlParams(); } public override bool GetIsPreviewing() { return Lib_GetIsPreviewing(); } public override int SetCtrlValue(string type, int value) { int result = -1; if (type == "PU_BRIGHTNESS") { Lib_SetBrightness(value); result = 0; } else if (type == "PU_CONTRAST") { Lib_SetContrast(value); result = 0; } return result; } public override void OnTextureUpdate(int width, int height, bool bUpdate) { if (_cameraTexture == null) return; if (!GetIsPreviewing()) return; _command.IssuePluginCustomTextureUpdateV2( GetTextureUpdateCallback(), _cameraTexture, (uint)(Time.time * 60) ); Graphics.ExecuteCommandBuffer(_command); _command.Clear(); } } }