当前位置: 首页 > news >正文

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

一、效果 

获取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关掉

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 手机扬声器音量总是不够大?试试“扬声器助推器”吧
  • 停车场小程序如何实现分账功能?
  • WIN11 ESP32 IDF + VSCODE 环境搭建[教程向]
  • 心法利器[118] | 向量检索组件(含代码)
  • [论文笔记] t-SNE数据可视化
  • 数字逻辑设计基础
  • 数据结构——单链表相关操作
  • 和服务端系统的通信
  • 正则表达式之grep
  • [C#学习笔记]注释
  • 信息学奥赛初赛天天练-86-NOIP2014普及组-基础题5-球盒问题、枚举算法、单源最短路、Dijkstra算法、Bellman-Ford算法
  • 营养方案调整执行流程 第十篇
  • Spring Batch
  • FPGA开发:Verilog数字设计基础
  • [论文笔记]QLoRA: Efficient Finetuning of Quantized LLMs
  • hexo+github搭建个人博客
  • 0基础学习移动端适配
  • Android优雅地处理按钮重复点击
  • ES学习笔记(12)--Symbol
  • HTTP请求重发
  • iOS帅气加载动画、通知视图、红包助手、引导页、导航栏、朋友圈、小游戏等效果源码...
  • java小心机(3)| 浅析finalize()
  • jquery cookie
  • node学习系列之简单文件上传
  • opencv python Meanshift 和 Camshift
  • Vue.js 移动端适配之 vw 解决方案
  • 安装python包到指定虚拟环境
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 全栈开发——Linux
  • 仓管云——企业云erp功能有哪些?
  • #QT(一种朴素的计算器实现方法)
  • (1)(1.13) SiK无线电高级配置(五)
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (待修改)PyG安装步骤
  • (二)WCF的Binding模型
  • (三)终结任务
  • (十三)Maven插件解析运行机制
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)iOS字体
  • *算法训练(leetcode)第四十七天 | 并查集理论基础、107. 寻找存在的路径
  • ./include/caffe/util/cudnn.hpp: In function ‘const char* cudnnGetErrorString(cudnnStatus_t)’: ./incl
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .NET HttpWebRequest、WebClient、HttpClient
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • .net 发送邮件
  • .Net 基于MiniExcel的导入功能接口示例
  • .NET 通过系统影子账户实现权限维持
  • .Net环境下的缓存技术介绍
  • .net下的富文本编辑器FCKeditor的配置方法
  • .NET运行机制
  • .net中调用windows performance记录性能信息
  • [ C++ ] STL_stack(栈)queue(队列)使用及其重要接口模拟实现
  • []C/C++读取串口接收到的数据程序
  • [100天算法】-实现 strStr()(day 52)