javascripthtmlhtml5-video

How to seamlessly play several videos and then loop the sequence?


I know that similar questions have been asked before but none has been able to solve this specific problem, they only solve parts of it.

I want to achieve the following:

  1. We have a bunch of videos. Let's call them video1, video2, video3, video4 and video5.
  2. The videos play in an ordered sequence which is repeated in an endless loop - so after video1 is finished, video2 is played, then video3, video4, video5 and then it starts again from video1.
  3. The starting point must be random. So this whole sequence should start from a randomly selected video in the list but then go through the rest of the list in the normal order. If it randomly selects to start with video3, it would then go on to play video4, video5, video1, video2 etc.
  4. The playback of the sequence has to start automatically without any user input.
  5. Now this last point is the most difficult one: There must be no gap in between the play of each video.

I have been able to write a code that does everything from the point 1 to 4 but I can not get it to solve point 5!

Here is my code. I have set the background-color of the video to red to make the gap between the videos visible - you will be able to see a red flash between the playback of each video. This is what I need to solve: I need that split second gap to be gone, so that the playback will be absolutely seamless.

var vidElement = document.getElementById('video');
    var vidSources = [
      "http://www.w3schools.com/html/mov_bbb.mp4",
      "http://www.w3schools.com/html/movie.mp4"
      ];
    var activeVideo = Math.floor((Math.random() * vidSources.length));
    vidElement.src = vidSources[activeVideo];
    vidElement.addEventListener('ended', function(e) {
      // update the active video index
      activeVideo = (++activeVideo) % vidSources.length;
      if(activeVideo === vidSources.length){
        activeVideo = 0;
      }

      // update the video source and play
      vidElement.src = vidSources[activeVideo];
      vidElement.play();
    });
video { background-color: red }
<video src="http://www.w3schools.com/html/mov_bbb.mp4" id="video" autoplay muted playsinline></video>
<p>(each video is just ~ 10 seconds)</p>


Solution

  • You can create two video elements with preload attribute and add it to div containar. Then we can switch between the videos by toggling the display state like follows:

    var videoContainer = document.getElementById('videoContainer'),
        output = document.getElementById('output'),
        nextVideo,
        videoObjects =
        [
            document.createElement('video'),
            document.createElement('video')
        ],
        vidSources =
        [
            "http://www.w3schools.com/html/mov_bbb.mp4",
            "http://www.w3schools.com/html/movie.mp4",
            "http://www.w3schools.com/html/mov_bbb.mp4",
            "http://www.w3schools.com/html/movie.mp4",
            "http://www.w3schools.com/html/mov_bbb.mp4",
            "http://www.w3schools.com/html/movie.mp4"
            //this list could be additionally filled without any other changing from code
        ],
        //random starting point
        nextActiveVideo = Math.floor((Math.random() * vidSources.length));
    
    videoObjects[0].inx = 0; //set index
    videoObjects[1].inx = 1;
    
    initVideoElement(videoObjects[0]);
    initVideoElement(videoObjects[1]);
    
    videoObjects[0].autoplay = true;
    videoObjects[0].src = vidSources[nextActiveVideo];
    videoContainer.appendChild(videoObjects[0]);
    
    videoObjects[1].style.display = 'none';
    videoContainer.appendChild(videoObjects[1]);
    
    function initVideoElement(video)
    {
        video.playsinline = true;
        video.muted = false;
        video.preload = 'auto'; //but do not set autoplay, because it deletes preload
    
        //loadedmetadata is wrong because if we use it then we get endless loop
        video.onplaying = function(e)
        {
            output.innerHTML = 'Current video source index: ' + nextActiveVideo;
    
            //select next index. If is equal vidSources.length then it is 0
            nextActiveVideo = ++nextActiveVideo % vidSources.length;
    
            //replace the video elements against each other:
            if(this.inx == 0)
                nextVideo = videoObjects[1];
            else
                nextVideo = videoObjects[0];
    
            nextVideo.src = vidSources[nextActiveVideo];
            nextVideo.pause();
        };
    
        video.onended = function(e)
        {
            this.style.display = 'none';
            nextVideo.style.display = 'block';
            nextVideo.play();
        };
    }
    video{background-color: red}
    <div id="videoContainer" style="display:inline-block"></div>
    <b id="output" style="vertical-align:top"></b>