Unity之获取Avpro视频画面并在本地创建缩略图

news/2024/9/17 7:22:34/ 标签: unity, 音视频, 游戏引擎

一、效果 

获取StreamingAssets文件夹下的所有视频(包含其子文件夹),获取指定时间的视频画面,然后将图片保存到本地磁盘中。

二、关于Avpro的事件监听

当指定视频时间进度时会触发FinishedSeeking,代表加载完成这时我们在进行缩略图创建功能,否则视频帧未更新创建缩略图会出现问题。

//使用方法   
mediaPlayer.Events.AddListener(OnVideoEvent);//监听private void OnVideoEvent(MediaPlayer mp, MediaPlayerEvent.EventType et, ErrorCode errorCode){switch (et){case MediaPlayerEvent.EventType.MetaDataReady:Debug.Log("当元数据(宽度,持续时间等)可用时触发");break;case MediaPlayerEvent.EventType.ReadyToPlay:Debug.Log("可以播放");break;case MediaPlayerEvent.EventType.Started:Debug.Log("播放开始时触发");break;case MediaPlayerEvent.EventType.FirstFrameReady:Debug.Log("第一帧渲染完成");break;case MediaPlayerEvent.EventType.FinishedPlaying:Debug.Log("视频结束");break;case MediaPlayerEvent.EventType.Closing:Debug.Log("媒体关闭时触发");break;case MediaPlayerEvent.EventType.Error:Debug.Log("发生错误时触发");break;case MediaPlayerEvent.EventType.SubtitleChange:Debug.Log("字幕改变时触发");break;case MediaPlayerEvent.EventType.Stalled:Debug.Log("当介质停止时触发(例如。当失去与媒体流的连接时)");break;case MediaPlayerEvent.EventType.Unstalled:Debug.Log("当媒体从停止状态恢复时触发(例如。当失去的连接重新建立时)");break;case MediaPlayerEvent.EventType.ResolutionChanged:Debug.Log("当视频的分辨率发生变化(包括加载)时触发,用于自适应流");break;case MediaPlayerEvent.EventType.StartedSeeking:Debug.Log("搜索开始时触发");break;case MediaPlayerEvent.EventType.FinishedSeeking:Debug.Log("搜索完成时触发 Seek视频指定时间跳转结束后调用");break;case MediaPlayerEvent.EventType.StartedBuffering:Debug.Log("缓冲开始时触发");break;case MediaPlayerEvent.EventType.FinishedBuffering:Debug.Log("缓冲完成时触发");break;case MediaPlayerEvent.EventType.PropertiesChanged:Debug.Log("当任何属性被触发(例如立体声包装被改变)-这必须手动触发");break;case MediaPlayerEvent.EventType.PlaylistItemChanged:Debug.Log("当新项目在播放列表中播放时触发");break;case MediaPlayerEvent.EventType.PlaylistFinished:Debug.Log("当播放列表结束时触发");break;case MediaPlayerEvent.EventType.TextTracksChanged:Debug.Log("当添加或删除文本轨道时触发");break;}}

三、脚本

