Unity3d 基于UGUI和VideoPlayer 实现一个多功能视频播放器功能(含源码)

news2024/12/25 4:40:21

前言

随着Unity3d引擎在数字沙盘、智慧工厂、数字孪生等场景的广泛应用,视频已成为系统程序中展示时,不可或缺的一部分。在 Unity3d 中,我们可以通过强大的 VideoPlayer 组件和灵活的 UGUI 系统,将视频播放功能无缝集成到用户界面中,从而提升应用的用户体验。作为展示内容的媒体播放器,视频播放功能都需要一个清晰、易于交互的界面,所以本文就是以 VideoPlayer 组件为播放功能,通过UGUI搭建配套的操作界面,实现一个视频播放器功能。其功能包括:VideoClip播放、选择文件播放、播放/暂停、进度拖拽、快进/快退、速度调节、音量条件和视频画面尺寸自适应。
关注并私信 U3D视频播放器 免费获取源码(底部公众号)。

效果

选择文件播放:
在这里插入图片描述

快进:
在这里插入图片描述

进度拖拽:
在这里插入图片描述

横屏自动适配:
在这里插入图片描述

实现

实现关键组件包括:
1.VideoPlayer 组件:
VideoPlayer 是 Unity 中用于播放视频文件的核心组件。它能够播放本地视频文件或者通过网络流播放视频,并支持控制视频播放的各项参数,如播放、暂停、停止、音量控制、视频进度等。

2.RawImage 组件:
为了在 UI 中显示视频内容,我们可以使用 RawImage 组件。RawImage 是 Unity UGUI 中的一种 UI 组件,能够显示纹理,可以将视频流(VideoPlayer 播放的视频)输出到 RawImage 上进行显示。

3.Button、Slider 和 Text 组件:
为了实现播放、暂停、音量控制等功能,UGUI 提供了按钮(Button)、滑块(Slider)和文本(Text)组件,允许用户通过界面直接与视频进行交互。

按照步骤将实现过程拆分为UI搭建和编码实现。

UI搭建

播放器UI搭建的效果如下图:
在这里插入图片描述

使用 Button 控件来创建播放/暂停、快进快退按钮;使用 Slider 控件创建音量滑块、速度滑块和播放进度条实时更新视频的播放进度。使用 RawImage 控件显示视频内容,VideoPlayer 的视频输出会被设置为 RawImage.texture,从而将视频渲染到 UI 上。

编码

视频播放器的UI搭建好后,绑定对应的事件:

 #region 事件处理
    //点击暂停
    public void ClickPause()
    {
        LastInTime = Time.time;
        videoPlayer.Pause();
        PlayBtn.SetActive(true);
        PauseBtn.SetActive(false);
        CenterPlayBtn?.SetActive(true);
        ShowTip("暂停");
    }

    //点击播放 
    public void ClickPlay()
    {
        CenterPlayBtn?.SetActive(false);
        videoPlayer.Play();
        PlayBtn.SetActive(false);
        PauseBtn.SetActive(true);
        if (isIn)
        {
            isIn = false;
            CtrlTran.DOAnchorPos3D(OutPos, ScaleDura * 2);
        }
        ShowTip("播放");
    }


    //快进
    public void ClickForward() {
        double nowPos = videoPlayer.time + SpeedStep;
        videoPlayer.time = nowPos > VideoLength ? VideoLength : nowPos;
        LastInTime = Time.time;
        ShowTip("快进");
    }


    //快退
    public void ClickBackward() 
    {
        double nowPos = videoPlayer.time - SpeedStep;
        videoPlayer.time = nowPos < 0 ? 0 : nowPos;
        LastInTime = Time.time;
        ShowTip("快退");
    }

    public void MouseInCtrls()
    {
        LastInTime = Time.time;
        isOverCtrls = true;
    }
    public void MouseOutCtrls()
    {
        LastInTime = Time.time;
        isOverCtrls = false;
    }


    //音量滑动条变更
    public void OnVolumeChanged()
    {
        LastInTime = Time.time;
        // Set new audio output volume
        videoPlayer.SetDirectAudioVolume(0, VolSlider.value); // * 100

        ShowTip("播放音量:"+ (VolSlider.value * 100).ToString("F0"));
    }


    //进度滑动条变更
    public void OnTimeChanged(float val)
    {
        LastInTime = Time.time;
        videoPlayer.time = val * VideoLength;
        TimeSlider.value = val;


        ShowTip("播放时间:" + videoPlayer.time.ToString("F0"));
    }

    //速度重置
    public void ClickSpeed()
    {
        SpeedSlider.value = 0.2f;
        videoPlayer.playbackSpeed = 1;
        SpeedText.text = "速度×1.0";

        ShowTip("播放速度" + videoPlayer.playbackSpeed);
    }


    //速度滑动条拖拽
    public void OnSpeedChange(float val)
    {
        float speed = val / 0.2f;
        videoPlayer.playbackSpeed = speed;
        SpeedText.text = "速度×" + speed.ToString("F1");


        ShowTip("播放" + SpeedText.text);
    }

    #endregion 事件处理

