Unity3d 基于UGUI和VideoPlayer 实现一个多功能视频播放器功能(含源码)
前言
随着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