Unity 使用AVProMovieCapture实现Game视图屏幕录制

news2024/12/28 19:25:56

内容将会持续更新,有错误的地方欢迎指正,谢谢!
 

Unity 使用AVProMovieCapture实现Game视图屏幕录制
     
TechX 坚持将创新的科技带给世界!

拥有更好的学习体验 —— 不断努力,不断进步,不断探索
TechX —— 心探索、心进取!

助力快速掌握 AVProMovieCapture 屏幕录制

为初学者节省宝贵的学习时间,避免困惑!


文章目录

  • 一、导入AVProMovieCapture包
  • 二、屏幕捕捉基本设置
  • 三、实现Game视图屏幕捕捉功能
    • 1、屏幕捕捉功能
    • 2、视频列表功能
    • 3、视频播放功能
  • 四、MovieCapture项目地址


一、导入AVProMovieCapture包


在Asset Store资源商店里面可以下载这个插件:

https://assetstore.unity.com/packages/tools/video/avpro-movie-capture-desktop-edition-221914

目前这个插件比较贵,以下提供了老一点的版本,也是可以用的。
https://download.csdn.net/download/caiprogram123/89517225

下载之后解压,并把这个包导入到Unity中,可以看到RenderHeads/AVProMovieCapture

在这里插入图片描述



二、屏幕捕捉基本设置


在开始录制Game视图时要对录制做一些基本的设置:

  • 输出文件夹类型:输出视频到哪个位置
    在这里插入图片描述

  • 输出子文件夹:输出视频位置的子文件夹

  • 分辨率:设置视频的分辨率
    在这里插入图片描述

  • 帧率:设置视频的帧率

  • 视频前缀:设置视频名称的前缀

//视频输出路径
public string videoOutFolder;
//视频输出路径类型
public OutputPath outputFolderType = defaultOutputFolderType;
//视频输出文件夹
public string outputFolderPath = defaultOutputFolderPath;

//视频降分辨率
public CaptureBase.DownScale downScale = CaptureBase.DownScale.Original;
//视频帧率
public float frame = 60;
//视频前缀
public string prefix = "ScreenCapture";

/// <summary>
/// 设置视频输出路径
/// </summary>
private void SetOutFolderPath()
{
    videoOutFolder = GetFolder(outputFolderType, outputFolderPath);

    if (!Directory.Exists(videoOutFolder))
        Directory.CreateDirectory(videoOutFolder);
    _movieCapture.OutputFolderPath = videoOutFolder;
}

/// <summary>
/// 设置视频画质
/// </summary>
private void SetDownScale()
{
    _movieCapture.ResolutionDownScale = downScale;
}

/// <summary>
/// 设置帧率
/// </summary>
private void SetFrameRate()
{
    _movieCapture.FrameRate = frame;

}

/// <summary>
/// 设置文件前缀
/// </summary>
private void SetPrefix()
{
    _movieCapture.FilenamePrefix = prefix;
}


三、实现Game视图屏幕捕捉功能


1、屏幕捕捉功能


