using System.Collections; using System.Collections.Generic; using System; using UnityEngine; using UnityEngine.UI; #if UNITY_ANDROID using UnityEngine.Android; #endif namespace Aisu.SIM1.Face.Samples.FaceDetectionDemo { /// /// MVP 摄像头预览,使用 WebCamTexture。 /// public sealed class FaceDetectionDemoCamera : MonoBehaviour { [SerializeField] private RawImage m_preview; // 预览图。 [SerializeField] private AspectRatioFitter m_aspectFitter; // 宽高比适配。 private WebCamTexture m_texture; // 当前摄像头纹理。 private FaceDetectionDemoLogger m_logger; // 日志。 private WebCamDevice[] m_devices; // 当前摄像头设备列表。 public bool IsOpen => m_texture != null && m_texture.isPlaying; /// /// 绑定 UI 和日志。 /// public void Bind(RawImage preview, AspectRatioFitter aspectFitter, FaceDetectionDemoLogger logger) { m_preview = preview; m_aspectFitter = aspectFitter; m_logger = logger; } /// /// 枚举摄像头名称。 /// public string[] GetDeviceNames() { m_devices = WebCamTexture.devices; var names = new List(); for (var i = 0; i < m_devices.Length; i++) { names.Add(i + ": " + m_devices[i].name); m_logger?.Info("摄像头[" + i + "] " + m_devices[i].name + ",前置=" + m_devices[i].isFrontFacing + ",自动对焦=" + m_devices[i].isAutoFocusPointSupported); } return names.ToArray(); } /// /// 请求权限后枚举摄像头。 /// public void GetDeviceNamesWhenAuthorized(Action callback) { StartCoroutine(GetDeviceNamesWhenAuthorizedRoutine(callback)); } /// /// 打开摄像头。 /// public void Open(int deviceIndex) { Close(); if (m_devices == null || m_devices.Length == 0) { m_logger?.Error("没有可用摄像头"); return; } if (deviceIndex < 0 || deviceIndex >= m_devices.Length) { m_logger?.Error("摄像头索引无效: " + deviceIndex); return; } StartCoroutine(OpenWhenAuthorized(deviceIndex)); } private IEnumerator OpenWhenAuthorized(int deviceIndex) { yield return EnsureCameraAuthorization(); if (!HasCameraAuthorization()) { m_logger?.Error("摄像头权限未授权"); yield break; } var deviceName = m_devices[deviceIndex].name; m_texture = new WebCamTexture(deviceName, 1280, 720, 30); m_texture.Play(); if (m_preview != null) { m_preview.texture = m_texture; } m_logger?.Info("摄像头已打开: " + deviceName); } private IEnumerator GetDeviceNamesWhenAuthorizedRoutine(Action callback) { Close(); yield return EnsureCameraAuthorization(); if (!HasCameraAuthorization()) { m_logger?.Error("摄像头权限未授权,无法枚举摄像头"); callback?.Invoke(new string[0]); yield break; } string[] names = null; for (var i = 0; i < 5; i++) { names = GetDeviceNames(); if (names.Length > 0) { break; } yield return new WaitForSeconds(0.3f); } callback?.Invoke(names ?? new string[0]); } private IEnumerator EnsureCameraAuthorization() { #if UNITY_ANDROID && !UNITY_EDITOR if (!Permission.HasUserAuthorizedPermission(Permission.Camera)) { m_logger?.Info("正在请求摄像头权限"); Permission.RequestUserPermission(Permission.Camera); var timeout = 10f; while (!Permission.HasUserAuthorizedPermission(Permission.Camera) && timeout > 0f) { timeout -= Time.deltaTime; yield return null; } } #else yield return null; #endif } private static bool HasCameraAuthorization() { #if UNITY_ANDROID && !UNITY_EDITOR return Permission.HasUserAuthorizedPermission(Permission.Camera); #else return true; #endif } /// /// 关闭摄像头。 /// public void Close() { if (m_texture != null) { if (m_texture.isPlaying) { m_texture.Stop(); } Destroy(m_texture); m_texture = null; } if (m_preview != null) { m_preview.texture = null; } } private void Update() { if (m_texture == null || m_aspectFitter == null || m_texture.width <= 16 || m_texture.height <= 16) { return; } m_aspectFitter.aspectRatio = (float)m_texture.width / m_texture.height; if (m_preview != null) { m_preview.rectTransform.localEulerAngles = new Vector3(0f, 0f, -m_texture.videoRotationAngle); m_preview.uvRect = m_texture.videoVerticallyMirrored ? new Rect(0f, 1f, 1f, -1f) : new Rect(0f, 0f, 1f, 1f); } } private void OnDestroy() { Close(); } } }