Reputation: 1264
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
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
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
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