HLS, DASH and the VBRs conundrum

  • In the interest of giving back to this community from which I have learned sooo much, anyone interested in diving into the rabbit-hell-hole called VBRs delivery and seeing how we do it read on…

    The “issue” with VBRs natively in KRPano is they don’t work, except for HLS/Apple devices.
    DASH, what every other major browser uses for VBRs delivery uses requires a bridge to get it to work.
    That is where dash.js comes in.

    First, load dash.js
    <script type="text/javascript" src="/node_modules/dashjs/dist/dash.all.min.js"></script>

    Second, create the following function. The URL is the path to a dash.mpd file. It logs a few parameters so you know what's going on.
    function initDash(url){
    console.log('initDash...JS ' + url);
    let video = krpano.get("plugin[video]”).videoDOM;
    const player = dashjs.MediaPlayer().create();
    streaming: {
    buffer: {
    fastSwitchEnabled: true
    abr: {
    initialBitrate: { audio: -1, video: 10000 }

    player.initialize(video, url, true);
    player.on(dashjs.MediaPlayer.events["PLAYBACK_ENDED"], function () {
    var eventPoller = setTimeout(function () {
    var streamInfo = player.getActiveStream().getStreamInfo();
    var dashMetrics = player.getDashMetrics();
    var dashAdapter = player.getDashAdapter();
    if (dashMetrics && streamInfo) {
    const periodIdx = streamInfo.index;
    var repSwitch = dashMetrics.getCurrentRepresentationSwitch('video', true);
    var bitrate = repSwitch ? Math.round(dashAdapter.getBandwidthForRepresentation(repSwitch.to, periodIdx) / 1000) : NaN;
    console.log(bitrate + " Kbps interval");
    }, 1000);
    if (video.webkitVideoDecodedByteCount !== undefined) {
    var lastDecodedByteCount = 0;
    const bitrateInterval = 5;
    var bitrateCalculator = setTimeout(function () {
    var calculatedBitrate = (((video.webkitVideoDecodedByteCount - lastDecodedByteCount) / 1000) * 8) / bitrateInterval;
    console.log( Math.round(calculatedBitrate) + " Kbps webkitVideoDecodedByteCount");
    lastDecodedByteCount = video.webkitVideoDecodedByteCount;
    }, bitrateInterval * 1000);
    } else {
    console.log('video.webkitVideoDecodedByteCount IS UNDEFINED !!!!!! ');

    Third, create the initDash action.
    <action name="initDash">
    trace('initDash...action ', %1);

    Fourth, for the plugin referenced in initDash():
    videourl.safari="<?php echo $base_path; ?>/HLS/master.m3u8"
    videourl.chrome="<?php echo $base_path; ?>/DASH/dash.mpd"
    videourl.edge="<?php echo $base_path; ?>/DASH/dash.mpd"
    videourl.firefox="<?php echo $base_path; ?>/DASH/dash.mpd"
    onloaded.chrome="initDash('<?php echo $base_path; ?>/DASH/dash.mpd')"
    onloaded.edge="initDash('<?php echo $base_path; ?>/DASH/dash.mpd')"
    onloaded.firefox="initDash('<?php echo $base_path; ?>/DASH/dash.mpd')"

    That is the easy part. Creating the DASH "package" with all of the chunks and reference files is the complicated one. It takes time and computational resources.
    We use FFMPEG on a custom built processing machine. I'm bound by NDA so I really can't let the cat completely out of the bag about how we pull this off.
    However, here are some links that will get you headed in the right direction.

    And here is an example of this in-action:
    Spin around and click "The Cellar" in any browser.
    For Safari, you'd see *.ts and for everything else *.m4s files showing up in the Network tab of developer-tools

  • Hi Douglas,

    thanks for sharing!
    Interesting stuff.
    Never really tried something like this though.
    Sad that it is such a pain in the a** to do some video streaming.

    Tuur *thumbsup*

  • Tuur,

    It truly is a PITA and I've turned this into a science-fair experiment. But the results are well worth it.
    It does help if you have an NVIDIA GPU. You can leverage hardware decoding/encoding in the FFMEPEG commands which does speed things up DRASTICALLY. Our weak link in the system is upload speeds to s3.

Participate now!

Don’t have an account yet? Register yourself now and be a part of our community!