Unity之VideoPlayer视频播放(二)

一、效果

全屏缩小画面、播放暂停、进度条拖拽、视频播放时长、倍速、音量等功能。 长时间不移动鼠标自动隐藏播放控制器、鼠标离开倍速、音量时隐藏倍速、音量ui

二、脚本

cs 复制代码
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};
        
        //倍速playSpeedDropdownOnclike
        speedDropdown.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);

            //取消invoke
            if (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;//秒

        #endregion

        return data;
    }

    #endregion

    #region 视频委托

    //视频准备完成
    void PrepareCompleted(VideoPlayer _player)
    {
        // Debug.Log("视频准备完成" + _player.length);

        //设置视频总时长
        SetTxtTimer((float)_player.length, sumTimeTxt);

        //设置RT
        rt = 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 创建RenderTexture

    public 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)
    {
        //识别物体为空直接返回false
        if (detectionObjs == null)
        {
            Debug.Log("识别物体为空");
            return false;
        }
        
        EventSystem eventSystem = EventSystem.current;
        PointerEventData pointerEventData = new PointerEventData(eventSystem);
        pointerEventData.position = position;
        //射线检测ui
        List<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

相关推荐
余~~185381628001 小时前
矩阵NFC碰一碰发视频的源码技术开发攻略,支持OEM
线性代数·矩阵·音视频
寰宇软件1 小时前
PHP音视频课程培训系统
小程序·uni-app·php·音视频
学习嵌入式的小羊~18 小时前
流式传输的实现为什么需要缓存?
音视频
xiejiashu19 小时前
我准备做一个24H的摄像机模拟器,用录像视频模拟实时画面,如果能支持时间水印就更好了
音视频·rtsp模拟器·视频文件转rtsp·摄像机模拟器·onvif模拟器
Lzg_na19 小时前
音视频协议
音视频
m0_7482398319 小时前
爬虫基础之爬取某站视频
爬虫·音视频
扫地僧0091 天前
基于Java的远程视频会议系统(源码+系统+论文)
java·开发语言·网络协议·microsoft·udp·音视频·视频编解码
Quz1 天前
OpenCV:视频背景减除
人工智能·opencv·计算机视觉·音视频
嵌入式Sky2 天前
音频知识基础
驱动开发·音视频·嵌入式·音频·语音识别