Unity实现摄像头录像功能

Posted 波波斯维奇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity实现摄像头录像功能相关的知识,希望对你有一定的参考价值。

Unity实现摄像头录像功能

前言

在之前的很多展馆展示的项目中,甲方有很多要求实现用摄像头录像的功能。使用Unity实现调用USB摄像头画面的功能非常容易实现,但是实现录屏的功能有一些困难,我使用了几种方法都没有实现出想要的效果,后来我在网上找到一款叫做AVProMovieCapture的插件,实现了录屏的良好效果,同时也实现了使用Unity实现摄像头录像的效果,具体实现方法如下所示:

实现步骤

1.在项目中导入AVProMovieCapture插件,如下图所示:

2.在场景中新建plane物体,设置如下图所示:
3.在场景中拖入ScreenGameObject物体,如下图所示:

4.在场景中新建WebCapture物体,在该物体上挂载WebCapture.cs脚本,脚本代码如下图所示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace RenderHeads.Media.AVProMovieCapture.Demos

    public class WebCapture : MonoBehaviour
    
        private class Instance
        
            public string name;
            public WebCamTexture texture;
            public CaptureFromTexture capture;
            public CaptureGUI gui;
        

        [SerializeField]
        private GUISkin _skin;

        //[SerializeField]
        //private GameObject _prefab;

        [SerializeField]
        private int _webcamResolutionWidth = 1920;

        [SerializeField]
        private int _webcamResolutionHeight = 1080;

        [SerializeField]
        private int _webcamFrameRate = 30;

        //State
        private Instance[] _instances;
        private int _selectedWebcamIndex;
        //显示视频的面板
        public MeshRenderer plane;
        //调用录像的脚本物体
        public CaptureGUI captureObject;

        private void Start()
        
            //Create instance data per webcam
            int numCams = WebCamTexture.devices.Length;
            _instances = new Instance[numCams];
            for (int i = 0;i < numCams;i++)
            
                //GameObject go = (GameObject)GameObject.Instantiate(_prefab);

                Instance instance = new Instance();
                instance.name = WebCamTexture.devices[i].name;
                //instance.capture = go.GetComponent<CaptureFromTexture>();
                instance.capture = captureObject.gameObject.GetComponent<CaptureFromTexture>();
                instance.capture._autoFilenamePrefix = "Demo4Webcam-" + i;
                //instance.gui = go.GetComponent<CaptureGUI>();
                instance.gui = captureObject.gameObject.GetComponent<CaptureGUI>();
                instance.gui._showUI = true;

                _instances[i] = instance;
            

            if (numCams > 0)
            
                Change(0);
            
            StartCoroutine(OpenCamera());
            //captureObject = GameObject.Find("ScreenGameObject(Clone)").GetComponent<CaptureGUI>();
        
        /// <summary>
        /// 开启摄像头
        /// </summary>
        /// <returns></returns>
        IEnumerator OpenCamera()
        
            yield return new WaitForSeconds(0.5f);
            beginCamera();
            yield return new WaitForSeconds(0.5f);
            captureObject.ToStartCapture();
        

        private void StartWebcam(Instance instance)
        
            instance.texture = new WebCamTexture(instance.name,_webcamResolutionWidth,_webcamResolutionHeight,_webcamFrameRate);
            instance.texture.Play();
            if (instance.texture.isPlaying)
            
                instance.capture.SetSourceTexture(instance.texture);
                plane.material.mainTexture = instance.texture;
            
            else
            
                StopWebcam(instance);
            
        

        private void StopWebcam(Instance instance)
        
            if (instance.texture != null)
            
                if (instance.capture != null && instance.capture.IsCapturing())
                
                    instance.capture.SetSourceTexture(null);
                    instance.capture.StopCapture();
                
                instance.texture.Stop();
                Destroy(instance.texture);
                instance.texture = null;
            
        

        private void OnDestroy()
        
            for (int i = 0;i < _instances.Length;i++)
            
                StopWebcam(_instances[i]);
            
        

        private void Change(int index)
        
            _selectedWebcamIndex = index;
            for (int j = 0;j < _instances.Length;j++)
            
                _instances[j].gui._showUI = (j == _selectedWebcamIndex);
            
        
        /// <summary>
        /// 开启摄像头
        /// </summary>
        public void beginCamera()
        
            for (int i = 0;i<_instances.Length;i++)
            
                Instance webcam = _instances[i];
                StartWebcam(webcam);
            
        
    

5.运行场景,发现已经调用了摄像头,如下图所示:

6.虽然调用了摄像头,但是不知道是否已经进行了录像,查找到工程下的movie文件夹,发现已经录入了视频,从而实现了使用usb摄像头录像的功能,如下图所示:

7.实现录像功能,有的需求还需要获取到这些视频并且展示出来,这个也在我之前的项目实现了,具体怎么实现不再赘述了,在这里将核心代码分享在这里:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;


