Home » Guides » Encoding Recommendations » DASH Streaming and Playlists

permalink DASH Streaming and Playlists

Because DASH isn't a specific video format, codec, or data-agnostic packaging format (such as Zip), we've introduced a new option named streaming_delivery_format to specify that the media files should be structured / formatted according to a particular standard. Selecting "dash" as the streaming_delivery_format will modify some default options for compatibility with DASH, as well as put the output media files into a directory structure consistent with DASH requirements. DASH media outputs must also have type set to "segmented", to ensure the media is prepared for DASH streaming.

    {
      "input": "http://s3.amazonaws.com/zencodertesting/test.mov",
      "outputs": [
        {
          "streaming_delivery_format": "dash",
          "video_bitrate": 700,
          "type": "segmented",
          "url": "s3://mybucket/dash-examples/sbr/rendition.mpd"
        }
      ]
    }
  
    
      http://s3.amazonaws.com/zencodertesting/test.mov</input>
      
        
          dash
          700
          segmented
          s3://mybucket/dash-examples/sbr/rendition.mpd
        
      
    
  

Details for outputs with streaming_delivery_format set to "dash":

File structure for segmented DASH outputs:

  • The mpd manifest file will be at the root level of the output.
  • The audio and video media will each have their own subdirectory -- "audio/und" and "video/1" respectively.
  • In each of these directories there will be an "init.mp4" with the initialization data.
  • The media data will be in files named "seg-N.m4f" (where N starts at zero and increases for each segment).

DASH outputs with the streaming_delivery_profile set to "on_demand" will use fragmented media files rather than segments:

  • The mpd manifest file will be at the root level of the output.
  • The audio and video media will each be a single file in the same directory as the manifest.
  • The media files will be named similarly to the manifest, but with "-audio" or "-video" suffixes added, as appropriate.

Supported DASH configurations:

  • Formats supported: m4f and webm
  • Video codecs supported: h264, hevc, vp8, and vp9
  • Audio codecs supported: aac, ac3, eac3, and vorbis
  • Outputs in "webm" format currently only support the "on_demand" streaming_delivery_profile
  • Outputs in "webm" format currently do not support DRM

Multiple Bitrates

Zencoder-generated DASH outputs will have the necessary structure to be played on their own, but to truly benefit from such streaming delivery options, you should generate multiple versions at different bitrates (renditions) along with a "playlist" type output that lists the renditions so that a player can switch up / down bitrates as needed depending on the current network conditions. The playlist output is a dependent output - that is, it'll reference the other outputs by their label, and will use data from those outputs to generate the final rendition of the playlist. Note that you must be careful to set the stream paths in the playlist output so that they are relative paths to the location of the rendition files.

    {
      "input": "http://s3.amazonaws.com/zencodertesting/test.mov",
      "outputs": [
        {
          "label": "dash-1200",
          "streaming_delivery_format": "dash",
          "video_bitrate": 1200,
          "type": "segmented",
          "url": "s3://mybucket/dash-examples/mbr/1200k/rendition.mpd"
        },
        {
          "label": "dash-700",
          "streaming_delivery_format": "dash",
          "video_bitrate": 700,
          "type": "segmented",
          "url": "s3://mybucket/dash-examples/mbr/700k/rendition.mpd"
        },
        {
          "label": "dash-400",
          "streaming_delivery_format": "dash",
          "video_bitrate": 400,
          "type": "segmented",
          "url": "s3://mybucket/dash-examples/mbr/400k/rendition.mpd"
        },
        {
          "streaming_delivery_format": "dash",
          "type": "playlist",
          "url": "s3://mybucket/dash-examples/mbr/manifest.mpd",
          "streams": [
            { "source": "dash-1200", "path": "1200k" },
            { "source": "dash-700",  "path": "700k" },
            { "source": "dash-400",  "path": "400k" }
          ]
        }
      ]
    }
  
    
      http://s3.amazonaws.com/zencodertesting/test.mov</input>
      
        
          
          dash
          1200
          segmented
          s3://mybucket/dash-examples/mbr/1200k/rendition.mpd
        
        
          
          dash
          700
          segmented
          s3://mybucket/dash-examples/mbr/700k/rendition.mpd
        
        
          
          dash
          400
          segmented
          s3://mybucket/dash-examples/mbr/400k/rendition.mpd
        
        
          dash
          playlist
          s3://mybucket/dash-examples/mbr/manifest.mpd
          
            
              dash-1200
              1200k
            
            
              dash-700
              700k
            
            
              dash-400
              400k
            
          
        
      
    
  