完整代码如上,音量滑块(Slider 控件),通过 videoPlayer.SetDirectAudioVolume() 方法来调整音量;播放速度滑块(Slider 控件),通过videoPlayer.playbackSpeed 属性来调整播放速度;进度条(Slider 控件),实时更新视频的播放进度,并通过 videoPlayer.time 属性控制视频的当前播放时间;播放/暂停按钮(Button 控件),监听其点击事件,并通过 VideoPlayer 的 Play() 和 Pause() 方法控制视频的播放和暂停。其中TipText是提示的Text控件,状态变更时候会进行文字提示。

视频的控制按钮面板,对其进行了默认移出播放画面,鼠标点击移入,无操作一段时间后移出画面的处理。

视频画面高宽自适应:

Canvas canvas = transform.GetComponentInParent<Canvas>();
float WidRate = videoPlayer.width / (float)Screen.width;//Screen.width;
float HeightRate = videoPlayer.height / (float)Screen.height;//Screen.height;

//Debug.Log("VideoRt.sizeDelta:" + VideoRt.sizeDelta);
if (WidRate >= HeightRate)   //适配宽度
{
    float Width = (float)Screen.width / canvas.transform.localScale.x;
    float Height = (Screen.width / (float)videoPlayer.width) * videoPlayer.height / canvas.transform.localScale.y;

    VideoRt.sizeDelta = new Vector2(Width, Height);
    //Debug.Log("适配宽度  width:" + Width + "  height:" + Height);
}
else  //适配高度
{
    float Width = Screen.height / (float)videoPlayer.height * videoPlayer.width / canvas.transform.localScale.x;
    float Height = (float)Screen.height / canvas.transform.localScale.y;
    VideoRt.sizeDelta = new Vector2(Width, Height);
    //Debug.Log("适配高度 width:" + Width + "  height:" + Height);
}


// 先释放当前的 RenderTexture 资源
if (renderTexture != null)
{
    renderTexture.Release();

    // 设置新的宽高
    renderTexture.width = (int)videoPlayer.width;
    renderTexture.height = (int)videoPlayer.height;
}
else
    renderTexture = new RenderTexture((int)videoPlayer.width, (int)videoPlayer.height, 24);

renderTexture.Create();

videoPlayer.targetTexture = renderTexture;

fullImg.texture = renderTexture;

尺寸的适应采用高宽比的思路,如果宽度比 比 高度比高就适配宽度,反之则适配高度(这里比较拗口,详情参看代码)。因为renderTexture的尺寸需要动态变更,所以这里都是先进行释放了,然后再进行创建。

在播放过程中显示00:00:00/00:00:00的时间格式,设置函数如下:

//设置已播时长
void SetPlayerTime() //long playedTime
{
    TimeSpan time = TimeSpan.FromSeconds(videoPlayer.time);//TimeSpan.FromMilliseconds(playedTime);
    NowTimeText.text = string.Format("{0:D2}:{1:D2}:{2:D2}", time.Hours, time.Minutes, time.Seconds);

    if (isIn)
    {
        TimeSlider.value = VideoLength > 0 ? (float)(videoPlayer.time / VideoLength) : 0;
    }
}

//设置视频时长
void SetMediaLength(long mediaLength)
{
    VideoLength = mediaLength;

    //Debug.Log("SetMediaLength:" + mediaLength);
    var length = TimeSpan.FromSeconds(mediaLength);//TimeSpan.FromMilliseconds(mediaLength);

    AllTimeText.text = string.Format("{0:D2}:{1:D2}:{2:D2}", length.Hours, length.Minutes, length.Seconds);
}

使用方法

1.加入工程后将“VideoPlayer.prefab” 预设加入场景。

2.可以通过调用的接口的方式启动播放器:
传入VideoClip:

public void PlayClip(VideoClip clip, Transform tran = null)

clip是视频片段。

通过传入地址:

public void PlayVideoByUrl(string url, Transform tran = null)

url是地址。

tran 是动画的起始位置对象,可不传。传入后可以有触发位置移动到屏幕中间的动画效果:
在这里插入图片描述

案例中直接打开VideoClip的调用:

