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();
}
}
}