HTML5 Video - How to seamlessly play several videos and then loop the sequence?
Asked Answered
C

3

7

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>
Coster answered 26/9, 2018 at 9:34 Comment(0)
B
8

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>
Blanca answered 28/9, 2018 at 11:11 Comment(0)
A
4

Try with setting the display to block and none:

var vidElement0 = document.getElementById('video0');
var vidElement1 = document.getElementById('video1');
var vidElement2 = document.getElementById('video2');
var vidElement3 = document.getElementById('video3');
var vidElement4 = document.getElementById('video4');

    var vidSource0 = "http://www.w3schools.com/html/mov_bbb.mp4";
    var vidSource1 = "http://www.w3schools.com/html/movie.mp4";
    var vidSource2 = "http://www.w3schools.com/html/mov_bbb.mp4";
    var vidSource3 = "http://www.w3schools.com/html/movie.mp4";
    var vidSource4 = "http://www.w3schools.com/html/mov_bbb.mp4";
    
    vidElement0.src = vidSource0;
    vidElement1.src = vidSource1;
    vidElement2.src = vidSource2;
    vidElement3.src = vidSource3;
    vidElement4.src = vidSource4;

    var rand = Math.floor((Math.random() * 5 )); //5 = length of vidsources (Start counting from 0)
    
    var vidRandom = document.getElementById("video" + rand);
    console.log("Video "+rand+ " will be displayed first.");
    
    vidRandom.style.display = "block";
   

   
    vidElement0.addEventListener('ended', function(e) {
    vidElement1.play();
   
    vidElement0.style.display = "none";
     vidElement1.style.display = "block";
});

    vidElement1.addEventListener('ended', function(e) {
    vidElement2.play();
    
    vidElement1.style.display = "none";
    vidElement2.style.display = "block";
  });
  
    vidElement2.addEventListener('ended', function(e) {
    vidElement3.play();
    
    vidElement2.style.display = "none";
    vidElement3.style.display = "block";
  });
  
    vidElement3.addEventListener('ended', function(e) {
    vidElement4.play();
    
    vidElement3.style.display = "none";
    vidElement4.style.display = "block";
  });
  
    vidElement4.addEventListener('ended', function(e) {
    vidElement0.play();
    
    vidElement4.style.display = "none";
    vidElement0.style.display = "block";
  });
video {background-color: red; height: 200px; width: 300px;display: none; }
<video src="" id="video0"  preload autoplay muted playsinline></video>
<video src="" id="video1"  preload autoplay muted playsinline></video>
<video src="" id="video2"  preload autoplay muted playsinline></video>
<video src="" id="video3"  preload autoplay muted playsinline></video>
<video src="" id="video4"  preload autoplay muted playsinline></video>

EDIT: I have edited the sources, made it 5 sources, but I couldn't find the correct code to fade it in.

Abdication answered 26/9, 2018 at 10:57 Comment(9)
I like this concept. It will even allow me to create a soft transition between the videos by using "opacity: 0" instead of "display: none". Can you edit your code to work with five videos instead of two? Just use the same sources but as if they were five different videos..Coster
@JaschaGoltermann sure ill add 3 more. I will also include a transition for you.Abdication
Thanks for your effort!Coster
@JaschaGoltermann no problem :D I have edited it to your desire but I couldn't get the fading to work.Abdication
Hi @sam, thanks for updating your code. I have edited it further so now there is even a transition: jsfiddle.net/xuewkor1Coster
There is only one last thing that doesn't work right: If the script chooses to start with video0 (the bunny) then the video1 (bear) will not play until the end but instead it will end early. This only happens if it starts with video0 and only happens once. After that, all videos in the sequence are played until they end as they should. Any ideas what could cause this behaviour?Coster
Ive tried this with my videos and they also end at different times. Sometimes they play until the end, sometimes they finish early. Might this be because the video files have different lenghts?Coster
@JaschaGoltermann im in class right now, I’ll take a look at it when I get home, but, I’m almost sure it doesn’t stop early because of the code I posted. It has an event listener so, the chances are not much. I’ll have an answer ready in 1 or 2 hours.Abdication
Let us continue this discussion in chat.Abdication
O
0

No need to have two (or more) video elements. One video element will do. Just one problem. Autoplay is only possible with audio muted.

<video id="video" autoplay muted>

See code snippet:

const videoSources = [
  "//www.w3schools.com/html/mov_bbb.mp4", 
  "//www.w3schools.com/html/movie.mp4",
];

//var activeVideo = 0; //Start with first video
var activeVideo = Math.floor((Math.random() * videoSources.length)); //Start with random video
const videoElm = document.getElementById("video");
videoElm.src = videoSources[activeVideo];
videoElm.addEventListener("ended", function() { 
  activeVideo = ++activeVideo % videoSources.length; 
  videoElm.src = videoSources[activeVideo];  
});
#video {
  width: 480px;
  height: 360px;
  border: 1px solid #000;
}
<video id="video" autoplay muted></video>
Optimum answered 27/4, 2024 at 21:9 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.