Search Unity

Video RenderTexture retaining last video player frame

Discussion in 'Audio & Video' started by emongev, Oct 4, 2017.

  1. emongev

    emongev

    Joined:
    Jul 5, 2012
    Posts:
    36
    So whenever i try showing the video, I get a single frame of the last frame popping up before playing the video.

    How would I go about fixing this? :)

    Thanks in advance!
     
    Razek07 likes this.
  2. Fl0oW

    Fl0oW

    Joined:
    Apr 24, 2017
    Posts:
    21
    This might be late, but for future reference:

    The videoPlayer retains the last frame instead of resetting to the first frame when the end / the loop point is reached. You can manually reset the frame to the first one by subscribing to the method which is invoked as soon as the videoPlayer reaches the loop point:

    Code (CSharp):
    1. // Subscribe to loopPointReached event
    2.         videoPlayer.loopPointReached += EndReached;
    and then

    Code (CSharp):
    1. void EndReached(UnityEngine.Video.VideoPlayer vp)
    2.     {
    3.         // Reset video to first frame
    4.         videoPlayer.frame = 0;
    5.     }
    Next time you play the video it should start from frame 0 instead of from the last frame.

    Hope this helps!
     
  3. MSachs

    MSachs

    Joined:
    Nov 22, 2017
    Posts:
    122
    Hi,

    I have the same issue and the code you suggested doesn't seem to do the trick... I still see the last frame of the video everytime I start it again...
     
  4. Fl0oW

    Fl0oW

    Joined:
    Apr 24, 2017
    Posts:
    21
    Can you post some code of the script which loads/starts the video? Also, what settings do you have for looping, playOnAwake etc.?
     
  5. MSachs

    MSachs

    Joined:
    Nov 22, 2017
    Posts:
    122
    this is the code. PlayVid() gets called when tapping on a collider.
    Looping is off since I want to disable the gameObject after it played once.
    Play on Awake is on and wait for first frame as well.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Video;
    5.  
    6.  
    7. public class WorldSpaceVideo : MonoBehaviour
    8. {
    9.    
    10.     public GameObject VP;
    11.     public VideoPlayer videoPlayer;
    12.     private int videoClipIndex;
    13.  
    14.  
    15.  
    16.     // Use this for initialization
    17.     void Start ()
    18.     {
    19.         videoPlayer.loopPointReached += EndReached;
    20.     }
    21.        
    22.  
    23.     public void PlayVid()
    24.     {
    25.         if (!VP.activeSelf)
    26.         {
    27.             VP.SetActive (true);
    28.         }
    29.     }
    30.  
    31.        
    32.     void EndReached (VideoPlayer videoPlayer)
    33.     {
    34.         VP.SetActive (false);
    35.     }
     
  6. Fl0oW

    Fl0oW

    Joined:
    Apr 24, 2017
    Posts:
    21
    So did you already try setting videoPlayer.frame = 0 in EndReached?
     
  7. MSachs

    MSachs

    Joined:
    Nov 22, 2017
    Posts:
    122
    Yes I added it right here in the but it had no effect. I don't know if I have to change anything else or if this way of implementing it is completely wrong :D


    Code (CSharp):
    1.     void EndReached (VideoPlayer videoPlayer)
    2.     {
    3.         VP.SetActive (false);
    4.         videoPlayer.frame = 0;
    5.     }
     
  8. kishanrathod

    kishanrathod

    Joined:
    Jan 9, 2018
    Posts:
    1
    I'm having the same issue. The video player hold on to the last frame that it played
     
  9. pamelacook

    pamelacook

    Joined:
    Dec 13, 2017
    Posts:
    10
    I have a problem when I execute VideoPlayer.Stop. It keeps the last frame that played. That is by design according to the scripting documentation. I tried videoPlayer.frame = 0; but it's not working.
     
  10. pumpedbarbarous

    pumpedbarbarous

    Joined:
    Mar 18, 2015
    Posts:
    16
    Hey all! I saved the first frame of the video as an Texture2D and used 'Graphics.Blit(firstFrameTexture, videoRenderTexture)' to basically reset the render texture before I call VideoPlayer.Play.

    When you call 'VideoPlayer.Stop' it doesn't clear the render texture, which means once you start it again, it shows the last frame.

    edit:
    Using RenderTexture.DiscardContents did not seem to do the trick, neither does VideoPlayer.frame.
     
    jsleek likes this.
  11. jsleek

    jsleek

    Joined:
    Oct 3, 2014
    Posts:
    61

    Can anyone from Unity comment on why this doesn't work? It's very annoying. Seems like a bug.
     
    pumpedbarbarous likes this.
  12. codemonkeynorth

    codemonkeynorth

    Joined:
    Dec 5, 2017
    Posts:
    13
    I currently use this when hiding my video ready for the next time

    Code (CSharp):
    1. renderTexture.DiscardContents();
    2. Graphics.Blit(firstFrameTexture, renderTexture);
    but it relies on having a bitmap of the first frame (which I guess you could get from the video at startup etc)

    you could maybe use this technique
    https://forum.unity.com/threads/video-player-preview.527061/#post-3464306
     
    Last edited: Jun 30, 2018
  13. Harrison_Perry

    Harrison_Perry

    Joined:
    Jan 16, 2017
    Posts:
    9
    I got this to go away by using GL.Clear on the Video Player's awake.

    Code (CSharp):
    1. RenderTexture.active = videoplayer.targetTexture;
    2. GL.Clear(true, true, Color.black);
    3. RenderTexture.active = null;
     
  14. Zeratul3D

    Zeratul3D

    Joined:
    Nov 11, 2015
    Posts:
    7
    Changing the frame in the same method as we stop the player won't allow it to render the next (zero) frame before stopping.

    It would be enough to set videoPlayer.frame = 0; then yield return new WaitForEndOfFrame(); and then videoPlayer.stop();
     
  15. konzeptzwei

    konzeptzwei

    Joined:
    Feb 10, 2006
    Posts:
    64
    well, so actually videoPlayer.frame = framenumber does not work at all?
     
  16. pumpedbarbarous

    pumpedbarbarous

    Joined:
    Mar 18, 2015
    Posts:
    16
    Nope. Try my solution above, it worked for me.
     
  17. marianomdq

    marianomdq

    Joined:
    Sep 29, 2015
    Posts:
    17
    Hi everyone

    Thanks for all the useful help. I've been trying all the proposed solutions, but in my case it's been a pain in the neck.

    I'm not trying to obtain the 0 frame. My code needs to get an specific frame that it's not the current frame played by the videoplayer. For example, I could have a video from 0 to 500 frames, the current frame being 455 and I would need to obtain the renderTexture from frame 200. This last frame can change depending on player's decisions.

    For this I'm following the next approach:
    • Having a parallel hidden videoplayer2
    • Bind handlers for the videoplayer2.started and videoplayer2.prepareCompleted events
    • Stop the videoplayer2
    • Set videoplayer2.clip = videoplayer1.clip
    • Set videoplayer2.frame = videoplayer1.frame
    • videoplayer2.Prepare()
    • on prepareCompleted -> videoplayer2.Play()
    • on videoplayer2.started -> here I go for the videoplayer2 renderTarget's Texture
    But, I'm still dealing with the issue that the renderTarget it is still not getting updated on this frame.

    The only solution that I've found this far is to add a yield return new WaitForFrames(numberOfFrames) after the videoplayer2.started has began.

    Code (CSharp):
    1. private void VideoPlayer_started(VideoPlayer source)
    2. {
    3.     StartCoroutine(WaitForFramesAndCopyRenderTexture(20, source));
    4. }
    Code (CSharp):
    1. private IEnumerator WaitForFramesAndCopyRenderTexture(int frames, VideoPlayer source)
    2. {
    3.     // Videoplayer has a delay until it renders the targetTexture, we need to wait until it's done
    4.     yield return new WaitForFrames(frames);
    5.  
    6.     source.Pause();
    7.  
    8.     var renderTexture = source.targetTexture;
    9.     var copy = new RenderTexture(renderTexture);
    10.     Graphics.CopyTexture(renderTexture, copy);
    11. }
    But this is awful. Depending on the hardware, this could take more frames to render the texture. Is there actually no other solution for this?

    Thanks, help is appreciated.
     
  18. ookk47oo

    ookk47oo

    Joined:
    Mar 17, 2017
    Posts:
    80
    Code (CSharp):
    1.  videoPlayer.targetTexture.Release();
    This code might work.
     
    Last edited: Apr 4, 2019
  19. rcalabrezi

    rcalabrezi

    Joined:
    Mar 7, 2015
    Posts:
    3
    Nothing here has worked for me, as some videos were still locking up the render texture after
    VideoPlayer
    stops playing them. But surprisingly, calling
    Stop()
    right after it stops the video playback did the trick.

    Nonsense or not, I noticed calling
    Stop()
    anytime before the end always worked fine, so I thought the method internally may do its cleaning magic.

    Oh, I'm (still) using Unity 2019.1.3 around here.
     
    Last edited: Sep 24, 2019
  20. jdbenitez

    jdbenitez

    Joined:
    Feb 11, 2014
    Posts:
    7
    videoPlayer.targetTexture.Release(); worked fine for me.

    videoPlayer.Stop() didn't worked. My unity version is 2018.4.8f1
     
    blablablamaris and Joel123341 like this.
  21. icehotter

    icehotter

    Joined:
    May 15, 2014
    Posts:
    1
    Hi,

    My problem was that my videos also kept the last frame in their target texture. When using:

    videoPlayer.targetTexture.Release();

    this caused the texture to just be a black square which is not a good starting point for videos with an alpha. (or a camera not set up to respect it)

    This is what has worked for me to resolve it:

    I made a random image in blender with an alpha layer. (A simple square with no color) and then imported it into unity.

    code on the video player object:

    Code (CSharp):
    1. public Texture Blank;
    2.  
    3. void Awake()
    4. {
    5.     videoPlayer.targetTexture.DiscardContents();
    6.     videoPlayer.targetTexture.Release();
    7.  
    8.     Graphics.Blit(Blank, videoPlayer.targetTexture);
    9. }

    (Drag the blank image to the Blank variable in inspector)

    This forces the target texture to the alpha texture (i.e nothing) and then when you call videoPlayer.Play() the next frame to be written to the target texture is the first frame of the video (which is the desired result).

    Every time you load the scene the video player game object will blank the last frame with the alpha texture.

    Word of warning unity will use a screen shot of the game view for the texture if you forget to drag the blank image in.

    Again this is what worked for me, I hope it helps.
     
  22. campbal

    campbal

    Joined:
    Oct 19, 2015
    Posts:
    3
    Adding "videoPlayer.targetTexture.Release();" after video (or whenever I stop it) like ookk4700 suggested worked for me.
     
    tigerss likes this.
  23. Propagant

    Propagant

    Joined:
    Nov 18, 2013
    Posts:
    38
    Working well, thanks!
     
    Harrison_Perry likes this.
  24. abermann_O

    abermann_O

    Joined:
    Aug 16, 2018
    Posts:
    42
    Work perfect for me, thanks!!
     
    LuciaFt likes this.
  25. Fatamos

    Fatamos

    Joined:
    May 27, 2020
    Posts:
    12
    targetTexture.Release() works in PrepareVideo method in VideoPlayerController script that is subbed to VideoPlayer:

    Code (CSharp):
    1. IEnumerator PrepareVideo()
    2.         {
    3.             yield return new WaitForEndOfFrame();
    4.             _videoPlayer.Prepare();
    5.             _videoPlayer.targetTexture.Release();       //remove last frame of previously played video
    6.         }
    Not sure why this method works, but the last frame gets removed and its not played the second time I play the video. Don't forget to add StartCoroutine(PrepareVideo()) in SetVideo method
     
    wicea likes this.
  26. Jesserdi

    Jesserdi

    Joined:
    Nov 18, 2021
    Posts:
    2
    This is a working solution, but not quite the right one.
     
  27. DungDajHjep

    DungDajHjep

    Joined:
    Mar 25, 2015
    Posts:
    202
    Thanks you ! It's work perfectly !
     
    LuciaFt likes this.
  28. yuziil

    yuziil

    Joined:
    May 16, 2023
    Posts:
    1
    This might be late, but I think I have found a solution to the problem!
    I added the rendered texture of the video player onto a raw image so that I can display the video on the raw image. After that all you have to do is just simply set the "enable" property to false on the raw image when the video player is at frame 0, and then change it to true when the frame has passed 0. Like this:
    Code (CSharp):
    1. using UnityEngine.Video;
    2. using UnityEngine.UI;
    3.  
    4. public RawImage videoDisplay;
    5. public VideoPlayer videoPlayer;
    6.  
    7. private void Update()
    8. {
    9.         if (videoPlayer.frame < 0)
    10.         {
    11.             videoDisplay.enabled = false;
    12.         }
    13.         else if (videoPlayer.frame > 0)
    14.         {
    15.             videoDisplay.enabled = true;
    16.         }
    17. }
    Hope this helps!