Back when I was still a student assistant and did my first steps in the media streaming industry, I had the chance to attend my first DASH-IF meetings. At this time, I was working on specific features to enable server and client-side ad-insertion in dash.js. While these new features (XLink, DASH events) were only really used much later, someone in the meeting said something that is still stuck in my head even after all these years:
This has to work—This is what pays our billsA wise man
And to be fair: With FAST channels popping up everywhere, the quote above is still true. So, here we go, let’s take a look at a new feature in dash.js: Segment preloading and how we can use it to enable broadcast-broadband ad-insertion on HbbTV terminals.
Broadcast-Broadband Ad-Insertion on HbbTV terminals
The idea behind broadcast-broadband ad-insertion aka dynamic ad substitution on HbbTV terminals is simple:
When a viewer turns on a broadcast channel, we start an HbbTV application in the background. At this point, the application is invisible to the user. Upcoming ad breaks in the broadcast stream are signaled via stream events in the transport stream to our application running in the background. That way we know exactly when an ad is to be started; typically, upcoming ad breaks are announced multiple seconds before they start. Using this information we can request a personalized broadband advertisement from an ad-server and pre-buffer it in our application. Once the ad is to be shown, we simply put our application into the foreground and play the broadband ad instead of the broadcast ad. Afterward, we switch back to the common broadcast feed.
For playback of broadband ads in MPEG-DASH format, we have two options. We can either rely on native playback using a type-1 player or we use a type-3 player that utilizes W3C APIs such as the Media Source Extensions (MSE) and the Encrypted Media Extensions (EME, only required for playback of DRM protected content). Official support for the MSE was added in HbbTV version 2.0.3 . However, a wide range of HbbTV terminals below version 2.0.3 already support the MSE enabling playback via type-3 players such as dash.js.
The technical challenges
While the basic idea of broadcast-broadband ad-insertion itself sounds simple, there are quite some technical challenges that we need to overcome:
First we need to make sure that the upcoming ad breaks are signaled in advance. Our application needs enough time to contact the ad decisioning server and preload the ad, otherwise the transition between broadcast and broadband is not fluent.
Next, moving the HbbTV app from the background to the foreground can take some time as well. While we will not discuss this in more detail here, keep in mind that devices behave differently. Careful testing is required to determine how long it takes to perform this transition.
Finally, most of the HbbTV terminals only provide a single decoder, meaning that broadcast and broadband content share the same decoder. Typically, MSE based players such as dash.js download the manifest and the media segments and immediately append them to the corresponding Source Buffers. The underlying platform then starts decoding the media data. Consequently, we cannot append any media data to the source buffers before the broadcast part has been decoded completely. To overcome this challenge, we added a preload functionality to dash.js version 4.6.0.
Preloading in dash.js
The idea of preloading segments is simple: The main logic for manifest fetching and parsing and downloading the media segments remains untouched. But instead of appending the segments to the Source Buffers we save them in a “virtual” buffer. Once the application decides to perform the transition from broadcast to broadband, we empty the virtual buffer and append the media data to the “real” buffers. That way we already have enough data to immediately start the playback, leading to significant improvements regarding the startup/transition time. The simplified dash.js workflow is depicted in the sequence diagram below:
The application calls the
preload() function to trigger the manifest processing and the segment download. Once a segment has been downloaded, it is appended to a virtual buffer that we maintain within the
PreBufferSink. To switch between the virtual buffer and the real buffer, the application calls the
attachView() function, providing a reference to the video element. As a result, the virtual buffer is emptied and the segments are appended to the corresponding Source Buffers. An example of the preload functionality in dash.js can be found in the sample section: https://reference.dashif.org/dash.js/nightly/samples/advanced/preload.html
Application providers that use the preload functionality should pay close attention to the buffer targets of the player. Since the media segments are stored in the memory, there might be some memory restrictions that apply to specific platforms. dash.js offers various settings regarding the target buffer level, more information can be found in the sample section: https://reference.dashif.org/dash.js/nightly/samples/index.html#Buffer
While the main reason for preloading segments into a virtual buffer originates from the aforementioned HbbTV broadcast-broadband ad-insertion use-case, there are additional scenarios in which preloading can be useful. As an example, the transition from an unencrypted to an encrypted DASH period typically requires a reset of the MSE. By utilizing the preload functionality the transition time can be optimized.
If you have any questions regarding our DASH and HbbTV activities or dash.js in particular, feel free to check out our website and contact us.
Armand Zangue says:
Very interesting article, segment preloading is really a handy instrument to optimise a lot of use cases. Thanks for sharing. Also, I’m wondering if you managed to make the transition from broadband back to broadcast as seamless considering the mentioned single decoder constraint?
Daniel Silhavy says:
From our experience the switch from broadband to broadcast is the one in which we don’t have much control. We saw situations in which the audio broadcast started slightly before the video broadcast. That is why we were working with still images for examples.
Another thing that can play a role is the GoP size of the broadcast. Long GoPs can lead to longer black frames after the transition.