We're hiring!
*

Generating MPEG-DASH streams for Open Source adaptive streaming with GStreamer

Stéphane Cerveau avatar

Stéphane Cerveau
June 12, 2020

Share this post:

Adaptive streaming is a technique to provide flexibility and scalability by offering variable bit-rate streams to the client. Designed to work over HTTP, it provides media content as separate streams with media type and various bit-rates, the client will be able to select according to its network bandwidth or its CPU power.

The most popular adaptive streaming systems are:

  • HLS (Apple HTTP Live Streaming)
  • MSS (Microsoft Smooth Streaming)
  • ADS (Adobe HTTP Dynamic Streaming)
  • MPEG-DASH (MPEG Dynamic Adaptive Streaming over HTTP)

MPEG-DASH is the most complete adaptive streaming technique. This format is based on an XML description file called an MPD (Media Presentation Description). This format describes a set of representations which has a media type (audio, video or subtitles) and provides various bit-rate or media format.

This solution is an open standard and is widely supported by the industry. For more information about it, you can visit the DASH-IF website.

In the example below, the MPD describes a static content with three media content type (adaptation sets). Each adaptations sets contains representations. The video has 5 different representations, which allows to switch to 5 different bit rates according to the playback constraints.

<MPD mediaPresentationDuration="PT634.566S" minBufferTime="PT2.00S" profiles="urn:hbbtv:dash:profile:isoff-live:2012,urn:mpeg:dash:profile:isoff-live:2011" type="static" 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">
 <BaseURL>./</BaseURL>
 <Period>
  <AdaptationSet id="1" mimeType="video/mp4" contentType="video" subsegmentAlignment="true" subsegmentStartsWithSAP="1" par="16:9">
   <SegmentTemplate duration="120" timescale="30" media="$RepresentationID$/$RepresentationID$_$Number$.m4v" startNumber="1" initialization="$RepresentationID$/$RepresentationID$_0.m4v"/>
   <Representation id="bbb_30fps_1280x720_4000k" codecs="avc1.64001f" bandwidth="4952892" width="1280" height="720" frameRate="30" sar="1:1" scanType="progressive"/>
   <Representation id="bbb_30fps_320x180_200k" codecs="avc1.64000d" bandwidth="254320" width="320" height="180" frameRate="30" sar="1:1" scanType="progressive"/>
   <Representation id="bbb_30fps_480x270_600k" codecs="avc1.640015" bandwidth="759798" width="480" height="270" frameRate="30" sar="1:1" scanType="progressive"/>
   <Representation id="bbb_30fps_640x360_800k" codecs="avc1.64001e" bandwidth="1013310" width="640" height="360" frameRate="30" sar="1:1" scanType="progressive"/>
   <Representation id="bbb_30fps_3840x2160_12000k" codecs="avc1.640033" bandwidth="14931538" width="3840" height="2160" frameRate="30" sar="1:1" scanType="progressive"/>
  </AdaptationSet>

  <AdaptationSet id="2" mimeType="audio/mp4" contentType="audio" subsegmentAlignment="true" subsegmentStartsWithSAP="1">
   <Accessibility schemeIdUri="urn:tva:metadata:cs:AudioPurposeCS:2007" value="6"/>
   <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
   <SegmentTemplate duration="192512" timescale="48000" media="$RepresentationID$/$RepresentationID$_$Number$.m4a" startNumber="1" initialization="$RepresentationID$/$RepresentationID$_0.m4a"/>
   <Representation id="bbb_a64k" codecs="mp4a.40.5" bandwidth="67071" audioSamplingRate="48000">
    <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
   </Representation>
  </AdaptationSet>

  <AdaptationSet id="3" mimeType="image/jpeg" contentType="image">
    <SegmentTemplate media="$RepresentationID$/tile_$Number$.jpg" duration="100" startNumber="1"/>
    <Representation bandwidth="12288" id="thumbnails_320x180" width="3200" height="180">
      <EssentialProperty schemeIdUri="http://dashif.org/thumbnail_tile" value="10x1"/>
    </Representation>
  </AdaptationSet>

 </Period>
