Shaka Packager for MPEG-DASH Packaging – Live and VOD

In this edition of the Hitchhiker’s Guide to MPEG-DASH, we dig into the Shaka MPEG DASH tools. Shaka is a versatile toolkit that can package and encrypt videos for transmission using the MPEG-DASH protocol. Shaka is free, BSD 3-clause open-source, and very easy to use – as we’ll see in this tutorial. 

MPEG-DASH is one of the most popular video-streaming protocols and is widely used to deliver media via Video on Demand (VOD) or Live Streaming to various end-user devices, including smartphones, tablets, SmartTVs, gaming consoles, and more.

Fundamental to the MPEG-DASH protocol is the manifest or MPD (Media Presentation Description) created when the media is packaged and prepared for transmission via DASH.

MPEG-DASH packaging using Shaka packager

So, without further ado, let’s dive deep into the Shaka packager and learn how to package and create MPEG-DASH compliant bitstreams for both Live and VOD streaming using Shaka packager.

Shaka Toolkit Licensing

The Shaka toolkit developer Google licenses it under the BSD 3-clause license.

Supported Platforms

Shaka is available with pre-compiled binaries for Docker, Windows 10, macOSX, and Linux x86_64. Cross-compiling for ARM is also supported.

Getting the Shaka Toolkit

There are three ways to get hold of the Shaka toolkit –

  1. Using Docker. Instructions are available here.
  2. Go to Shaka’s GitHub page and download the latest release.
  3. Or, go to the Shaka downloads page to download binaries for Windows 10, macOSX, and Linux.

Shaka provides a single command-line tool packager to do the fragmenting and packaging. The Shaka GitHub page names these files packager-win.exe, packager-osx, and packager-linux for Windows, MacOSX, and Linux. This article uses the generic name packager.

Shaka Packager for MPEG-DASH VOD and Live Packaging

Packaging a Video

Now that we have the packaging toolkit installed, let’s package a video for DASH streaming.

Step 0: Content Preparation

The packager doesn’t change the actual content encoding, just the file packaging format. You need to encode the content for streaming before you get to the actual packaging. Encoding a video for streaming is a whole subject on its own, but here are the key things to remember.

  • Codecs: HEVC is the most efficient video codec currently in use, but it is not as widely supported as H264. MPEG DASH allows you to encode the video using both codecs, each in its own Adaptation Set.
  • Bitrates/Resolutions: Adaptive Bitrate (ABR) streaming lets you encode the video in a range of bitrates and resolutions, allowing for uninterrupted viewing under a wide range of network bandwidths.
  • GOP Length: MPEG DASH requires all of the Representations in an Adaptation Set to have the same GOP length. Consistent GOP lengths allow the media player to switch representations from one segment to the next. Each segment will contain one or more GOPs. For example, if the GOP length is 2 seconds, you can package the content with segments that are 2 seconds, 4 seconds, 6 seconds, etc.

For the following example, we will be using a video encoded in four different resolutions:

myvideo_1920x1080.mp4
myvideo_1280x720.mp4
myvideo_640x360.mp4
myvideo_320x180.mp4

Note: read OTTVerse’s Introduction to Video Encoding for a deeper look at video compression.

Step 1: Fragmenting the Video

The Shaka packager command-line tool fragments the video during the packaging step. You do not need to fragment the video files before packaging.

Step 2: Packaging the Video

Shaka provides two different methods for packaging DASH content. 

  • The default method creates one file for each representation, where the individual segments are accessed using HTTP byte ranges. A result is a small number of media files, where each segment is defined individually with the corresponding byte range.
  • The alternative method creates separate files for each segment. The result is lots of segment files using segment templates.

Packaging with Byte-range Segments

To prepare byte-range DASH content with the Shaka packager, the parameters are:

  • in adds a file to the representations. You must indicate which stream (audio or video) to use for the output and the output file name. You can specify the directory for the files and the name of the file. If the specified directory does not exist, the packager will create it for you. The output directory can be different for each file if you want.
  • --segment_duration sets the fragment duration in seconds. The actual segment duration will be the closest value consistent with the media file GOP duration.
  • --mpd_output sets the MPD file name. You can specify the directory for the MPD and the name of the file. If the specified directory does not exist, the packager will create it for you.
