Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

Question How to make VideoPlayer pause/stop and render a given frame on demand?

Discussion in 'Audio & Video' started by mikejm_, Apr 2, 2022.

  1. mikejm_

    mikejm_

    Joined:
    Oct 9, 2021
    Posts:
    346
    I am running a VideoPlayer "mainLoadScreenVP" to display itself through UI Toolkit with the main code being:

    Code (csharp):
    1. VideoClip videoClip = Resources.Load<VideoClip>("video-clip");
    2.         RenderTexture renderingTexture = new RenderTexture((int)videoClip.width, (int)videoClip.height, 0);
    3.         mainScreenVE.style.backgroundImage = new StyleBackground(Background.FromRenderTexture(renderingTexture));
    4.         mainScreenVP.targetTexture = renderingTexture;
    5.         mainScreenVP.clip = videoClip;
    6.         mainScreenVP.Play();
    I want to go back to stop/pause the video and go back to frame zero on demand.

    However, if I try a reset function to try to get it back to showing the video at frame zero and stay there:

    Code (csharp):
    1.         mainScreenVP.frame = 0;
    2.         mainScreenVP.Stop();
    This doesn't actually work. It seems the stop command registers but the frame reset one doesn't. If I take out the Stop() command it goes back to frame zero, but then it keeps playing again. So I can't find any way to actually make it stop while on frame zero.

    From debugging the .frame output, I see the actual playback of the video player (frame by frame) is desynchronized from everything else - it lags by two frames roughly in my tests. So while the video player can start and stop immediately, it cannot respond quickly or predictably to frame commands.

    Currently the only option I can think of then is to destroy the video player and make a new one every time I want to reset the video player back to zero frame. This is inefficient and is also giving some different slightly weird issues where it seems to glitch the first few frames.

    There is also a VideoPlayer.stepForward() command that works to force the player to render the next frame on demand, but no "stepBackward()".

    Is there any reasonable way to reset the frame back to zero and keep it there with the player stopped/paused on this frame?

    The closest I've come now is this ridiculous coroutine, which lets the video play for 1.5 seconds then tries to put it back to frame zero and step forward one frame then stop. It still creates a visual glitch as it tries to go back to frame zero, and it ends up on frame one rather than frame zero:

    Code (csharp):
    1. IEnumerator resetVideoPlayer() {
    2.             float totalAnimationTime = 1.5f;
    3.             float startTime = Time.time;
    4.             while (Time.time - startTime < totalAnimationTime) {
    5.                 yield return null;
    6.             }
    7.             mainScreenVP.Pause();
    8.             mainScreenVP.frame = 0;
    9.  
    10. //visual glitch occurs here as it doesn't visually render back to frame 0 but rather some intermediate frame
    11.  
    12.             int frameTimer = 0;
    13.             while(frameTimer < 5) {
    14.                 frameTimer++;
    15.                 yield return null;
    16.             }
    17.  
    18. //step forward is then needed and some more time given for it to render or it won't process the change
    19.  
    20.             mainScreenVP.StepForward();
    21.  
    22. //another delay is needed before stopping or it won't render the stepForward command
    23.  
    24.             frameTimer = 0;
    25.             while (frameTimer < 20) {
    26.                 frameTimer++;
    27.                 yield return null;
    28.  
    29.             }
    30.  
    31.             mainScreenVP.Stop();
    32.  
    33. //finally stops on frame 1 (wanted frame 0)
    34.         }
    If I then had a stepBackward() command I could put it back to 0 the same way but there is no such command. So I would have to re-render all my videos with a duplicate 0 and 1 frame and plan to start on frame 1.

    There has to be some better solution than this. Any ideas?
     
    Last edited: Apr 3, 2022
  2. The_Island

    The_Island

    Unity Technologies

    Joined:
    Jun 1, 2021
    Posts:
    502
    Code (CSharp):
    1.             videoPlayer.Pause();
    2.             videoPlayer.frame = 0;
    This works for me on Windows with Unity 2022.2. Have you tried pausing and not stopping the VideoPlayer? Can you try reimporting the clip and check if there are any info/warnings in your console? Is it possible your clip doesn't start at frame 0? This could be why your results are out of sync. Can you share your Unity version and the platform you work on?
     
  3. mikejm_

    mikejm_

    Joined:
    Oct 9, 2021
    Posts:
    346
    Thank you very much. You are correct. There must have been something wrong with the way I created the videos in terms of their frame numbers. I made a new video from scratch and it worked fine and with all them if I use videoPlayer.Pause(); videoPlayer.time = 0; this avoids the issue.Thanks.

    I have one follow up question: Is there any negative to leaving the player on pause vs. stop or starting/stopping? Ie. If I have a simple animation Icon that I want to play repeatedly whenever it is clicked, and this will happen regularly, is it best to pause it and leave it on pause when it is not playing? Or does this consume resources? If I have a 5-10 such animated icons, does the same apply? If I want them to go back to frame zero and stop, how would I do that? I note:

    Code (csharp):
    1. mainScreenVP.Pause();
    2.             mainScreenVP.frame = 0;
    3.             mainScreenVP.Stop();
    Does not work as it prevents it from going to frame zero.

    Should I put a delayed function by a few frames to stop them when they are not in use, or just leave them paused? Is there any major cost to having paused video players?

    Alternatively, what if a player is only used once every hour or so? (Not often.) Is that worth stopping?

    Thanks for your help.
     
    Last edited: Apr 5, 2022
  4. The_Island

    The_Island

    Unity Technologies

    Joined:
    Jun 1, 2021
    Posts:
    502
    There is no drawback to pausing the video player other than using some memory. In the case of a small video, it is negligible. The only thing stopping does more than pausing is stopping any remaining decoding jobs. When you set the frame to 0 and then stop, the frame is never set as it gets canceled.
    You can wait for the seek to complete and then stop it. You can do that by subscribing to VideoPlayer.seekCompleted