使用 setTimeout 循环播放视频

4

我想要循环播放视频。由于某些原因,我不想在结束事件中更改视频src。因此,我为循环中的每个视频创建了视频元素。同时,我还有视频src和持续时间的数组。

我的想法是: 只有当前正在播放的视频标签可见。其他将被隐藏。 我想使用setTimeout函数来代替ended事件。视频的持续时间将作为延迟参数。

但是它们都同时播放。我无法使它们按顺序播放。

以下是我目前所做的:

videoArray = [
    {"video":video1.mp4, "duration": 5},
    {"video":video2.mp4, "duration": 7},
    {"video":video3.mp4, "duration": 9},
    {"video":video4.mp4, "duration": 10},
]

for (var j = 0; j < videoArray.length; j++){
    var video = document.createElement("video");
    video.src=videoArray[j];
    video.id="video-"+j;
    video.preload = "metadata";
    video.type="video/mp4";
    video.autoplay = true; 
    video.style.display="none";
    document.body.appendChild(video); 
}

for (var count = 0; count < videoArray.length; count++) {
    (function(num){
        setTimeout(function() {
            videoArray[num].video.style.display="block";
            videoArray[num].video.play();
        }, 1000 * videoArray[num].duration);
        videoArray[num].video.style.display="none";
    })(count);
}

1
你需要使用 timeupdateplaypause 事件监听器,而不是尝试使用 setTimeout。请记住:https://developers.google.com/web/updates/2017/06/play-request-was-interrupted - Alexandre Elshobokshy
为什么你想要使用setTimeout来完成它? - Mufaddal Hamid
请注意,在Firefox的上下文菜单中,用户可以更改视频速度。其他浏览器不确定。 - artanik
我添加了第二个答案,它使用了 setTimeout。再次强调,我不建议采用这种方法,但是它是可行的。 - Shahar
3个回答

9

免责声明

我知道这个问题是没有使用“ended”事件提出的,但我不认为设置时间限制是一个好方法。
想想视频缓冲或因任何原因变慢的情况,您的setTimeout将会失去同步。

在最下面,我添加了另一种解决方案来满足不使用“ended”事件的要求,但我仍然不建议使用它。

解决方案

想法是为视频结束时添加事件监听器,在这种情况下,即使您以不同的速度运行视频,也将继续运行下一个视频,而不考虑持续时间。

另一个好处是,您不需要事先知道视频的持续时间。

PS。 您需要监听的事件便是 video.addEventListener("ended", callback);

您可以运行代码或查看我为您创建的工作示例

工作示例

    const videoUrls = [
        'https://videos-play-loop.netlify.com/video1.mp4',
        'https://videos-play-loop.netlify.com//video2.mp4',
        'https://videos-play-loop.netlify.com//video3.mp4',
    ];

    const createVideo = ({id, src, width, cls = 'video', display = 'block', playbackRate = 1, muted = true, type = 'video/mp4', autoplay = false, controls = true}) => {
        const videoElement = document.createElement("video");
        videoElement.id = id;
        videoElement.src = src;
        videoElement.classList.add(src);
        videoElement.type = type;
        videoElement.autoplay = autoplay;
        videoElement.controls = controls;
        videoElement.style.display = display;
        videoElement.muted = muted;
        videoElement.playbackRate = playbackRate;
        return videoElement;
    };


    const addVideos = (container, videoUrls) => {
        const videos = videoUrls.map((url, index) => {
            const first = index === 0;
            const display = first ? 'block' : 'none';
            return createVideo({id: `video-${index}`, src: url,display, width: 640, autoplay: first, playbackRate: 3});
        });
        videos.forEach((video, index) => {
            const last = index === videos.length - 1;
            const playNext = (element) => {
                element.target.style.display = "none";
                const nextElementIndex = last ? 0 : index + 1;
                const nextElement = videos[nextElementIndex];
                nextElement.autoplay = true;
                nextElement.style.display="block";
                nextElement.load();
            };
            video.addEventListener("ended", playNext);
            container.appendChild(video)
        });
    };
    const videoWrapper = document.getElementById('video-wrapper');
    addVideos(videoWrapper, videoUrls);
