Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTML5 Video - How to do a seamless play and/or loop of several videos?

How can I reliably play several videos one after another seamlessly? As there is a small pause or flicker between playing 2 videos.

In my particular example I have 3 videos. I need to play all 3 of them seamlessly one after another, and I also need to loop middle video an arbitrary number of times (say 2 or 3). All of that needs to happen seamlessly and consistently across different browsers.

I've been trying everything under the moon, from starting video playback on video end, to using several video tags and hiding and replacing them, I even tried to implement this in Flash, but alas nothing works, and the same problem happens in current Flash as well.

I've seen this (or similar) question asked many times but I haven't seen a reliable solution yet.

Does anyone know a solution to this?

like image 318
Tanuki Avatar asked Dec 04 '15 21:12

Tanuki


1 Answers

After trying various things I have finally been able to create what seems to be a working solution. I haven't tested this on older browsers or other OSes, but this works on latest versions of Chrome, IE, Firefox and Opera. (Although some more feedback of whether this works on other systems would be appreciated)

The idea is to have all 3 videos output frames to HTML5 canvas. The original videos are hidden and preloaded in advance to avoid pause between loading.

Here is the code:

var playCounter = 0;
var clipArray = [];

var $video1 = $("#video1");
var $video2 = $("#video2");
var $video3 = $("#video3");

$video1.attr("src", "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4");
$video2.attr("src", "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4");
$video3.attr("src", "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4");

var timerID;

var $canvas = $("#myCanvas");
var ctx = $canvas[0].getContext("2d");

function stopTimer() {
  window.clearInterval(timerID);
}

$('#startPlayback').click(function() {
  stopTimer();
  playCounter = $('#playbackNum').val();
  clipArray = [];

  // addd element to the end of the array
  clipArray.push(1);
  for (var i = 0; i < playCounter; i++) {
    clipArray.push(2);
  }
  clipArray.push(3);

  $video2[0].load();
  $video3[0].load();

  $video1[0].play();
});

function drawImage(video) {
  //last 2 params are video width and height
  ctx.drawImage(video, 0, 0, 640, 360);
}

// copy the 1st video frame to canvas as soon as it is loaded
$video1.one("loadeddata", function() {
  drawImage($video1[0]);
});

// copy video frame to canvas every 30 milliseconds
$video1.on("play", function() {
  timerID = window.setInterval(function() {
    drawImage($video1[0]);
  }, 30);
});
$video2.on("play", function() {
  timerID = window.setInterval(function() {
    drawImage($video2[0]);
  }, 30);
});
$video3.on("play", function() {
  timerID = window.setInterval(function() {
    drawImage($video3[0]);
  }, 30);
});

function onVideoEnd() {
  //stop copying frames to canvas for the current video element
  stopTimer();

  // remove 1st element of the array
  clipArray.shift();

  //IE fix
  if (!this.paused) this.pause();

  if (clipArray.length > 0) {
    if (clipArray[0] === 1) {
      $video1[0].play();
    }
    if (clipArray[0] === 2) {
      $video2[0].play();
    }
    if (clipArray[0] === 3) {
      $video3[0].play();
    }
  } else {
    // in case of last video, make sure to load 1st video so that it would start from the 1st frame 
    $video1[0].load();
  }
}

$video1.on("ended", onVideoEnd);
$video2.on("ended", onVideoEnd);
$video3.on("ended", onVideoEnd);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<div id="border">
  <video id="video1" width="640" height="360" hidden>
            <source type="video/mp4">
            Your browser does not support playing this Video
        </video>
  <video id="video2" width="640" height="360" hidden>
            <source type="video/mp4">
            Your browser does not support playing this Video
        </video>
  <video id="video3" width="640" height="360" hidden>
            <source type="video/mp4">
            Your browser does not support playing this Video
        </video>
  <div>
    <canvas id="myCanvas" width="640" height="360"> </canvas>
  </div>
  <div role="controls">
    <div>
      <label>
           Times the middle video will repeat itself:
      </label>
    </div>
    <div>
      <input id="playbackNum" value="1" />
    </div>
    <p>
      <button id="startPlayback">Start</button>
    </p>
  </div>
</div>

Please note, the code is not very pretty and would benefit from some cleanup and optimization, but at least this should show the way to work around the problem and implement a seamless playback of several videos in HTML5. Also make sure to include jQuery source file in html file location for the code to work.

like image 170
Tanuki Avatar answered Oct 22 '22 09:10

Tanuki