public VideoClip vc;
//直接播放片段
public void ClickPlayClip(GameObject sender) {
    VideoPlayerCtrl.instance?.PlayClip(vc, sender.transform);
}

案例中的选择视频的调用:

//打开视频文件
public void ClickChooseBtn(GameObject sender)
{
    OpenFileName file = new OpenFileName();
    file.structSize = Marshal.SizeOf(file);
    file.filter = "文件(*.MP4;*.mp4;*.Mp4;*.wmv;*.rm;*.rmvb;*.avi;*.mkv;*.flv)\0*.mp4;*.mp4;*.Mp4;*.wmv;*.rm;*.rmvb;*.avi;*.mkv;*.flv";
    file.file = new string(new char[256]);
    file.maxFile = file.file.Length;
    file.fileTitle = new string(new char[64]);
    file.maxFileTitle = file.fileTitle.Length;
    file.initialDir = Application.streamingAssetsPath.Replace('/', '\\');//默认路径
    file.title = "选择文件";
    file.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000008;

    if (SelectFileDialog.GetSaveFileName(file))
    {
        VideoPlayerCtrl.instance?.PlayVideoByUrl(file.file, sender.transform);
    }

}

这里使用了comdlg32.dll,comdlg32.dll是Windows操作系统中的一个动态链接库(DLL)文件,主要用于提供多种标准对话框的实现功能。这些对话框包括文件打开/保存对话框、颜色选择器等,对于本视频播放器来说主要就是选择视频文件并打开播放。

Unity3d中的Comdlg32.dll引用:

using System.Runtime.InteropServices;