$ packager \ in=myvideo_1920x1080.mp4,stream=audio,out=myvideo/audio.mp4 \
in=myvideo_1920x1080.mp4,stream=video,out=myvideo/1920x1080.mp4 \
in=myvideo_1280x720.mp4,stream=video,out=myvideo/1280x720.mp4 \
in=myvideo_640x360.mp4,stream=video,out=myvideo/640x360.mp4 in=myvideo_320x180.mp4,stream=video,out=myvideo/320x180.mp4 \
--segment_duration 4 \
--mpd_output myvideo/myvideo.mpd

Here is the resulting DASH MPD file myvideo.mpd.

<?xml version="1.0" encoding="UTF-8"?>
<!--Generated with https://github.com/google/shaka-packager version v2.4.3-dd98700-release-->
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT339.239990234375S">
  <Period id="0">
    <AdaptationSet id="0" contentType="video" maxWidth="1920" maxHeight="1080" frameRate="12800/256" subsegmentAlignment="true" par="16:9">
      <Representation id="0" bandwidth="283138" codecs="avc1.640015" mimeType="video/mp4" sar="1:1" width="320" height="180">
        <BaseURL>320x180.mp4</BaseURL>
        <SegmentBase indexRange="869-1920" timescale="12800">
          <Initialization range="0-868"/>
        </SegmentBase>
      </Representation>
      <Representation id="1" bandwidth="896084" codecs="avc1.64001f" mimeType="video/mp4" sar="1:1" width="640" height="360">
        <BaseURL>640x360.mp4</BaseURL>
        <SegmentBase indexRange="871-1922" timescale="12800">
          <Initialization range="0-870"/>
        </SegmentBase>
      </Representation>
      <Representation id="2" bandwidth="2405660" codecs="avc1.640020" mimeType="video/mp4" sar="1:1" width="1280" height="720">
        <BaseURL>1280x720.mp4</BaseURL>
        <SegmentBase indexRange="869-1920" timescale="12800">
          <Initialization range="0-868"/>
        </SegmentBase>
      </Representation>
      <Representation id="3" bandwidth="4298566" codecs="avc1.64002a" mimeType="video/mp4" sar="1:1" width="1920" height="1080">
        <BaseURL>1920x1080.mp4</BaseURL>
        <SegmentBase indexRange="871-1922" timescale="12800">
          <Initialization range="0-870"/>
        </SegmentBase>
      </Representation>
    </AdaptationSet>
    <AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
      <Representation id="4" bandwidth="133169" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
        <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
        <BaseURL>audio.mp4</BaseURL>
        <SegmentBase indexRange="822-1873" timescale="44100">
          <Initialization range="0-821"/>
        </SegmentBase>
      </Representation>
    </AdaptationSet>
  </Period>
</MPD>

Packaging with Individual Segment Files

To prepare individual segment file DASH content with the Shaka packager, the parameters are:

  • in adds a file to the representations. You must indicate which stream (audio or video) to use for the output and the output file name. Add names for the initialization segment and the template for the media segments. You can specify the directory for the files and the name of the file. If the specified directory does not exist, the packager will create it for you. The output directory can be different for each file if you want.
  • --segment_duration sets the fragment duration in seconds. The actual segment duration will be the closest value consistent with the media file GOP duration.
  • --generate_static_live_mpd will create a static instead of dynamic MPD. Note that this will result in a Live MPD profile, even for VOD content.

--mpd_output sets the MPD file name. You can specify the directory for the MPD and the name of the file. If the specified directory does not exist, the packager will create it for you.