</MPD>

DASH in GStreamer

Since 2012, GStreamer includes only a DASH client called dashdemux whereas, for HLS, it provides the both elements, demuxer and sink.

DASH Demuxer

This element landed in the GStreamer repository in 2012 and had evolved a lot since that time to support the various use-cases DASH offers in its specifications and its applications. Indeed it is able to support multiple streams (video/audio/subtitles) and allows the user to select from the available streams or automatically select the best representation according to the network.

DASH Sink

A first attempt to propose a DASH sink was also in 2012. The design was not mature enough to be landed and the author never had the time to complete it.

In 2014, a new element called splitmuxsink was introduced. It handles the most complex part of creating a fragmented stream, it cuts files with synchronized audio and video. Based on this element, a new HLS sink called hlssink2 was created in 2017. I decided to finally create a DASH sink based on this approach to fill the gap in GStreamer.

MPD Parser

In order to unify the MPD support, a first task has been to relocate and redesign the base classes to read, and write, an MPD file. Based on XML, the Media Presentation Description scheme is based on multiple nodes owning children and properties as described above. A first important work item was to split the code in 'objects' each identifying an XML node from the MPD schema, including the root node, periods, adaptation sets, etc. An object oriented approach has been selected to unify the work regarding the parsing, object property manipulation and the XML format generation.

The sink

Inspired from the work on hlssink2, the dash sink is a "super bin" and includes a splitmuxsink to provide the multiple media segments. Most of the challenge, here, was to write the MPD compliant with the DASHIF conformance test here with usable and suitable media segments.

This plugin is now capable of:

  • Multiple input audio/video streams
  • Multiple periods
  • TS segment supported (MP4 support is not yet complete), need additional work for the segment transition in short segment scheme.
  • Fragment segment with given duration
  • Static/Dynamic MPD (Passing the DASH-IF conformance test)

An example is worth a thousand words

In the following pipeline a static MPD file is created in /tmp along with one single segment long for a single video stream during a period of 60s. The segment will be encoded as H.264 and encapsulated in MPEG transpor stream files.

$ gst-launch-1.0 -m dashsink name=dashsink mpd-root-path=/tmp target-duration=60 dynamic=false period-duration=60000 muxer=ts  v4l2src ! video/x-raw,framerate=30/1,width=320,height=240 ! videoconvert ! queue ! x264enc bitrate=400 ! dashsink.video_0

Future work includes implementing support for creating MP4 fragment files following the CMAF (MPEG-A Part 19) specification.

If you would like to learn more about dashsink or any other parts of GStreamer, please contact us!