在导入包后就可以进行屏幕录制功能开发,包含开始录频、结束录频、查看最近录制,同时在录制的过程中也能够看到当前当前录制视频的大小和时长。

 private long _lastFileSize;
 private uint _lastEncodedMinutes;
 private uint _lastEncodedSeconds;
 private uint _lastEncodedFrame;

 private StringBuilder _fileSize = new StringBuilder();
 private StringBuilder _videoLength = new StringBuilder();
 
 /// <summary>
 /// 开始录制
 /// </summary>
 private void StartCapture()
 {
     _lastFileSize = 0;
     _lastEncodedMinutes = _lastEncodedSeconds = _lastEncodedFrame = 0;
     if (_movieCapture != null)
     {
         _movieCapture.StartCapture();
         startRecord.interactable = false;
         stopRecord.interactable = true;
     }
 }

 /// <summary>
 /// 停止录制
 /// </summary>
 private void StopCapture()
 {
     if (_movieCapture != null)
     {
         if (_movieCapture.IsCapturing())
         {
             _movieCapture.StopCapture();
             startRecord.interactable = true;
             stopRecord.interactable = false;
         }
     }
 }

 /// <summary>
 /// 文件大小设置
 /// </summary>
 /// <param name="lastFileSize"></param>
 private void FileSize()
 {
     _lastFileSize = _movieCapture.GetCaptureFileSize();

     _fileSize.Clear();
     _fileSize.Append((_lastFileSize / (1024f * 1024f)).ToString("F1"));
     _fileSize.Append("MB");
 }

 /// <summary>
 /// 视频长度设置
 /// </summary>
 private void VideoLength()
 {
     if (!_movieCapture.IsRealTime)
     {
         _lastEncodedSeconds = (uint)Mathf.FloorToInt(_movieCapture.CaptureStats.NumEncodedFrames / _movieCapture.FrameRate);
     }
     else
     {
         _lastEncodedSeconds = _movieCapture.CaptureStats.TotalEncodedSeconds;
     }

     _lastEncodedMinutes = _lastEncodedSeconds / 60;
     _lastEncodedSeconds = _lastEncodedSeconds % 60;
     _lastEncodedFrame = _movieCapture.CaptureStats.NumEncodedFrames % (uint)_movieCapture.FrameRate;

     _videoLength.Clear();

     _videoLength.Append(_lastEncodedMinutes.ToString("00"));
     _videoLength.Append(":");
     _videoLength.Append(_lastEncodedSeconds.ToString("00"));
     _videoLength.Append(".");
     _videoLength.Append(_lastEncodedFrame.ToString("000"));
 }
 
  • 开始录制: 开始进行Game视图录制
  • 结束录制: 结束录制,录制结束后,视频会进进行保存
  • 最新录制: 显示最近录制的视频记录
  • File Size: 当前录制视频的文件大小
  • Video Length: 当前录制视频的时长

在这里插入图片描述

2、视频列表功能


在视频录制完成后,会将视频信息进行保存,当点击最新录制会显示视频列表窗口,在这里你可以找到所有的最近录制的视频记录。

public class RecordList : MonoBehaviour
{
    public RecordItem recordItemPre;
    private List<RecordItem> records = new List<RecordItem>();

    /// <summary>
    /// 初始化记录表
    /// </summary>
    /// <param name="saveInfos"></param>
    public void InitRecordList(List<VideoInfo> videoList)
    {
        gameObject.SetActive(true);

        for (int i = 0; i < records.Count; i++)
        {
            Destroy(records[i].gameObject);
        }

        records.Clear();

        for (int i = 0; i < videoList.Count; i++)
        {
            RecordItem recordItem = Instantiate(recordItemPre, recordItemPre.transform.parent);
            recordItem.InitRecordItem(videoList[i]);
            records.Add(recordItem);
            recordItem.gameObject.SetActive(true);
        }
    }
}
 public class RecordItem : MonoBehaviour
 {
     public Text videoName;
     public Text videoSize;
     public Text videoLength;
     public Text lastModifyTime;
     public Button view;
     public VideoControl videoControl;
     private VideoInfo videoInfo;

     // Start is called before the first frame update
     void Start()
     {
         view.onClick.AddListener(() => {
             videoControl.VideoControlInit(videoInfo.videoPath);
         });
     }

     /// <summary>
     /// 初始化记录表
     /// </summary>
     /// <param name="saveInfo"></param>
     public void InitRecordItem(VideoInfo videoInfo)
     {
         this.videoInfo = videoInfo;
         videoName.text = videoInfo.videoName;
         videoSize.text = (videoInfo.videoSize / (1024f * 1024f)).ToString("F1") + "MB";
         videoLength.text = (videoInfo.videoLength / 60).ToString("00") + ":" + (videoInfo.videoLength % 60).ToString("00");
         lastModifyTime.text = videoInfo.lastModifyTime;
     }
 }
  • 名称: 视频名称
  • 大小: 视频文件大小
  • 时长: 视频时长
  • 最后修改: 视频保存时间
  • 查看: 播放视频