$ packager \
in=myvideo_1920x1080.mp4,stream=audio,init_segment='myvideo/audio_init.mp4',segment_template='myvideo/audio_$Number%03d$.m4s' \
in=myvideo_1920x1080.mp4,stream=video,init_segment='myvideo/1920x1080_init.mp4',segment_template='myvideo/1920x1080_$Number%03d$.m4s' \ 
in=myvideo_1280x720.mp4,stream=video,init_segment='myvideo/1280x720_init.mp4',segment_template='myvideo/1280x720_$Number%03d$.m4s' \ 
in=myvideo_640x360.mp4,stream=video,init_segment='myvideo/640x360_init.mp4',segment_template='myvideo/640x360_$Number%03d$.m4s' \ in=myvideo_320x180.mp4,stream=video,init_segment='myvideo/320x180_init.mp4',segment_template='myvideo/320x180_$Number%03d$.m4s' \ --segment_duration 10 \
--generate_static_live_mpd \
--mpd_output myvideo/myvideo.mpd

Here is the resulting DASH MPD file myvideo.mpd.

<?xml version="1.0" encoding="UTF-8"?>
<!--Generated with https://github.com/google/shaka-packager version v2.4.3-dd98700-release-->
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" profiles="urn:mpeg:dash:profile:isoff-live:2011" minBufferTime="PT2S" type="dynamic" publishTime="2021-04-16T23:20:19Z" availabilityStartTime="2021-04-16T23:20:06Z" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
  <Period id="0" start="PT0S">
    <AdaptationSet id="0" contentType="video" maxWidth="1920" maxHeight="1080" frameRate="12800/256" segmentAlignment="true" par="16:9">
      <Representation id="0" bandwidth="4101336" codecs="avc1.64002a" mimeType="video/mp4" sar="1:1" width="1920" height="1080">
        <SegmentTemplate timescale="12800" initialization="1920x1080_init.mp4" media="1920x1080_$Number%03d$.m4s" startNumber="1">
          <SegmentTimeline>
            <S t="0" d="128000" r="32"/>
            <S t="4224000" d="118272"/>
          </SegmentTimeline>
        </SegmentTemplate>
      </Representation>
      <Representation id="1" bandwidth="228071" codecs="avc1.640015" mimeType="video/mp4" sar="1:1" width="320" height="180">
        <SegmentTemplate timescale="12800" initialization="320x180_init.mp4" media="320x180_$Number%03d$.m4s" startNumber="1">
          <SegmentTimeline>
            <S t="0" d="128000" r="32"/>
            <S t="4224000" d="118272"/>
          </SegmentTimeline>
        </SegmentTemplate>
      </Representation>
      <Representation id="2" bandwidth="720891" codecs="avc1.64001f" mimeType="video/mp4" sar="1:1" width="640" height="360">
        <SegmentTemplate timescale="12800" initialization="640x360_init.mp4" media="640x360_$Number%03d$.m4s" startNumber="1">
          <SegmentTimeline>
            <S t="0" d="128000" r="32"/>
            <S t="4224000" d="118272"/>
          </SegmentTimeline>
        </SegmentTemplate>
      </Representation>
      <Representation id="3" bandwidth="2343747" codecs="avc1.640020" mimeType="video/mp4" sar="1:1" width="1280" height="720">
        <SegmentTemplate timescale="12800" initialization="1280x720_init.mp4" media="1280x720_$Number%03d$.m4s" startNumber="1">
          <SegmentTimeline>
            <S t="0" d="128000" r="32"/>
            <S t="4224000" d="118272"/>
          </SegmentTimeline>
        </SegmentTemplate>
      </Representation>
    </AdaptationSet>
    <AdaptationSet id="1" contentType="audio" segmentAlignment="true">
      <Representation id="4" bandwidth="131387" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
        <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
        <SegmentTemplate timescale="44100" initialization="audio_init.mp4" media="audio_$Number%03d$.m4s" startNumber="1">
          <SegmentTimeline>
            <S t="0" d="441344" r="1"/>
            <S t="882688" d="440320"/>
            <S t="1323008" d="441344" r="1"/>
            <S t="2205696" d="440320"/>
            <S t="2646016" d="441344" r="1"/>
            <S t="3528704" d="440320"/>
            <S t="3969024" d="441344" r="1"/>
            <S t="4851712" d="440320"/>
            <S t="5292032" d="441344" r="1"/>
            <S t="6174720" d="440320"/>
            <S t="6615040" d="441344" r="1"/>
            <S t="7497728" d="440320"/>
            <S t="7938048" d="441344" r="1"/>
            <S t="8820736" d="440320"/>
            <S t="9261056" d="441344" r="1"/>
            <S t="10143744" d="440320"/>
            <S t="10584064" d="441344" r="1"/>
            <S t="11466752" d="440320"/>
            <S t="11907072" d="441344" r="1"/>
            <S t="12789760" d="440320"/>
            <S t="13230080" d="441344" r="1"/>
            <S t="14112768" d="440320"/>
            <S t="14553088" d="407552"/>
          </SegmentTimeline>
        </SegmentTemplate>
      </Representation>
    </AdaptationSet>
  </Period>
