Skip to content

Rewinding (DVR) while playing HLS

A current playlist segments are cached by a browser while playing HLS. This allows to rewind a stream back (a simple DVR function) in HLS player. Let's consider the DVR implementation based on VideoJS.

The following parameters should be set when creating a VideoJS player instance

code

const LIVE_THRESHOLD = 5;
const LIVE_TOLERANCE = 5;
...
const initVideoJsPlayer = function(video) {
    let videoJsPlayer = videojs(video, {
        ...
        liveui: true,
        liveTracker: {
            trackingThreshold: LIVE_THRESHOLD,
            liveTolerance: LIVE_TOLERANCE
        },
        ...
    });
    ...
    return videoJsPlayer;
}

Where:

  • liveui: true - enables rewind interface
  • liveTracker.trackingThreshold - sets a minimal time in seconds to play before displaying rewind interface
  • liveTracker.liveTolenrace - sets how far from the seekable end should be considered live playback, in seconds

A maximum time to rewind back depend on a segments count in playlist and on a segment size. The parameters are set at server side

hls_list_size=8
hls_time_min=2000

By default, the maximum time to rewind is 16 seconds

8 * 2000 = 16000

Playlist size should be increased to rewind a more time back

hls_list_size=30

Segment size should not be changed because some browsers (Safari) may stop playing HLS segments of other size.

Use Player.currentTime() method to rewind a currently playing stream. Get the maximum time range to rewind using Player.seekable() method

code

const backBtnClick = function(event) {
    if (player != null && player.liveTracker) {
        ...
        let seekable = player.seekable();
        let backTime = -1;
        if (event.target.id.indexOf("10") !== -1) {
            backTime = player.currentTime() - 10;
        } else if (event.target.id.indexOf("30") !== -1) {
            backTime = player.currentTime() - 30;
        }
        if (backTime < 0) {
            backTime = seekable ? seekable.start(0) : player.currentTime();
        }
        player.currentTime(backTime);
    }
}

Use Player.liveTracker.seekToLiveEdge() to return back to live playback

code

const liveBtnClick = function() {
    if (player != null && player.liveTracker) {
        player.liveTracker.seekToLiveEdge();
        ...
    }
}

Rewind interface may not be enabled for the first HLS subscriber, in this case the Player.liveTracker.seekToLiveEdge() method should be called explicitly after some time since playback starts

code

const liveUIDisplay = function() {
    stopLiveUITimer()
    if (player && player.liveTracker) {
        liveUITimer = setInterval(function() {
            if (!player.liveTracker.isLive() && player.liveTracker.liveWindow() > LIVE_THRESHOLD) {
                // Live UI is not displayed yet, seek to live edge to display
                player.liveTracker.seekToLiveEdge();
            }
        }, LIVE_UI_INTERVAL)
    }
}