| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- // Copyright (c) 2021 homuler
- //
- // Use of this source code is governed by an MIT-style
- // license that can be found in the LICENSE file or at
- // https://opensource.org/licenses/MIT.
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine;
- #if UNITY_ANDROID
- using UnityEngine.Android;
- #endif
- namespace Mediapipe.Unity
- {
- public class WebCamSource : ImageSource
- {
- private readonly int _preferableDefaultWidth = 1280;
- private const string _TAG = nameof(WebCamSource);
- private readonly ResolutionStruct[] _defaultAvailableResolutions;
- public WebCamSource(int preferableDefaultWidth, ResolutionStruct[] defaultAvailableResolutions)
- {
- _preferableDefaultWidth = preferableDefaultWidth;
- _defaultAvailableResolutions = defaultAvailableResolutions;
- }
- private static readonly object _PermissionLock = new object();
- private static bool _IsPermitted = false;
- private WebCamTexture _webCamTexture;
- private WebCamTexture webCamTexture
- {
- get => _webCamTexture;
- set
- {
- if (_webCamTexture != null)
- {
- _webCamTexture.Stop();
- }
- _webCamTexture = value;
- }
- }
- public override int textureWidth => !isPrepared ? 0 : webCamTexture.width;
- public override int textureHeight => !isPrepared ? 0 : webCamTexture.height;
- public override bool isVerticallyFlipped => isPrepared && webCamTexture.videoVerticallyMirrored;
- public override bool isFrontFacing => isPrepared && (webCamDevice is WebCamDevice valueOfWebCamDevice) && valueOfWebCamDevice.isFrontFacing;
- public override RotationAngle rotation => !isPrepared ? RotationAngle.Rotation0 : (RotationAngle)webCamTexture.videoRotationAngle;
- private WebCamDevice? _webCamDevice;
- private WebCamDevice? webCamDevice
- {
- get => _webCamDevice;
- set
- {
- if (_webCamDevice is WebCamDevice valueOfWebCamDevice)
- {
- if (value is WebCamDevice valueOfValue && valueOfValue.name == valueOfWebCamDevice.name)
- {
- // not changed
- return;
- }
- }
- else if (value == null)
- {
- // not changed
- return;
- }
- _webCamDevice = value;
- resolution = GetDefaultResolution();
- }
- }
- public override string sourceName => (webCamDevice is WebCamDevice valueOfWebCamDevice) ? valueOfWebCamDevice.name : null;
- private WebCamDevice[] _availableSources;
- private WebCamDevice[] availableSources
- {
- get
- {
- if (_availableSources == null)
- {
- _availableSources = WebCamTexture.devices;
- }
- return _availableSources;
- }
- set => _availableSources = value;
- }
- public override string[] sourceCandidateNames => availableSources?.Select(device => device.name).ToArray();
- #pragma warning disable IDE0025
- public override ResolutionStruct[] availableResolutions
- {
- get
- {
- #if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR
- if (webCamDevice is WebCamDevice valueOfWebCamDevice) {
- return valueOfWebCamDevice.availableResolutions.Select(resolution => new ResolutionStruct(resolution)).ToArray();
- }
- #endif
- return webCamDevice == null ? null : _defaultAvailableResolutions;
- }
- }
- #pragma warning restore IDE0025
- public override bool isPrepared => webCamTexture != null;
- public override bool isPlaying => webCamTexture != null && webCamTexture.isPlaying;
- private IEnumerator Initialize()
- {
- yield return GetPermission();
- if (!_IsPermitted)
- {
- yield break;
- }
- if (webCamDevice != null)
- {
- yield break;
- }
- availableSources = WebCamTexture.devices;
- if (availableSources != null && availableSources.Length > 0)
- {
- // webCamDevice = availableSources[0];
- // 施工区
- for (int i = 0; i < availableSources.Length; i++)
- {
- Debug.LogWarning(availableSources[i].name);
- if (availableSources[i].name == "MX Brio") //
- {
- webCamDevice = availableSources[i];
- break;
- }
- }
- // 施工区
- }
- }
- private IEnumerator GetPermission()
- {
- lock (_PermissionLock)
- {
- if (_IsPermitted)
- {
- yield break;
- }
- #if UNITY_ANDROID
- if (!Permission.HasUserAuthorizedPermission(Permission.Camera))
- {
- Permission.RequestUserPermission(Permission.Camera);
- yield return new WaitForSeconds(0.1f);
- }
- #elif UNITY_IOS
- if (!Application.HasUserAuthorization(UserAuthorization.WebCam)) {
- yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);
- }
- #endif
- #if UNITY_ANDROID
- if (!Permission.HasUserAuthorizedPermission(Permission.Camera))
- {
- Debug.LogWarning("Not permitted to use Camera");
- yield break;
- }
- #elif UNITY_IOS
- if (!Application.HasUserAuthorization(UserAuthorization.WebCam)) {
- Debug.LogWarning("Not permitted to use WebCam");
- yield break;
- }
- #endif
- _IsPermitted = true;
- yield return new WaitForEndOfFrame();
- }
- }
- public override void SelectSource(int sourceId)
- {
- if (sourceId < 0 || sourceId >= availableSources.Length)
- {
- throw new ArgumentException($"Invalid source ID: {sourceId}");
- }
- webCamDevice = availableSources[sourceId];
- }
- public override IEnumerator Play()
- {
- yield return Initialize();
- if (!_IsPermitted)
- {
- throw new InvalidOperationException("Not permitted to access cameras");
- }
- InitializeWebCamTexture();
- webCamTexture.Play();
- yield return WaitForWebCamTexture();
- }
- public override IEnumerator Resume()
- {
- if (!isPrepared)
- {
- throw new InvalidOperationException("WebCamTexture is not prepared yet");
- }
- if (!webCamTexture.isPlaying)
- {
- webCamTexture.Play();
- }
- yield return WaitForWebCamTexture();
- }
- public override void Pause()
- {
- if (isPlaying)
- {
- webCamTexture.Pause();
- }
- }
- public override void Stop()
- {
- if (webCamTexture != null)
- {
- webCamTexture.Stop();
- }
- webCamTexture = null;
- }
- public override Texture GetCurrentTexture() => webCamTexture;
- private ResolutionStruct GetDefaultResolution()
- {
- var resolutions = availableResolutions;
- return resolutions == null || resolutions.Length == 0 ? new ResolutionStruct() : resolutions.OrderBy(resolution => resolution, new ResolutionStructComparer(_preferableDefaultWidth)).First();
- }
- private void InitializeWebCamTexture()
- {
- Stop();
- if (webCamDevice is WebCamDevice valueOfWebCamDevice)
- {
- webCamTexture = new WebCamTexture(valueOfWebCamDevice.name, resolution.width, resolution.height, (int)resolution.frameRate);
- return;
- }
- throw new InvalidOperationException("Cannot initialize WebCamTexture because WebCamDevice is not selected");
- }
- private IEnumerator WaitForWebCamTexture()
- {
- const int timeoutFrame = 2000;
- var count = 0;
- Debug.Log("Waiting for WebCamTexture to start");
- yield return new WaitUntil(() => count++ > timeoutFrame || webCamTexture.width > 16);
- if (webCamTexture.width <= 16)
- {
- throw new TimeoutException("Failed to start WebCam");
- }
- }
- private class ResolutionStructComparer : IComparer<ResolutionStruct>
- {
- private readonly int _preferableDefaultWidth;
- public ResolutionStructComparer(int preferableDefaultWidth)
- {
- _preferableDefaultWidth = preferableDefaultWidth;
- }
- public int Compare(ResolutionStruct a, ResolutionStruct b)
- {
- var aDiff = Mathf.Abs(a.width - _preferableDefaultWidth);
- var bDiff = Mathf.Abs(b.width - _preferableDefaultWidth);
- if (aDiff != bDiff)
- {
- return aDiff - bDiff;
- }
- if (a.height != b.height)
- {
- // prefer smaller height
- return a.height - b.height;
- }
- // prefer smaller frame rate
- return (int)(a.frameRate - b.frameRate);
- }
- }
- }
- }
|