#video-wrapper video {
    max-width: 600px;
}
<div id="video-wrapper"></div>

使用 setTimeout 的解决方案(请使用上面的解决方案)

const videoUrls = [{
    url: `https://videos-play-loop.netlify.com/video3.mp4`,
    duration: 3,
  },
  {
    url: `https://videos-play-loop.netlify.com/video2.mp4`,
    duration: 4
  },
  {
    url: `https://videos-play-loop.netlify.com/video1.mp4`,
    duration: 5
  }
];


const createVideo = ({
  id,
  src,
  width,
  cls = 'video',
  display = 'block',
  duration,
  playbackRate = 1,
  muted = true,
  type = 'video/mp4',
  autoplay = false,
  controls = true
}) => {
  const videoElement = document.createElement("video");
  videoElement.id = id;
  videoElement.src = src;
  videoElement.classList.add(src);
  videoElement.type = type;
  videoElement.autoplay = autoplay;
  videoElement.controls = controls;
  videoElement.style.display = display;
  videoElement.muted = muted;
  videoElement.playbackRate = playbackRate;
  videoElement.setAttribute('data-duration', duration);
  return videoElement;
};

const playNext = (videos, index) => {
  const current = videos[index];
  const activeVideoDuration = parseInt(current.dataset.duration) * 1000;
  setTimeout(() => {
    const last = index === videos.length - 1;
    current.style.display = "none";
    current.pause();
    const activeVideoIndex = last ? 0 : index + 1;
    const next = videos[activeVideoIndex];
    next.autoplay = true;
    next.style.display = "block";
    next.load();
    next.play();
    playNext(videos, activeVideoIndex);
  }, activeVideoDuration);
};


const addVideos = (container, videoUrls) => {
  const videos = videoUrls.map((video, index) => {
    const {
      url,
      duration
    } = video;
    const first = index === 0;
    const display = first ? 'block' : 'none';
    return createVideo({
      id: `video-${index}`,
      src: url,
      duration,
      display,
      width: 640,
      autoplay: first,
    });
  });

  videos.forEach(video => container.appendChild(video));
  playNext(videos, 0);
};

const videoWrapper = document.getElementById('video-wrapper');
addVideos(videoWrapper, videoUrls);
#video-wrapper video {
  max-width: 600px;
}
<div id="video-wrapper"></div>


1
你可以将视频的持续时间保存在一个变量中,并将该变量与上一个视频的持续时间累加,然后将其设置为 setTimeOut 的持续时间。
请注意,视频的时间以秒为单位。对于第一个视频播放,用户必须进行交互,否则视频将无法播放。 工作示例:

function startVideos(event) {
 event.target.style.display= "none";
        (function() {
          videoArray = [
            {
              video:
                "http://techslides.com/demos/sample-videos/small.mp4",
              duration: 5
            },
            {
              video:
                "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4",
              duration: 60
            },
            {
              video:
                "https://mobamotion.mobatek.net/samples/sample-mp4-video.mp4",
              duration: 120
            },
            {
              video:
                "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
              duration: 600
            }
          ];

          let videArrayElem = [];

          for (var j = 0; j < videoArray.length; j++) {
            var video = document.createElement("video");
            video.src = videoArray[j].video;
            video.id = "video-" + j;
            video.preload = "metadata";
            video.type = "video/mp4";
            video.autoplay = false;
            video.controls= true;
            video.style.display = "none";
            videArrayElem.push(video);
            document.body.appendChild(video);
          }

          let prviousVideoDuration = 0;
          for (var count = 0; count < videoArray.length; count++) {
            (function(num) {
              setTimeout(function() {
                videArrayElem[num].style.display = "block";
                videArrayElem[num].play();
              }, prviousVideoDuration);
              prviousVideoDuration += 1000 * videoArray[num].duration;
              videArrayElem[num].style.display = "none";
            })(count);
          }
        })();
      }
