最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to seamlessly play several videos and then loop the sequence? - Stack Overflow

programmeradmin9浏览0评论

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 = [
      ".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:

  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>

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
Add a comment  | 

4 Answers 4

Reset to default 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>

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;
}
发布评论

评论列表(0)

  1. 暂无评论