Encryption

Zencoder also supports generating CENC-encrypted DASH outputs, with necessary headers for integrating with Marlin or Playready license servers. For each output, simply specify a hash of drm options, including the method, key_id, and content_key. The key_id and content_key should either be retrieved from your DRM vendor, or pre-generated and sent to your DRM vendor. Once you have those keys, the Zencoder API structure for a single rendition is:

    {
      "input": "http://s3.amazonaws.com/zencodertesting/test.mov",
      "outputs": [
        {
          "streaming_delivery_format": "dash",
          "video_bitrate": 700,
          "type": "segmented",
          "url": "s3://mybucket/dash-examples/sbr/rendition.mpd",
          "drm": {
            "method": "cenc",
            "key_id": "d57d416ccd454d5a08d05bff0742ee76",
            "content_key": "f15cae8f4e48a023056e1960ff2228b0"
          }
        }
      ]
    }
  
    
      http://s3.amazonaws.com/zencodertesting/test.mov</input>
      
        
          dash
          700
          segmented
          s3://mybucket/dash-examples/sbr/rendition.mpd
          
            cenc
            d57d416ccd454d5a08d05bff0742ee76
            f15cae8f4e48a023056e1960ff2228b0
          
        
      
    
  

The content will be encrypted with the content_key, and the .mpd manifest file will include the key_id in its headers. However, to ensure this output is playable, it also needs headers specifying how to retrieve the content_key. On a multi-bitrate DASH encode, these headers only need to be added to the playlist output, but can also be added to each rendition, so the rendition is individually playable. This is done by adding one or more DRM schemas:

    {
      "input": "http://s3.amazonaws.com/zencodertesting/test.mov",
      "outputs": [
        {
          "streaming_delivery_format": "dash",
          "video_bitrate": 700,
          "type": "segmented",
          "url": "s3://mybucket/dash-examples/sbr/rendition.mpd",
          "drm": {
            "method": "cenc",
            "key_id": "d57d416ccd454d5a08d05bff0742ee76",
            "content_key": "f15cae8f4e48a023056e1960ff2228b0",
            "schemas": [
              { "type": "marlin" },
              { "type": "playready", "license_acquisition_url": "https://playready.example.com/license_server/" }
            ]
          }
        }
      ]
    }
  
    
      http://s3.amazonaws.com/zencodertesting/test.mov</input>
      
        
          dash
          700
          segmented
          s3://mybucket/dash-examples/sbr/rendition.mpd
          
            cenc
            d57d416ccd454d5a08d05bff0742ee76
            f15cae8f4e48a023056e1960ff2228b0
            
              
                marlin
              
              
                playready
                https://playready.example.com/license_server/
              
            
          
        
      
    
  