</MPD>

Step 3: Hosting the DASH Video

Now that we have the video packaged, the final step is to put it onto a web server for streaming.  Copy the entire contents of the output directory to your web server, and make sure to set the MIME TYPE of .mpd files to application/dash+xml so that the web browser will know to send it to the DASH player.

Packaging a Live Video using Shaka Packager

Shaka also supports real-time DASH packaging for Live video. There are two essential differences. You will use named pipes instead of actual media files on the input side. You need to push the packaged media files and manifests to the server promptly to minimize latency on the output side. See the basic architecture below.

shaka packager for mpeg-dash

Live Packaging Parameters

The packager parameters are slightly different for live packaging.

  • in adds a file to the representations. You must indicate which stream (audio or video) to use for the output and the output file name. Add names for the initialization segment and the template for the media segments. You can specify the directory for the files and the name of the file. If the specified directory does not exist, the packager will create it for you. The output directory can be different for each file if you want.
  • --segment_duration sets the fragment duration in seconds. The actual segment duration will be the closest value consistent with the media file GOP duration.
  • --mpd_output sets the MPD file name. You can specify the directory for the MPD and the name of the file. If the specified directory does not exist, the packager will create it for you.
  • --segment-name defines the segment names, the same as VOD.
  • --profile sets the DASH MPD profile. For live use the live profile.
  • --time_shift_buffer_depth defines the MPD duration in seconds. The MPD duration controls how long segments remain in the MPD, allowing users to seek backward and replay. For example, 900 will enable the users to go back up to 15 minutes.
  • --preserved_segments_outside_live_window defines the number of segments to preserve. Older segments are automatically deleted. Set it to match the segment duration and time-shift buffer duration. For example, with 10-second segments and a 900-second buffer, the value would be 90.

The resulting command is:

$ packager \
in=audio.aac,stream=audio,init_segment='myvideo/audio_init.mp4',segment_template='myvideo/audio_$Number%03d$.m4s' \
in=1080p.h264,stream=video,init_segment='myvideo/1920x1080_init.mp4',segment_template='myvideo/1920x1080_$Number%03d$.m4s' \
in=720p.h264,stream=video,init_segment='myvideo/1280x720_init.mp4',segment_template='myvideo/1280x720_$Number%03d$.m4s' \
in=360p.h264,stream=video,init_segment='myvideo/640x360_init.mp4',segment_template='myvideo/640x360_$Number%03d$.m4s' \
in=180p.h264,stream=video,init_segment='myvideo/320x180_init.mp4',segment_template='myvideo/320x180_$Number%03d$.m4s' \
--segment_duration 10 \
--time_shift_buffer_depth 900 \
--preserved_segments_outside_live_window 90 \
--mpd_output myvideo/myvideo.mpd

Conclusion

Thanks for reading this tutorial on MPEG-DASH packaging using Shaka’s MPEG-DASH toolbox. I hope this helped you create MPEG-DASH-compliant bitstreams and you were able to successfully stream your content to a DASH-compliant player.

Note, if you are new to video streaming and MPEG-DASH, then these articles will help you get to speed.

Until next time, stay safe, and happy streaming.

Ron Garrison
Ron Garrison

Ron has lead streaming optimization Product Management teams at companies including Ortiva Wireless, Allot Communications, and MediaMelon.

1200x200-Pallycon

Leave a Comment

Your email address will not be published. Required fields are marked *

Enjoying this article? Subscribe to OTTVerse and receive exclusive news and information from the OTT Industry.