public class SelectFileDialog
{
    //系统函数  
    [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
    public static extern bool GetSaveFileName([In, Out] OpenFileName ofn);
    public static bool GetSFN([In, Out] OpenFileName ofn)
    {
        return GetSaveFileName(ofn);
    }
}

源码

https://download.csdn.net/download/qq_33789001/90178128

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

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

相关文章

WebGAL 项目下载及安装教程

WebGAL 项目下载及安装教程 WebGAL A brand new web Visual Novel engine | 全新的网页端视觉小说引擎 [这里是图片001] 项目地址: https://gitcode.com/gh_mirrors/web/WebGAL 1、项目介绍 WebGAL 是一个全新的网页端视觉小说引擎&#xff0c;旨在提供美观、功能强大且易于…

虚幻引擎是什么?

Unreal Engine&#xff0c;是一款由Epic Games开发的游戏引擎。该引擎主要是为了开发第一人称射击游戏而设计&#xff0c;但现在已经被成功地应用于开发模拟游戏、恐怖游戏、角色扮演游戏等多种不同类型的游戏。虚幻引擎除了被用于开发游戏&#xff0c;现在也用于电影的虚拟制片…

Kubernetes 架构图和组件

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;历代文学&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编程&#xff0c;高并发设计&#xf…

GESP2024年12月认证C++五级( 第三部分编程题(2))

参考程序&#xff1a; #include<bits/stdc.h> using namespace std; #define ll long long int n, m; int cnt[1010]; vector<int> cs[1010]; ll calc(int aim) {int cur_cnt cnt[1];ll res 0;vector<int> tmp;for (int i 2; i<n; i){int buy max((…

基于DockerCompose搭建Redis主从哨兵模式

linux目录结构 内网配置 哨兵配置文件如下&#xff0c;创建3个哨兵配置文件 # sentinel26379.conf sentinel26380.conf sentinel26381.conf 内容如下 protected-mode no sentinel monitor mymaster redis-master 6379 2 sentinel down-after-milliseconds mymaster 60000 s…

npm error code ETIMEDOUT

参考:https://blog.csdn.net/qq_38572963/article/details/142052986 二、解决办法 1、清空缓存 npm cache clean --force 2、查看当前的npm镜像设置 npm config get registry 3、切换新镜像源 npm config set registry https://registry.npmmirror.com 4、查看新源是否设置成功…

【终端工具】FinalShell v4.5.12 官方版

1.下载地址 【终端工具】FinalShell v4.5.12 官方版 2.简介 FinalShell是一款免费的跨平台远程管理工具&#xff0c;专为开发者和运维人员设计。它支持通过 SSH、SFTP 等方式连接到 Linux 和 Windows 服务器&#xff0c;提供类似于终端的操作界面。除了常规的远程登录功能&a…

微前端qiankun的使用——实践

qiankun 创建主应用项目——vue2 main.js注册子应用 $ yarn add qiankun # 或者 npm i qiankun -Simport { registerMicroApps, start } from qiankun; import Vue from "vue"; import App from "./App.vue"; import router from "./router"; …

ansible play-book玩法

使用ansible-playbook实现安装nginx_ansible 安装nginx-CSDN博客文章浏览阅读1.5k次&#xff0c;点赞14次&#xff0c;收藏19次。本文详细介绍了如何在Linux环境中准备Ansible环境&#xff0c;包括配置主机、下载和安装Ansible&#xff0c;以及使用yum模块和tar包源码安装Nginx…

Require:离线部署 Sourcegraph

Sourcegraph 使读取、编写和修复代码变得容易——即使在庞大而复杂的代码库中。 代码搜索&#xff1a;搜索所有分支和所有代码主机的所有存储库。代码智能&#xff1a;导航代码、查找引用、查看代码所有者、跟踪历史记录等。修复和重构&#xff1a;一次对许多存储库进行大规模更…

大数据新视界 -- Hive 集群性能监控与故障排查(2 - 16 - 14)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

Windows搭建域控服务器时本地administrator账户密码不符合要求解决办法

cmd命令行执行以下命令&#xff0c;再重试&#xff1a; net user administrator /passwordreq:yesWindows Server 2016 域控服务器搭建教程&#xff1a;https://blog.csdn.net/u010091664/article/details/122072506

【研究生必备|学术会议|高录用|见刊后1个月检索】第三届材料科学与智能制造国际学术会议(MSIM2025)

用处 1. 学术交流 参加学术会议是展示您研究成果和获取反馈的绝佳机会。在会议上&#xff0c;您可以与来自各地的研究者进行深入交流&#xff0c;讨论最新的研究动态与趋势&#xff0c;分享经验与观点。 2. 拓展人脉 学术会议汇聚了来自不同高校和研究机构的优秀学者和学生。…

ubuntu开机进入initramfs状态

虚拟机卡死成功起后进入了initramfs状态&#xff0c;可能是跟文件系统有问题或者检索不到根文件系统&#xff0c;或者是配置错误&#xff0c;系统磁盘等硬件问题导致 开机后进入如下图的界面&#xff0c; 文中有一条提示 要手动fsck 命令修复 /dev/sda1 命令如下 fsck /de…

C# 线程安全集合

文章目录 引言一、ConcurrentBag<T>二、ConcurrentQueue<T>三、ConcurrentStack<T>四、ConcurrentDictionary<TKey, TValue>五、总结引言 在多线程编程环境中,多个线程可能同时访问和操作集合数据。如果使用普通集合,很容易引发数据不一致、错误结果…

S32K324 MCAL中的Postbuild和PreCompile使用

文章目录 前言Postbuild和PreCompile的概念MCAL中配置差异总结 前言 之前一直看到MCAL配置中有这个Postbuild和PreCompile的配置&#xff0c;但是不太清楚这两个的区别和使用方法。最近在使用中出现了相关问题&#xff0c;本文介绍一下MCAL中这两种配置的区别和使用。 Postbu…

中国电信网络下多方通话 SIP消息交互记录

如下表格记录了一个日志中,在中国电信网络下多方语音通话 发起方的 SIP消息交互记录,省略部分SIP消息,记录下和多方通话的重要SIP消息。 progress1:发起方A通过拨号盘呼叫B 此操作建立A和B之间的通话,网络会向终端分配QCI=1的专有承载。 同时此专有承载包含四个pkt_filt…

应用(APP)部署容器化演进之路

应用&#xff08;Application&#xff09;部署容器化演进之路 一、应用程序部署痛点 1.1 应用程序部署流程 举例&#xff1a;部署一个JAVA编程语言开发的Web应用&#xff0c;以War包放入Tomcat方式部署。 部署过程如下&#xff1a; 服务器配置运行环境:JAVA代码运行环境&am…

SDMTSP:粒子群优化算法PSO求解单仓库多旅行商问题,可以更改数据集和起点(MATLAB代码)

一、单仓库多旅行商问题 单仓库多旅行商问题&#xff08;Single-Depot Multiple Travelling Salesman Problem, SD-MTSP&#xff09;&#xff1a;&#x1d45a;个推销员从同一座中心城市出发&#xff0c;访问其中一定数量的城市并且每座城市只能被某一个推销员访问一次&#x…

AI在线医生

第一章:背景介绍与Unit的使用 1.1背景介绍 1.2 Unit对话API的使用 第二章:在线医生的总体架构与工具介绍 第三章:neo4j图数据库 第四章:离线部分 第五章:命名实体审核任务 第六章:命名实体识别任务 第七章:在线部分 第八章:句子主题相关任务 第九章:系统联调与测试