18

I'm trying to play an 8.6 second video once completely, and then loop a small section of the video infinitely, to keep the illusion of a never-ending video. So far I've looked into the media fragments URI, and the ended event of the video. Setting the currentTime attribute in the ended event listener works, but it makes the video "blink".

At present, I'm using a timeupdate event listener to change the time when the video is approaching the end [shown below]

elem.addEventListener('timeupdate', function () {
if (elem.currentTime >= 8.5) {
    elem.currentTime = 5;
    elem.play();
}
}, false);

JSFiddle here

This works as well, but the video pauses visibly before restarting at 5 seconds. Is there a smoother way of playing the video once and then looping a segment of it?

WeNeigh
  • 3,489
  • 3
  • 27
  • 40

5 Answers5

3

Your code is fine, the problem is with your MP4 file! Try using a much smaller video like this one ( http://www.w3schools.com/tags/movie.mp4 ) to confirm the issue is not with your code.

So how can you achieve the same result but with large videos files? You will need two video files:

  • video1 is the main video
  • video2 is the looping video

Remember: HTML5 video has no problem playing and looping large video files so we will use this method to play the videos.

In the example below we will play the first video and when it finishes we will execute a function to hide video1 and then show/play video2. (Video 2 is already set to loop)

Don't forget to load JQuery in your head otherwise this will not work.

<video id="video1" width="1080" height="568" poster="movie.png" autoplay onended="run()">
  <source src="movie.webm" type="video/webm">
  <source src="movie.ogg" type="video/ogg">
  <source src="movie.mp4" type="video/mp4">
  <object data="movie.mp4" width="1080" height="568">
    <embed width="1080" height="568" src="movie.swf">
  </object>
Optional test to be displayed if the browser doesn't support the video tag (HTML 5)
</video>


<video id="video2" width="1080" height="568" poster="loop.png" loop>
  <source src="loop.webm" type="video/webm">
  <source src="loop.ogg" type="video/ogg">
  <source src="loop.mp4" type="video/mp4">
  <object data="loop.mp4" width="1080" height="568">
    <embed width="1080" height="568" src="loop.swf">
  </object>
Optional test to be displayed if the browser doesn't support the video tag (HTML 5)
</video>


<script> 
$( "#video2" ).hide();
function run(){
   $( "#video1" ).hide();
    $( "#video2" ).show();
    document.getElementById("video2").play();
   };
</script> 
Tremours
  • 245
  • 2
  • 9
2

Try the following, to 'rewind' it as soon as it ends:

vidElem.addEventListener("ended", function () {
        vidElem.currentTime = 2.5;
        vidElem.play();
}, false);

Updated fiddle: http://jsfiddle.net/Lt4n7/1/

Max
  • 2,082
  • 19
  • 25
  • Thanks, but I already tried using the ended event listener. Perhaps that was the wrong sample video to use (It has its own pauses), but there's a clear pause before the video moves to 2.5 seconds. I'm looking to make the loop seamless. – WeNeigh Jan 21 '14 at 07:59
  • Try splitting it up into two videos – Max Jan 21 '14 at 08:16
  • 1
    You mean a full-length video and a video of the bit I want to loop? That seems wasteful! There's *got* to be an HTML5+JS way! :) – WeNeigh Jan 21 '14 at 09:02
  • just the video up to the part you want to loop. If you could create a fiddle with a loopable example, that'd also help a lot – Max Jan 21 '14 at 18:48
  • Worked great for me. Wrapped it in a jQuery ready, and done. `$(function(){ var vidElem = $("#bgvid>VIDEO")[0]; vidElem.addEventListener("ended", function () { vidElem.currentTime = 21; vidElem.play(); }, false); });` – Bernesto Jan 04 '16 at 07:14
  • 2
    FYI this doesn't work well with some videos because sometimes the browser just can't change the `currentTime` and play instantly, so you'll have a delay between each loop. [Using two videos](https://stackoverflow.com/a/25722747/288906) is (sadly) more reliable. – fregante Apr 20 '18 at 06:36
2

I just had to deal with the same problem and noticed the same issues with flickering. Here was my solution:

  • Get 2 videos (or sets of videos) - one for the non-looped section, the other for the looped section
  • Create 2 video elements
  • set the looping element to 'display:none'

Then just capture the ended event and swap display status (example uses jquery but you could use 'style.display="none/block"' just as easily:

VideoPlayer1 = document.getElementById('video1');
VideoPlayer2 = document.getElementById('video2');
VideoPlayer1.addEventListener('ended', videoLooper, false);

function videoLooper()
{
    VideoPlayer2.play();
    $(VideoPlayer2).show();
    $(VideoPlayer1).hide();
}
Random
  • 31
  • 3
2

You can't solve this issue in javascript. That delay you see depends on the video compression and the hardware.

To start playing at a time that is not 0, the video decoder has to go back and find a key frame and then build the current frame by reading everything between the last key frame and your chosen time.

I'm not an expert in video compression, but maybe there is a way to pick these key frames and place them exactly where you need them. I don't think it will be easy and smooth, though.


If you're looking for an easier solution, use @Random's, but it uses two <video> tags to work around this limit.

Community
  • 1
  • 1
fregante
  • 29,050
  • 14
  • 119
  • 159
0

var iterations = 1;
var flag = false;
document.getElementById('iteration').innerText = iterations;
var myVideo = document.getElementById('video-background');
myVideo.addEventListener('ended', function() {
  alert('end');
  if (iterations < 2) {
    this.currentTime = 0;
    this.play();
    iterations++;
    document.getElementById('iteration').innerText = iterations;
  } else {
    flag = true;
    this.play();
  }
}, false);
myVideo.addEventListener('timeupdate', function() {
  if (flag == true) {
    console.log(this.currentTime);
    if (this.currentTime > 5.5) {
      console.log(this.currentTime);
      this.pause();
    }
  }
}, false);
<div>Iteration: <span id="iteration"></span></div>

<video id="video-background" autoplay="" muted="" controls>
            <source src="https://res.cloudinary.com/video/upload/ac_none,q_60/bgvid.mp4" type="video/mp4">
    </video>
<div>Iteration: <span id="iteration"></span></div>

// Please note that loop attribute should not be there in video element in order for the 'ended' event to work in ie and firefox

Mateus Wolkmer
  • 706
  • 4
  • 26
dxpkumar
  • 371
  • 2
  • 9
  • Please check here for reference https://jsfiddle.net/dxpkumar/fuqmfde8/ – dxpkumar Aug 10 '17 at 09:10
  • While this code snippet may be the correct solution, [including an explanation](https://meta.stackexchange.com/questions/114762/explaining-entirely-%E2%80%8C%E2%80%8Bcode-based-answers) really helps to improve quality of your post. Remember that you're answering for readers in the future, and those people might not know the reasons behind your code suggestion. Also, please add link the answer itself and not as a comment. – Milan Chheda Aug 10 '17 at 09:44