Upon first thought, you might think that synchronized playback of two video elements would be simple – however – because the timeupdate
event of the video element is indeterminate beyond its specification description of “Every 15 to 250ms, or whenever the MediaController’s media controller position changes”, this is actually non-trivial.
Today, on the Web Made Movies mailing list, a poster asked whether or not Popcorn.js was capable of synchronizing the playback of multiple videos or video and audio elements. While Popcorn.js does not ship with any kind of “sync A to B” functionality, it occurred to me that such a task should not be hard to achieve using Popcorn.js’s event management system.
With simplicity in mind, the concept goes like this: when Video A does something, trigger the same behaviour on Video B. Behaviours include, but are not limited to events such as play, pause, seeking and timeupdate. Armed with a rough plan, I created following fiddle….
After posting this back to the mailing list, Ben Moskowitz upped the ante by pointing out that synchronizing two videos is a much different beast, noting the example given on HTML5Demos.com – which easily falls out of sync (this fact is clearly a known flaw, hence the emphasis on “should” in the description).
So I returned to the fiddle and began reworking the demo to use two videos instead of an audio and video combo and I realized that what was needed was a simple way to subtly “re-sync” the video’s currentTime
value, enter requestAnimationFrame
. With requestAnimationFrame
, I was able to quietly re-sync the two videos as frequently as the browser would allow:
Thanks to Paul Irish for requestAnimFrame()
Comments
We moved off of Disqus for data privacy and consent concerns, and are currently searching for a new commenting tool.
i tried this myself. doing animation frame all the time does not work. it just hangs the player. i think a better\u00a0solution\u00a0would\u00a0be to do it on specific situation when\u00a0required.
cool demonstration! eventhough HTML5 audio player might not pack all of the features it works well.. it let\u2019s iOS folk hear the mp3, tho the player will launch in a new webpage; and to return to your original page, html5 music player
Interesting stuff. You need to use requestAnimationFrame now. requestAnimFrame returns an error.
Hi Jude, requestAnimFrame is a shim provided by Paul Irish, which uses requestAnimationFrame: https://raw.github.com/gist…
If you experience lags in second video, just add the folowing check into sync function. This prevents syncing each time.
time=videos.a.currentTime()
b_time=videos.b.currentTime()
if (Math.abs(time-b_time)>0.1){
videos.b.currentTime(time)
}
Perfect! Very important!
Perfect!
doesn’t work on chrome, not sync at all.
IE yes
FF yes
HELP, it says Popcorn not defined. How do i fix this?
\\
Can this be done between multiple clients? For example if I had three Raspberry Pi(s) running side-by-side-by-side could I sync the video on all three?
Once, HTML5 video streams are in sync and playing, they will begin to drift out of sync. This is due to performance issues in the player and hardware. So, as in your example, above, the streams must constantly be put back into sync. However, I did not have any luck with setting currentPosition on the feeds to keep them in sync. Any change to currentPosition fires off events which cascade through the rest of my code and cause all types of issues. The streams would never stay in sync. If the streams were in sync one moment, three seconds later due to drift, they would start creeping out of sync. A minute later they could be seconds out of sync. I came up with the solution, below, which adjusts the playback rate of the videos, forcing them to stay in sync. Example: _masterPlayer is playing at a rate of 1.00. _slavePlayer[0] is sped up to 1.02 until it catches up with _masterPlayer. I found it works best when fired off 5-10 times per second.
//Compensate for discrepency in playback sync by changing the frame rate of the player(s)
//timeDiff is used to allow videos to start at different times
//_masterPlayer is the track whose playback rate will be steady
//_slavePlayers are all the tracks who will be forced to stay in sync with _masterPlayer
for (i = 0; i < _slavePlayers.length; i++) {
var timeDiff = ((_masterPlayer.currentTime + _masterStartOffset) – (_slavePlayers[i].currentTime + _slaveStartOffsets[i]));
var compensatingFrameRate = ((Math.min(Math.max((timeDiff / 2 + 1), 0.33), 3.00))).toFixed(2);
if (compensatingFrameRate > .99 && compensatingFrameRate < 1.01) {
compensatingFrameRate = 1.00;
} else {
if ((i == 0 && !_slave0IsInBlackout) || (i == 1 && !_slave1IsInBlackout)) {
log.info(\”### video[\” + i + \”]FrameRate: \” + compensatingFrameRate);
}
};
_slavePlayers[i].playbackRate = compensatingFrameRate;
}
what is _masterStartOffset here?
I know that Popcorn.JS is not maintained and this is really old post,
Anyway, \”this.media.paused\” is a function. It should be \”this.media.paused()\”.
Thanks for the comment. `this.media` refers to the actual video element itself, which has a `paused` property, not a `paused()` method. https://html.spec.whatwg.or…