As head developers of the dash.js project we are frequently facing situations in which we have to evaluate if the failure of a DASH stream is caused by an actual bug in the implementation of the dash.js player or by wrong content authoring. In this blog post we share some common mistakes in DASH streams. Moreover, we give an insight on what we typically look for in problematic streams.
DRM specific pitfalls
Stay safe, use https
A very common mistake in the context of playing DRM protected streams is related to the hosting of the underlying application. In order to be able to use the Encrypted Media Extensions (EME) – the W3C API which is mandatory for DRM playback and communication with the content decryption module (CDM) – web browsers typically mandate the use of https. If the application is called with http, dash.js outputs a warning that DRM playback is not possible:
No supported version of EME detected on this user agent! - Attempts to play encrypted content will fail!
Protect yourself against protection
DRM itself can be a complicated topic. One thing that is fairly easy to remember, is the fact that there are three major DRM systems available: Google Widevine, Microsoft Playready and Apple Fairplay. In Google Chrome and Mozilla Firefox, Widevine is required to enable DRM playback while Edge Legacy only supports Playready. Some devices like SmartTVs or FireTVs support both Widevine and Playready. Consequently, before trying to play DRM protected content on a specific platform the underlying capabilities should be evaluated. When working with dash.js an output as shown below is generated as soon as a suitable DRM system has been found and selected:
DRM: KeySystem Access Granted (com.widevine.alpha)!
If a platform supports multiple DRM systems it can be useful to define a selection priority
In this case, dash.js checks for the support of Widevine before Playready.
You can learn more about DRM in our previous blog posts “Enabling Hardware DRM on Android Chrome using the Encrypted Media Extensions” and “dash.js: License acquisition for multiple EME versions”.
Model everything you can
In “dash.js: License acquisition for multiple EME versions” we describe the concept of dash.js protection models. The key takeaway from this is, that dash.js implements three different versions of the EME, wrapped into protection models. Unfortunately, there are devices (greetings to everyone who has the “pleasure” to develop for Smart TVs and set-top boxes) which need customized versions of one of these protection models. When debugging DRM problems on such devices it is always worth checking if the EME calls need to be prefixed or changed.
Timing specific pitfalls
Don’t fall out of your window
A key concept when developing a DASH player or creating DASH MPDs is the understanding of the DASH timing model. The DASH-IF IOP guidelines and the DASH-IF implementation guidelines: restricted timing model are very good resources to start with this.
A problem we encountered various times is caused by streams in which the presentation times of the available media segments are outside of the time shift buffer. The player can adapt his behavior in case explicit timing information with <SegmentTimeline> is given. The following figure illustrates this behavior:
The player uses the MPD@timeShiftBufferDepth attribute to determine the DVR window. In addition, a live delay is subtracted from the “UTC now” time in order to shorten the DVR window which results in an “effective DVR window”. During playback the underlying application is allowed to seek within the effective DVR window.
In our example the presentation end time of the last available segment (segment 5) is outside of the DVR window. In this case the player has no segment to download and play. dash.js is able to handle such situations by adjusting the anchor time. The “UTC now” time is replaced by the “presentation end time” of the last segment. This results in adjusted values for the calculation of the “effective DVR window”. This feature is enabled by adjusting the settings parameters in the following way:
Use offsets to avoid upsets
The use of multiple periods in an MPD is a very common practice to enable ad-insertion in DASH streams. Let’s consider a very simple example in which we want to add a midroll to our main content:
In this case we play 8 seconds of main content before switching to the ad content. After the ad is finished we resume playback of the main content. The sum of all period durations leads to a media presentation duration of 18 seconds.
In order to map segments to its target position in the media buffer, the MSE uses the internal presentation timestamps (earliest presentation time (EPT)) of the media segments and adds a configurable timestampOffset. Consequently, the application can control the position of the segment in the buffer by adjusting the timestampOffset.
Now, what does this mean for our example? Let’s assume the first segment of the main content and the first segment of the ad content have a EPT of 0. In DASH streaming, the presentation time of a segment is relative to the start of its period. So what happens if we simply set the MSE.timestampOffset for each segment to the start time of its period? This works fine for period 1 and period 2:
--- Period 1 ---
MSE.timestampOffset = Period@start = 0
BufferPosition(Seg 1) = MSE.timestampOffset + EPT = 0 + 0 = 0
BufferPosition(Seg 4) = MSE.timestampOffset + EPT = 0 + 6 = 6
--- Period 2 ---
MSE.timestampOffset = Period@start = 8
BufferPosition(Seg 1) = MSE.timestampOffset + EPT = 8 + 0 = 8
BufferPosition(Seg 2) = MSE.timestampOffset + EPT = 8 + 2 = 10
Now the problem occurs if we look into period 3. Since we start with segment 5 the EPT is not set to zero:
--- Period 3 ---
MSE.timestampOffset = Period@start = 12
BufferPosition(Seg 5) = MSE.timestampOffset + EPT = 12 + 8 = 20
Instead of positioning the first segment of period 3 at 12 seconds in the media presentation timeline, it ends up at 20 seconds. Luckily, there is an easy fix for this: On MPD level we can assign an individual @presentationTimeOffset for each period (Note: In this example we are simplifying things a bit. The @presentationTimeOffset can differ for each Representation in the MPD). dash.js uses the @presentationTimeOffset for the calculation of the MSE.timestampOffset. We set the value of the @presentationTimeOffset to the EPT of the first segment of the period:
--- Period 3 ---
MSE.timestampOffset = Period@start - @presentationTimeOffset = 12 - 8 = 4
BufferPosition(Seg 5) = MSE.timestampOffset + EPT = 4 + 8 = 12
BufferPosition(Seg 6) = MSE.timestampOffset + EPT = 4 + 10 = 14
Now all the segments are at the correct position in the media buffer and we end up with a continuous media presentation timeline.
Watch your buffer – gaps ahead
A huge problem for MSE based players are gaps in the timeline. Most MSE implementations can not handle situations in which the media buffer is not continuous and will stall as soon as the play position reaches a gap. Now what exactly do we mean when we talk about gaps and what causes gaps? From our experience, gaps are mainly caused by two reasons:
- Subsequent periods do not align and consequently segments at period boundaries do not align.
- The summed up media sample duration in a segment is shorter than indicated by its presentation duration.
Ultimately this leads to the following situation:
In this case segment 1 and segment 2 are perfectly aligned, while there is a gap between segment 2 and segment 3. In order to avoid playback stalling in such situations dash.js has a sophisticated gap jumping mechanism in place. It can be enabled and configured with the following settings:
In this blog post we shared six of the most common pitfalls in MPEG-DASH streaming.
We highlighted the need for https when playing DRM protected streams and outlined the importance of using the correct platform for specific DRM systems. In addition, we motivated the need for implementing legacy versions of the EME.
The timing model in MPEG-DASH is not always easy to understand. Wrong DVR windows lead to playback stalling and failing . In the context of multi-period ad-insertion it is important to align all periods using MPD specific attributes to avoid inconsistencies in the media buffer. Moreover, gaps in the media timeline should be avoided as MSE implementations can not handle gaps in the media buffer.
Players like dash.js can handle most of these situations and can help identifying and solving such problems.
If you have any additional question regarding our DASH activities or dash.js in particular, feel free to check out our website.