Unity代码调用网络摄像头WebCamTexture

Unity代码调用网络摄像头WebCamTexture

初始代码

编辑器模式或Android环境和实机测试都没有问题。

using System.Collections;
using UnityEngine;
using UnityEngine.UI;

public class WebCamTest : MonoBehaviour
{
    /// <summary>
    /// 图片组件
    /// </summary>
    public RawImage rawImage;
    /// <summary>
    /// 当前相机索引
    /// </summary>
    private int index = 0;
    /// <summary>
    /// 当前运行的相机
    /// </summary>
    private WebCamTexture currentWebCam;

    void Start()
    {
        StartCoroutine(Call());
    }

    /// <summary>
    /// 开启摄像机
    /// </summary>
    public IEnumerator Call()
    {
        yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);//请求权限
        if (Application.HasUserAuthorization(UserAuthorization.WebCam) && WebCamTexture.devices.Length > 0)//权限成功,且存在摄像机
        {
            //创建相机贴图
            currentWebCam = new WebCamTexture(WebCamTexture.devices[index].name, Screen.width, Screen.height, 60);
            rawImage.texture = currentWebCam;
            currentWebCam.Play();//运行下一个
                                 //前置后置摄像头需要旋转一定角度,否则画面是不正确的,必须置于Play()函数后
            rawImage.rectTransform.localEulerAngles = new Vector3(0, 0, -currentWebCam.videoRotationAngle);
        }
    }

    /// <summary>
    /// 切换前后摄像头
    /// </summary>
    public void SwitchCamera()
    {
        if (WebCamTexture.devices.Length < 1)//只有一个摄像机
            return;
        if (currentWebCam != null)
            currentWebCam.Stop();//暂停之前的
                                 //索引下一个
        index++;
        index = index % WebCamTexture.devices.Length;
        //创建相机贴图
        currentWebCam = new WebCamTexture(WebCamTexture.devices[index].name, Screen.width, Screen.height, 60);
        rawImage.texture = currentWebCam;
        currentWebCam.Play();
        //前置后置摄像头需要旋转一定角度,否则画面是不正确的,必须置于Play()函数后
        rawImage.rectTransform.localEulerAngles = new Vector3(0, 0, -currentWebCam.videoRotationAngle);
    }
}

后续功能&代码更新

2022.10.21更新:先上代码,可直接复制使用,对照代码再对其中几个比较重要的点进行记录解释。

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Serialization;
using UnityEngine.UI;
using static my_code.ShowWebCam;

namespace my_code
{
    [RequireComponent(typeof(RawImage))]
    public class WebCam : MonoBehaviour
    {
        public ShowWebCam WebCamObject { get; set; }

        [FormerlySerializedAs("onChange")]
        [SerializeField]
        private ChangeWebCamEvent m_onChange = new ChangeWebCamEvent();

        protected void Awake()
        {
            WebCamObject = new ShowWebCam(GetComponent<RawImage>())
            {
                OnChange = m_onChange
            };
        }

        //private IEnumerator Start()
        //{
        //    yield return m_webCam.RequestWebCam();
        //}

        private void OnDestroy()
        {
            if (null != WebCamObject)
                WebCamObject.Shutdown();
        }
    }

    /// <summary> RawImage播放网络摄像机 </summary>
    public class ShowWebCam
    {
        public ShowWebCam(RawImage image)
        {
            Show = image;
            RequestedFPS = 60;
            {//正方形效果更好
                RequestedWidth = 720;//1280;
                RequestedHeight = 720;
            }
            OnChange = new ChangeWebCamEvent();
            m_showRTF = Show.transform as RectTransform;
            m_root = (RectTransform)m_showRTF.GetComponentInParent<Canvas>().transform;
        }

        private WebCamTexture[] m_webCamTextures;
        // 画布对象,画布的根对象
        private readonly RectTransform m_showRTF = null, m_root = null;
        /// <summary> 画布尺寸 </summary>
        private Vector2 m_showSizeDelta = new Vector2() { x = 0, y = 0 };

        /// <summary> 相机映射显示区域 </summary>
        public RawImage Show { get; set; }
        /// <summary> 当前相机索引 </summary>
        public virtual int CurrentIndex { get; protected set; }
        /// <summary> 当前的相机映射纹理 </summary>
        public WebCamTexture CurrentWebCam { get; protected set; }
        /// <summary> Web端是否有相机权限 </summary>
        public bool HaveAuthorization { get; protected set; }