Comments (13)

  1. cb:
    Jan 04, 2021 at 11:57 AM

    I found this today, this is awesome! Im using hlssink2 for a while and always was looking for something similar for dash.

    Is there a reason why just ts and mp4 muxers are supported right now. I wanted to give it a try with VP9 ( The main reason why I would like to switch from HLS to DASH) but it does not seem to work. So it would be great if webm would be supported as well.

    Reply to this comment

    Reply to this comment

    1. Stéphane Cerveau:
      Jan 11, 2021 at 04:09 PM

      Thank you for your interest.

      Indeed webm is not supported yet by the dash sink. On the first version of the element, the target was to support the most common supported formats for DASH which are TS and MP4.

      If you need this support, feel free to contribute to the code on the GStreamer gitlab codebase. You can participate or follow this entry https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/1496#note_753320. Or you can contact us and we will be pleased to add this support for you.

      Reply to this comment

      Reply to this comment

  2. vandana:
    Feb 16, 2021 at 02:29 PM

    Thanks for the pipeline example for dashsink.

    However I get the below error when i have to read from dvbsrc instead of v4l2src:

    could not link dvbsrc0 to videoconvert0, dvbsrc0 can't handle caps video/x-raw, framerate=(fraction)30/1, width=(int)320, height=(int)240
    WARNING: erroneous pipeline: could not link dvbsrc0 to videoconvert0, dvbsrc0 can't handle caps video/x-raw, framerate=(fraction)30/1, width=(int)320, height=(int)240

    My pipeline:
    gst-launch-1.0 -m dashsink name=dashsink mpd-root-path=/tmp target-duration=60 dynamic=false period-duration=60000 muxer=ts dvbsrc modulation=5 adapter=0 frequency=165000000 delsys=dvb-c-b ! video/x-raw,framerate=30/1,width=320,height=240 ! videoconvert ! queue ! x264enc bitrate=400 ! dashsink.video_0

    Reply to this comment

    Reply to this comment

    1. Stéphane Cerveau:
      Feb 16, 2021 at 02:44 PM

      Hello,

      According to my understanding, the problem is related to the accepted caps of your "dvbsrc" and not really related to the "dashsink" itself.

      Could you please confirm that this pipeline works first:

      gst-launch-1.0 dvbsrc modulation=5 adapter=0 frequency=165000000 delsys=dvb-c-b ! video/x-raw,framerate=30/1,width=320,height=240 ! videoconvert ! fakesink

      Reply to this comment

      Reply to this comment

      1. vandana:
        Feb 17, 2021 at 11:24 AM

        You were correct on the capabilities. The fakesink pipeline also gives error:
        0:00:00.014350347 27012 0x55e7e4a02a30 ERROR GST_PIPELINE subprojects/gstreamer/gst/parse/grammar.y:755:gst_parse_perform_link: could not link dvbsrc0 to videoconvert0, dvbsrc0 can't handle caps video/x-raw, framerate=(fraction)30/1, width=(int)320, height=(int)240
        WARNING: erroneous pipeline: could not link dvbsrc0 to videoconvert0, dvbsrc0 can't handle caps video/x-raw, framerate=(fraction)30/1, width=(int)320, height=(int)240


        When i see the dvbsrc capacilities using gst-inspect-1.0, I get:

        Pad Templates:
        SRC template: 'src'
        Availability: Always
        Capabilities:
        video/mpegts
        mpegversion: 2
        systemstream: true

        How do I resolve this capability incompatibility? Without this, I get error:
        gst-launch-1.0 -m dashsink name=dashsink mpd-root-path=/tmp target-duration=60 dynamic=false period-duration=60000 muxer=ts dvbsrc modulation=5 adapter=0 frequency=165000000 delsys=dvb-c-b ! queue ! x264enc bitrate=400 ! dashsink.video_0
        0:00:00.031501501 27077 0x55bcda470e30 ERROR GST_PIPELINE subprojects/gstreamer/gst/parse/grammar.y:774:gst_parse_perform_link: could not link queue0 to x264enc0
        WARNING: erroneous pipeline: could not link queue0 to x264enc0

        gst-launch-1.0 -m dashsink name=dashsink mpd-root-path=/tmp target-duration=60 dynamic=false period-duration=60000 muxer=ts dvbsrc modulation=5 adapter=0 frequency=165000000 delsys=dvb-c-b ! dashsink.video_0
        0:00:00.017987747 27082 0x556785554700 ERROR GST_PIPELINE subprojects/gstreamer/gst/parse/grammar.y:774:gst_parse_perform_link: could not link dvbsrc0 to dashsink
        WARNING: erroneous pipeline: could not link dvbsrc0 to dashsink

        gst-launch-1.0 -m dashsink name=dashsink mpd-root-path=/tmp target-duration=60 dynamic=false period-duration=60000 muxer=ts dvbsrc modulation=5 adapter=0 frequency=165000000 delsys=dvb-c-b ! queue ! dashsink.video_0
        0:00:00.042886015 27085 0x55eb6d745b30 ERROR GST_PIPELINE subprojects/gstreamer/gst/parse/grammar.y:774:gst_parse_perform_link: could not link queue0 to dashsink
        WARNING: erroneous pipeline: could not link queue0 to dashsink

        Reply to this comment

        Reply to this comment

        1. Stéphane Cerveau:
          Feb 17, 2021 at 02:19 PM

          Hello,

          Indeed dvbsrc ouputs mpeg2 ts stream which needs to be demuxed and parsed to be passed to the dashsink.

          Can you give a try to this pipeline where dvbsrc stream is demuxed by tsdemux and parsed by mpegvideoparse.

          ```
          gst-launch-1.0 dashsink name=dashsink mpd-root-path=/tmp target-duration=60 dynamic=false period-duration=60000 muxer=ts dvbsrc modulation=5 adapter=0 frequency=165000000 delsys=dvb-c-b ! queue ! tsdemux ! mpegvideoparse ! dashsink.video_0
          ```
          I assume you only have one video stream to feed the dashsink.

          Regards.

          Reply to this comment

          Reply to this comment

          1. vandana:
            Feb 18, 2021 at 10:39 AM

            Not the same error, but got this: Pls note that the gstreamer was built using gst-build. Could that be a problem? I am running hlssink and udpsink with this compiled version, and all work ok, I think.

            gst-launch-1.0 dashsink name=dashsink mpd-root-path=/tmp target-duration=60 dynamic=false period-duration=60000 muxer=ts dvbsrc modulation=5 adapter=0 frequency=165000000 delsys=dvb-c-b ! queue ! tsdemux ! mpegvideoparse ! dashsink.video_0

            Setting pipeline to PAUSED ...
            Pipeline is live and does not need PREROLL ...
            Pipeline is PREROLLED ...
            Setting pipeline to PLAYING ...
            New clock: GstSystemClock

            (gst-launch-1.0:13326): GStreamer-CRITICAL **: 10:35:50.452: gst_caps_get_structure: assertion 'GST_IS_CAPS (caps)' failed

            (gst-launch-1.0:13326): GStreamer-CRITICAL **: 10:35:50.452: gst_structure_get_name: assertion 'structure != NULL' failed

            (gst-launch-1.0:13326): GStreamer-CRITICAL **: 10:35:50.452: gst_structure_get_value: assertion 'structure != NULL' failed

            (gst-launch-1.0:13326): GStreamer-CRITICAL **: 10:35:50.452: gst_structure_get_string: assertion 'structure != NULL' failed
            Caught SIGSEGV
            exec gdb failed: No such file or directory
            Spinning. Please run 'gdb gst-launch-1.0 13326' to continue debugging, Ctrl-C to quit, or Ctrl-\ to dump core.

            Reply to this comment

            Reply to this comment

            1. Stéphane Cerveau:
              Feb 18, 2021 at 03:21 PM

              Hello,

              Interesting as my test was using a filesrc and not the dvbsrc.

              Could you please open an issue on https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/ where we could track the problem and try to address it (you can put @dabrain34 in cc) ?

              Could you please provide the full backtrace in the issue in order to see where it could fail ?

              All the critical logs can also be debugged using the environment variable G_DEBUG=fatal-warnings

              Regards.

              Stéphane

              Reply to this comment

              Reply to this comment

  3. vandana:
    Feb 22, 2021 at 09:29 AM

    Have posted my issue;
    https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/1534
    Didnt find any way to do a cc, hence giving the ticket link here.
    Thanks for all your guidance.

    Reply to this comment

    Reply to this comment

  4. vandana:
    Mar 05, 2021 at 05:59 AM

    Stephane, am back again. I just cannot arrive at the correct pipeline which would read from dvbsrc, transcode using x264enc and avenc_aac and output both audio and video streams in the dashsink. Could you pls suggest, whats wrong with this one:
    gst-launch-1.0 dashsink name=dashsink mpd-baseurl=http://localhost/media/kllywq84 mpd-root-path=/var/www/localhost/media/kllywq84 mpd-filename=live.mpd target-duration=5 min-buffer-time=10 minimum-update-period=10 dynamic=true muxer=ts dvbsrc modulation=5 adapter=0 frequency=147000000 delsys=dvb-c-b ! tsdemux name=demux demux. ! queue ! audioresample ! audioconvert ! avenc_aac bitrate = 128000 demux. ! queue ! x264enc bitrate=1200 key-int-max=60 ! video/x-h264,stream-format=byte-stream,profile=main ! dashsink.

    The last one which worked for me, and which you suggested, doesnt have audio, and no transcoding.
    gst-launch-1.0 --gst-debug=3 dashsink name=dashsink mpd-baseurl=http://50.239.254.201/media/kllywq84/ mpd-root-path=/var/www/vividcoredash/media/kllywq84/ mpd-filename=live.mpd target-duration=60 dynamic=false period-duration=60000 muxer=ts dvbsrc modulation=5 adapter=0 frequency=165000000 delsys=dvb-c-b ! queue ! tsdemux ! mpegvideoparse ! dashsink.video_0

    Reply to this comment

    Reply to this comment

    1. Stéphane Cerveau:
      Mar 05, 2021 at 02:18 PM

      Hello Vandana,

      As far as I understand you issue, you should first decode your branches to then encode to another format. Moreover, as I recommend you on the GStreamer mailing list, you have to give a name to your dashsink pad (dashsink.video_0 or dashsink_audio_0) according to the media type branch your are passing.

      I am sorry to hear you are having other issues with the dashsink.
      Please continue sharing feedback directly on the GStreamer mailing list or on Gitlab for issues where others can help as well.

      Otherwise, you can also get in touch with us to look at setting up a proper support contract between your company and Collabora.

      Best regards.

      Stéphane.

      Reply to this comment

      Reply to this comment

  5. vandana:
    Mar 09, 2021 at 07:04 AM

    Thanks for the tip Stephane, added a decodebin and the transcding pipeline for video worked.

    Reply to this comment

    Reply to this comment