在这里插入图片描述

3、视频播放功能


在视频列表中,点击查看按钮就可以播放该视频。

public class VideoControl : MonoBehaviour
{
    public Text title;
    public VideoPlayer player;
    public Slider videoSlider;
    public Button close;
    public Text videotime;
    public Text videoLength;

    string videoPath;

    private void Update()
    {
        if (player.isPlaying)
        {
            SetCurPlayTime();
            SetPlaySchedule();
        }
    }

    private void Awake()
    {
        player.prepareCompleted += OnPrepareCompleted;
    }

    private void OnDestroy()
    {
        player.prepareCompleted -= OnPrepareCompleted;
    }

    public void VideoControlInit(string videoPath)
    {
        this.videoPath = videoPath;

        gameObject.SetActive(true);
        SetVideoPlayPath(videoPath);
        PlayVideo();
    }

    /// <summary>
    /// 视频准备
    /// </summary>
    /// <param name="videoSource"></param>
    private void OnPrepareCompleted(VideoPlayer videoSource)
    {
        SetVideoName();
        SetVideoLength();
    }

    /// <summary>
    /// 设置视频名称
    /// </summary>
    private void SetVideoName()
    {
        title.text = Path.GetFileNameWithoutExtension(videoPath);
    }

    /// <summary>
    /// 设置播放器路径
    /// </summary>
    /// <param name="path"></param>
    public void SetVideoPlayPath(string path)
    {
        player.url = path;
    }

    /// <summary>
    /// 当前视频播放时间
    /// </summary>
    private void SetCurPlayTime()
    {
        videotime.text = TimeProcess(player.time);
    }

    /// <summary>
    /// 设置视频时长
    /// </summary>
    /// <param name="length"></param>
    private void SetVideoLength()
    {
        videoLength.text = TimeProcess(player.length);
    }

    /// <summary>
    /// 设置播放进度
    /// </summary>
    private void SetPlaySchedule()
    {
        videoSlider.value = (float)player.frame / player.frameCount;
    }

    /// <summary>
    /// 时间处理
    /// </summary>
    /// <param name="time"></param>
    /// <returns></returns>
    private string TimeProcess(double time)
    {
        int minutes = (int)time / 60;
        int seconds = (int)time % 60;
        return minutes.ToString("00") + ":" + seconds.ToString("00");
    }

    /// <summary>
    /// 视频播放
    /// </summary>
    public void PlayVideo()
    {
        player.Play();
    }
}

视频播放时,会显示视频名称、时长、当前时间和播放进度

在这里插入图片描述


四、MovieCapture项目地址


项目完整地址:

https://gitcode.com/CTLittleNewbie/ScreenRecord_240520/





TechX —— 心探索、心进取!

每一次跌倒都是一次成长

每一次努力都是一次进步

END
感谢您阅读本篇博客!希望这篇内容对您有所帮助。如果您有任何问题或意见,或者想要了解更多关于本主题的信息,欢迎在评论区留言与我交流。我会非常乐意与大家讨论和分享更多有趣的内容。
如果您喜欢本博客,请点赞和分享给更多的朋友,让更多人受益。同时,您也可以关注我的博客,以便及时获取最新的更新和文章。
在未来的写作中,我将继续努力,分享更多有趣、实用的内容。再次感谢大家的支持和鼓励,期待与您在下一篇博客再见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1896881.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

react框架,使用vite和nextjs构建react项目

react框架 React 是一个用于构建用户界面(UI)的 JavaScript 库,它的本质作用是使用js动态的构建html页面&#xff0c;react的设计初衷就是为了更方便快捷的构建页面&#xff0c;官方并没有规定如何进行路由和数据获取&#xff0c;要构建一个完整的react项目&#xff0c;我们需要…

全国现状建筑数据,选中范围即可查询下载,富含建筑物位置、层数、建筑物功能、名称地址等信息!