        private float m_requestedFPS;
        public float RequestedFPS
        {
            get => m_requestedFPS;
            set
            {
                m_requestedFPS = value;
                for (int i = 0; null != m_webCamTextures && i < WebCamTexture.devices.Length; i++)
                {
                    if (null != m_webCamTextures[i])
                    {
                        m_webCamTextures[i].requestedFPS = value;
                    }
                }
            }
        }
        private int m_requestedWidth;
        public int RequestedWidth
        {
            get => m_requestedWidth;
            set
            {
                m_requestedWidth = value;
                for (int i = 0; null != m_webCamTextures && i < WebCamTexture.devices.Length; i++)
                {
                    if (null != m_webCamTextures[i])
                    {
                        m_webCamTextures[i].requestedWidth = value;
                    }
                }
            }
        }
        public int m_requestedHeight;
        public int RequestedHeight
        {
            get => m_requestedHeight;
            set
            {
                m_requestedHeight = value;
                for (int i = 0; null != m_webCamTextures && i < WebCamTexture.devices.Length; i++)
                {
                    if (null != m_webCamTextures[i])
                    {
                        m_webCamTextures[i].requestedHeight = value;
                    }
                }
            }
        }

        [Serializable]
        public class ChangeWebCamEvent : UnityEvent<WebCamTexture> { }
        public ChangeWebCamEvent OnChange { get; set; }

        /// <summary> 请求权限创建对象,并屏幕适配 </summary>
        /// <returns> 协程 </returns>
        public IEnumerator RequestWebCam()
        {
            Vector3 eul = new Vector3(0, 0, 0);
            switch (Application.platform)
            {//平台(移动端)屏幕适配
                case RuntimePlatform.Android://安卓
                    if (0 < WebCamTexture.devices.Length)
                    {//是否存在摄像机硬件
                        m_webCamTextures = new WebCamTexture[WebCamTexture.devices.Length];
                    }
                    goto SetCanvas;//安卓自动请求权限
                case RuntimePlatform.IPhonePlayer://IPhone
                    yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);//iOS需要手动请求权限
                    eul.y = 180;//竖直翻转180度旋转
                    SetCanvas:
                    {
                        eul.z = -90;//向右90度旋转
                        m_showSizeDelta.x = m_root.sizeDelta.y;//计算画布的大小
                    }
                    break;
                case RuntimePlatform.WebGLPlayer://Web端权限确认
                    if (!(HaveAuthorization = Application.HasUserAuthorization(UserAuthorization.WebCam)))
                    {
                        Debug.LogError("Failed to get webcam permissions in the Web Player!");
                    }
                    break;
                case RuntimePlatform.OSXEditor://Mac编辑器
                    eul.y = 180;//竖直翻转180度旋转
                    m_showSizeDelta.y = m_root.sizeDelta.y;
                    break;
                case RuntimePlatform.WindowsEditor://Win编辑器
                default:
                    Show.color = Color.black;
                    m_showSizeDelta = m_root.sizeDelta;//设置画布的大小
                    //Debug.Log(rectTransform.sizeDelta + "+" + root.localScale + "+" + root.sizeDelta);
                    break;
            }
            m_showRTF.localEulerAngles = eul;
            m_showRTF.sizeDelta = m_showSizeDelta;//设置画布的大小
            //OpenWebCam();//0:手机后置摄像机
        }

        /// <summary> 打开摄像头 </summary>
        /// <param name="index"> 摄像头的下标索引。0:手机后置摄像机 </param>
        /// <returns> 当前运行的相机 </returns>
        public WebCamTexture OpenWebCam(int index = 0)
        {
            if (0 < WebCamTexture.devices.Length)
            {//是否存在摄像机硬件
                if (null == m_webCamTextures)
                {//权限成功后
                    m_webCamTextures = new WebCamTexture[WebCamTexture.devices.Length];
                }
                CurrentIndex = index %= WebCamTexture.devices.Length;//计数循环
                //Debug.Log("Actual:" + index);
                if (null == m_webCamTextures[index])
                {//创建实例化一个摄像机显示区域
                    m_webCamTextures[index] = new WebCamTexture(WebCamTexture.devices[index].name)//创建相机贴图
                    {
                        requestedWidth = RequestedWidth,
                        requestedHeight = RequestedHeight,
                        requestedFPS = RequestedFPS
                    };
                }
                Show.texture = CurrentWebCam = m_webCamTextures[index];//显示的图片信息
                switch (Application.platform)
                {//平台(移动端)屏幕适配
                    case RuntimePlatform.Android | RuntimePlatform.IPhonePlayer:
                        m_showSizeDelta.y = m_root.sizeDelta.y * ((float)CurrentWebCam.width / (float)CurrentWebCam.height);//计算画布的大小
                        break;
                    case RuntimePlatform.OSXEditor://Mac编辑器
                        m_showSizeDelta.x = m_root.sizeDelta.y * ((float)RequestedWidth / (float)RequestedHeight);//计算画布的大小
                        break;
                    default: break;
                }
                m_showRTF.sizeDelta = m_showSizeDelta;//设置画布的大小
                OnChange.Invoke(CurrentWebCam);
                CurrentWebCam.Play();//打开摄像机运行识别
                return CurrentWebCam;
            }
            else
            {
                Debug.Log("WebCam permissions were obtained successfully, but no webcam was detected!");
                return null;
            }
        }

