using UnityEngine; using System; using System.Collections; using System.Runtime.InteropServices; using SLAMUVC; using UnityEngine.UI; using System.Collections.Generic; using AOT; using System.Threading; using UnityEngine.Events; using UnityEngine.Android; namespace SLAMUVC { [StructLayout(LayoutKind.Sequential, Pack = 4)] public struct UVCCtrlInfo { public string name; public Int32 current; public Int32 min; public Int32 max; public Int32 def; public override string ToString() { return $"{base.ToString()}(name={name},min={min},max={max},def={def},current={current})"; } } [System.Serializable] public class UVCCtrl { public string name; public bool isAuto; public bool isEnable; public int[] limit; public int value; } [System.Serializable] public class UVCCtrlWrapper { public UVCCtrl[] uvcCtrls; } public enum CameraFormat { MJPEG, YUV, } public enum CameraMirror { NONE, HORIZONTAL,//水平翻转 VERTICAL//垂直翻转 } public enum UVCCameraPixelFormat { PIXEL_FORMAT_RAW, PIXEL_FORMAT_YUV, PIXEL_FORMAT_NV12, // one format of YUV420SemiPlanar PIXEL_FORMAT_NV21, // one format of YUV420SemiPlanar PIXEL_FORMAT_RGB, PIXEL_FORMAT_RGB565, PIXEL_FORMAT_RGBX } //UVC的管理类 public class UVCInterface : MonoBehaviour { private const string UVC_MANAGER = "com.slambb.myuvc.MyUVCManager"; //java对象 private AndroidJavaObject uvcManagerObj = null; CameraFormat mCameraFormat = CameraFormat.MJPEG; CameraMirror mCameraMirror = CameraMirror.VERTICAL;//默认垂直 int Width = 1280; int Height = 720; Texture2D _cameraTexture; public Texture2D CameraTexture => _cameraTexture; private UVCCtrl[] uvcCtrls; public UVCCtrl[] UVCCtrls => uvcCtrls; private SynchronizationContext mainContext; /// /// 初始化相机权限成功 /// public CameraPermissionHandle systemCameraPermissionHandle; public delegate void CameraPermissionHandle(); /// /// 纹理更新事件 /// public CameraTextureHandle cameraTextureHandle; public delegate void CameraTextureHandle(); private static readonly string ActivityClassName = "com.slambb.myuvc.UsbPermissionActivity"; //public void RequestUsbPermission() //{ // using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) // { // AndroidJavaObject activity = unityPlayer.GetStatic("currentActivity"); // AndroidJavaClass usbPermissionActivity = new AndroidJavaClass(ActivityClassName); // // Start UsbPermissionActivity // activity.Call("startActivity", usbPermissionActivity.CallStatic("newIntent", activity)); // } //} void Awake() { try { // 创建 uvcManagerObj 对象 uvcManagerObj = new AndroidJavaObject(UVC_MANAGER); } catch (Exception e) { Debug.LogError("UVC_MANAGER Exception: " + e.Message); } //RequestUsbPermission(); } void Start() { OpenCameraPermisson(); } private void OnDestroy() { Remove(this); uvcManagerObj.Call("clearCameraHelper"); } /// /// 创建一个纹理id到插件 /// private void CreateTextureAndPassToPlugin() { // 销毁纹理 if (_cameraTexture != null) { Destroy(_cameraTexture); _cameraTexture = null; } // Create a texture Texture2D tex = new Texture2D(Width, Height, TextureFormat.ARGB32, false); // 设置点过滤,以便我们可以清楚地看到像素 tex.filterMode = FilterMode.Point; // 调用Apply(),使其实际上传到GPU tex.Apply(); _cameraTexture = tex; //将纹理指针传递给插件 SetTexture(tex.GetNativeTexturePtr(), tex.width, tex.height); cameraTextureHandle?.Invoke(); } //private IEnumerator CallPluginAtEndOfFrames() //{ // while (true) // { // //等待所有帧渲染完成 // yield return new WaitForEndOfFrame(); // //发出具有任意整数标识符的插件事件。 // //该插件可以区分不同的 // //它需要根据这个ID做的事情。 // //对于我们的简单插件,我们在这里传递哪个ID并不重要。 // if(GetIsPreviewing()) GL.IssuePluginEvent(GetRenderEventFunc(), 1); // } //} /// /// 更新纹理 /// /// /// /// public void OnTextureUpdate(int width, int height, bool bUpdate) { mainContext.Post(__ => { if (bUpdate) { Debug.Log("创建新纹理:size=[" + width + "," + height + "]"); Width = width; Height = height; CreateTextureAndPassToPlugin(); } else { GL.IssuePluginEvent(GetRenderEventFunc(), 1); } }, null); } public bool GetIsPreviewing() { if (uvcManagerObj != null) { if (uvcManagerObj.Call("GetIsPreviewing") == 1) { return true; } } return false; } /// /// 初始化相机和对应的操作,初始化后会自动打开相机 /// /// /// public void InitCamera(int width, int height) { Width = width; Height = height; uvcManagerObj.Call("initCameraHelper", Width, Height, mCameraFormat.ToString(), mCameraMirror.ToString()); //主线程 mainContext = SynchronizationContext.Current; //注册c回调 Add(this); //mainContext.Post(__ => //{ // //CreateTextureAndPassToPlugin(); //}, null); //StartCoroutine("CallPluginAtEndOfFrames"); } public void OpenCamera() { uvcManagerObj.Call("OpenCamera"); } public void CloseCamera() { uvcManagerObj.Call("CloseCamera"); } public void ChangeCameraInfo(int width, int height) { uvcManagerObj.Call("ChangeCameraInfo", width, height, mCameraFormat.ToString()); } public string[] GetSupportedResolutions() { if (uvcManagerObj != null) { var objPtr = uvcManagerObj.Call("GetSupportedResolutions").GetRawObject(); if (objPtr != IntPtr.Zero) return AndroidJNIHelper.ConvertFromJNIArray(objPtr); } return null; } /// /// 水平翻转 /// public void FlipHorizontally() { uvcManagerObj.Call("FlipHorizontally"); } /// /// 垂直翻转 /// public void FlipVertically() { uvcManagerObj.Call("FlipVertically"); } public void resetControlParams() { uvcManagerObj.Call("resetControlParams"); } public void GetUvcCtrlList() { if (uvcManagerObj != null) { string json = uvcManagerObj.Call("GetUvcCtrlList"); UVCCtrlWrapper wrapper = JsonUtility.FromJson("{\"uvcCtrls\":" + json + "}"); if (wrapper != null && wrapper.uvcCtrls != null) { //赋值 uvcCtrls = wrapper.uvcCtrls; //foreach (UVCCtrl ctrl in wrapper.uvcCtrls) //{ // Debug.Log($"name:{ctrl.name}, isAuto: {ctrl.isAuto}, isEnable: {ctrl.isEnable}, limit: {string.Join(", ", ctrl.limit)}, value: {ctrl.value}"); //} } else { Debug.LogError("Failed to parse JSON data."); } } } public void SetBrightness(int value) { uvcManagerObj.Call("SetBrightness", value); } public void SetContrast(int value) { uvcManagerObj.Call("SetContrast", value); } public int SetCtrlValue(string type, Int32 value) { int result = -1; if (type == "PU_BRIGHTNESS") { uvcManagerObj.Call("SetBrightness", value); result = 0; } else if (type == "PU_CONTRAST") { uvcManagerObj.Call("SetContrast", value); result = 0; } return result; } //-------------------------------------------------------------------------------- /** * 先处理相机权限 */ private void OpenCameraPermisson() { if (Permission.HasUserAuthorizedPermission(Permission.Camera)) { //Debug.LogError("HasUserAuthorizedPermission!"); systemCameraPermissionHandle?.Invoke(); return; } bool useCallbacks = true; if (!useCallbacks) { // We do not have permission to use the microphone. // Ask for permission or proceed without the functionality enabled. Permission.RequestUserPermission(Permission.Camera); } else { var callbacks = new PermissionCallbacks(); callbacks.PermissionDenied += PermissionCallbacks_PermissionDenied; callbacks.PermissionGranted += PermissionCallbacks_PermissionGranted; callbacks.PermissionDeniedAndDontAskAgain += PermissionCallbacks_PermissionDeniedAndDontAskAgain; Permission.RequestUserPermission(Permission.Camera, callbacks); } } void PermissionCallbacks_PermissionDenied(string PermissionName) { Debug.LogError($"PermissionCallbacks_PermissionDenied[{PermissionName}]"); } //本次允许 void PermissionCallbacks_PermissionGranted(string PermissionName) { Debug.Log($"PermissionCallbacks_PermissionGranted[{PermissionName}]"); systemCameraPermissionHandle?.Invoke(); } void PermissionCallbacks_PermissionDeniedAndDontAskAgain(string PermissionName) { Debug.Log($"PermissionCallbacks_PermissionDeniedAndDontAskAgain[{PermissionName}]"); systemCameraPermissionHandle?.Invoke(); } //设置GL纹理 [DllImport("TransferTexture")] private static extern void SetTexture(IntPtr texture, int w, int h); //GL渲染事件 [DllImport("TransferTexture")] private static extern IntPtr GetRenderEventFunc(); [UnmanagedFunctionPointer(CallingConvention.StdCall)] public delegate void TextureUpdateDelegate(Int32 id, int width, int height, bool bUpdate); [DllImport("TransferTexture")] private static extern void RegisterTextureUpdateCallback(Int32 id, TextureUpdateDelegate callback); [DllImport("TransferTexture")] private static extern void UnregisterTextureUpdateCallback(Int32 id, TextureUpdateDelegate callback); //记录MyUVCInterface private static Dictionary mUVCInterfaces = new Dictionary(); private static TextureUpdateDelegate textureUpdateDelegate; //注册回调事件 public static void Add(UVCInterface myUVCInterface) { Int32 id = myUVCInterface.GetHashCode(); textureUpdateDelegate = new TextureUpdateDelegate(TextureUpdateHandler); mUVCInterfaces.Add(id, myUVCInterface); RegisterTextureUpdateCallback(id, textureUpdateDelegate); } //移除回调事件 public static void Remove(UVCInterface myUVCInterface) { Int32 id = myUVCInterface.GetHashCode(); UnregisterTextureUpdateCallback(id, textureUpdateDelegate); mUVCInterfaces.Remove(id); } //数据更新时候回调 [MonoPInvokeCallback(typeof(TextureUpdateDelegate))] private static void TextureUpdateHandler(Int32 id, int width, int height, bool bUpdate) { var myUVCInterface = mUVCInterfaces.ContainsKey(id) ? mUVCInterfaces[id] : null; if (myUVCInterface != null) { myUVCInterface.OnTextureUpdate(width, height, bUpdate); } } } }