public class Load : MonoBehaviour

    public List<string> filePaths;
    public static string[][] pic;
    private List<string> LAN;
    private string movieUrl;
    //遍历的视频数量
    public static int movieNumber = 0;

    private void Start()
    
        movieUrl = ConfigTest.dic["录像路径"]["url"];
        LAN = new List<string>();
        LAN.Add(movieUrl);
        pic = new string[LAN.Count][];
        Debug.Log(pic.Length);
        LoadIma();
    

    void LoadIma()
    
        for (int i = 0;i < pic.Length;i++)
        
            pic[i] = (load(LAN[i],i));
        
    

    string[] load(string LAN,int t)
    
        filePaths = new List<string>();
        string imgtype = "*.mp4|*.mov|*.avi";
        string[] ImageType = imgtype.Split('|');
        for (int i = 0;i < ImageType.Length;i++)
        
            //获取所有视频视频的路径
            string[] dirs = Directory.GetFiles(@"" + LAN,ImageType[i]);
            //Debug.Log(dirs.Length);
            //movieNumber = dirs.Length;
            for (int j = 0;j < dirs.Length;j++)
            
                filePaths.Add(dirs[j]);
                movieNumber = j;
                //Debug.Log(movieNumber);
            
        
        return fuzhi(t);
    

    public string[] fuzhi(int t)
    
        pic[t] = new string[filePaths.Count];
        for (int i = 0; i < filePaths.Count;i++)
        
            pic[t][i] = filePaths[i];
        
        return pic[t];
    

结尾语

网上开发的各种大神有很多,他们开发出许许多多的插件供我们使用,极大节省了我们的开发时间,在这里向他们表示感谢。我作为一名Unity小菜鸟,希望和大家有问题一起讨论,共同进步,大家有问题可以私聊我。

关于调用摄像头录像功能

 

之前有说到用Aforge去调用笔记本上的自带摄像头进行拍照,然后我就想既然能拍照,那么应该也是可以录像,于是我就去百度了怎么实现这个功能。然后我在这里把我遇到的几个坑给说一哈。

首先第一个就是按着百度中别人的例子,发现我的项目中没有VideoFileWriter这个类,而别人的项目确有,然后我就看了一下aforge的版本,发现我用的版本比较早,所以我更新了新的2013年的aforge就有这个类了。我将新的aforge上传到网盘https://pan.baidu.com/s/1i5mmKlR

微云https://share.weiyun.com/73e88808612fc2ac523f76c49a79e8ea

第二个坑还是VideoFileWriter这个类,在new实例化的时候,报错,什么版本不兼容什么的,有两个需要改的,第一给就是将aforge文件里面的ffmpeg文件夹里面的dll放到项目的bin-》debug中,第二个是在项目右键属性技术分享

然后选择生成,将生成平台选择x86,因为我之前有改成x64,所以运行不了

技术分享

 

第三个坑就是将从摄像头获取的图像写入到视频文件中,我当时是直接调用VideoFileWriter这个类实例化的对象,然后用里面的Open方法,将视频的路径,视频的分辨率,和视频的播放帧数传,视频的格式类型传进去,然后开始录,发现录完后视频只有几k的大小,打开后视频是黑的,然后就一直搞不懂是哪里出错了。跑回去看别人写好的代码是怎么录制的,发现他们里面有写了一个摄像头的事件

videoSource.NewFrame += new NewFrameEventHandler(VideoSource_NewFrame);//添加事件,不断从摄像头获取每一帧写到视频文件中

videoSource是VideoCaptureDevice这个类的对象,然后NewFrame这个事件估计是每一帧调用一次,然后将每一帧的图像写到视频文件中,代码这样子的:

/// <summary>
/// 摄像头每一帧事件,不断将每一帧的图像传输到视频文件中
/// </summary>
/// <param name="sender"></param>
/// <param name="eventArgs"></param>
private void VideoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Bitmap bitmap = eventArgs.Frame;//从摄像头中获取每一帧的图像

if (isRecord)
{

writer.WriteVideoFrame(bitmap);
}
}

里面写了一个bool的变量来控制开始录像和结束录像

写道这了,视频可以录制了,但是还有一个问题,那就是我之前以为open里面传的帧数设置是录制的视频的帧数质量,那我像帧数高一点,播放的效果好一点啊,然后我就设置成30帧,然后就发现录制出来的10秒视频3秒钟就播放完了,就像在快进一样,去百度了,才发现是帧数设置过高的原因。这里的帧数是每秒播放几帧,并不是用来控制录像的每秒录几帧,帧数调高会使播放速度变快,反之变慢,9是临界值

然后就可以录制啦,收工











以上是关于Unity实现摄像头录像功能的主要内容,如果未能解决你的问题,请参考以下文章

使用Photon引擎进行unity网络游戏开发

unity游戏开发看什么书?

小白_Unity引擎_常用API

Unity游戏开发第三人称摄像机跟随

小白_Unity引擎_Scene场景5个功能按钮和常用快捷方式

unity3d是干啥用的,除了做游戏还能干啥?