We can then put this together to create a multi-bitrate, DRM-encrypted DASH job:

    {
      "input": "http://s3.amazonaws.com/zencodertesting/test.mov",
      "outputs": [
        {
          "label": "dash-1200",
          "streaming_delivery_format": "dash",
          "video_bitrate": 1200,
          "type": "segmented",
          "url": "s3://mybucket/dash-examples/mbr/1200k/rendition.mpd",
          "drm": {
            "method": "cenc",
            "key_id": "d57d416ccd454d5a08d05bff0742ee76",
            "content_key": "f15cae8f4e48a023056e1960ff2228b0"
          }
        },
        {
          "label": "dash-700",
          "streaming_delivery_format": "dash",
          "video_bitrate": 700,
          "type": "segmented",
          "url": "s3://mybucket/dash-examples/mbr/700k/rendition.mpd",
          "drm": {
            "method": "cenc",
            "key_id": "d57d416ccd454d5a08d05bff0742ee76",
            "content_key": "f15cae8f4e48a023056e1960ff2228b0"
          }
        },
        {
          "label": "dash-400",
          "streaming_delivery_format": "dash",
          "video_bitrate": 400,
          "type": "segmented",
          "url": "s3://mybucket/dash-examples/mbr/400k/rendition.mpd",
          "drm": {
            "method": "cenc",
            "key_id": "d57d416ccd454d5a08d05bff0742ee76",
            "content_key": "f15cae8f4e48a023056e1960ff2228b0"
          }
        },
        {
          "streaming_delivery_format": "dash",
          "type": "playlist",
          "url": "s3://mybucket/dash-examples/mbr/manifest.mpd",
          "streams": [
            { "source": "dash-1200", "path": "1200k" },
            { "source": "dash-700",  "path": "700k" },
            { "source": "dash-400",  "path": "400k" }
          ],
          "drm": {
            "method": "cenc",
            "key_id": "d57d416ccd454d5a08d05bff0742ee76",
            "content_key": "f15cae8f4e48a023056e1960ff2228b0",
            "schemas": [
              { "type": "marlin" },
              { "type": "playready", "license_acquisition_url": "https://playready.example.com/license_server/" }
            ]
          }
        }
      ]
    }
  
    
      http://s3.amazonaws.com/zencodertesting/test.mov</input>
      
        
          
          dash
          1200
          segmented
          s3://mybucket/dash-examples/mbr/1200k/rendition.mpd
          
            cenc
            d57d416ccd454d5a08d05bff0742ee76
            f15cae8f4e48a023056e1960ff2228b0
          
        
        
          
          dash
          700
          segmented
          s3://mybucket/dash-examples/mbr/700k/rendition.mpd
          
            cenc
            d57d416ccd454d5a08d05bff0742ee76
            f15cae8f4e48a023056e1960ff2228b0
          
        
        
          
          dash
          400
          segmented
          s3://mybucket/dash-examples/mbr/400k/rendition.mpd
          
            cenc
            d57d416ccd454d5a08d05bff0742ee76
            f15cae8f4e48a023056e1960ff2228b0
          
        
        
          dash
          playlist
          s3://mybucket/dash-examples/mbr/manifest.mpd
          
            
              dash-1200
              1200k
            
            
              dash-700
              700k
            
            
              dash-400
              400k
            
          
          
            cenc
            d57d416ccd454d5a08d05bff0742ee76
            f15cae8f4e48a023056e1960ff2228b0
            
              
                marlin
              
              
                playready
                https://playready.example.com/license_server/
              
            
          
        
      
    
  

Transmuxing

Of course, generating multiple formats of a video can get expensive and wasteful. So Zencoder supports repackaging the same encoded streams into different formats (called transmuxing), by using the copy_video and copy_audio options. Outputs for which the video is transmuxed rather than encoded are charged at 1/4 the regular duration. So if you're planning to make multiple formats of the same video (MP4, HLS, and DASH, for example), you can encode the MP4 version of each bitrate first, and then transmux those outputs to create the HLS and DASH versions. (Note that we don't support transmuxing from a format that's segmented, since the video is no longer a single stream.)

To ensure that the MP4 is prepared according to the constraints of the subsequent segmented streaming formats, also use the prepare_for_segmenting option on the MP4 output. This will control default values for keyframes and captions when encoding the video stream of the MP4 to ensure that it will be compatible with transmuxing to segmented formats afterward.