今天分享的是一个绘制范围即可下载范围内的建筑数据下载工具&#xff0c;内含高质量建筑数据数据源&#xff0c;助力场地建设规模一目了然。 数据可视化&#xff1a; 建筑物位置、层数、建筑轮廓地图可见&#xff0c;辅助分析。 数据字段&#xff1a; 建筑高度、层数、基地面…

通用代码生成器模板体系,语句和语句组

通用代码生成器或者叫动词算子式通用目的代码生成器是一组使用Java编写的通用代码生成器。它们的原理基于动词算子和域对象的笛卡尔积。它们没有使用FreeMarker和或者Velocity等现成的文件式模板引擎。而是使用java语言开发了一套专门为动词算子式代码生成器使用的模板API。而其…

【BUUCTF-PWN】11-ciscn_2019_c_1

64位&#xff0c;开启了NX保护 执行效果如下&#xff1a; main函数 encrypt()函数 gets()函数存在栈溢出&#xff0c;但是中间部分代码会对传入的字符串做加密处理 中间的部分是对字符串进行处理&#xff0c;strlen的作用是得知字符串的长度&#xff0c;但是遇到’\0‘就…

煤矿安全生产新利器!电力无线测温技术助力保障安全

煤矿变电所作为矿山电力系统的重要组成部分&#xff0c;承担着电能输送与分配的任务&#xff0c;它们的好坏直接影响煤矿的正常生产及安全运营&#xff0c; 煤矿环境复杂多变&#xff0c;高温、高压、潮湿等因素交织在一起&#xff0c;对电气设备的正常运转构成了巨大威胁。尤其…

什么是数字化产科管理平台?

什么是数字化产科管理平台&#xff1f; 数字化产科管理平台是为医院产科量身定制的信息管理系统&#xff0c;旨在提高医院产科的服务质量和管理效率。该平台全面覆盖了孕妇从怀孕开始到生产结束以及产后42天以内的一系列医院保健服务信息。以下是数字产科管理平台的详细介绍&a…

图书商城系统java项目ssm项目jsp项目java课程设计java毕业设计

文章目录 图书商城系统一、项目演示二、项目介绍三、部分功能截图四、部分代码展示五、底部获取项目源码&#xff08;9.9&#xffe5;带走&#xff09; 图书商城系统 一、项目演示 图书商城系统 二、项目介绍 语言: Java 数据库&#xff1a;MySQL 技术栈&#xff1a;SpringS…

Go基础知识

目标 简单介绍一下 GO 语言的诞生背景&#xff0c;使用场景&#xff0c;目前使用方案简单介绍一下 GO的使用&#xff0c;GO的基础语法&#xff0c;简单过一下一些GO的语言例子着重介绍一下GO的特性&#xff0c;为什么大家都使用GO语言&#xff0c;GO的内存结构、为什么都说GO快…

小蜜蜂WMS与小蜜蜂WMS对接集成根据条件获取客户信息列表(分页)连通新增客户信息(小蜜蜂读写测试)

小蜜蜂WMS与小蜜蜂WMS对接集成根据条件获取客户信息列表&#xff08;分页&#xff09;连通新增客户信息(小蜜蜂读写测试) 接通系统&#xff1a;小蜜蜂WMS 天津市小蜜蜂计算机技术有限公司&#xff08;acbee&#xff0c;TianJinACBEEComputerTechnologyCo.,Ltd&#xff09;成立于…

如何选择合适的滑动变阻器?

滑动变阻器是可以改变电阻值的电子元件&#xff0c;广泛应用于各种电子设备和电路中。选择合适的滑动变阻器对于保证电路的正常工作和提高设备的性能具有重要意义。以下是选择滑动变阻器时需要考虑的几个关键因素&#xff1a; 1. 电阻范围&#xff1a;滑动变阻器的电阻范围是指…

【基于R语言群体遗传学】-7-遗传变异(genetic variation)

一些新名词 Continuous time: 连续时间&#xff0c;是指不间断流动的时间&#xff0c;不以单位时间形式出现。 Diffusion: 扩散&#xff0c;是指粒子从高浓度区域向低浓度区域的被动净移动。 Discrete time: 离散时间&#xff0c;是指被划分为单位的时间&#xff0c;例如每个…

