Enhancing Video Streaming Quality for Exoplayer -- Part 2: Buffering Strategy to Lower Startup Time and Video On-Demand Rebuffering
Co-written by: Mark Greve, Engineering Manager at Akamai. Part of the Media Client Team
The first part of this blog series discussed the quality of user experience (QoE) metrics and two strategies that heavily influence the QoE: the bitrate selection strategy and the buffering strategy. In this second part, we’ll discuss ExoPlayer's buffering strategy and how to configure it to reduce the startup time and video on-demand (VOD) content rebuffering.
ExoPlayer buffering strategy
In this blog, we investigate ExoPlayer Version 2.9.6. Classes implementing the LoadControl interface define the buffering strategy of ExoPlayer. Buffering strategy answers questions like:
Do we need to load more media data?
Do we have enough media data to start playback?
The buffering strategy is not responsible for managing the buffers or downloading media data (that's the MediaSource), or playback of media data (that's the Renderer). The buffering strategy is agnostic to the media format being played and has only a "consultative" role. It may occasionally happen that ExoPlayer will "ask" the LoadControl whether new media data should be loaded, and ignore the answer (e.g., ExoPlayer is already in the process of downloading media data).
ExoPlayer comes with a default implementation, DefaultLoadControl. This is a customizable implementation of the LoadControl interface.
DefaultLoadControl can be used to configure:
How many milliseconds (ms) of media data ExoPlayer should buffer before starting playback (referred to as bufferForPlaybackMs). ExoPlayer will start playback as soon as it has at least bufferForPlaybackMs of media data, even if ExoPlayer did not fully buffer the complete segment.
The minimum amount of buffered media data (in ms) before ExoPlayer starts loading more data (referred to as minBufferMs).
The maximum amount of media data (in ms) ExoPlayer should buffer before it stops to load more (referred to as maxBufferMs).
How many milliseconds of media data ExoPlayer should buffer before restarting playback after a rebuffering event (referred to as bufferForPlaybackAfterRebufferMs).
DefaultLoadControl has default values for each of these settings. In v2.9.6, these values are:
bufferForPlaybackMs | 2500 |
minBufferMs | 15000 |
maxBufferMs | 50000 |
bufferForPlaybackAfterRebufferMs | 5000 |
However, the values vary from ExoPlayer version to version. For example, between ExoPlayer v2.7.3 and v2.8.0, the maxBufferMs for video streams has changed from 30 seconds to 50 seconds.
ExoPlayer's modular architecture also allows you to implement your own buffering strategy (that implements the LoadControl interface) and plug it into ExoPlayer. Lowering Startup Time
In ExoPlayer, it is easy to configure how much media data is needed before playback is started. In the first part of this blog series, we highlighted the importance of startup time as a QoE metric. A report Akamai published in 2016 found that "viewers will start abandoning a video if startup takes longer than two seconds to begin playing and for every additional second of delay, roughly an additional 6% of the audience leaves. [...] with a 10 second delay, nearly half the audience has left."
ExoPlayer version 2.9.6 requires by default 2.5 seconds of media data buffered before initiating playback. It's possible to lower the startup time by requiring less data to be buffered. On one hand, lowering the media data buffering value would result in lowering the video startup time, however, this might also result in increasing the rebuffering metrics at startup.
In our first blog, we used a radar chart to visualize the impact of the different trade-offs on the five QoE metrics. The chart below shows the impact of lowering the minimum required amount of media data before initiating playback.
Since the default value for bufferForPlaybackMs of 2.5 seconds is a conservative value, we believe it is a good choice to lower it.
The graph below shows the impact on startup time for a 3 Mbps stream when varying the value of this configuration option (not taking into account the round-trip time to the server, nor whether the server has to fetch the content from elsewhere). For example, on a 4 Mbps connection playing a 3 Mbps stream, configuring ExoPlayer to start playback after buffering 1.5 s of media data means the theoretical startup time will be of 1.1 s, instead of the 1.9 s with the default configuration of buffering 2.5 s of media data.
Now let’s discuss how to configure the ExoPlayer to lower the startup time and the hand-waving latency. If you are not familiar with ExoPlayer, we recommend you first follow Google's Codelabs on Media streaming with ExoPlayer.
Configuring the DefaultLoadControl
Assuming that you create your ExoPlayer instance with the default LoadControl implementation using the following code (or similar):
ExoPlayer player = ExoPlayerFactory.newSimpleInstance(
new DefaultRenderersFactory(this),
new DefaultTrackSelector(),
new DefaultLoadControl())
You can configure the DefaultLoadControl using a DefaultLoadControl.Builder:
/* Instantiate a DefaultLoadControl.Builder. */
DefaultLoadControl.Builder builder = new DefaultLoadControl.Builder();
/* Milliseconds of media data buffered before playback starts or resumes. */
final long loadControlStartBufferMs = 1500;
Configure the new DefaultLoadControl to use our setting for how many milliseconds of media data must be buffered before playback starts or resumes after a user action event:
builder.setBufferDurationMs(
DefaultLoadControl.DEFAULT MAX BUFFER MS,
loadControlStartBufferMs,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS);
/* Build the actual DefaultLoadControl instance */
DefaultLoadControl loadControl = builder.createDefaultLoadControl();
/* Instantiate ExoPlayer with our configured DefaultLoadControl */
ExoPlayer player = ExoPlayerFactory.newSimpleInstance(
new DefaultRenderersFactory(this),
new DefaultTrackSelector(), loadControl);
Lowering Rebuffering Metrics for VOD Content
Besides configuring settings that lead to lower startup time, you can configure the DefaultLoadControl to establish how much media data to buffer, which can impact rebuffering metrics for VOD content.
ExoPlayer v2.9.6 will by default load 50 seconds of media data into its internal buffer if it can (the maxBufferMs setting). In the case of VOD content, increasing this value will give the player more room to handle fluctuations in network bandwidth and lower rebuffering metrics -- the downside is that it will also increase the memory usage of ExoPlayer. Keeping memory usage low is important on low-end devices. Another issue is the wasted bandwidth usage in case playback stops prematurely.
To find the value that works best for your setup of VOD content, we recommend doing A/B testing with various values of the configuration option to find the one that gives a good tradeoff between rebuffering rates and memory usage. We recommend being conservative by increasing the value to, for example, 60 seconds initially to find out if it provides a material difference for rebuffering metrics.
Configuring the DefaultLoadControl
We assume that you create your ExoPlayer instance with the default LoadControl implementation (as shown above in Configuring the DefaultLoadControl).
You can configure the DefaultLoadControl using a DefaultLoadControl.Builder:
/* Instantiate a DefaultLoadControl.Builder. */
DefaultLoadControl.Builder builder = new
DefaultLoadControl.Builder();
/* Maximum amount of media data to buffer (in milliseconds). */
final long loadControlMaxBufferMs = 60000;
/*Configure the DefaultLoadControl to use our setting for how many
Milliseconds of media data to buffer. */
builder.setBufferDurationsMs(
DefaultLoadcontrol.DEFAULT MIN BUFFER MS,
loadControlMaxBufferMs,
/* To reduce the startup time, also change the line below */
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS);
/* Build the actual DefaultLoadControl instance */
DefaultLoadControl loadControl = builder.createDefaultLoadControl();
/* Instantiate ExoPlayer with our configured DefaultLoadControl */
ExoPlayer player = ExoPlayerFactory.newSimpleInstance(
new DefaultRenderersFactory(this),
new DefaultTrackSelector(),
loadControl);
In case minBufferMs and maxBufferMs have different values, ExoPlayer will have a bursty behavior refilling the buffer. ExoPlayer will buffer until it fills its buffer with maxBufferMs of media data, then wait until it decreases to minBufferMs (mainly applicable to VOD). Once the buffer level falls below minBufferMs of media data, ExoPlayer will start loading media data again until it has a buffer worth maxBufferMs of media data. Such a bursty behavior can lead to rebuffering issues. This is the default behavior in ExoPlayer v2.9.6 and prior, as these values differ. In v2.9.6, minBufferMs has a default value of 15000 and maxBufferMs is 50000.
To further reduce rebuffering chances, we recommend maintaining a large buffer in ExoPlayer at all times, by setting the minBufferMs to the same value as maxBufferMs. The ExoPlayer team conducted experiments that found setting minBufferMs to the same value as maxBufferMs (and thus changing the buffering behavior from bursty to drip-style) reduced rebuffering events significantly, while increasing battery usage only slightly. In fact, starting with ExoPlayer v2.10, the video use case has the default minBufferMs equal to maxBufferMs and set to 50s.
How to configure the DefaultLoadControl using a DefaultLoadControl.Builder:
/* Instantiate a DefaultLoadControl.Builder. */
DefaultLoadControl.Builder builder = new
DefaultLoadControl.Builder();
/*How many milliseconds of media data to buffer at any time. */
final long loadControlBufferMs = DefaultloadControl.MAX_BUFFER_MS; /* This is 50000 milliseconds in ExoPlayer 2.9.6 */
/* Configure the DefaultLoadControl to use the same value for */
builder.setBufferDurationMs(
loadControlBufferMs,
loadControlBufferMs,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS);
Recommendations
LoadControl is the entry point to ExoPlayer's buffering strategy. ExoPlayer comes with a default, yet configurable implementation of the LoadControl interface that should be sufficient for most use cases. Here’s a recap of our recommendations:
To reduce the startup time, lower the value of bufferForPlaybackMs; effectively, lowering the minimum amount of media data buffered before starting playback. This has the drawback of potentially increasing the number of rebuffering events.
To reduce the rebuffering metrics for VOD content, increase the value of maxBufferMs -- effectively increasing the maximum amount of media data buffered. However, keep in mind that this change can negatively impact low-end devices.
To reduce rebuffering metrics, set minBufferMs and maxBufferMs to the same value. This will change ExoPlayer's behavior from a bursty to a drip-style buffering.
We would like to thank our colleagues Christian Worm Mortensen and Laust Brock-Nannestad for feedback in writing this post.