一、效果
全屏缩小画面、播放暂停、进度条拖拽、视频播放时长、倍速、音量等功能。 长时间不移动鼠标自动隐藏播放控制器、鼠标离开倍速、音量时隐藏倍速、音量ui
二、脚本
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Video;public class VideoController : MonoBehaviour
{[Header("视频进度时间")] [SerializeField] Text sumTimeTxt; //总时间[SerializeField] Text currentTimeTxt; //当前时间[SerializeField] Slider scheduleSlider; //进度条[Header("播放按钮")] [SerializeField] Sprite playSprite; //播放[SerializeField] Sprite pauseSprite; //暂停[SerializeField] Button playBtn; //播放暂停[SerializeField] GameObject playIcon; //播放图标[Header("加载视频按钮")] [SerializeField] Button lastBtn; //上一个[SerializeField] Button nextBtn; //下一个[Header("视频类型切换按钮")] [SerializeField] Text videoTypeTxt; //视频类型文本[SerializeField] Button videoTypeBtn; //视频类型按钮[Header("音量按钮")]// [SerializeField] Sprite volumCross; //静音// [SerializeField] Sprite volumMiddle; //未静音[SerializeField] Button volumBtn; //音量按钮[SerializeField] Slider volumSlider; //音量滑动条[SerializeField] CanvasGroup volumbg; //音量背景(渐隐)[SerializeField] AudioSource audioSource; //音量控制器[SerializeField] List<Transform> volumMaskList; //音量遮罩(ui检测用)[Header("倍速")][SerializeField] Color32 selectColor=new Color32(0, 99, 242, 255); [SerializeField] Dropdown speedDropdown; //倍速[SerializeField] List<Transform> speedMaskList; //倍速遮罩(ui检测用)[Header("全屏小屏控制器物体列表")][SerializeField] List<Transform> fullControllerObjList; //播放控制器物体(ui检测用)[SerializeField] List<Transform> lessenControllerObjList; //播放控制器物体(ui检测用)[Header("放大缩小按钮")] [SerializeField] Button fullBtn; //放大按钮[SerializeField] Button lessenBtn; //缩小按钮[SerializeField] Button lessenPlayBtn; //小屏播放按钮RenderTexture rt;[Header("视频参数")] [SerializeField] RawImage img; //视频画面[SerializeField] VideoPlayer videoPlayer;[Header("节点")] [SerializeField] GameObject root;[SerializeField] List<VideoClip> clipList;[SerializeField] List<string> urlList;//单例public static VideoController instance;private void Awake(){instance = this;}void Start(){// SwitchVideoType(); //默认设置视频类型#region 委托添加videoPlayer.prepareCompleted += PrepareCompleted; //准备完成videoPlayer.loopPointReached += LoopPointReached; //播放结束videoPlayer.started += Started; //Play后立即调用videoPlayer.frameDropped += FrameDropped; //有丢帧发生时被执行videoPlayer.errorReceived += ErrorReceived; //通过此回调报告 HTTP 连接问题等错误。videoPlayer.seekCompleted += SeekCompleted; //查询帧操作完成时被执行videoPlayer.frameReady += FrameReady; //新的一帧准备好时被执行#endregion//视频播放playBtn.onClick.AddListener(PlayVideo);lessenPlayBtn.onClick.AddListener(PlayVideo);img.GetComponent<Button>().onClick.AddListener(PlayVideo); //视频画布可控制播放暂停//上一个下一个视频切换lastBtn.onClick.AddListener(() => { SwitchVideo(-1); });nextBtn.onClick.AddListener(() => { SwitchVideo(1); });//视频类型切换videoTypeBtn.onClick.AddListener(SwitchVideoType);//音量volumBtn.onClick.AddListener(VolumeShowOrHide);volumSlider.onValueChanged.AddListener(SetSliderVolume);volumFade=new FadeOutData{canvasGroup=volumbg,onComplete = VolumOnComplete};//倍速playSpeedDropdownOnclikespeedDropdown.onValueChanged.AddListener(PlayBackSpeed);speedDropdown.value = 3;//默认设置为1倍速//视频lessenBtn.onClick.AddListener(VideoLessen);fullBtn.onClick.AddListener(VideoFull);}void Update(){#region UI物体检测//全屏状态下执行if (isVideoFull){//全屏模式下控制器显示隐藏检测if (isVideoFull)FullControllerShow();//音量物体显示&& 鼠标未在音量物体上时if (!ismute && !RayDetectionUI(Input.mousePosition, volumMaskList))VolumeShowOrHide(); //音量物体隐藏//倍速下拉框开启if (speedDropdown.transform.Find("Dropdown List") ){if (!RayDetectionUI(Input.mousePosition, speedMaskList))speedDropdown.Hide();//鼠标不在倍速mask上时 隐藏下拉列表}else if (isSpeedRaycast){//倍速物体射线启用 && 倍速下拉框处于关闭时 设置Mask物体不可射线检测isSpeedRaycast = false;foreach (var item in speedMaskList)item.GetComponent<Image>().raycastTarget = isSpeedRaycast;}}#endregion}private void LateUpdate(){#region 视频总时间长度、视频已播放时长、滑动条设置// 在播放时 && 进度条没有被按下if (videoPlayer.isPlaying && !isSliderDrag){SetTxtTimer((float)videoPlayer.time, currentTimeTxt); //视频时间显示scheduleSlider.value = (float)(videoPlayer.time / (videoPlayer.frameCount / videoPlayer.frameRate)); //进度条}#endregion//根据视频加载情况设置是否禁用滑动条// scheduleSlider.interactable = videoPlayer.isPrepared;}#region 视频小屏和大屏播放private bool isVideoFull;//当前视频是否是全屏 true全屏//小屏void VideoLessen(){isVideoFull = false;//全屏控制器隐藏foreach (var item in fullControllerObjList)item.gameObject.SetActive(false);//全屏控制器显示foreach (var item in lessenControllerObjList)item.gameObject.SetActive(true);playIcon.SetActive(false);//小屏模式下隐藏videoPlayer.isLooping=true;//缩小屏幕RectTransform rect = root.GetComponent<RectTransform>();rect.anchorMax = rect.anchorMin = new Vector2(0, 1f);rect.anchoredPosition = new Vector2(240f, -630f);rect.sizeDelta = new Vector2(400f, 225f);//屏幕缩小 kienct右下角画面显示、角度提示显示KinectManager.Instance.computeColorMap = true;// CalculatedAngle.instance.gameObject.SetActive(true);}//全屏void VideoFull(){isVideoFull = true;//全屏控制器显示foreach (var item in fullControllerObjList)item.gameObject.SetActive(true);//全屏控制器隐藏foreach (var item in lessenControllerObjList)item.gameObject.SetActive(false);playIcon.SetActive(isPlay);//全屏模式并且暂停状态下显示videoPlayer.isLooping=false;//放大屏幕RectTransform rect = root.GetComponent<RectTransform>();rect.anchorMin = new Vector2(0, 0);rect.anchorMax = new Vector2(1, 1);rect.anchoredPosition = rect.sizeDelta = new Vector2(0f, 0f);//屏幕放大 kienct右下角画面隐藏、角度提示隐藏KinectManager.Instance.computeColorMap = false;// CalculatedAngle.instance.gameObject.SetActive(false);}#endregion#region 全屏模式下 播放控制器显示隐藏private Vector3 oldMousePos;void FullControllerShow(){// 当全屏状态下当前鼠标位置与上次鼠标位置不同时显示播放控制器if (Input.mousePosition!=oldMousePos){oldMousePos = Input.mousePosition;foreach (var VARIABLE in fullControllerObjList)VARIABLE.gameObject.SetActive(true);//取消invokeif (IsInvoking("InvokeControllerHide"))CancelInvoke("InvokeControllerHide");//不在控制器ui下时if (!RayDetectionUI(Input.mousePosition,fullControllerObjList))Invoke("InvokeControllerHide", 3f);//开启3秒控制器隐藏}}//全屏控制器3秒隐藏void InvokeControllerHide(){foreach (var VARIABLE in fullControllerObjList)VARIABLE.gameObject.SetActive(false);}#endregion#region 修改指定文本时长/// <summary>/// 修改指定文本时长/// </summary>void SetTxtTimer(float time, Text timeTxt){TimeData timeData = VideoTimeConversion(time);//时:分:秒// timeTxt.text = timeData == null// ? "00:00:00"// : $"{timeData.h.ToString("00")}:{timeData.m.ToString("00")}:{timeData.s.ToString("00")}";//分:秒int m = timeData.h * 60 + timeData.m;timeTxt.text = timeData == null? "00:00": $"{m.ToString("00")}:{timeData.s.ToString("00")}";}//时间数据class TimeData{public int h;public int m;public int s;}/// <summary>/// video时间换算/// </summary>/// <param name="totalTime">总时长</param>/// <returns></returns>TimeData VideoTimeConversion(float totalTime){TimeData data = new TimeData();/*1.VideoPlayer.time / 3600 通过时间获取(其中Time表示当前可用时间)*/data.h = (int)totalTime / 3600;data.m = (int)(totalTime - data.h * 3600) / 60;data.s = (int)totalTime % 60;#region 使用帧方式换算(暂不用)/*2.VideoPlayer.frameCount / VideoPlayer.frameRate 通过帧获取(总帧数/1秒多少帧)*///int timer = (int)(videoPlayer.frameCount / videoPlayer.frameRate);//int h = timer / (60 * 60);//时//int m = (timer - (h * 3600)) / 60;//分//int s = timer % 60;//秒#endregionreturn data;}#endregion#region 视频委托//视频准备完成void PrepareCompleted(VideoPlayer _player){// Debug.Log("视频准备完成" + _player.length);//设置视频总时长SetTxtTimer((float)_player.length, sumTimeTxt);//设置RTrt = CrteateRT((int)_player.clip.width, (int)_player.clip.height);_player.targetTexture = rt;img.texture = rt;//播放视频isPlay = true;PlayVideo(); //播放视频}private bool isVideoEnd;//视频播放结束void LoopPointReached(VideoPlayer _player){Debug.Log("视频播放结束");_player.Stop();isVideoEnd = true;//视频播放按钮状态修改isPlay = true;lessenPlayBtn.gameObject.SetActive(true);playBtn.image.sprite = playSprite;}//Play开始播放void Started(VideoPlayer _player){Debug.Log("Play开始播放");}//有丢帧发生时被执行void FrameDropped(VideoPlayer _player){Debug.Log("有丢帧发生时被执行");}//查询帧操作完成时被执行void SeekCompleted(VideoPlayer _player){Debug.Log("查询帧操作完成时被执行");isSliderDrag = false;//播放视频isPlay = true;PlayVideo();}//通过此回调报告 HTTP 连接问题等错误。void ErrorReceived(VideoPlayer _player, string message){Debug.Log("通过此回调报告 HTTP 连接问题等错误。" + message);}//新的一帧准备好时被执行void FrameReady(VideoPlayer _player, long frameIdx){Debug.Log("新的一帧准备好时被执行。" + frameIdx);}#endregion#region 创建RenderTexturepublic RenderTexture CrteateRT(int width, int hight){RenderTexture rt = new RenderTexture(width, hight, 0, RenderTextureFormat.ARGB32);rt.Create();return rt;}#endregion#region 滑动条控制bool isSliderDrag;//滑动条按下public void ScheduleSliderDown(){Debug.Log("slider按下");isSliderDrag = true;}private float DragTime; //滑动条拖动的时间// 滑动条拖动public void ScheduleSliderDrag(){isSliderDrag = true;DragTime = scheduleSlider.value * (videoPlayer.frameCount / videoPlayer.frameRate);SetTxtTimer(DragTime, currentTimeTxt); //修改视频已播放时长}//滑动条抬起public void ScheduleSliderUP(){Debug.Log("slider抬起");videoPlayer.time = DragTime; //修改播放进度if (isVideoEnd){isVideoEnd = false;isSliderDrag = false;isPlay = true;PlayVideo();}}#endregion#region 播放控制bool isPlay = true; //默认下次播放private void PlayVideo(){Debug.Log($"调用Play方法:{isPlay}");if (isPlay){videoPlayer.Play(); //播放lessenPlayBtn.gameObject.SetActive(false);}else{videoPlayer.Pause(); //暂停lessenPlayBtn.gameObject.SetActive(true);}playIcon.SetActive(isVideoFull&&!isPlay);//全屏模式并且暂停状态下显示playBtn.image.sprite = isPlay ? pauseSprite : playSprite;isPlay = !isPlay;}#endregion#region 视频类型切换void SwitchVideoType(){currentVideoIndex = -1; //视频当前下标switch (videoPlayer.source){case VideoSource.VideoClip:videoTypeTxt.text = "URL";videoPlayer.source = VideoSource.Url;break;case VideoSource.Url:videoTypeTxt.text = "Clip";videoPlayer.source = VideoSource.VideoClip;break;}SwitchVideo(1); //播放视频}#endregion#region 上一个下一个视频int currentVideoIndex;void SwitchVideo(int index){isPlay = true; //默认下一次播放currentVideoIndex += index;switch (videoPlayer.source){case VideoSource.VideoClip:if (currentVideoIndex > clipList.Count - 1)currentVideoIndex = clipList.Count - 1;if (currentVideoIndex < 0)currentVideoIndex = 0;videoPlayer.clip = clipList[currentVideoIndex];break;case VideoSource.Url:if (currentVideoIndex > urlList.Count - 1)currentVideoIndex = urlList.Count - 1;if (currentVideoIndex < 0)currentVideoIndex = 0;videoPlayer.url = urlList[currentVideoIndex];break;}videoPlayer.Prepare(); //视频预先加载准备}#endregion#region 播放指定视频public void PlayAssignedVideo(string videoName){foreach (var clip in clipList){if (clip.name==videoName){videoPlayer.clip = clip;videoPlayer.Prepare(); //视频预先加载准备return;}}Debug.Log($"{videoName}");}public void PlayAssignedVideo(VideoClip clip){OpenPanel(); //开启面板videoPlayer.clip = clip;videoPlayer.Prepare(); //视频预先加载准备}#endregion#region 音量控制bool ismute = true;FadeOutData volumFade;IEnumerator volumeFadeOut; //当前渐隐协程/// <summary>/// 音量显示隐藏/// </summary>void VolumeShowOrHide(){ismute = !ismute;//设置Mask物体的射线检测效果foreach (var item in volumMaskList)item.GetComponent<Image>().raycastTarget = !ismute;//判断是否有音量协程在执行if (volumFade.isFading) StopCoroutine(volumeFadeOut);//渐隐volumFade.fadeOutValue = ismute ? 0 : 1;//设置当前执行的音量协程volumeFadeOut = FadeOut(volumFade);StartCoroutine(volumeFadeOut);// 点击按钮静音并存储当前音量// if (ismute)// volumSlider.value = oldVolumeValue;//不静音 还原音量// else// {// //静音// oldVolumeValue = audioSource.volume; //记录原先音频数值// volumSlider.value = 0;// }}//音量渐隐回调void VolumOnComplete(){// 渐隐结束 音量背景显示隐藏volumbg.gameObject.SetActive(!ismute);}private float oldVolumeValue; //静音前的原始音频//音量滑动条监听void SetSliderVolume(float value){// Debug.Log("滑动条value");audioSource.volume = value; //设置音频音量// 按钮静音// ismute = value > 0;// volumBtn.image.sprite = ismute ? volumMiddle:volumCross;//设置静音图片效果}#endregion#region 倍速控制private bool isSpeedRaycast;//倍速物体射线是否启用//Dropdown下的挂载的Event Trigger调用public void playSpeedDropdownOnclike(){isSpeedRaycast = true;//设置Mask物体可以射线检测foreach (var item in speedMaskList)item.GetComponent<Image>().raycastTarget = isSpeedRaycast;// 遍历所有选项for (int i = 0; i < speedDropdown.options.Count; i++){Text optionText = speedDropdown.transform.Find("Dropdown List/Viewport/Content").GetChild(i).GetComponentInChildren<Text>();if (i == speedDropdown.value+1){// 设置选中选项颜色optionText.color = selectColor;}else{// 设置默认选项颜色}}}public void PlayBackSpeed(int value){videoPlayer.playbackSpeed = float.Parse(speedDropdown.options[value].text.Split('x')[0]);//Debug.Log(videoPlayer.playbackSpeed);}#endregion#region 开启关闭视频public void OpenPanel(){root.SetActive(true);}public void ClosePanel(){root.SetActive(false);}#endregion#region UI渐隐public class FadeOutData{public bool isFading; //是否正在渐隐public float duration = 0.15f; //渐隐时间public float fadeOutValue; //渐隐值public CanvasGroup canvasGroup; //渐隐物体public Action onComplete; //回调函数}/// <summary>/// 音量渐隐/// </summary>private IEnumerator FadeOut(FadeOutData data){//显示物体data.canvasGroup.gameObject.SetActive(true);data.isFading = true;float elapsedTime = 0f;// 设置当前的 alpha 值float startAlpha = data.canvasGroup.alpha ;// canvasGroup.alpha = startAlpha;//N秒渐隐while (elapsedTime < data.duration){elapsedTime += Time.deltaTime;// 计算新的 alpha 值float newAlpha = Mathf.Lerp(startAlpha, data.fadeOutValue, elapsedTime / 1);data.canvasGroup.alpha = newAlpha;yield return null; // 等待下一帧}// 确保最终 alpha 值为 最终值data.canvasGroup.alpha = data.fadeOutValue;//结束渐隐data.isFading = false;//执行回调data.onComplete?.Invoke();}#endregion#region UI触发检测/// <summary>/// Ui触发检测/// </summary>/// <param name="position">点击屏幕坐标</param>/// <param name="detectionObjs">识别物体</param>/// <returns></returns>private bool RayDetectionUI(Vector2 position, List<Transform> detectionObjs){//识别物体为空直接返回falseif (detectionObjs == null){Debug.Log("识别物体为空");return false;}EventSystem eventSystem = EventSystem.current;PointerEventData pointerEventData = new PointerEventData(eventSystem);pointerEventData.position = position;//射线检测uiList<RaycastResult> uiRaycastResultCache = new List<RaycastResult>();eventSystem.RaycastAll(pointerEventData, uiRaycastResultCache);//检测鼠标是否在 指定UI上foreach (var result in uiRaycastResultCache){if (detectionObjs.IndexOf(result.gameObject.transform)!=-1)return true;}return false;}#endregion}
三、下载链接
https://pan.baidu.com/s/1ShS1de7X7JWzSdT4PRicyQ?pwd=syq1