Hi.
I'm Ollie from the Android team.
I want to tell you about ExoPlayer, an application level
media player for Android.
Built on top of Android's low-level media APIs,
ExoPlayer delivers a number of benefits
over Android's built-in media player.
You'll be glad to hear it supports
both dash and smooth streaming adaptive play backs.
At Google, we're already using ExoPlayer
in YouTube and to play movies.
And now we're open sourcing it so
that you can use it in your own app.
I'm going to show you the lower level APIs in which ExoPlayer
is built, outline some of the benefits of application level
media players, and show you how you can integrate ExoPlayer
into your own applications.
Before we take a look at ExoPlayer,
let's first take a look at Android's media APIs.
Prior to Jelly Bean, Android's high-level media player API
was the de facto way for developers
to videos to their applications.
It's really easy to use.
This example starts playing a video
with just two lines of code.
One to create the player and the second to start the playback.
These two lines of code hide nearly all
of the complexities of video playback from the developer.
However, under the hood, the media player implementation
is doing a lot of work in order for the video to be played.
For streaming, the first thing that the player needs to do
is to load the video data over the network.
The data then needs to be buffered according
to some policy, which specifies when more data needs
to be loaded and how much.
Before the video can be rendered,
the individual audio and video samples
need to be extracted from the container
format in which they're delivered.
These samples then need to be decoded.
And finally, the decoder samples need
to be rendered to the screen and to the speaker.
At a slightly higher level, the player
needs to track its overall state, such as the playback
position and whether the playback is currently
advancing.
The media player API is simple and easy to use
because it hides all of this complexity.
However, the one drawback of this approach
is that more advanced developers are then
unable to modify or extend the underlying behaviors
to better suit their needs.
For example, a developer is unable to tweak the buffering
policy or to add a persistent cache for buffered media data.
To better support these use cases,
we added low-level media APIs to Android.
From Jelly Bean onwards the medial extractor API
provides networking, buffering, and media extraction
functionality.
We also added the MediaCodec API,
which provides access to decoders, including hardware
accelerated video decoders.
The MediaCodec API supports rendering of video frames
directly.
And playing decoded audio can be done using the audio track
API, which has been around since Cupcake.
These low-level APIs provide developers with an alternative
to Android's high-level media player.
They make it possible to build application level media players
written in Java while they player
logic is implemented in application code.
This code will typically call into the provided APIs
in order to load and extract the media samples,
decode them, and render them.
A developer may optionally choose
to implement more of this functionality
at the application level.
For example, implementing networking, buffering,
and sample extraction allows the developer
to more easily customize these components.
Within Google, we've developed our own application level media
player called ExoPlayer.
It supports both DASH and SmoothStreaming adaptive
playbacks, DRM protected content,
and has been designed specifically
to be easy to modify and to extend.
Google's YouTube and Play Movies applications
are already using ExoPlayer on some of the more recent Android
devices.
And we're seeing some great results.
For example, in Play Movies, dash playbacks using ExoPlayer
have been shown to reduce startup playback latency
by 65%.
A 40% less likely to rebuffer and deliver video at 11%
higher resolution on average than when using media player.
Since ExoPlayer is an application level medial
player, we're able to tweak it and to add new functionality
through Play Store updates.
And we hope that this will allow us to further improve
these numbers going forward.
We're really pleased with the improvements
that ExoPlayer has brought to our own applications.
But we recognize that for many developers,
the barrier to entry for adopting a similar approach
is quite high.
ExoPlayer is itself around 16,000 lines of code.
And using Android's low-level media APIs can be a challenge.
So creating such a player from scratch
requires a considerable effort.
For this reason, we've decided to open source ExoPlayer.
We hope that this will lower the barrier to entry allowing
third party developers to obtain similar improvements
without having to incur the cost of developing
their own application level media players from scratch.
Let's take a look at how ExoPlayer is designed
and how it can be used in your own application.
Rather than being a single Java Objects,
an ExoPlayer is composed from a range of modular components,
each of which contributes a desired behavior or piece
of functionality to the player.
At the top level, we have the ExoPlayer
object itself, which does little beyond
maintain the overall player states.
This object calls into components
called track renderers whose job it
is to render the media during playback.
The ExoPlayer library provides a track renderer
for playing video, which uses a MediaCodec
API to decode the video samples and to render them
onto the surface.
It supports any video format for which
there exists an underlying decoder.
H.264 is commonly used.
The ExoPlayer library also provides the track renderer
for playing audio, which uses a MediaCodec API to decode
the audio samples and the audio track API to play them.
Both the audio and video track renderer implementations
need to be provided with a sample source component
from which samples can be obtained.
For a developer who doesn't require control
over the networking, buffering, and sample extraction
behaviors, the ExoPlayer library provides
an implementation called FrameworkSampleSource,
which hooks into Android's media extractor API.
By doing this, it provides support for all container
formats supported by the version of Android on which it's
running.
Let's take a look at the corresponding code.
First, we build the sample source
passing the URI where the video is located.
We then build our audio and video renderers
passing the sample source.
And finally, we build an instance of ExoPlayer
passing the two renderers and start the playback.
This is the simplest example of how ExoPlayer can be used.
Let's now take a look at a more complicated use case,
specifically, how ExoPlayer supports
DASH and SmoothStreaming adaptive playbacks.
For DASH and SmoothStreaming, the ExoPlayer library
contains components that completely
replace Android's media extractor API.
Individual instances of a component
called ChunkSampleSource are used
to supply audio and video samples to the renderers.
Each ChunkSampleSource requires a chunk source component
from which chunks of media, typically
between 2 and 10 seconds in duration, can be obtained.
In this example, we'll focus on DASH paybacks
for which DASH MP4 ChunkSource components should be used.
Finally, each ChunkSource requires a data source.
As the name suggests, data source components
are responsible for actually loading the media.
In this case we use HTTP DataSource,
which moves data over the network.
Note that for DASH playbacks audio and video are normally
streamed separately, which is why there are two HTTP
DataSource components rather than just one.
Going back to looking at code, you
can see how each component is injected
with the component on which it depends.
The video renderer is injected with a sample source, which
is injected with the ChunkSource, which
is injected with the DataSource.
This approach, where the player is constructed
from much of the components using dependency injection,
makes it easy for an application developer
to replace any or all of these components
with their own custom implementations.
What I've shown so far is a slightly simplified object
model.
And in a full example, a few more components are required.
Firstly, something called a LoadControl
is required to manage the buffering of the media chunks.
Secondly, and most importantly for adaptive playbacks,
each ChunkSource requires something
called a format evaluator.
Format evaluators select from the available formats
before each chunk of media is requested.
Here we're using a fixed implementation
for audio, which will stick to a single format.
For video, we're using an adaptive implementation,
which will select a format suitable
for the current network conditions aiming
to provide the user with the highest quality
possible without causing any buffering.
We now know how to build an ExoPlayer
for adaptive playbacks using the standard components provided
by the ExoPlayer library.
I also touched on how easy it is for an application developer
to customize such a player to better suit
their particular use case.
Let us now take a look at some examples.
Suppose that the developer wants to add a persistent cache
for buffered media data so that if the user watches
the same video twice, the second time around it
would be played from the cache.
In the ExoPlayer model, this is easy.
The developer can simply insert cache data source components
when building the player.
A cache DataSource component is provided
by the ExoPlayer library.
But equally, a developer is free to write
their own implementation from scratch.
Similarly, a developer may choose
to replace the default LoadControl implementation
in order to achieve different buffering behavior
or implement an entirely custom track renderer,
for example, to render an overlay on top of the video.
Of most use for adaptive playbacks
is the ability to inject custom format evaluators.
This allows the developer to experiment
with their own adaptive algorithms.
There are many other ways in which ExoPlayer
can be extended and customized.
And we're looking forward to seeing
what developers can do with it.
In summary, we've seen how Android's low-level media
APIs allow the development of powerful application level
media players, which can be more easily updated,
modified, and extended by developers
than is possible with Android standard media player.
Google is using ExoPlayer to deliver
some great benefits for our own applications.
And we hope that by open sourcing ExoPlayer,
we will allow other developers to achieve similar results.
So if you're curious and want to learn more,
then visit the developer guide.
You're going to find a ton of useful information
as well as some great examples to help get you started.