How to play a video in a Seamless loop using media source extensions
Asked Answered
V

4

16

I am working on media source extension to play the video in a seamless loop without any delay. I have done an extensive r&d about it and also done different things. Now i am working on this code

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
  </head>
  <body>
    <video controls></video>
    <script>
      var video = document.querySelector('video');
      var assetURL = 'test1.mp4';
      // Need to be specific for Blink regarding codecs
      // ./mp4info frag_bunny.mp4 | grep Codec
      var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
      if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
        var mediaSource = new MediaSource;
        //console.log(mediaSource.readyState); // closed
        video.src = URL.createObjectURL(mediaSource);
        mediaSource.addEventListener('sourceopen', sourceOpen);
      } else {
        console.error('Unsupported MIME type or codec: ', mimeCodec);
      }
      function sourceOpen (_) {
        //console.log(this.readyState); // open
        var mediaSource = this;
        var sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
        fetchAB(assetURL, function (buf) {
          sourceBuffer.addEventListener('updateend', function (_) {
            mediaSource.endOfStream();
            video.play();
            //console.log(mediaSource.readyState); // ended
          });
          sourceBuffer.appendBuffer(buf);
        });
      };
      function fetchAB (url, cb) {
        console.log(url);
        var xhr = new XMLHttpRequest;
        xhr.open('get', url);
        xhr.responseType = 'arraybuffer';
        xhr.onload = function () {
          cb(xhr.response);
        };
        xhr.send();
      };
    </script>
  </body>
</html>

It is working fine but the video is playing again with a slight delay. I want to play the video without any delay and I know that it is possible with media source extensions but after spending a lot of time still didn't get any idea that how to do it. Any help would be really appreciated. Thanks

Veneer answered 20/2, 2017 at 23:2 Comment(5)
Hey, did you ever get anywhere with this? I'm struggling with the same problem.Crescantia
video tag (in HTML, besides "controls") can get "autoplay" attribute. not work for you? you can also manipulate this from js - video.autoplay = true/falseKono
Are you trying to bypass the policy that forces the mute attribute on autoplay videos as described here: developers.google.com/web/updates/2017/09/…?Tortile
I personally am not interested in autoplay, nor is it mentioned anywhere in this question. I am interested in seamless looping - no delay between playing a piece of media content, and still being able to seek correctly with the same duration. No matter what I try, I get a few-hundred ms delay in between loops of content (worse on mobile). Now that I think about it, perhaps I should have opened my own question.Crescantia
The video has to be loaded into memory in order to be able to play it. Could this be the cause of the behaviour?Flodden
B
1

Setting the mode value to sequence worked for me, it ensures continuous media playback, no matter if the media segment timestamps were discontinuous.

sourceBuffer.mode = 'sequence';
Bick answered 30/12, 2019 at 6:25 Comment(0)
S
0

May be this code solve Your Problem ....play the video in a seamless loop without any delay

for (let chunk of media) {
        await new Promise(resolve => {
          sourceBuffer.appendBuffer(chunk.mediaBuffer);
          sourceBuffer.onupdateend = e => {
            sourceBuffer.onupdateend = null;
            sourceBuffer.timestampOffset += chunk.mediaDuration;
            console.log(mediaSource.duration);
            resolve()
          }
        })

      }

if you need more information visit this link..... http://www.esjay.org/2020/01/01/videos-play-without-buffering-in-javascript/

Somato answered 1/1, 2020 at 12:2 Comment(1)
Tried this out, but it still exhibits the slight pause before it loops. Tested in Chrome on mobile, on desktop, as well as Firefox. The only thing I've found that does seem to work is to wait for the timeupdate event and append the same thing to the end right before it hits the end (thus truely seamless playback), but that means that the duration is extended, slight increase in memory usage each loop, and that I have to fake the duration for my video player's chrome.Crescantia
A
0

You can't really do that because it really depends on how fast your PC runs. Its delay should only be there if you have a slow PC but if not it shouldn't have a noticeable delay. Maybe the video that you have is big or it just delays inside the video because only thing I could tell you is autoplay loop inside the videos element as a attribute unless you find a way to replay the video before the video ends but even if it doesn't delay for you it may delay big or just play over the video for others

Asquith answered 23/5, 2022 at 3:39 Comment(1)
This is incorrect. It is possible. Please fix the answer (with a working result after trying the provided test code). I even did it 10 years ago in Adobe Flash (using its appendBytes API which is equivalent to MSE's appendBuffer). The Answer will come from understanding (1) What a browser does when a video ends, and how to avoid it. (2) What an MPEG decoder does when given a fragmented MP4 (think "Moov" atom vs the "Moof+Mdat" combo) and how to use it to play seamlessly. (3) Working with timestamp values (work with or edit the given values) to make seamless repeats...Aeriform
A
0

@CoolOppo

The simplest thing to do is to just rewind the video when it reaches it's end time (duration).

See demo here: https://vc-lut.000webhostapp.com/demos/public/mse_loop_example1.html
(to play video just click the picture part, since no controls for looping background)

The code:

<!DOCTYPE html>
<html>
<head> <meta charset="utf-8"/> </head>
<body>

<div>
<video id="video_mse" > </video>
</div>

<script>

var assetURL = "testloop.mp4";

//# use correct mime/codecs or else Error is "source not open"...
var mimeCodec = 'video/mp4; codecs="avc1.42C01E"';

var mediaSource; var sourceBuffer;

var video = document.getElementById( "video_mse" );

video.onclick = vid_togglePlay; //# for playing/pausing
video.ontimeupdate = vid_checkTime; //# for looping

//# handle play/pause (because controls are hidden)
function vid_togglePlay() 
{
    if( video.paused == true ) { video.play(); }
    else { video.pause(); }
}

//# handle looping...
function vid_checkTime() 
{
    if( video.currentTime == video.duration)
    { 
        video.currentTime = 0; 
        video.play(); 
    } 
}

if ( 'MediaSource' in window && MediaSource.isTypeSupported(mimeCodec) ) 
{
    mediaSource = new MediaSource;
    
    video.src = URL.createObjectURL(mediaSource);
    mediaSource.addEventListener('sourceopen', sourceOpen);
} 
else 
{ console.error('Unsupported MIME type or codec: ', mimeCodec); }

function sourceOpen() 
{
    //console.log(this.readyState); // open
    var mediaSource = this;
    sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
    
    fetchAB(assetURL, function (buf) {
        sourceBuffer.addEventListener('updateend', function() {
        mediaSource.endOfStream();
        video.play();
      });
      
      sourceBuffer.appendBuffer(buf);
    
    });
};

function fetchAB (url, callbackfunc ) 
{
    console.log("loading file: " + url);
    var xhr = new XMLHttpRequest;
    xhr.open('get', url);
    xhr.responseType = 'arraybuffer';
    xhr.onload = function() { callbackfunc( xhr.response ); }
    xhr.send();
}
      
</script>
</body>
</html>
Aeriform answered 27/5, 2022 at 9:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.