【问题标题】:Play different videos back to back seamlessly using Unity Video Player使用 Unity 视频播放器无缝播放不同的视频
【发布时间】:2018-05-04 05:56:19
【问题描述】:

关于 Unity 的视频播放器组件,是否有人对此问题有任何解决方案?

基本上,我有一个半交互式应用程序,当发生某些事情时,它会背靠背播放一系列视频。问题是,一旦第一个视频结束,就会有 3-5 秒的空白,因为第二个视频需要时间来加载,但这在我的应用程序中看起来不太好。

我需要一种方法来预加载第二个视频(理想)或一种相当简单的方法来隐藏间隙(例如顶部的静止帧)。对于后一种想法,我应该提到视频是球形显示的。

using UnityEngine;
using UnityEngine.Video;

public class selectAndPlay_video : MonoBehaviour {

    public VideoPlayer videoPlayer;
    public VideoClip NewClip;
    void OnEnable()
    {
        videoPlayer.loopPointReached += loopPointReached;
    }

    void OnDisable()
    {
        videoPlayer.loopPointReached -= loopPointReached;
    }

   void loopPointReached(VideoPlayer v)

    {
       videoPlayer.clip = NewClip;
       videoPlayer.Play();
     }
}

【问题讨论】:

    标签: c# unity3d video video-player


    【解决方案1】:

    解决这个问题的关键是VideoPlayer.Prepare()函数,VideoPlayer.timeVideoPlayer.clip.length属性。首先,我建议您忘记当前播放事件视频的方式。像this 问题的示例中那样使用协程,因为下面答案中的所有内容都假设您处于协程函数中。以下是如何播放不同视频而无需长时间等待:

    1.有VideoClip 的数组/列表来播放。

    2.从#1中的VideoClip数组创建VideoPlayer的新列表。只需使用 #1 中的VideoClips 设置VideoPlayer.clip 属性。

    3.调用VideoPlayer.Prepare() 准备列表中的第一个 VideoPlayer 然后在while 循环中等待直到准备完成或VideoPlayer.isPrepared变为true

    4.致电VideoPlayer.Play()播放您刚刚在#3中准备的视频。

    无缝地背靠背播放不同的视频

    这是最重要的部分。

    在播放视频时,检查正在播放的VideoPlayer的当前时间是否为视频长度的一半。如果是一半,请在数组中的下一个视频上调用VideoPlayer.Prepare(),然后等待来自 #4 的视频播放完毕,然后再播放下一个视频。

    通过这样做,下一个视频将在当前视频仍在播放时自行开始准备,并且该准备过程应在当前视频播放完毕时完成。然后,您可以播放下一个视频,而无需等待很长时间加载。

    5。等待来自#4的视频在while循环中完成播放,直到VideoPlayer.isPlaying变为false

    6。在 #5 中的 while 循环内等待时,检查视频是否在 if (videoPlayerList[videoIndex].time >= (videoPlayerList[videoIndex].clip.length / 2)) 播放到一半。如果这是真的,请在列表中的下一个VideoPlayer 上调用VideoPlayer.Prepare() 以使其准备就绪。

    7.while循环存在后,当前视频播放完毕。播放列表中的下一个VideoPlayer,然后从#5再次重复以准备列表中的下一个VideoPlayer

    下面的脚本应该完成我上面描述的所有事情。只需创建一个RawImage 并将其插入图像插槽即可。你所有的视频也到videoClipList 变量。它应该一个接一个地播放视频,而不需要很长的加载时间。 Debug.Log 很昂贵,因此一旦您确认它工作正常,请移除它们。

    //Raw Image to Show Video Images [Assign from the Editor]
    public RawImage image;
    //Set from the Editor
    public List<VideoClip> videoClipList;
    
    private List<VideoPlayer> videoPlayerList;
    private int videoIndex = 0;
    
    
    void Start()
    {
        StartCoroutine(playVideo());
    }
    
    IEnumerator playVideo(bool firstRun = true)
    {
        if (videoClipList == null || videoClipList.Count <= 0)
        {
            Debug.LogError("Assign VideoClips from the Editor");
            yield break;
        }
    
        //Init videoPlayerList first time this function is called
        if (firstRun)
        {
            videoPlayerList = new List<VideoPlayer>();
            for (int i = 0; i < videoClipList.Count; i++)
            {
                //Create new Object to hold the Video and the sound then make it a child of this object
                GameObject vidHolder = new GameObject("VP" + i);
                vidHolder.transform.SetParent(transform);
    
                //Add VideoPlayer to the GameObject
                VideoPlayer videoPlayer = vidHolder.AddComponent<VideoPlayer>();
                videoPlayerList.Add(videoPlayer);
    
                //Add AudioSource to  the GameObject
                AudioSource audioSource = vidHolder.AddComponent<AudioSource>();
    
                //Disable Play on Awake for both Video and Audio
                videoPlayer.playOnAwake = false;
                audioSource.playOnAwake = false;
    
                //We want to play from video clip not from url
                videoPlayer.source = VideoSource.VideoClip;
    
                //Set Audio Output to AudioSource
                videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
    
                //Assign the Audio from Video to AudioSource to be played
                videoPlayer.EnableAudioTrack(0, true);
                videoPlayer.SetTargetAudioSource(0, audioSource);
    
                //Set video Clip To Play 
                videoPlayer.clip = videoClipList[i];
            }
        }
    
        //Make sure that the NEXT VideoPlayer index is valid
        if (videoIndex >= videoPlayerList.Count)
            yield break;
    
        //Prepare video
        videoPlayerList[videoIndex].Prepare();
    
        //Wait until this video is prepared
        while (!videoPlayerList[videoIndex].isPrepared)
        {
            Debug.Log("Preparing Index: " + videoIndex);
            yield return null;
        }
        Debug.LogWarning("Done Preparing current Video Index: " + videoIndex);
    
        //Assign the Texture from Video to RawImage to be displayed
        image.texture = videoPlayerList[videoIndex].texture;
    
        //Play first video
        videoPlayerList[videoIndex].Play();
    
        //Wait while the current video is playing
        bool reachedHalfWay = false;
        int nextIndex = (videoIndex + 1);
        while (videoPlayerList[videoIndex].isPlaying)
        {
            Debug.Log("Playing time: " + videoPlayerList[videoIndex].time + " INDEX: " + videoIndex);
    
            //(Check if we have reached half way)
            if (!reachedHalfWay && videoPlayerList[videoIndex].time >= (videoPlayerList[videoIndex].clip.length / 2))
            {
                reachedHalfWay = true; //Set to true so that we don't evaluate this again
    
                //Make sure that the NEXT VideoPlayer index is valid. Othereise Exit since this is the end
                if (nextIndex >= videoPlayerList.Count)
                {
                    Debug.LogWarning("End of All Videos: " + videoIndex);
                    yield break;
                }
    
                //Prepare the NEXT video
                Debug.LogWarning("Ready to Prepare NEXT Video Index: " + nextIndex);
                videoPlayerList[nextIndex].Prepare();
            }
            yield return null;
        }
        Debug.Log("Done Playing current Video Index: " + videoIndex);
    
        //Wait until NEXT video is prepared
        while (!videoPlayerList[nextIndex].isPrepared)
        {
            Debug.Log("Preparing NEXT Video Index: " + nextIndex);
            yield return null;
        }
    
        Debug.LogWarning("Done Preparing NEXT Video Index: " + videoIndex);
    
        //Increment Video index
        videoIndex++;
    
        //Play next prepared video. Pass false to it so that some codes are not executed at-all
        StartCoroutine(playVideo(false));
    }
    

    【讨论】:

    • 感谢您的详细解答。然而,这让我有点不知所措,在离开 Unity 几年后,我才刚刚回到 Unity 和编程
    • 如果我理解正确的话,这个脚本假定所有视频都将在 1 到 10 之间进行回放。这在某种程度上是我需要的,但不幸的是它变得有点复杂。它的工作原理更像这样:视频 1 播放,然后视频 2 播放并循环播放,直到用户执行某些操作。根据用户的操作,视频 3、4 或 5 将播放。这是我需要的结构。在大多数情况下,在用户选择某些内容之前,它永远不知道下一个视频将是什么时候或什么。
    • 好的,我想我现在明白了。我唯一有点困惑的是,如果在您的方法中,每个视频剪辑都有一个视频播放器吗?我遇到的 Prepare() 问题是,一旦您将视频播放器设置为新剪辑,它就会停止播放当前剪辑,据我所知,需要在新剪辑完成后调用 Prepare()选择否则它只是重新加载已经播放的剪辑。我尝试了您在视频剪辑中途调用 Prepare() 的方法,结果是一样的,请记住,这仅使用了 1 个视频播放器。
    • @Programmer,这对我在多个视频之间切换非常有帮助。就我而言,FPS 从 2 提高到 30-35 FPS,但我想要 50-60 FPS。是否有任何其他优化可以尝试进一步提高 FPS?
    • @MSDPaul 不。播放视频是一件非常昂贵的事情,Unity 已经在另一个线程中为您准备好了。 30-35 FPS 似乎还可以。你到底在做什么,你什么时候看到 fps 下降?
    猜你喜欢
    • 1970-01-01
    • 2014-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-01
    相关资源
    最近更新 更多