1

I know that there is a simple solution to play videos one after another in HTML. However, I have yet to find one that transitions from videos smoothly. My problem is that I have a very long stream of videos on my server composed of multiple MP4 files. I serve these files to my web client through HTTP and play them with video.js. To play one file after another, I simply implemented this solution which simply changes the source on the ended event. The problem is that there is a small stutter when a video ends and a new one starts. To the user, these small files must appear as a single continuous video, so I cannot accept a small stutter when files change.

Is there a way to do this in videojs or just in the video element of HTML5? I currently save my MP4 files as blobs on my client, so I was thinking that maybe I could try to 'merge' blobs together to avoid changing the source. However, I don't think I can simply concatenate MP4 files together in a blob and play them as a single source. Is there another format that could support 'merging' video files on the fly to avoid changing the video source?

Please note that any HTTP streaming protocols such as HLS or DASH would not work for me. My server must fetch MP4 files from possibly long-term archive storage and the total duration of the video is not known to me. Therefore, I cannot really build a manifest for the chunks. I also have my files in plain MP4, not fragmented MP4.

ThomasFromUganda
  • 380
  • 3
  • 17
  • Could you put up a small snippet, say with 3 of you blobs so we can see the stutter. It would help us try things out. – A Haworth Feb 10 '21 at 06:28

2 Answers2

0

If we always have a video set up and ready to play, i.e. two video elements, one playing one with src setup ready, there seems to be no stutter. This needs testing on other videos but this snippet seems not to stutter between videos.

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>
A Haworth
  • 30,908
  • 4
  • 11
  • 14
0

I tried many things, but there was always a small stutter during transitions, especially noticeable on the audio track. I ended up converting my MP4 files on my server to fragmented MP4. I simply append new MP4 fragments to the same buffer and it plays as a single video.

ThomasFromUganda
  • 380
  • 3
  • 17