Android Media ch. 1: Intro to ExoPlayer

Help for Junior Android Developers

Intro to ExoPlayer for Junior Developers

Introduction

Let’s use ExoPlayer to create an Android app from scratch that can play videos. We will do this in 5 easy steps. ExoPlayer is a library built on top of Android’s media API (android.media.*).

ExoPlayer makes it extremely easy to play an .mp3 or .mp4 file. If instead you want to play a more advanced file format or exert more granular control over your user’s experience, ExoPlayer also gives you great flexibility. Now, the 5 steps:

  1. Create an Android Studio project and name it Moving Water.
  2. In gradle, add ExoPlayer dependency
  3. In the manifest, request Internet permission
  4. Change your layout file to include the SimpleExoPlayerView
  5. In MainActivity, create an ExoPlayer instance and pass it the video URL to play

Step 1: Create project Moving Water in Android Studio

See the following three figures for how-to:

Create a new application called Moving Water
Add an empty activity
Activity Name: MainActivity

Step 2: In gradle, add ExoPlayer dependency

Make sure your root build.gradle file has jcenter repo. The “Android” view in Android Studio displays the file as build.gradle(Project:MovingWater)

Project level build.gradle

In the build.gradle file of the app module add the ExoPlayer dependency.

  • My version is r2.4.0. Check the release notes for the latest version.
  • compile ‘com.google.android.exoplayer:exoplayer:r2.4.0’

Step 3:

In the manifest, request Internet permission

<uses-permission android:name="android.permission.INTERNET"/>

Step 4: Add SimpleExoPlayerView to your layout file

Change your activity_main.xml file to this:

Step 5: Create an ExoPlayer Instance

In MainActivity, we are going to create an ExoPlayer instance and pass it the video URL to play. But since this is the final step, I want to entertain you and tell you about video streaming just a little bit before I send you on your way.

Say you go on to build a cool video app and it gets downloaded by millions of users. As you can imagine some of your users may have great internet connectivity, while others may have spotty connectivity that oscillate between great and okay, while others still may have poor connectivity. Before ExoPlayer, pleasing all these different users was hopeless for individual app creators and small companies. If you have a high quality video file, the guy with fancy wifi will be happy but the guy with spotty internet will spend most of his time waiting for the video to load. And oh forget about the guy with poor connection.

What ExoPlayer does to solve the problem is allow apps to download small chunks of media at a time, say 2 second long chunks. For each chunk ExoPlayer decides whether to download higher quality or lower quality media based on the user’s internet bandwidth. So if a user’s connection is spotty, now she may get a lower quality 2 seconds chunk and then 2 seconds later she gets a higher quality video chunk and so on — the beauty being her viewing experience is smoother than it might have been because ExoPlayer continuously tracks internet bandwidth.

Our goal in this step is still to simply create an instance of ExoPlayer and pass the video file to it. To instantiate SimpleExoPlayer (“the player”) we need a TrackSelector. A TrackSelector is actually what’s responsible for choosing which file chunks to download based on perceived bandwidth changes. So, for example, if a high quality chunk would take too long to download, the TrackSelector will choose something of lower quality to show the user. And since each chunk is usually about 2 to 12 seconds long, it’s not so bad if the user gets a lower quality chunk of media once in while for the benefit of a smooth experience.

Next the TrackSelector needs to be given a set of tracks. That’s where TrackSelection.Factory comes in. Here we select the set of tracks we need. For example, our app will specify AdaptiveTrackSelection since we want to adapt chunk quality based on internet bandwidth to maximize a smooth viewing experience for the user. So we mention bandwidth a lot. Someone needs to track bandwidth changes so that the TrackSelector can select based on bandwidth changes. To do this we will pass a BandwidthMeter to the AdaptiveTrackSelection object.

To recap:

SimpleExoPlayer(
TrackSelector (
AdaptiveTrackSelection( BandwidthMeter )
)
)

Inside onStart of your MainActivity, add the following code snippet

Yes, player is a field outside of your onStart method — I’m just checking if you are awake.

Woot! Woot! We have a working Player. But it’s not yet attached to any display. So let’s add a display for your users.

When it comes to displaying video content to your users, you have a lot of options — SurfaceView, TextureView, Surfaceholder, Surface. To use any of those views for displaying your content to your users, just call player.setVideoSurfaceView, player.setVideoTextureView, player.setVideoSurfaceholder, or player.setVideoSurface respectively. Again, ExoPlayer is all about freedom, especially for those who want highly customized control. However since we are not looking for customization, we are using the out of the box SimpleExoPlayerView. See activity_main.xml

Now you can connect the player to the view:

Ok, now for the final stretch. At this point we have a player and a surface to display our content, but we don’t have any content. I want to show my users the Moving Water movie. So what do I do?

To pass content to ExoPlayer we use MediaSource. Basically you pass the URI of the video you want to play to the MediaSource and then pass the MediaSource to ExoPlayer. Why MediaSource? Well, that’s actually a heavy question. MediaSource is flexible enough to do both simple things and fancy things. You can create playlists, loops, etc. etc. etc. One particular case of interest for large companies, for example, is adaptive streaming. Large companies tend to have fancy servers that can provide adaptive content: in other words, they have URLs for users that can adapt streaming content over fast, slow, and spotty connectivity. If you were building your app for one such company, you would use an adaptive MediaSource such as DashMediaSource or HlsMediaSource. But for our present example I will use ExtractorMediaSource which will simply extract and play my mp4/mp3 media. (DASH is the international standard, HLS is for Apple and SmoothStreaming is for Microsoft; and yes there are more formats out there).

Similar to ExoPlayer for instantiating, MediaSource needs a few objects to do its job: namely a BandwidthMeter to track internet connectivity and an ExtractorsFactory to determine how to extract the data from server. Add the following code to your onStart method.

And then inside onResume set

player.setPlayWhenReady(true);

Voila! Now you can run the app and it should play the Moving Water video for you!

You may want to protect against orientation changes. To do that just override onSaveInstanceState and onRestoreInstanceState in your MainActivity

I almost forgot something very important. You must release the player when you are done with it. A good place to do that is in onStop or in onPause depending on your android version. Before API 24 do it in onPause otherwise do it in onStop

The Complete project on Github

https://github.com/isaidamier/IntroExoPlayer