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:
- We have a bunch of videos. Let's call them
video1
,video2
,video3
,video4
andvideo5
. - The videos play in an ordered sequence which is repeated in an endless loop - so after
video1
is finished,video2
is played, thenvideo3
,video4
,video5
and then it starts again fromvideo1
. - 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 playvideo4
,video5
,video1
,video2
etc. - The playback of the sequence has to start automatically without any user input.
- 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 = [
".mp4",
".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=".mp4" id="video" autoplay muted playsinline></video>
<p>(each video is just ~ 10 seconds)</p>
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:
- We have a bunch of videos. Let's call them
video1
,video2
,video3
,video4
andvideo5
. - The videos play in an ordered sequence which is repeated in an endless loop - so after
video1
is finished,video2
is played, thenvideo3
,video4
,video5
and then it starts again fromvideo1
. - 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 playvideo4
,video5
,video1
,video2
etc. - The playback of the sequence has to start automatically without any user input.
- 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>
Share
Improve this question
edited Oct 19, 2024 at 17:39
j08691
208k32 gold badges268 silver badges280 bronze badges
asked Sep 26, 2018 at 9:34
Jascha GoltermannJascha Goltermann
1,1244 gold badges16 silver badges34 bronze badges
4 Answers
Reset to default 8You 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>
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.
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>
You can also make it like this. Check out the code samples.
JSX/TSX: for multiple video player
import React, { useState } from "react";
const videoSources = [
"https://example.com/video_1.webm",
"https://example.com/video_2.webm",
"https://example.com/video_3.webm",
];
const VideoPlayer = () => {
const [currentVideoIndex, setCurrentVideoIndex] = useState(0);
// This will handle video end and switch to the next video
const handleVideoEnd = () => {
setCurrentVideoIndex((prevIndex) => (prevIndex + 1) % videoSources.length);
};
return (
<div className="relative w-full h-full">
<video
className="top-0 left-0 object-cover absolute -z-10 w-screen h-screen video-fade-in"
autoPlay
muted
loop={false}
onEnded={handleVideoEnd}
key={currentVideoIndex}
>
<source src={videoSources[currentVideoIndex]} type="video/webm" />
</video>
</div>
);
};
export default VideoPlayer;
CSS: For FadeIn Animation
@keyframes videoFadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.video-fade-in {
animation-name: videoFadeIn;
animation-duration: 1s;
animation-timing-function: ease-in-out;
animation-delay: 0s;
animation-iteration-count: 1;
animation-direction: normal;
animation-fill-mode: forwards;
animation-play-state: running;
}