using System.IO;
using UnityEngine;
using RenderHeads.Media.AVProVideo;
using System.Collections.Generic;
using System.Collections;
using System;
using System.Linq;public struct ThumbnailData
{public Action OnComplete;      //回调函数public float thumbnailTime;    //时间戳,用于生成缩略图的位置public MediaPlayer mediaPlayer;
}public class ThumbnailGenerator : MonoBehaviour
{public MediaPlayer mediaPlayer;ThumbnailData thumbnailData;//缩略图数据List<string> videoPaths = new List<string>();//所有视频路径void Start(){//获取指定文件夹下的所有视频GetAllVideoFile($"{Application.streamingAssetsPath}");//创建缩略图数据thumbnailData = new ThumbnailData(){OnComplete = () => { Debug.Log("********创建结束*******"); },thumbnailTime = 5,//缩略图时间mediaPlayer = mediaPlayer,};//创建缩略图GenThumbnail(thumbnailData);}#region 获取指定文件夹所有视频文件void GetAllVideoFile(string path){//获取文件夹下指定类型视频videoPaths = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories).Where(s => IsAssignTypeFile(s)).ToList();}/// <summary>/// 判断是否是指定类型文件/// </summary>/// <param name="suffix">文件后缀</param>/// <returns></returns>bool IsAssignTypeFile(string suffix){string[] types = ".vid|.mp4|.wav".Split('|');//设置指定后缀//是指定类型for (int i = 0; i < types.Length; i++)if (suffix.EndsWith(types[i])) return true;return false;}#endregion#region 创建缩略图public void GenThumbnail(ThumbnailData _thumbnailData){thumbnailData = _thumbnailData;//视频状态监听 创建thumbnailData.mediaPlayer.Events.AddListener(OnVideoEvent);thumbnailData.mediaPlayer.OpenMedia(MediaPathType.AbsolutePathOrURL, videoPaths[0], false);thumbnailData.mediaPlayer.Control.Seek(thumbnailData.thumbnailTime);// 执行Seek操作}#endregion#region 视频状态监听int index;//当前视频地址private void OnVideoEvent(MediaPlayer mp, MediaPlayerEvent.EventType et, ErrorCode errorCode){switch (et){case MediaPlayerEvent.EventType.FinishedSeeking:Debug.Log("搜索完成时触发");//本地创建缩略图CreateThumbnailsLocally(mp);break;}}#endregion#region 在本地创建缩略图void CreateThumbnailsLocally(MediaPlayer mp){string path = mp.MediaPath.Path;//获取视频 RenderTextureRenderTexture renderTexture = GetVideoRenderTexture(mp);//将RenderTexture转换成texture2DTexture2D texture2D = RenderTexture2Texture2D(renderTexture);//将Texture2D写入本地string previewPath = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path)) + ".png";Texture2dWriteLocal(texture2D, previewPath);//创建下一个缩略图index++;if (index < videoPaths.Count){Debug.Log("加载下一个缩略图:" + videoPaths[index]);//播放视频mp.OpenMedia(MediaPathType.AbsolutePathOrURL, videoPaths[index], false);mp.Control.Seek(thumbnailData.thumbnailTime);// 执行Seek操作}elsethumbnailData.OnComplete?.Invoke();//执行回调}#endregion#region 获取视频 RenderTextureMaterial mt;RenderTexture GetVideoRenderTexture(MediaPlayer mp){if (mt == null){mt = new Material(Shader.Find("AVProVideo/Internal/Resolve"));mt.color = Color.white;//颜色设置mt.DisableKeyword("USE_HSBC");//禁用USE_HSBC关键字}VideoRender.SetupMaterialForMedia(mt, mp, -1); //设置材质贴图等VideoRender.ResolveFlags resolveFlags = (VideoRender.ResolveFlags.ColorspaceSRGB | VideoRender.ResolveFlags.Mipmaps | VideoRender.ResolveFlags.PackedAlpha | VideoRender.ResolveFlags.StereoLeft);//播放器标志return VideoRender.ResolveVideoToRenderTexture(mt, null, mp.TextureProducer, resolveFlags);//将视频解析为RenderTexture}#endregion#region 将RenderTexture转换为Texture2Dprivate static Texture2D RenderTexture2Texture2D(RenderTexture renderTexture){int width = renderTexture.width;int height = renderTexture.height;Texture2D texture2D = new Texture2D(width, height, TextureFormat.ARGB32, false);RenderTexture.active = renderTexture;texture2D.ReadPixels(new Rect(0, 0, width, height), 0, 0);texture2D.wrapMode = TextureWrapMode.Clamp;texture2D.Apply();return texture2D;}#endregion#region 将Texture2d写入本地void Texture2dWriteLocal(Texture2D texture2D, string localPath){File.WriteAllBytes(localPath, texture2D.EncodeToPNG());}#endregion}

在使用avpro制作缩略图时,我尝试使用mediaPlayer.TextureProducer.GetTexture();方法获取画面Texture,然后将其写入RenderTexture,在转换Texture2D写入本地会发现缩略图颜色泛白,经过排查MediaPlayer原脚本,发现在转换RenderTexture时需要使用avpro的指定shader处理才会显示正确的材质,感兴趣的朋友可以打开MediaPlayer脚本进行查看

改版

MediaPlayer脚本

原脚本查看方法:

注意:添加的MediaPlayer需要将AutoOpen和AutoPlay关掉


http://www.ppmy.cn/news/1522572.html

相关文章

muduo 网络库学习项目引入 Boost 依赖

文章目录 下载 [Boost 源码库](https://www.boost.org/)编译通过 CMake 引入 Boost 项目Boost 链接库指引文档的问题 muduo 这个项目比较老旧了&#xff0c;但是仍然是学习网络库实现的一个不错的参考&#xff0c;所以还是得看看书自己动手实践一下。 没想到跟着书上的代码练手…

2024国赛数学建模备赛|30种常用的算法模型之最优算法-非线性规划

1.1 非线性规划的实例与定义 如果目标函数或约束条件中包含非线性函数&#xff0c;就称这种规划问题为非线性规划问题。一般说来&#xff0c;解非线性规划要比解线性规划问题困难得多。而且&#xff0c;也不象线性规划有 单纯形法这一通用方法&#xff0c;非线性规划目前还没…

SpringBoot3+Vue3开发商店上货管理系统

系统介绍 上货管理系统是专门为各种类型商店打造的一款进货管理系统。针对整个商店进货流程&#xff0c;提供很多方便功能&#xff0c;帮助店家完成上货流程。比如上货清单管理功能、上货清单确认功能、供货商管理功能、商品管理功能等。 技术栈 后端&#xff1a;SpringBoot…

Spark MLlib模型训练—回归算法 Factorization Machines Regression

Spark MLlib模型训练—回归算法 Factorization Machines Regression 在大数据与机器学习领域,推荐系统、广告点击率预测以及评分预测等应用场景中,经常涉及到高度稀疏的特征数据,这对传统的回归模型提出了挑战。因子分解机(Factorization Machines, FMs)是一种广泛应用于…

python例子:相片处理工具(可视化)

作品名称&#xff1a;相片处理工具&#xff08;可视化&#xff09; 开发环境&#xff1a;PyCharm 2023.3.4 python3.7 用到的库&#xff1a;sys、os、cv2、numpy、math和random 作品简介&#xff1a;运行例子后&#xff0c;先选择需要处理的图片&#xff0c;然后可对图片进…

深入了解CSS混合模式

CSS混合模式&#xff08;也称为CSS Blend Modes&#xff09;是一种强大的功能&#xff0c;它允许开发者在CSS中控制元素如何与它们的背景或其他元素混合。这些模式类似于图像编辑软件&#xff08;如Photoshop&#xff09;中的混合模式&#xff0c;使得开发者能够创建出复杂而富…

vulhub Thinkphp5 2-rce远程代码执行漏洞

1.执行以下命令启动靶场环境并在浏览器访问 cd /vulhub/thinkphp/2-rce #进入漏洞环境所在目录 docker-compose up -d #启动靶场 docker ps #查看容器信息 2.访问网页 3.构造payload 192.168.157.142:8080?s/Index/index/L/${phpinfo()} 4、写入一句话木马&#xff0c;使用…

《JavaEE进阶》----12.<SpringIOCDI【扫描路径+DI详解+经典面试题+总结】>

本篇博客主要讲解 扫描路径 DI详解&#xff1a;三种注入方式及优缺点 经典面试题 总结 五、环境扫描路径 虽然我们没有告诉Spring扫描路径是什么&#xff0c;但是有一些注解已经告诉Spring扫描路径是什么了 如启动类注解SpringBootApplication。 里面有一个注解是componentS…

移动应用门户实现的技术方案

移动应用门户是专为移动设备&#xff08;如智能手机和平板电脑&#xff09;设计的应用程序&#xff0c;比如&#xff1a;小程序、APP等&#xff0c;用户可以通过应用商店下载并安装。这些应用程序提供了更好的用户体验&#xff0c;通常具有更高的性能和交互性&#xff0c;可以直…

数据结构的简单认识

数据结构是计算机存储、组织数据的方式。它可以分为逻辑结构和物理结构。 逻辑结构主要有集合、线性结构、树形结构和图形结构。集合中的数据元素间除“同属于一个集合”外&#xff0c;无其他关系&#xff1b;线性结构的数据元素之间存在一对一的关系&#xff0c;如链表、栈和队…

linux系统中,计算两个文件的相对路径

realpath --relative-to/home/itheima/smartnic/smartinc/blocks/ruby/seanet_diamond/tb/parser/test_parser_top /home/itheima/smartnic/smartinc/corundum/fpga/lib/eth/lib/axis/rtl/axis_fifo.v 检验方式就是直接在当前路径下&#xff0c;把输出的路径复制一份&#xff0…

Java | Leetcode Java题解之第386题字典序排数

题目&#xff1a; 题解&#xff1a; class Solution {public List<Integer> lexicalOrder(int n) {List<Integer> ret new ArrayList<Integer>();int number 1;for (int i 0; i < n; i) {ret.add(number);if (number * 10 < n) {number * 10;} els…

【RabbitMQ】基本概念以及安装教程

1. 什么是MQ MQ( Message queue),从字面意思上看,本质是个队列,FIFO 先入先出&#xff0c;只不过队列中存放的内容是消息(message)而已.消息可以非常简单,比如只包含文本字符串,JSON等,也可以很复杂,比如内嵌对象.MQ多用于分布式系统之间进行通信 系统之间的调用通常有两种方式…

揭秘 AMD GPU 上 PyTorch Profiler 的性能洞察

Unveiling performance insights with PyTorch Profiler on an AMD GPU — ROCm Blogs 2024年5月29日&#xff0c;作者&#xff1a;Phillip Dang。 在机器学习领域&#xff0c;优化性能通常和改进模型架构一样重要。在本文中&#xff0c;我们将深入探讨 PyTorch Profiler&#…

基于深度学习的结构优化与生成

基于深度学习的结构优化与生成技术应用于多种领域&#xff0c;例如建筑设计、机械工程、材料科学等。该技术通过使用深度学习模型分析和优化结构形状、材料分布、拓扑结构等因素&#xff0c;旨在提高结构性能、减少材料浪费、降低成本、并加快设计流程。 1. 结构优化与生成的核…

从零开始写论文:如何借助ChatGPT生成完美摘要?

AIPaperGPT&#xff0c;论文写作神器~ https://www.aipapergpt.com/ 在写论文的过程中&#xff0c;摘要是一个非常重要的部分&#xff0c;它能够帮助读者快速理解论文的核心内容&#xff0c;决定是否进一步阅读全文。但是许多学生在写摘要的时候常常感到困惑&#xff0c;不知…

怎么仿同款小程序的开发制作方法介绍

很多老板想要仿小程序系统&#xff0c;就是想要做个和别人界面功能类似的同款小程序系统&#xff0c;咨询瀚林问该怎么开发制作&#xff1f;本次瀚林就为大家介绍一下仿制同款小程序系统的方法。 1、确认功能需求 想要模仿同款小程序系统&#xff0c;那么首先需要找到自己想要…

24/9/3算法笔记 kaggle泰坦尼克

题目&#xff1a; 这次我用两种算法做了这道题 逻辑回归二分类算法 import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.metr…

CentOS 常用指令及作用解析

CentOS 常用指令及作用解析 在使用CentOS操作系统时&#xff0c;了解并熟练掌握常用的Linux指令是非常重要的。这些指令可以帮助你进行文件管理、系统管理、网络管理等操作。本篇文章将介绍一些CentOS下常用的指令及其主要作用。 目录 文件和目录操作指令文件内容操作指令系…

5千多道安全生产证考试题库ACCESS\EXCEL数据库

安全生产是保护劳动者的安全、健康和国家财产&#xff0c;促进社会生产力发展的基本保证&#xff0c;也是保证社会主义经济发展&#xff0c;进一步实行改革开放的基本条件。因此&#xff0c;做好安全生产工作具有重要的意义。今天的数据即是安全生产资格证、许可证考试题库。 大…