一个接一个播放视频流畅吗?

问题描述

我知道有一个 simple solution 可以在 HTML一个一个地播放视频。但是,我还没有找到一种可以顺利从视频过渡的。我的问题是我的服务器上有很长的视频流,由多个 MP4 文件组成。我通过 HTTP 将这些文件提供给我的网络客户端并使用 video.js 播放它们。为了一个一个地播放文件,我简单地实现了 this solution,它只是更改了 ended 事件的源。问题是当视频结束并开始新的视频时会出现轻微的口吃。对于用户来说,这些小文件必须以单个连续视频的形式出现,所以我不能接受文件变化时的小卡顿。

有没有办法在 videojs 或仅在 videoHTML5 元素中执行此操作?我目前在我的客户端上将我的 MP4 文件保存为 blob,所以我想也许我可以尝试“合并”blob 以避免更改源。但是,我认为我不能简单地将 MP4 文件连接在一个 blob 中并将它们作为单个源播放。是否有另一种格式可以支持动态“合并”视频文件以避免更改视频源?

请注意,任何 HTTP 流媒体协议(例如 HLSDASH)对我都不起作用。我的服务器必须从可能的长期存档存储中获取 MP4 文件,我不知道视频的总持续时间。因此,我无法真正为块构建清单。我的文件也是普通的 MP4,而不是碎片化的 MP4

解决方法

如果我们总是有一个视频设置并准备好播放,即两个视频元素,一个在准备好 src 设置的情况下播放一个,似乎没有卡顿。这需要在其他视频上进行测试,但此片段似乎不会在视频之间断断续续。

function createObjectURL(object) {
    return (window.URL) ? window.URL.createObjectURL(object) : window.webkitURL.createObjectURL(object);
}

async function makeBlob(i){
    let blob = await fetch(srcs[i]).then(r => r.blob());
    blobs.push(createObjectURL(blob));
    if ( i == (srcs.length -1) ) {
      videoEls[0].src = blobs[0];
      videoEls[1].src = blobs[1];
      videoEls[0].style.visibility = 'visible';
      videoEls[0].play();
    }
}

const srcs = ['https://vjs.zencdn.net/v/oceans.mp4','https://vjs.zencdn.net/v/oceans.mp4','https://vjs.zencdn.net/v/oceans.mp4'];
let blobs= [];
let curBlob = 0;
let curVideo = 0;

for (let i=0; i < srcs.length; i++) {
  makeBlob(i);
}

let videoEls = document.querySelectorAll('video');

for (let j = 0; j < videoEls.length; j++) {
    videoEls[j].addEventListener("ended",function() {
      videoEls[curVideo].style.visibility = 'hidden';
      curVideo = (curVideo+1)%(videoEls.length);
      videoEls[curVideo].play();
      videoEls[curVideo].style.visibility = 'visible';
      curBlob = (curBlob+1)%(blobs.length);
      videoEls[(curVideo+1)%(videoEls.length)].src = blobs[curBlob];    
   });
}
video {
  position: absolute;
  visibility: hidden;
  }
 <video></video>
 <video></video>

,

我尝试了很多方法,但在转换过程中总是有一点点卡顿,在音轨上尤其明显。我最终将服务器上的 MP4 文件转换为碎片化的 MP4。我只是将新的 MP4 片段附加到同一个缓冲区中,然后将其作为单个视频播放。