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实现摄像头录像功能的主要内容,如果未能解决你的问题,请参考以下文章