HTML5 Video: Synchronizing Playback of Two Videos

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.

  1. 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.

  2. 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)
    }

  3. 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;
    }

Contact Us

We'd love to hear from you. Get in touch!

Mail

P.O. Box 961436
Boston, MA 02196