【总线】AXI4第八课时:介绍AXI的 “原子访问“ :独占访问(Exclusive Access)和锁定访问(Locked Access)

大家好,欢迎来到今天的总线学习时间!如果你对电子设计、特别是FPGA和SoC设计感兴趣&#xff0c;那你绝对不能错过我们今天的主角——AXI4总线。作为ARM公司AMBA总线家族中的佼佼者&#xff0c;AXI4以其高性能和高度可扩展性&#xff0c;成为了现代电子系统中不可或缺的通信桥梁…

空间数据采集与管理:为什么选择ArcGISPro和Python?

你还在为找不到合适的数据而苦恼吗&#xff1f;你还在面对大量数据束手无策&#xff0c;不知如何处理吗&#xff1f;对于从事生产和科研的人员来说&#xff0c;空间数据的采集与管理是地理信息系统&#xff08;GIS&#xff09;和空间分析领域的关键环节。通过准确高效地采集和管…

数据库、创建表、修改表

一、数据库 1、登陆数据库 2、创建数据库zoo 3、修改数据库zoo字符集为gbk 4、选择当前数据库为zoo 5、查看创建数据库zoo信息 6、删除数据库zoo 二、创建表 1、创建一个名称为db_system的数据库 2、在该数据库下创建两张表&#xff0c;具体要求如下 员工表 user…

2024年洗地机哪个牌子好?内行人最建议这4个:清洁力口碑公认都不错

在当代生活中&#xff0c;洗地机可以称得上是一款必备“神器”&#xff0c;劳累的清洁、繁忙的时间、漫天纷飞的宠物毛发&#xff0c;都是家庭清洁面前的一座座大山。而洗地机的出现&#xff0c;完美解决了这些问题&#xff0c;既节约出了很多时间&#xff0c;又达到了很好的清…

检索增强生成RAG系列7--RAG提升之高级阶段

系列5中讲到会讲解3个方面RAG的提升&#xff0c;它们可能与RAG的准确率有关系&#xff0c;但是更多的它们是有其它用途。本期来讲解第三部分&#xff1a;高级阶段。之所以说是高级阶段&#xff0c;可能是不好归一&#xff0c;而且实现起来相对于前面来说可能更为复杂。 目录 1…

在Ubuntu上安装VNC服务器教程

Ubuntu上安装VNC服务器方法&#xff1a;按照root安装TeactVnc&#xff0c;随后运行vncserver输入密码&#xff0c;安装并打开RickVNC客户端&#xff0c;输入服务器的IP&#xff0c;最后连接输入密码即可。 VNC或虚拟网络计算&#xff0c;可让您连接到远程Linux / Unix服务器的…

如何在 Odoo 16 中继承和更新现有邮件模板

在本文中,让我们看看如何在 Odoo 16 中继承和编辑现有邮件模板。我们必须这样做才能对现有模板的内容进行任何调整或更新。让我们考虑一个在会计模块中更新邮件模板的示例。 单击“account.move”模型中的“发送并打印”按钮后,将打开上述向导。在这里,我们将进行更改。从向…

【遇坑笔记】Node.js 开发环境与配置 Visual Studio Code

【遇坑笔记】Node.js 开发环境与配置 Visual Studio Code 前言node.js开发环境配置解决pnpm 不是内部或外部命令的问题&#xff08;pnpm安装教程&#xff09;解决 pnpm : 无法加载文件 C:\Program Files\nodejs\pnpm.ps1&#xff0c;因为在此系统上禁止运行脚本。 vscode 插件开…

植物大战僵尸杂交版V2.1+修改器+融合版

植物大战僵尸杂交版v2.1 新增新植物&#xff0c;全新模式与玩法&#xff01; 内含窗口放大工具与修改器 主播同款游戏&#xff0c;下载使用即可&#xff01; 链接: https://pan.baidu.com/s/1k1BkDDgAtVILAEpHBNsZNw?pwdn81t 提取码: n81t