Using the MP4 as a source for the transmuxed outputs works similarly to the playlist ouputs. You specify a source option that matches the label of another output, but this time it's part of the main-level options for the output instead of in the streams hash.

    {
      "input": "http://s3.amazonaws.com/zencodertesting/test.mov",
      "outputs": [
        {
          "label": "mp4-700k",
          "prepare_for_segmenting": ["hls", "dash"],
          "video_bitrate": 700,
          "url": "s3://mybucket/transmux-examples/sbr/video.mp4"
        },
        {
          "source": "mp4-700k",
          "copy_video": true,
          "copy_audio": true,
          "type": "segmented",
          "url": "s3://mybucket/transmux-examples/sbr/hls/video.m3u8"
        },
        {
          "source": "mp4-700k",
          "copy_video": true,
          "copy_audio": true,
          "streaming_delivery_format": "dash",
          "type": "segmented",
          "url": "s3://mybucket/transmux-examples/sbr/dash/video.mpd"
        }
      ]
    }
  
    
      http://s3.amazonaws.com/zencodertesting/test.mov</input>
      
        
          
          
            hls
            dash
          
          700
          s3://mybucket/transmux-examples/sbr/video.mp4
        
        
          mp4-700k
          true
          true
          segmented
          s3://mybucket/transmux-examples/sbr/hls/video.m3u8
        
        
          mp4-700k
          true
          true
          dash
          segmented
          s3://mybucket/transmux-examples/sbr/dash/video.mpd
        
      
    
  

Optimizing for delivery

Since DASH is intended for streaming delivery, we recommend controlling the peaks of the bitrates in each rendition to avoid having the player rebuffer or switch to lower bitrate encodes unnecessarily. The options that control the variability of the encoded stream according to what the decoder/player can handle are decoder_bitrate_cap and decoder_buffer_size. (Note: max_video_bitrate is for controlling the maximum average bitrate over the entire stream, and is not suitable for use with streaming content.)

Our general recommendation is to set decoder_bitrate_cap to the maximum bitrate available for the video stream. Remember you need to take into account the audio, as well as a bit of overhead for the file format. The decoder_buffer_size is technically supposed to match the available video buffer memory on the decoding device, but is often better used to control how much content may be pre-buffered. It works as a multiple of the decoder_bitrate_cap, so that for example, if decoder_bitrate_cap was 500 (Kilobits per second), and decoder_buffer_size was 1000 (Kilobits), then the buffer could store 2 seconds worth of video. We also recommend setting the video_bitrate a little lower than the decoder_bitrate_cap, which allows the encoder to use more data to encode complex scenes and less data on simpler scenes. A decent starting point would be to assume up to 10% of overhead for the file format, setting the video_bitrate 10% lower than the decoder_bitrate_cap, and allowing about 1.5 seconds of video to be buffered.

Assuming a 1000 Kbps connection is available to the customer:

  • 1000 * 0.90 = 900 Kbps available after subtracting 10% for format overhead.
  • 900 - 128 = 772 Kbps video decoder_bitrate_cap after subtracting 128 Kbps for the audio.
  • 772 * 1.5 = 1158 Kb decoder_buffer_size (for 1.5 seconds worth of video).
  • 772 * 0.90 = 695 Kbps target video bitrate (10% lower than the decoder_bitrate_cap).

So, for a more correct streaming encode example:

    {
      "input": "http://s3.amazonaws.com/zencodertesting/test.mov",
      "outputs": [
        {
          "label": "mp4-1000k",
          "prepare_for_segmenting": ["hls", "dash"],
          "audio_bitrate": 128,
          "decoder_bitrate_cap": 772,
          "decoder_buffer_size": 1158,
          "video_bitrate": 695,
          "url": "s3://mybucket/transmux-examples/sbr/video.mp4"
        },
        {
          "source": "mp4-1000k",
          "copy_video": true,
          "copy_audio": true,
          "type": "segmented",
          "url": "s3://mybucket/transmux-examples/sbr/hls/video.m3u8"
        },
        {
          "source": "mp4-1000k",
          "copy_video": true,
          "copy_audio": true,
          "streaming_delivery_format": "dash",
          "type": "segmented",
          "url": "s3://mybucket/transmux-examples/sbr/dash/video.mpd"
        }
      ]
    }
  
    
      http://s3.amazonaws.com/zencodertesting/test.mov</input>
      
        
          
          
            hls
            dash
          
          772
          1158
          695
          s3://mybucket/transmux-examples/sbr/video.mp4
        
        
          
          true
          true
          segmented
          s3://mybucket/transmux-examples/sbr/hls/video.m3u8
        
        
          
          true
          true
          dash
          segmented
          s3://mybucket/transmux-examples/sbr/dash/video.mpd
        
      
    
  

