Search Unity

Video How to Know video player is finished playing video?

Discussion in 'Audio & Video' started by abhayaagrawal, Jul 18, 2017.

  1. abhayaagrawal

    abhayaagrawal

    Joined:
    Sep 30, 2016
    Posts:
    8
    I want to have callback when video player is finished playing video.
    If i use videoplayer.isPlaying , this won't work because this will send call back in case i want to pause video.
    there is no bool to know video is stopped or not.
     
    lxz123233 and Asis2015 like this.
  2. FMark92

    FMark92

    Joined:
    May 18, 2017
    Posts:
    1,243
  3. unitynoob24

    unitynoob24

    Joined:
    Dec 27, 2014
    Posts:
    398
    @abhayaagrawal I was also looking for an answer for this and found this thread but could not really make heads or tails of it. My video only plays once so there is no looping involved. But I made up my own way of checking if the video is finished playing!

    Code (csharp):
    1.  
    2.  
    3. //Play the video!
    4. VP.GetComponent<VideoPlayer>().Play();
    5.  
    6. //Invoke repeating of checkOver method
    7. InvokeRepeating("checkOver", .1f,.1f);
    8.  
    9.  
    Code (csharp):
    1.  
    2.  
    3. //checkOver function will use current frame and total frames of video player video
    4. //to determine if the video is over.
    5.  
    6. private void checkOver()
    7. {
    8.        long playerCurrentFrame = VP.GetComponent<VideoPlayer>().frame;
    9.        long playerFrameCount = Convert.ToInt64(VP.GetComponent<VideoPlayer>().frameCount);
    10.      
    11.        if(playerCurrentFrame < playerFrameCount)
    12.        {
    13.            print ("VIDEO IS PLAYING");
    14.        }
    15.        else
    16.        {
    17.            print ("VIDEO IS OVER");
    18.           //Do w.e you want to do for when the video is done playing.
    19.        
    20.           //Cancel Invoke since video is no longer playing
    21.            CancelInvoke("checkOver");
    22.        }
    23. }
    24.  
    25.  
    Hope this helps someone else! I spent way too much time on figuring this out and figured I would share!
     
  4. smetzzz

    smetzzz

    Joined:
    Mar 24, 2014
    Posts:
    145
    Thanks for this idea. It works well but I found that InvokeRepeating significantly slowed down my video compared to just running checkOver(); in Update. I'm not well versed in code optimization but I wonder why this is? I also wonder how much System.Covert.ToInt64 running every frame (or every Invoke) slows things down. Maybe someone who knows the engine well and code optimizations can chime in.
     
  5. smetzzz

    smetzzz

    Joined:
    Mar 24, 2014
    Posts:
    145
    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.Video;
    6.  
    7. public class Scene_Intro : MonoBehaviour {
    8. public VideoPlayer vid;
    9.  
    10.  
    11. void Start(){vid.loopPointReached += CheckOver;}
    12.  
    13. void CheckOver(UnityEngine.Video.VideoPlayer vp)
    14. {
    15.      print  ("Video Is Over");
    16. }
    17.  
    18. }
    This works great too. As far as I understand it the VideoPlayer has a delegate system. vid.loopPointReached invokes the CheckOver(); function. Works, even if your video is not looping. I'm still unsure this is the most optimized way to do it. Optimization is pretty key when running HD video on mobile devices.
     
  6. nove34

    nove34

    Joined:
    Aug 22, 2017
    Posts:
    1
    Code (CSharp):
    1.     public double time;
    2.     public double currentTime;
    3.     // Use this for initialization
    4.     void Start () {
    5.  
    6.     time = gameObject.GetComponent<VideoPlayer> ().clip.length;
    7.     }
    8.  
    9.    
    10.     // Update is called once per frame
    11.     void Update () {
    12.         currentTime = gameObject.GetComponent<VideoPlayer> ().time;
    13.         if (currentTime >= time) {
    14.             Debug.Log ("//do Stuff");
    15.         }
    16.     }
    i usually do this
     
    pg_abd, RLCFrena, JekMena12 and 4 others like this.
  7. ismaelnascimentoash

    ismaelnascimentoash

    Joined:
    Apr 2, 2017
    Posts:
    30
    GamdineProductions likes this.
  8. pamelacook

    pamelacook

    Joined:
    Dec 13, 2017
    Posts:
    10
    videoPlayer.loopPointReached += EndReached 
    works for me!
     
  9. 54956

    54956

    Joined:
    Jan 8, 2017
    Posts:
    2
    Code (CSharp):
    1. if ((ulong)videoPlayer.frame == videoPlayer.frameCount)
    2.         {
    3.             //Video Finished
    4.         }
     
  10. metroidsnes

    metroidsnes

    Joined:
    Jan 5, 2014
    Posts:
    67
    For me the loopPointReached delegate for non-looping video wasn't triggered. Also the solution with checking frames gives me weird result.



    It worked when I casted to float instad of ulong.

    Other thing is that the VideoPlayer.frame stops a couple of frames before the frameCount. I needed to adjust for that:

    (float)m_GameIntro.frame < m_GameIntro.frameCount - 3
     
  11. FMark92

    FMark92

    Joined:
    May 18, 2017
    Posts:
    1,243
  12. metroidsnes

    metroidsnes

    Joined:
    Jan 5, 2014
    Posts:
    67
    You need to cast because otherwise there's a compile error, it cannot compare ulong with long. In the picture I compare -1 to 3000 and the result is that -1 is bigger.
     
  13. FMark92

    FMark92

    Joined:
    May 18, 2017
    Posts:
    1,243
    >In the picture I compare -1 to 3000
    No, you compare -1 cast to 18446744073709551615 to 3000.
    a being bigger is expected behavior.
     
  14. metroidsnes

    metroidsnes

    Joined:
    Jan 5, 2014
    Posts:
    67
    Yeah, apparently this is the result of casting -1 to ulong. Thanks for pointing this out.
     
  15. OndraPaska

    OndraPaska

    Joined:
    Jul 5, 2014
    Posts:
    14
    I think this started only with 2018.3, didn't? I suddenly need to add this, but before it was working (last frame was correctly reported)
     
  16. metroidsnes

    metroidsnes

    Joined:
    Jan 5, 2014
    Posts:
    67
    I don't how it was before. I'm having this problem with Unity 2018.3.0f1.
     
  17. DropoutGamer

    DropoutGamer

    Joined:
    Jul 3, 2019
    Posts:
    5
    @unitynoob24
    thanks man.. saved a lot of time because you
     
  18. Zeghra1

    Zeghra1

    Joined:
    May 28, 2020
    Posts:
    2
    FYI, if I used double currentTime = gameObject.GetComponent<VideoPlayer> ().time; it didn't work on Android 10 (it worked on Android 8). Instead I used as it was advised by @FMark92: videoPlayer.loopPointReached += EndReached; and I put it under Start() and worked on Android 10 too.
     
  19. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    691
    General note: avoid calling
    gameObject.GetComponent<VideoPlayer> ()
    or any GetComponent in Update(), or in any function which runs a lot, as it's wasteful and unnecessary. Cache it in Start and use the local reference.
     
    hassanali4 likes this.
  20. Scander_the_Clown

    Scander_the_Clown

    Joined:
    Sep 16, 2018
    Posts:
    1
    Hi Guys, I think I found out a solution.... its a pretty good solution if you want to play a queue of videos.... check out....
    Hope it helps...
    --------------------------------------------------------------------------------------------------------------------------------------------------------
    Code (CSharp):
    1. //function to play the clips, if the video player object is present
    2.     public bool playVideoClip(VideoClip video) {
    3.         VideoPlayer videoPlayer = getVideoPlayerInstance();
    4.         if (videoPlayer == null)
    5.             return false;
    6.  
    7.         //set the functions
    8.         videoPlayer.Stop();
    9.         videoPlayer.clip = video;
    10.         videoPlayer.source = VideoSource.VideoClip;
    11.  
    12.         videoPlayer.Prepare();
    13.  
    14.         videoPlayer.Play();
    15.  
    16.         return true;
    17.     }
    18.  
    19.  
    20.     //function to fetch the instance of the videoplayer component
    21.     public VideoPlayer getVideoPlayerInstance() {
    22.         GameObject videoPlayerObject = GameObject.FindGameObjectWithTag(VIDEO_PLAYER_TAG);
    23.         if (videoPlayerObject == null)
    24.             return null;
    25.  
    26.         return videoPlayerObject.GetComponent<VideoPlayer>();
    27.     }
    28.  
    29.  
    30.  
    31.     //Coroutine to play a queue of videos one by one
    32.     IEnumerator playVideoClipQueue(VideoClip []clips) {
    33.         VideoPlayer vp = getVideoPlayerInstance();
    34.  
    35.         for (int i = 0; i < clips.Length; i++) {
    36.             playVideoClip(clips);
    37.  
    38.             while (vp.frame < (long)vp.frameCount - 1) { //as frame goes upto frameCount - 1
    39.                 yield return null;
    40.             }
    41.         }
    42.  
    43.     }
    44.  
    45.  
    46. void Start()
    47.     {
    48.         //play the intro clips if any
    49.         //playIntroClips();
    50.  
    51.         IEnumerator introRoutine = playVideoClipQueue(introClips);
    52.         StartCoroutine(introRoutine);
     
  21. JackReivaj

    JackReivaj

    Joined:
    Feb 7, 2021
    Posts:
    33
    This is what i did, i don't know if it's the best optimized way but it works fine for me.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.SceneManagement;
    5.  
    6.  
    7. public class ControladorDeTiempo : MonoBehaviour
    8. {  
    9.     public float timer;
    10.  
    11.     // Start is called before the first frame update
    12.     void Start()
    13.     {
    14.              
    15.     }
    16.  
    17.     // Update is called once per frame
    18.     void Update()
    19.     {
    20.         timer -= Time.deltaTime;
    21.  
    22.         if (timer <= 0)
    23.         {
    24.             SceneManager.LoadScene("StartScreen");
    25.         }
    26.        
    27.     }
    28.    
    29. }
    In timer I put the time that the video lasts and maybe i add 1 second more, but that it's a personal decision.
     
  22. unity_BD1000D08C18D3028A82

    unity_BD1000D08C18D3028A82

    Joined:
    Nov 16, 2022
    Posts:
    16
    I know that this topic is from long ago. But this solution may be way simpler.


    Code (CSharp):
    1. public class videoEnd : MonoBehaviour
    2. {
    3.  
    4.     [SerializeField]
    5.     VideoPlayer videoPlayer;
    6.     float videoTime;
    7.  
    8.  
    9.     //when video end, change scene
    10.     void Start()
    11.     {
    12.         videoTime = (float)videoPlayer.length;
    13.         Invoke("videoEnded", videoTime);
    14.  
    15.  
    16.     }
    17.  
    18.  
    19.  
    20.     void videoEnded()
    21.     {
    22.         SceneManager.LoadScene("menu");
    23.     }
    24.    
    25. }

    the idea is simple. Just get the lenght of the video and invoke a function with that time of a delay.
     
    pachermann likes this.
  23. pachermann

    pachermann

    Joined:
    Dec 18, 2013
    Posts:
    133
    i guess there are always people who can use these kind of tips thanks! @unity_bd1000d08c18d3028a82.11340148