video {
        height: 100px;
        width: 100px;
        display: inline-block;
        margin: 4px;
        float: left;
      }
<button type="button" onclick="startVideos(event)">Start Video Demo</button>


抱歉回复晚了。由于COVID-19的问题,我无法在这里检查。这个工作解决方案正是我所需要的。 - linepisode

0
除了你试图实现一些奇怪的东西,以及你的代码示例无法编译之外,我认为你已经做到了。 唯一缺少的是 pause()display = "none"。只需进行最小的编辑,你就可以得到所需的结果。
const videoArray = [
    {"video":"video1.mp4", "duration": 5}, // of cause you need "" 
    {"video":"video2.mp4", "duration": 7},
    {"video":"video3.mp4", "duration": 9},
    {"video":"video4.mp4", "duration": 10},
]

for (let j = 0; j < videoArray.length; j++){
    const video = document.createElement("video");
    // you need to save DOM nodes somewhere to use them in the second loop
    videoArray[j].video_el = video
    video.src=videoArray[j].video; // `.video` is added
    video.id="video-"+j;
    video.preload = "metadata";
    video.type="video/mp4";
    video.autoplay = true; 
    video.style.display="none";
    document.body.appendChild(video); 
}

for (var count = 0; count < videoArray.length; count++) {
    (function(num){
        setTimeout(function() {
            // add this to hide previous video node and stop video from playing 
            if( num ) {
                videoArray[num-1].video_el.style.display="none";
                videoArray[num-1].video_el.pause()
            }
            // videoArray[num].video - is a string, not a DOM node
            // so, you need to change this:
            // videoArray[num].video.style.display="block";
            // for this:
            videoArray[num].video_el.style.display="block";
            // no need. `autoplay` is set to `true` in the first loop
            // videoArray[num].video_el.play();
        }, 1000 * videoArray[num].duration);
        // no need. already done in the first loop
        // videoArray[num].video_el.style.display="none";
    })(count);
}

但是,存在很多缺陷:

  1. setTimeout 不关心网络延迟和其他与时间有关的问题,因此您的视频序列很可能无法无缝播放。
  2. 由于第一个流程以及我怀疑 duration 值不准确,您应该使用 pause()
  3. 正如 @IslamElshobokshy 在评论中指出的那样,使用 play/pause 并不简单。
  4. 如果用户打开页面并什么都不做,您将会得到:

    Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first.

    在 Chrome 中。而且

    Autoplay is only allowed when approved by the user, the site is activated by the user, or media is muted.
    NotAllowedError: The play method is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.

    在 Firefox 中。

所以最好还是使用ended事件,并使用muted属性(以减轻最后一个问题):

for (let j = 0; j < videoArray.length; j++){
    const video = document.createElement("video")
    videoArray[j].video_el = video

    video.src      = videoArray[j].video
    video.id       = "video-"+j
    video.preload  = "metadata"
    video.type     = "video/mp4"
    video.autoplay = true

    // show the first video right away
    if( j !== 0 ) video.style.display = "none"
    // set muted attribute
    video.muted = "muted"
    // play next video after the previous had ended
    video.addEventListener('ended', (num => function() {
        this.style.display = "none";
        if( num !== videoArray.length-1 ) {
            videoArray[num+1].video_el.style.display="block";
            // only needed if `muted` is not set 
            videoArray[num+1].video_el.play();
        }
    })(j), false);

    document.body.appendChild(video); 
}

如果您不想使用"muted"属性,可以在上添加一些事件监听器,在用户开始与页面交互时立即调用第一个视频的方法。也许您想在这里阅读更多关于的内容:https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接