Note: The above is not sufficient to guarantee the HLS encode would pass Apple's validation. While it would stream seamlessly on a 1000 Kbps connection, Apple measures bitrates per-segment (including the final segment which may have a short duration), without accounting for the buffering aspects. To ensure HLS encodes pass Apple's validation, see our HLS guide.

Putting it all together

    {
      "input": "http://s3.amazonaws.com/zencodertesting/test.mov",
      "outputs": [
        {
          "label": "mp4-1500k",
          "prepare_for_segmenting": ["hls", "dash"],
          "audio_bitrate": 128,
          "decoder_bitrate_cap": 1222,
          "decoder_buffer_size": 1833,
          "video_bitrate": 1100,
          "size": "1280x720",
          "url": "s3://mybucket/full-examples/mp4/1500.mp4"
        },
        {
          "label": "mp4-1000k",
          "prepare_for_segmenting": ["hls", "dash"],
          "audio_bitrate": 128,
          "decoder_bitrate_cap": 772,
          "decoder_buffer_size": 1158,
          "video_bitrate": 695,
          "size": "960x540",
          "url": "s3://mybucket/full-examples/mp4/1000.mp4"
        },
        {
          "label": "mp4-500k",
          "prepare_for_segmenting": ["hls", "dash"],
          "audio_bitrate": 128,
          "decoder_bitrate_cap": 322,
          "decoder_buffer_size": 483,
          "video_bitrate": 290,
          "size": "640x360",
          "url": "s3://mybucket/full-examples/mp4/500.mp4"
        },
        {
          "label": "hls-1500k",
          "source": "mp4-1500k",
          "copy_video": true,
          "copy_audio": true,
          "type": "segmented",
          "url": "s3://mybucket/full-examples/hls/1500.m3u8"
        },
        {
          "label": "hls-1000k",
          "source": "mp4-1000k",
          "copy_video": true,
          "copy_audio": true,
          "type": "segmented",
          "url": "s3://mybucket/full-examples/hls/1000.m3u8"
        },
        {
          "label": "hls-500k",
          "source": "mp4-500k",
          "copy_video": true,
          "copy_audio": true,
          "type": "segmented",
          "url": "s3://mybucket/full-examples/hls/500.m3u8"
        },
        {
          "type": "playlist",
          "url": "s3://mybucket/full-examples/hls/multi_bitrate_playlist.m3u8",
          "streams": [
            { "path": "1000.m3u8", "source": "hls-1000k" },
            { "path": "1500.m3u8", "source": "hls-1500k" },
            { "path": "500.m3u8", "source": "hls-500k" }
          ]
        },
        {
          "label": "dash-1500k",
          "source": "mp4-1500k",
          "copy_video": true,
          "copy_audio": true,
          "streaming_delivery_format": "dash",
          "type": "segmented",
          "url": "s3://mybucket/full-examples/dash/1500k/rendition.mpd",
          "drm": {
            "method": "cenc",
            "key_id": "d57d416ccd454d5a08d05bff0742ee76",
            "content_key": "f15cae8f4e48a023056e1960ff2228b0"
          }
        },
        {
          "label": "dash-1000k",
          "source": "mp4-1000k",
          "copy_video": true,
          "copy_audio": true,
          "streaming_delivery_format": "dash",
          "type": "segmented",
          "url": "s3://mybucket/full-examples/dash/1000k/rendition.mpd",
          "drm": {
            "method": "cenc",
            "key_id": "d57d416ccd454d5a08d05bff0742ee76",
            "content_key": "f15cae8f4e48a023056e1960ff2228b0"
          }
        },
        {
          "label": "dash-500k",
          "source": "mp4-500k",
          "copy_video": true,
          "copy_audio": true,
          "streaming_delivery_format": "dash",
          "type": "segmented",
          "url": "s3://mybucket/full-examples/dash/500k/rendition.mpd",
          "drm": {
            "method": "cenc",
            "key_id": "d57d416ccd454d5a08d05bff0742ee76",
            "content_key": "f15cae8f4e48a023056e1960ff2228b0"
          }
        },
        {
          "streaming_delivery_format": "dash",
          "type": "playlist",
          "url": "s3://mybucket/full-examples/dash/manifest.mpd",
          "streams": [
            { "source": "dash-1500k", "path": "1500k" },
            { "source": "dash-1000k", "path": "1000k" },
            { "source": "dash-500k",  "path": "500k" }
          ],
          "drm": {
            "method": "cenc",
            "key_id": "d57d416ccd454d5a08d05bff0742ee76",
            "content_key": "f15cae8f4e48a023056e1960ff2228b0",
            "schemas": [
              { "type": "marlin" },
              { "type": "playready", "license_acquisition_url": "https://playready.example.com/license_server/" }
            ]
          }
        }
      ]
    }
  
    
      http://s3.amazonaws.com/zencodertesting/test.mov</input>
      
        
          
          
            hls
            dash
          
          128
          1222
          1833
          1100
          s3://mybucket/full-examples/mp4/1500.mp4
        
        
          
          
            hls
            dash
          
          128
          772
          1158
          695
          960x540
          s3://mybucket/full-examples/mp4/1000.mp4
        
        
          
          
            hls
            dash
          
          128
          322
          483
          290
          640x360
          s3://mybucket/full-examples/mp4/500.mp4
        
        
          
          mp4-1500k
          true
          true
          segmented
          s3://mybucket/full-examples/hls/1500.m3u8
        
        
          
          mp4-1000k
          true
          true
          segmented
          s3://mybucket/full-examples/hls/1000.m3u8
        
        
          
          mp4-500k
          true
          true
          segmented
          s3://mybucket/full-examples/hls/500.m3u8
        
        
          playlist
          s3://mybucket/full-examples/hls/multi_bitrate_playlist.m3u8
          
            
              1000.m3u8
              hls-1000k
            
            
              1500.m3u8
              hls-1500k
            
            
              500.m3u8
              hls-500k
            
          
        
        
          
          mp4-1500k
          true
          true
          dash
          segmented
          s3://mybucket/full-examples/dash/1500k/rendition.mpd
          
            cenc
            d57d416ccd454d5a08d05bff0742ee76
            f15cae8f4e48a023056e1960ff2228b0
          
        
        
          
          mp4-1000k
          true
          true
          dash
          segmented
          s3://mybucket/full-examples/dash/1000k/rendition.mpd
          
            cenc
            d57d416ccd454d5a08d05bff0742ee76
            f15cae8f4e48a023056e1960ff2228b0
          
        
        
          
          mp4-500k
          true
          true
          dash
          segmented
          s3://mybucket/full-examples/dash/500k/rendition.mpd
          
            cenc
            d57d416ccd454d5a08d05bff0742ee76
            f15cae8f4e48a023056e1960ff2228b0
          
        
        
          dashplaylist
          s3://mybucket/full-examples/dash/manifest.mpd
          
            
              dash-1500k
              1500k
            
            
              dash-1500k
              1000k
            
            
              dash-500k
              500k
            
          
          
            cenc
            d57d416ccd454d5a08d05bff0742ee76
            f15cae8f4e48a023056e1960ff2228b0
            
              
                marlin
              
              
                playready
                https://playready.example.com/license_server/