UE 录屏自动化上传阿里云OSS

前言

       最近在做一个功能,然后就发现了一个很有趣的东西,虽然在一定程度上属于偷懒,但是在一些短频快的应用中还是很适用的,下面我就针对于这个测试做一些简单的分享,希望帮助到大家,在实际的开发中获得一些灵感和帮助,具体的实现方式,UE通过Texture2D将每一帧的图片存储到本地,存完以后调用一个本地PythonEXE执行文件进行视频封装和OSS上传,我这里使用的版本UE5.3,大家根据代码自己调试下。

UE开发调试过程

  1. 新建一个带有C++内容的项目,因为有一些代码功能需要用到C++,我这里的名称因为创建过了所以有个提示。
  2. 然后在Edit -> Plugins -> Add点击新建一个BlueprintLibeary的插件,因为我个人写一些封装性功能的时候喜欢用插件,这样其他的项目用到的时候直接导入调用就可以了,如果你想在类里面使用的话创建一个BlueprintFunctionLibrary的类就可以了。
  3. 创建完插件后,会在VistualStudio中提示,直接点全部加载,然后点击全部保存关闭项目,因为有时候有些编译会有问题,在UE和VS都关闭的状态下,在你的工程根目录打开sln的VS主文件,我们直接进行操作
  4. 接下来在插件中TextureVideoBPLibrary.h和TextureVideoBPLibrary.cpp中,我们添加两个功能,打开.h文件将原有的函数进行删除然后添加我们新的函数
    // Copyright Epic Games, Inc. All Rights Reserved.
    
    #pragma once
    
    #include "Kismet/BlueprintFunctionLibrary.h"
    #include "TextureVideoBPLibrary.generated.h"
    
    /* 
    *	Function library class.
    *	Each function in it is expected to be static and represents blueprint node that can be called in any blueprint.
    *
    *	When declaring function you can define metadata for the node. Key function specifiers will be BlueprintPure and BlueprintCallable.
    *	BlueprintPure - means the function does not affect the owning object in any way and thus creates a node without Exec pins.
    *	BlueprintCallable - makes a function which can be executed in Blueprints - Thus it has Exec pins.
    *	DisplayName - full name of the node, shown when you mouse over the node and in the blueprint drop down menu.
    *				Its lets you name the node using characters not allowed in C++ function names.
    *	CompactNodeTitle - the word(s) that appear on the node.
    *	Keywords -	the list of keywords that helps you to find node when you search for it using Blueprint drop-down menu. 
    *				Good example is "Print String" node which you can find also by using keyword "log".
    *	Category -	the category your node will be under in the Blueprint drop-down menu.
    *
    *	For more info on custom blueprint nodes visit documentation:
    *	https://wiki.unrealengine.com/Custom_Blueprint_Node_Creation
    */
    UCLASS()
    class UTextureVideoBPLibrary : public UBlueprintFunctionLibrary
    {
    	GENERATED_UCLASS_BODY()
    	UFUNCTION(BlueprintCallable, meta = (DisplayName = "SavePixtureToFile", KeyWords = "Save Pic To File"), Category = "TextureVideoTesting")
    	static bool SavePicToFile(UTextureRenderTarget2D* rt, const FString& fileDestination);
    
    	UFUNCTION(BlueprintCallable, meta = (DisplayName = "OpenExeVideo", Keywords = "Open Exe Video"), Category = "TextureVideoTesting")
    	static bool OpenExe(FString URL);
    };
    
  5. 在cpp文件中我们添加以下逻辑,大家看到这里的时候基本已经知道了这两个函数的作用一个是存储图片一个是打开exe
    // Copyright Epic Games, Inc. All Rights Reserved.
    
    #include "TextureVideoBPLibrary.h"
    #include "TextureVideo.h"
    #include "Engine/TextureRenderTarget2D.h"
    #include "Misc/FileHelper.h"
    #include <ImageUtils.h>
    
    UTextureVideoBPLibrary::UTextureVideoBPLibrary(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
    {
    
    }
    
    bool UTextureVideoBPLibrary::SavePicToFile(UTextureRenderTarget2D* rt, const FString& fileDestination)
    {
    	FTextureRenderTargetResource* rtResource = rt->GameThread_GetRenderTargetResource();
    	FReadSurfaceDataFlags readPixelFlags(RCM_UNorm);
    	TArray<FColor> outBMP;
    
    	for (FColor& color : outBMP)
    	{
    		color.A = 255;
    	}
    	outBMP.AddUninitialized(rt->GetSurfaceWidth() * rt->GetSurfaceHeight());
    	rtResource->ReadPixels(outBMP, readPixelFlags);
    	FIntPoint destSize(rt->GetSurfaceWidth(), rt->GetSurfaceHeight());
    	TArray<uint8> CompressedBitmap;
    	FImageUtils::CompressImageArray(destSize.X, destSize.Y, outBMP, CompressedBitmap);
    	bool imageSavedState = FFileHelper::SaveArrayToFile(CompressedBitmap, *fileDestination);
    	return imageSavedState;
    }
    
    bool UTextureVideoBPLibrary::OpenExe(FString URL)
    {
    	FProcHandle ExeHandle = FPlatformProcess::CreateProc(*URL, nullptr, true, false, false, nullptr, 0, nullptr, nullptr);
    	bool ret = FPlatformProcess::IsProcRunning(ExeHandle);
    	return ret;
    }
    
  6. 然后对项目进行清理和重新生成,如果重新编译的过程中出现了报错,别管他,全部保存,然后关闭VS再重新打开再次编译生成即可。编译后打开我们的UE,在UE插件的Content文件中我们可以创建一个BP文件夹放置我们的一些文件,鼠标右键在Texture中创建一个RenderTarget文件用来进行渲染UE画面
  7. 双击打开我们的RenderTarget,将SizeX和SizeY进行调试,这是我们最终生成图片的比例,但是这块,大家要实际和电脑性能进行以下调试,因为图片分辨率越大输出渲染占用的资源就越高,所以这块自己在用的时候要注意下。
  8. 新建一个Actor,我这里用的画面是一个角色,所以我就创建了一个Character类型的Actor,这块根据自己需求不需要的话,就创建一个基础的Actor就可以,打开新建的Actor,在Add中添加一个SceneCaptureComponent2D组件,我这里都在一起所以我直接就调整了它们之间的位置关系,如果你这块是不需要的话,那你直接把Actor拖拽到场景中调整位置关系即可,然后点击SceneCaptureComponent2D组件,细节中的TextureTarget设置为刚才创建的RenderTarget
  9. 现在插件功能开发和基础的设置就已经做完了,接下来我们开始进行调试我们的功能,考虑到后续UE可能进行打包操作,这块的路径我就直接设置为插件路径,在插件目录下创建了一个VideoInDEP的文件下面有三个文件Image;Video;Data,Image和Video就是存放我们的缓存图片和缓存视频,Data是可调整的一个参数文件,EXE为调用执行的文件
  10. 在事件开始运行时,我们对图片还有EXE进行了变量存储,这的SetActorHiddenInGame作用是为了隐藏项目运行可能会出现一个控制器小球,然后ImagePath和VideoPath创建两个字符串的变量进行连接即可
  11. 现在开始图片存储功能通过一个事件委托,我们调用SavePixtureToFile的函数节点,将其进行设置Rt是我们创建的RnderTarget,Timer提示为变量这个变量作用是在关闭的时候断开捕捉存储图片用的,新建一个int变量初始值为0,然后作为图片下标进行使用,接下来你就可以测试第一个功能图片存储,直接调用SaveImage自定义事件,在我们的插件对应的路径下你就会看到你生成的图片,这里time为0.04秒,就是40毫秒,也就是一秒25帧。
  12. 第二个功能打开EXE,这块你可以先随便找个exe进行测试只要路径填写对就可以测试

 Python开发流程

  1. 我这用的最新的Pycharm写的,不会Python的也没关系我后面会把插件还有EXE链接放到下面的直接下载也能用,新建一个工程和一个py文件命名为VideoToOSS,这里oss的包的装以下,直接终端pip install oss2就行,有其他包的环境如果提示没有的话记得也装一下,代码
    #ImageToVideo
    import cv2
    import os
    import sys
    import glob
    
    #数据上传
    import oss2
    import json
    
    dataPath = os.path.dirname(os.path.realpath(sys.executable)) + '\\Data\\data.json'
    
    
    def ImageToVideo(ImagePath,VideoPath,Fps,PngImage):
        print('This is PNG Path:',ImagePath)
        print('This is Video Path:',VideoPath)
    
        fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')  # 设置输出视频为mp4格式
        # size要和图片的size一样,但是通过img.shape得到图像的参数是(height,width,channel),
        # 可以实现在图片文件夹下查看图片属性,获得图片的分辨率
        size = (1024, 768)
        video = cv2.VideoWriter(VideoPath, fourcc, Fps, size)  # 设置保存视频的名称和路径,默认在根目录下
        file_lst = os.listdir(ImagePath)
        count = 0
        for filename in file_lst:
            img = cv2.imread(ImagePath + 'TextureImage' + str(count) + '.png')
            count += 1
            video.write(img)
        video.release()
        delete_all_pngs(PngImage,VideoPath)
    def delete_all_pngs(folder_path,Video_Path):
        # 使用glob查找文件夹下所有的.png文件
        png_files = glob.glob(os.path.join(folder_path, '*.png'))
        # 遍历并删除找到的文件
        for png_file in png_files:
            try:
                os.remove(png_file)
                #print(f"已删除: {png_file}")
            except OSError as e:
                print(f"删除失败: {png_file} - {e.strerror}")
        print("This set of data has now been deleted!")
        VideoToOSS(Video_Path)
    
    def JsonToStr(JsPath):
        with open(JsPath, 'r', encoding='utf-8') as file:
            json_data = json.load(file)
        return json_data
        print(json_data)
    
    def VideoToOSS(VideoPath):
        access_key_id = JsonToStr(dataPath)['access_key_id']
        access_key_secret = JsonToStr(dataPath)['access_key_secret']
        endpoint = JsonToStr(dataPath)['endpoint']
        bucket_name = JsonToStr(dataPath)['bucket_name']
        object_name = JsonToStr(dataPath)['object_name']  # OSS上的对象路径和名称
        local_file = VideoPath
    
        # 创建Bucket的句柄
        auth = oss2.Auth(access_key_id, access_key_secret)
        bucket = oss2.Bucket(auth, endpoint, bucket_name)
        # 上传文件
        bucket.put_object_from_file(object_name, local_file)
        print(f"文件 {local_file} 已成功上传到 OSS,路径为 {object_name}")
    
        if os.path.exists(local_file):
            os.remove(local_file)
            print(f"本地缓存文件 {local_file} 已被删除")
        else:
            print(f"文件 {local_file} 不存在")
    
    
        # 按装订区域中的绿色按钮以运行脚本。
    if __name__ == '__main__':
        #本地的图片视频地址信息
        PathVideo = os.path.dirname(os.path.realpath(sys.executable)) + '\\Video\\result.mp4'
        PathImage = os.path.dirname(os.path.realpath(sys.executable)) + '\\Image\\'
        PathDelayImage = os.path.dirname(os.path.realpath(sys.executable)) + '\\Image'
    
        FpsPath = JsonToStr(dataPath)['Video_fps']
        ImageToVideo(PathImage,PathVideo,FpsPath,PathDelayImage)
    
    
  2. 这是完整逻辑,函数ImageToVideo用来将图片转为视频的,delete_all_pngs函数作用是将本地图片进行删除的,JsonToStr是用来读取本地设置信息的,VideoToOSS将本地视频提交OSS然后进行删除,main就是调用了,这块东西很简单自己看下就会了,然后把代码进行打包在终端直接打包,运行完成后会在本地生成一个EXE执行文件
    
    Pyinstaller -F VideoToOSS.py
  3. data.json中是我们的oss的配置信息,这块我就不写了,自己找一下配置一下就行,Videofps是视频生成时的帧数
    {
        "Video_fps": 25,
        "access_key_id": "<自己的KeyID>",
        "access_key_secret": "<自己的secre>",
        "endpoint": "<自己的服务地址>",
        "bucket_name": "<自己的bucket文件名称>",
        "object_name": "video/object.mp4"
    }

 结语

        确保最终的UE打开EXE名称为VideoToOSS,基本的使用过程就是这样,因为UE直接做视频和OSS需要对于的FFMPEG或者OSS其他库,处理起来很麻烦,很多应用也不一定能找到,通过这种方式可以巧妙的解决掉这个麻烦,如果你觉得exe没有回调的话出现问题时怎么办,可以做一个简单的通信,让UE和这个EXE去协同处理来解决或者通过句柄的方式,但是这块呢大家各自发挥。

链接:https://pan.baidu.com/s/1DI-iWjwAO9Hy4pQGE6FInA 
提取码:8i55 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java-常用API-1

Math类 public static int abs(int a) 获取绝对值public static double ceil(double a)向上取整&#xff08;向数轴右边取整&#xff09;public static double floor(double a)向下取整&#xff08;向数轴左边取整&#xff09;public static int round(float a)四舍五入public…

SQL SERVER的安装

目录 1.百度SQL SERVER找到图下的所显示的&#xff0c;点击进去 2.找到图下红色框起来的&#xff0c;点击立即下载 3.下载好之后点开&#xff0c;选择下载介质 4.SQLSERVER下载成功之后选择打开文件夹 6.双击后缀名是.iso的镜像文件 7.双击setup.exe进行安装 8.安装成功…

Web3D智慧医院平台(HTML5+Threejs)

智慧医院的建设将借助物联网、云计算、大数据、数字孪生等技术&#xff0c;以轻量化渲染、极简架构、三维可视化“一张屏”的形式&#xff0c;让医院各大子系统管理既独立又链接&#xff0c;数据相互融合及联动。 建设医院物联网应用的目标对象&#xff08;人、物&#xff09;都…

Java复习第二十天学习笔记(过滤器Filter),附有道云笔记链接

【有道云笔记】二十 4.8 过滤器Filter https://note.youdao.com/s/dSofip3f 一、为什么要使用过滤器 项目开发中&#xff0c;经常会用到重复代码的实现。 1、请求每个servlet都要设置编码 2、判断用户是否登录&#xff0c;只有登录了才有操作权限。 二、过滤器相关Api int…

【机器学习300问】71、神经网络中前向传播和反向传播是什么?

我之前写了一篇有关计算图如何帮助人们理解反向传播的文章&#xff0c;那为什么我还要写这篇文章呢&#xff1f;是因为我又学习了一个新的方法来可视化前向传播和反向传播&#xff0c;我想把两种方法总结在一起&#xff0c;方便我自己后续的复习。对了顺便附上往期文章的链接方…

论文笔记:(INTHE)WILDCHAT:570K CHATGPT INTERACTION LOGS IN THE WILD

iclr 2024 spotlight reviewer 评分 5668 1 intro 由大型语言模型驱动的对话代理&#xff08;ChatGPT&#xff0c;Claude 2&#xff0c;Bard&#xff0c;Bing Chat&#xff09; 他们的开发流程通常包括三个主要阶段 预训练语言模型在被称为“指令调优”数据集上进行微调&…

通过腾讯云搭建跨境电商demo的详细操作过程(建站系统 保姆级指导,巨详细)

引言&#xff1a; 有许多做跨境电商的朋友&#xff0c;或者为跨境电商服务的小企业&#xff0c;都会面临搭建电商平台V1.0的问题 因此&#xff0c;花了点时间&#xff0c;找了一个开源的项目&#xff0c;让大家可以跑起来&#xff0c;一方面了解平台都有哪些模块&#xff0c;另…

护网行动 | 蓝队应急响应流程概述

了解蓝队应急响应的流程 应急响应通常是指为了应对各种意外事件发生前所做的准备&#xff0c;以及在意外事件发生后所采取的措施。 网络安全应急响应是指对已经发生或可能发送的安全事件进行监控、分析、协调、处理、保护资产安全。 网络安全应急响应主要是为了让人们对网络安全…

3D模型处理的并行化

今天我们将讨论如何使用 Python 多进程来处理大量3D数据。 我将讲述一些可能在手册中找到的一般信息&#xff0c;并分享我发现的一些小技巧&#xff0c;例如将 tqdm 与多处理 imap 结合使用以及并行处理存档。 那么我们为什么要诉诸并行计算呢&#xff1f; 使用数据有时会出现…

IAM 统一身份认证与访问管理服务

即统一身份认证与访问管理服务&#xff0c;是云服务商提供的一套云上身份管理解决方案&#xff0c;可帮助企业安全地管理云上资源的访问权限。 在当今云计算时代&#xff0c;企业越来越依赖云服务来存储和处理敏感数据。然而&#xff0c;这也带来了新的安全挑战&#xff0c;即…

ssm 体检预约管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 ssm 体检预约管理系统是一套完善的信息系统&#xff0c;结合springMVC框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c; 系统主要采用B/S…

URL GET +号后台接收成空格

问题&#xff1a;参数spdmwhbs001 其中包含URL特殊符号 如果用GET请求方式不做任何不处理那么浏览器自动将转为%20 请求链接为 details?spdmwhbs%20001&limitKcysType1 后台接收到的参数为 whbs 001 &#xff0c;自动将号转成空格了。 尝试解决&#xff08;失败&#…

【Java】@RequestMapping注解在类上使用

RequestMapping 是 Spring Web 应用程序中最常被用到的注解之一。这个注解会将 HTTP 请求映射到控制器&#xff08;controller类&#xff09;的处理方法上。 Request Mapping 基础用法 在 Spring MVC 应用程序中&#xff0c;RequestDispatcher (在 Front Controller 之下) 这…

git clone遇到报错“SSL certificate problem: self signed certificate”

在git clone的时候发现遇到了一个问题&#xff1a; cristDESKTOP-JKRNKSH MINGW64 ~/Desktop $ git clone -b dev https://xxx.xxx.xxx.xxx:3001/crist/AVM_V9M.git Cloning into AVM_V9M... fatal: unable to access https://xxx.xxx.xxx.xxx3001/crist/AVM_V9M.git/: SSL ce…

PSCAD|应用于输电线路故障测距的行波波速仿真分析

1 主要内容 该程序参考文献《应用于输电线路故障测距的行波波速仿真分析》&#xff0c;利用线路内部故障产生的初始行波浪涌达线路两端测量点的绝对时间之差值计算故障点到两端测量点之间的距离&#xff0c;并利用小波变换得到初始行波波头准确到达时刻&#xff0c;从而精准定…

WPS的JS宏如何实现全文件路径字符串中截取文件名(excel)

从全文件路径的字符串中&#xff0c;截取文件名称&#xff0c;例如&#xff1a; 全文件路径字符串为&#xff1a;C:\Windows\System32\drivers\acpi1.sys 需要截取文件名&#xff1a;acpi1.sys 方法如下&#xff1a; 1、简单的方式&#xff1a;把全文件路径字符串拷贝&…

Python基于深度学习的车辆特征分析系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

YOLOv8改进 | 知识蒸馏 | 利用模型蒸馏改进YOLOv8进行无损涨点(在线蒸馏 + 离线蒸馏)

一、本文介绍 这篇文章给大家带来的是模型的蒸馏&#xff0c;利用教师模型指导学生模型从而进行模型的涨点&#xff0c;本文的内容不仅可以用于论文中&#xff0c;在目前的绝大多数的工作中模型蒸馏是一项非常重要的技术&#xff0c;所以大家可以仔细学习一下本文的内容&#…

PHP-$$变量覆盖

[题目信息]&#xff1a; 题目名称题目难度PHP-$$变量覆盖1 [题目考点]&#xff1a; 变量覆盖指的是用我们自定义的参数值替换程序原有的变量值&#xff0c;一般变量覆盖漏洞需要结合程序的其它功能来实现完整的攻击。 经常导致变量覆盖漏洞场景有&#xff1a;$$&#xff0c;…

快速切换node.js版本方法(使用开源项目方便切换版本)

1、安装nvm nvm下载地址&#xff1a;https://github.com/coreybutler/nvm-windows/ 2、输入nvm -v 3、查看可以安装的node.js版本 4、安装你想要的版本 5、查看是否安装成功&#xff08;*表示目前你使用的版本&#xff09; 6、切换版本 7、查询当前使用的版本