cs.matyi
cs.matyi

Reputation: 1264

run 2 html video side by side at the same time JS

I would like to play 2 html video exactly at the same time (side-by-side).

I made a button which has a click EventListener on it. This listener trigger the 2 <video> tag to play it, but I think there is 150 ms a delay at the second play trigger.

index.html

<section>
    <video src="source1" id="video1"></video>
    <video src="source2" id="video2"></video>
    <button id="play">Play</button>
</section>

and here is the basic script.js file.

    const $video1 = document.getElementById('video1');
    const $video2 = document.getElementById('video2');
    const $play = document.getElementById('play');

    const playVideo = () => {
        $video1.play();
        $video2.play();
    };

    $play.addEventListener('click', playVideo);

These 2 videos are almost the same, except the first video size is about 12MB and the other one is around 20MB

What I tried:

Tried to add a console.time('video') that could logs the delay between each play function call, but that can be different in each environment.

Upvotes: 3

Views: 3163

Answers (3)

cs.matyi
cs.matyi

Reputation: 1264

UPDATE

Both of the answers was correct. What I didn't know, that one of the video file has sound, and the other don't. That caused the 150ms delay.

Solved it with ffmpeg. Create an .mp3 file with the sound (and play it with <audio>), and 2 .mp4 files without sound. They are playing exactly at the same time now.

Upvotes: 2

Mos&#232; Raguzzini
Mos&#232; Raguzzini

Reputation: 15821

The only way I'm aware of about playing video in sync is to emit a custom event to sync the video in requestAnimationFrame:

var videos = {
    a: Popcorn("#a"),
    b: Popcorn("#b"),
  },
  scrub = $("#scrub"),
  loadCount = 0,
  events = "play pause timeupdate seeking".split(/\s+/g);

// iterate both media sources
Popcorn.forEach(videos, function(media, type) {

  // when each is ready... 
  media.on("canplayall", function() {

    // trigger a custom "sync" event
    this.emit("sync");

    // set the max value of the "scrubber"
    scrub.attr("max", this.duration());

    // Listen for the custom sync event...    
  }).on("sync", function() {

    // Once both items are loaded, sync events
    if (++loadCount == 2) {

      // Iterate all events and trigger them on the video B
      // whenever they occur on the video A
      events.forEach(function(event) {

        videos.a.on(event, function() {

          // Avoid overkill events, trigger timeupdate manually
          if (event === "timeupdate") {

            if (!this.media.paused) {
              return;
            }
            videos.b.emit("timeupdate");

            // update scrubber
            scrub.val(this.currentTime());

            return;
          }

          if (event === "seeking") {
            videos.b.currentTime(this.currentTime());
          }

          if (event === "play" || event === "pause") {
            videos.b[event]();
          }
        });
      });
    }
  });
});

scrub.bind("change", function() {
  var val = this.value;
  videos.a.currentTime(val);
  videos.b.currentTime(val);
});

// With requestAnimationFrame, we can ensure that as 
// frequently as the browser would allow, 
// the video is resync'ed.
function sync() {
  if (videos.b.media.readyState === 4) {
    videos.b.currentTime(
      videos.a.currentTime()
    );
  }
  requestAnimationFrame(sync);
}

sync();
html{font-family:arial;}
<script src="https://static.bocoup.com/js/popcorn.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<video height="180" width="300" id="a" controls> 
<source src="https://videos.mozilla.org/serv/webmademovies/popcorntest.mp4"></source>
<source src="https://videos.mozilla.org/serv/webmademovies/popcorntest.ogv"></source>
<source src="https://videos.mozilla.org/serv/webmademovies/popcorntest.webm"></source>
</video>
<video height="180" width="300" id="b"> 
<source src="https://videos.mozilla.org/serv/webmademovies/popcorntest.mp4"></source>
<source src="https://videos.mozilla.org/serv/webmademovies/popcorntest.ogv"></source>
<source src="https://videos.mozilla.org/serv/webmademovies/popcorntest.webm"></source>
</video>

<input type="range" value="0" id="scrub" />

Ref: https://bocoup.com/blog/html5-video-synchronizing-playback-of-two-videos

Upvotes: 2

Altair312
Altair312

Reputation: 348

I will also add this link here, as evident someone had a very similar problem, albeit with audio

Run function after audio is loaded

It appears you are looking for this event listener "canplaythrough", check more in the link.

function checkAudio() {
  audioElem.setAttribute("src", audioFile);
  audioElem.addEventListener('canplaythrough', (event) => {
    resultScreen.innerHTML = "loaded audio";
  });
}

Upvotes: 1

Related Questions