Working with ExoPlayer — The clean way — and customization

Prashant Barahi
MindOrks
Published in
4 min readMay 17, 2019
Photo by Maximilian Weisbecker on Unsplash

ExoPlayer is a open-source super customizable audio/video player from Google. It is able to play DASH (Dynamic Adaptive Streaming over HTTP), HLS (HTTP Live Streaming) and SmoothStreaming; merge, loop, concatenate, cache medias — while allowing developer to define custom load control, define seamless transition between successive medias and much more. So without further delay, lets get started.

Installation

In your build.gradle file, include following dependencies and turn on Java 8 support.

repositories {
google()
jcenter()
}
implementation 'com.google.android.exoplayer:exoplayer:2.X.X'

P.S For cleaner code, we will be using Data binding Library and BindingAdapter so do not forget to enable these in gradle.

UI setup

Now lets head to UI setup. Create a layout file called item_video. This may be inflated in RecyclerView or a Fragment or a Activity but for now, lets assume this will be inflated in RecyclerView.

Usage

Since we are inflating our layout in RecyclerView’s adapter, lets create a class that extends RecyclerView.Adapterand on RecyclerView.Adapter#onBindViewHolder, we will bind the video stream URL to the variable we have defined in our xml i.e url. Optionally, if we need to know the current state of PlayerView, we will have to implement a listener PlayerStateCallback and pass it to the PlayerView to get notified of the state change .

RecyclerView’s Adapter code implementing the PlayerStateCallback

P.S- Here’s a helpful gist containing a number of streaming URLs you can use to test your implementation.

Notice how we are setting the stream URL for the video in url variable available from the data binding library. The app:video_url and the app:on_state_change part in the xml file is from BindingAdapter. The callback is used to communicate the state of the video player like buffering, paused, playing or idle so that we can handle these change of state in our main code. Now for the fun part — Lets create an extension function with @BindingAdapter annotation, that we will use to setup our PlayerView, with the values we have passed in our xml file as the arguments.

Use the binding we have passed in the xml file

You can also pass in the view for ProgressBar as an argument to above extension function.

Great! Look at how clean the RecyclerView.ViewAdapter code is! There’s barely anything there. We have successfully started streaming the videos from the test URLs.

Now for the advance part!

Caching

In order to prevent media from buffering again and again, you’ll need to implement a local cache. You can do this by creating a subclass of DataSource.Factory and building a CacheDataSource.

Note: I have used a local Context here, but in singleton dependencies, you should use the application context. It’s better to inject it.

And to use this cache as data source, instead of DefaultHttpDataSoruceFactory — use the above created LocalCacheDataSourceFactory.

Using local cache to playback media

Seamless transition between medias

Need a seamless buffer-free transition between successive medias? Want to have control over the looping or the playback sequences of the media? Then MediaSource is what you need! Here’s a nice article about it.

Using Media source composition

Load Control

Want to have a control on the duration of media buffered for playing or before playing? Then you’ll need to override the DefaultLoadControl. It provides a dummy constructor as well as a builder to allow you to customize the property of the ExoPlayer.

--

--