        /// <summary> 切换前后摄像头 </summary>
        /// <returns> 当前运行的相机 </returns>
        public WebCamTexture SwitchWebCam()
        {
            CloseWebCam();
            return OpenWebCam(CurrentIndex + 1);//索引下一个
        }

        /// <summary> 关闭摄像机 </summary>
        public void CloseWebCam()
        {
            if (CurrentWebCam != null)
            {//暂停之前的
                Show.texture = null;
                CurrentWebCam.Stop();
            }
        }

        /// <summary> 清理内存 </summary>
        public void Shutdown()
        {
            UnityEngine.Object.Destroy(CurrentWebCam);
            if (null != m_webCamTextures) Array.Clear(m_webCamTextures, 0, m_webCamTextures.Length);
        }
    }
}

注意事项

  • 脚本中有两个类,ShowWebCam类与WebCam类:ShowWebCam类所有的逻辑都在其中,创建时需要传入RawImage组件,用于画面的播放;WebCam是Mono类,其实就是将ShowWebCam类在外面包了一层,可以直接拖拽到物体上当组件使用;
  • WebCam类的IEnumerator Start()方法被我注释掉了,是因为项目中我是要手动调用里面的m_webCam.RequestWebCam();,且经过我亲自测试m_webCam.RequestWebCam();不能在Awake()调用,会导致协程中yield return之后的代码无法运行
  • 协程RequestWebCam()需要提前调用,来获取权限。其中比较坑的是各个平台的权限获取方式是不一样的,我之前没有认真看API以为所有平台都是一样的,这个问题就卡了很久,协程RequestWebCam()中的是经过本人安卓、苹果、Mac实机测试后的结果,如有遗漏欢迎指出:(权限获取在第一次安装程序时才会弹窗)
    • Android:WebCamTexture.devices.Length,第一次调用弹窗同意之后,需要在调用一次才可使用,不然会出现黑屏情况,所以我在OpenWebCam函数中的开始又调用了一次;
    • IPhonePlayer:Application.RequestUserAuthorization(UserAuthorization.WebCam);
  • 获取画面之后的,画布屏幕适配也是一个小坑。这边我不知道是什么逻辑,不管WebCamTexture.requestedWidthWebCamTexture.requestedHeight我如何设置,最后我获取到的画面永远都是一个宽(WebCamTexture.width)高(WebCamTexture.height)等长的正方形画面,所以我在构造函数中专门注释了:正方形效果更好
    在此逻辑前提下,我做了画面的屏幕适配(就是画面正常无拉伸),因为我的项目基本都是移动端竖屏全屏显示,故我只需要将RawImage画布,以屏幕的高设置为长宽等高的正方形即可(当然我项目中写的比较复杂,只是为了记录方法,可自行更改忽略)。
  • 安卓和IOS的画面还需要各自做个旋转逻辑才能正常,在代码中挺简单的,就不详细说明了。
  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Unity调用设备摄像头进行录像,你使用Unity的内置API来实现。下是一个简单的示例代码: ```csharp using UnityEngine; using System.Collections; using UnityEngine.UI; public class CameraCapture : MonoBehaviour private WebCamTexture webCamTexture; public RawImage rawImage; void Start() { // 获取设备上的第一个摄像头 WebCamDevice[] devices = WebCamTexture.devices; webCamTexture = new WebCamTexture(devices[0].name); // 将摄像头的图像显示在RawImage组件上 rawImage.texture = webCamTexture; // 开始捕捉摄像头图像 webCamTexture.Play(); } public void StartRecording() { // 开始录制视频 webCamTexture.Stop(); StartCoroutine(Record()); } IEnumerator Record() { // 创建一个新的视频文件 string fileName = "video.mp4"; string path = Application.persistentDataPath + "/" + fileName; // 开始录制 Handheld.StartRecordingVideo(path); // 等待一段时间,例如10秒 yield return new WaitForSeconds(10f); // 停止录制 Handheld.StopRecordingVideo(); // 重新捕捉摄像头图像 webCamTexture.Play(); } } ``` 上述代码中,我们首先获取设备上的第一个摄像头,并将其图像显示在一个RawImage组件上。然后,通过调用`StartRecording()`方法可以开始录制视频,录制时间为10秒。录制结束后,视频将保存在应用程序的持久化数据路径下的video.mp4文件中。请确保在使用前已经在Unity中设置了摄像头的访问权限。 希望这个示例能够帮助到你!如果有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天富儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值