Search Unity

RenderTexture / VideoPlayer issue

Discussion in 'WebGL' started by sirrus, Feb 16, 2018.

  1. sirrus

    sirrus

    Joined:
    Jun 10, 2012
    Posts:
    250
    I am attempting to play a video into a RenderTexture more than once and it does not seem to work in WebGL/WASM.

    I have a UI Panel which includes a Raw Image and a Video Player component. The Video Player has a valid URL on it.

    I then have the following script attached in the scene as well:

    Code (CSharp):
    1.  
    2. public class VideoStuff : MonoBehaviour {
    3.  
    4.     public VideoPlayer vidPlayer;
    5.     RenderTexture renderTexture;
    6.  
    7.     void PlayVideo()
    8.     {
    9.         if (renderTexture==null)
    10.             renderTexture = new RenderTexture(350, 300, 24);
    11.  
    12.         RawImage img = vidPlayer.gameObject.GetComponent<RawImage>();
    13.  
    14.         img.texture = renderTexture;
    15.         vidPlayer.renderMode = UnityEngine.Video.VideoRenderMode.RenderTexture;
    16.        
    17.         vidPlayer.targetTexture = renderTexture;
    18.  
    19.         vidPlayer.Play();
    20.     }
    21.     // Update is called once per frame
    22.     void Update () {
    23.  
    24.         if (Input.GetKeyDown(KeyCode.V))
    25.             PlayVideo();
    26.  
    27.         if (Input.GetKeyDown(KeyCode.S))
    28.             vidPlayer.Stop();
    29.        
    30.     }
    31. }
    As you can see, a RenderTexture is dynamically created and then reused on subsequent playing of the video. This works fine in the editor and it works great in WebGL, once. If the video is started again, the RenderTexture doesn't change (it's as if the video is paused but the audio plays correctly).

    I have also tried creating a NEW RenderTexture each time and this simply renders a black screen where the video should be.

    Any ideas?

    Thanks much.
     
  2. sirrus

    sirrus

    Joined:
    Jun 10, 2012
    Posts:
    250
    I should add that I'm using v2017.2.1p4 although I believe it also happens in 2017.1x
     
  3. byrontik

    byrontik

    Joined:
    Dec 29, 2013
    Posts:
    5
  4. sirrus

    sirrus

    Joined:
    Jun 10, 2012
    Posts:
    250
    Thanks but this is not a server or CORS issue. The video plays fine once (thus its not an access problem). It is on any subsequent plays when the problem occurs.

    I have discovered that it works fine if the Video Player is destroyed and then recreated (.Stop() doesnt cut it). However, I have still had some strange errors doing so in WebAssembly. Im working on a simple, reproducible case to submit as a bug report. But still, we shouldnt have to recreate a Video Player each time, should we?
     
  5. GHSmediaSrl

    GHSmediaSrl

    Joined:
    Dec 2, 2015
    Posts:
    6
    Hi sirrus,
    did you find a solution? My project in Unity 2018.2.0f2 is showing the same issue: the video plays fine once, then a black screen is shown (only in WebGL build not in EDITOR)
     
  6. sirrus

    sirrus

    Joined:
    Jun 10, 2012
    Posts:
    250
  7. kwcae

    kwcae

    Joined:
    May 26, 2017
    Posts:
    34
    To hopefully add more light, we seem to encounter this issue or at least one similar in Edge 40, not Firefox or Chrome which play our videos fine. The .mp4 video is in the StreamingAssets folder on the same server as our content.
     
  8. MaskedMouse

    MaskedMouse

    Joined:
    Jul 8, 2014
    Posts:
    432
    Make a script that does, Destroy(videoPlayerComponent) -> AddComponent<VideoPlayer> -> configure it to your needs -> Play()
    Unity's VideoPlayer component has been quite an annoyance to work with since it was implemented(5.6), so many bugs in there.
     
  9. nsmith1024

    nsmith1024

    Joined:
    Mar 18, 2014
    Posts:
    726
  10. sirrus

    sirrus

    Joined:
    Jun 10, 2012
    Posts:
    250
    Here's some plugin (jslib) code. It requires that you have a DOM element called "vid_overlay" that is styled to be positioned in front of the Unity player canvas.

    Code (JavaScript):
    1.  
    2. /*
    3. A pretty basic JS plugin for handling a YouTube video overlay in WebGL. It requires a div (or iframe) element called "vid_overlay" that is positioned in front of the Unity canvas.
    4.  
    5. */
    6.  
    7. var YouTubeVideoInteraction = {
    8.  
    9.     LoadYouTubeAPI__deps: ['onYouTubePlayerAPIReady'],
    10.     LoadYouTubeAPI: function ()
    11.     {      
    12.         // Load the IFrame Player API code asynchronously.
    13.         var tag = document.createElement('script');
    14.         tag.src = "https://www.youtube.com/player_api";
    15.         var firstScriptTag = document.getElementsByTagName('script')[0];
    16.         firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
    17.  
    18.         this.ytPlayer = null;
    19.     },
    20.  
    21.     // register the callbacks as dependencies for emscripten
    22.     ShowVideo__deps: ['onPlayerReady', 'onPlayerStateChange', 'OnVideoComplete','checkVideoCompletion'],
    23.     ShowVideo: function (video_id, video_length)
    24.     {
    25.         var videoIdAsString = Pointer_stringify(video_id);
    26.  
    27.         // hide your unity canvas here
    28.         // hideUnity();
    29.  
    30.         this.videoId = videoIdAsString;
    31.         this.videoLength = video_length;
    32.         this.checkedTime = false;
    33.  
    34.         if (this.ytPlayer != null)
    35.         {
    36.             document.getElementById('vid_overlay').style.display = 'block';
    37.             this.ytPlayer.loadVideoById({
    38.                 videoId: videoIdAsString,
    39.                 endSeconds: video_length
    40.             });
    41.  
    42.         }
    43.         else // new player
    44.             this.ytPlayer = new YT.Player('vid_overlay', {
    45.                 height: 700,
    46.                 width: 600,
    47.                 playerVars: { 'autoplay': 1, 'controls': 0, 'color': 'white', 'showinfo': 0, 'rel': 0, 'end': video_length },
    48.                 events: { 'onStateChange': _onPlayerStateChange, 'onReady': _onPlayerReady },
    49.                 videoId: videoIdAsString
    50.             });
    51.  
    52.     },
    53.  
    54.  
    55.     onYouTubePlayerAPIReady: function ()
    56.     {
    57.       //  console.log('yt api ready');
    58.  
    59.     },
    60.  
    61.     onPlayerReady: function (e)
    62.     {    
    63.         // show the video overlay element
    64.         document.getElementById('vid_overlay').style.display = 'block';          
    65.     },
    66.  
    67.     onPlayerStateChange: function (e)
    68.     {
    69.         if (e.data)
    70.         {        
    71.             var duration = this.ytPlayer.getCurrentTime();
    72.             var endTime = this.videoLength > 0 ? this.videoLength : this.ytPlayer.getDuration();
    73.          
    74.             // since the YouTube API doesn't always register a "video end" event, we have to routinely check to see if the video is over
    75.             if (e.data == 1)
    76.             {
    77.                 if (!this.checkedTime)
    78.                     if (this.videoLength == 0) // no end time defined
    79.                     {
    80.                         setTimeout(_checkVideoCompletion, 1000);
    81.                         this.checkedTime = true;
    82.                     }
    83.             }
    84.  
    85.             if (e.data == 0)
    86.                 _OnVideoComplete();
    87.             else if (duration > 0 && endTime > 0 && duration >= endTime)
    88.                 _OnVideoComplete();
    89.         }
    90.     },
    91.  
    92.     checkVideoCompletion: function ()
    93.     {
    94.         var duration = this.ytPlayer.getCurrentTime();
    95.         var endTime = this.videoLength > 0 ? this.videoLength : this.ytPlayer.getDuration();
    96.  
    97.         if (duration > 0 && endTime > 0 && duration >= endTime)
    98.             _OnVideoComplete();
    99.         else
    100.             setTimeout(_checkVideoCompletion, 1000);
    101.     },
    102.     OnVideoComplete: function ()
    103.     {
    104.         // hide the video overlay element and reshow the Unity canvas            
    105.         document.getElementById('vid_overlay').style.display = 'none';
    106.         // showUnity();
    107.  
    108.         // send message back to Unity player here
    109.      
    110.     }
    111. };
    112.  
    113. mergeInto(LibraryManager.library, YouTubeVideoInteraction);
    Then in some video player component:

    Code (CSharp):
    1. public class VideoThing : MonoBehaviour
    2. {
    3. [DllImport("__Internal")]
    4.         private static extern void LoadYouTubeAPI();
    5.  
    6.         [DllImport("__Internal")]
    7.         private static extern void ShowVideo(string video_id, int video_length);
    8.  
    9.        void Awake()
    10. {  LoadYouTubeAPI();
    11. }
    12.  
    13. void PlayVideo()
    14. {
    15.     ShowVideo("youtubevideocode",0);
    16. }
    17.  
    18. }
    19.        
    When the video completes, youll still need a SendMessage back into Unity.

    Hope that helps.
     
  11. sirrus

    sirrus

    Joined:
    Jun 10, 2012
    Posts:
    250
  12. GHSmediaSrl

    GHSmediaSrl

    Joined:
    Dec 2, 2015
    Posts:
    6
unityunity