Add a Comment






Allowed tags: <b><i><br>Add a new comment:


Search the newsroom

Latest Blog Posts

An xrdesktop summer of code

10/09/2021

This summer, Christoph Haag and I had the pleasure of taking part in Google Summer of Code as mentors for xrdesktop, the Open Source project…

Adding VP9 and MPEG2 stateless support in v4l2codecs for GStreamer

23/06/2021

Earlier this year, from January to April 2021, I worked on adding support for stateless decoders for GStreamer as part of a multimedia internship…

Bag of Freebies for XR Hand Tracking: Machine Learning & OpenXR

17/06/2021

In our previous post, we presented a project backed by INVEST-AI which introduces a multi-stage neural network-based solution. Now let's…

Testing cameras with lc-compliance on KernelCI

15/06/2021

Initiated as a joint effort by the Google Chrome OS team and Collabora, the recent KernelCI hackfest brought the addition of new tests including…

Zink: Summer 2021 update

14/06/2021

There's a lot that has happened in the world of Zink since my last update, so let's see if I can bring you up to date on the most important…

Open Source OpenGL ES 3.1 on Mali GPUs with Panfrost

11/06/2021

Panfrost, the open source driver for Arm Mali, now supports OpenGL ES 3.1 on both Midgard (Mali T760 and newer) and Bifrost (Mali G31, G52,…

Open Since 2005 logo

We use cookies on this website to ensure that you get the best experience. By continuing to use this website you are consenting to the use of these cookies. To find out more please follow this link.

Collabora Ltd © 2005-2021. All rights reserved. Privacy Notice. Sitemap.

Collabora Limited is registered in England and Wales. Company Registration number: 5513718. Registered office: The Platinum Building, St John's Innovation Park, Cambridge, CB4 0DS, United Kingdom. VAT number: 874 1630 19.