MediaPlayer: Simplified Video Playback on Android

Playing videos is a common requirement in Android apps. In this tutorial learn about handling video playback via the MediaPlayer API on Android. By Bhavesh Misri.

4.6 (5) · 1 Review

Download materials
Save for later
Share

Playing audio or video in Android apps is a common requirement for many projects. Many apps in the Google Play Store, even some non-streaming ones, provide audio and video playback. Above all, it’s an important topic that will lead you to many job opportunities.

In this tutorial, you’ll build an Android app that plays video from various sources, such as videos locally stored in your phone, the res folder, gallery and a URL using MediaPlayer.

Along the way you’ll learn about:

  • MediaPlayer.
  • The states of MediaPlayer.
  • Playing video from the res/raw folder.
  • Playing video from a URL.
  • Best practices for MediaPlayer.
  • Digital Right Management.
Note: This tutorial assumes you’re familiar with Kotlin and Android development. If you’re a beginner, check out our Android: Beginners tutorial first.

Getting Started

Download the materials using the Download Materials button at the top or the bottom of this page. Extract and open the starter project in Android Studio.

Build and run. You’ll see something like this:


Starter app

The app isn’t interactive yet because the starter project only consists of UI and some basic code. You’ll implement the functionality throughout this tutorial.

Understanding the code

Before the hands-on part of this tutorial, take some time to understand the codebase you’ll build on. Navigate to these three files and check out their contents:

The class implements a few interface classes to manage MediaPlayer and seekBar callbacks. You’ll understand these implementations once you start working on the functionality.

Also, to keep your app from falling asleep, you’ll need to keep your screen on. Notice this line inside onCreate() which adds a flag window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON). Setting this flag ensures your screen stays on, while the app is in use. You don’t want the user’s device to fall asleep and lock while they’re watching a video on your app, do you?

  • A VideoView to play video.
  • A ProgressBar to shows the user it’s loading a video.
  • Two TextViews and a SeekBar to show progress.
  • An ImageButton to play and pause a video.
  1. AndroidManifest.xml: At the top of the manifest file you’ll find android.permission.INTERNET. In this tutorial, you’ll play a video from a URL, so you’ll need the INTERNET permission.
  2. activity_video.xml: This is the one and only layout file in the project. It consists of:
  3. VideoActivity.kt: This might look a bit overwhelming, but if you skim through and read the comments, you’ll find it quite simple.

MediaPlayer

MediaPlayer is a part of the Android multimedia framework that plays audio or video from the resource directory and gallery. It also streams music or video from a URL.

When a media file plays, the MediaPlayer API goes through several states, which are summarized in the diagram below:

MediaPlayer state diagram

That’s a lot of information to take in, but before you can use the MediaPlayer API efficiently, you need to understand these states, so let’s take a look at each of them.

At this stage, you can’t play, pause or stop the media. If you try to force it, the app might crash.

  1. Idle State: MediaPlayer is in an idle state when you first instantiate it, or first create it using the new keyword. You also reach this state after you call reset().
  2. End State: Calling MediaPlayer‘s release() method frees resources and moves it to the end state. At this stage, you can’t play or pause the media.
  3. Error State: You reach this state if you try to play, pause or stop an uninstantiated MediaPlayer object. However, you can catch the error using MediaPlayer’s onErrorListener.onError() callback.
  4. Initialized State: MediaPlayer reaches this state when you set a data source. To set a one, use setDataSource() method. Be aware that you can only set a data source when MediaPlayer is in an idle state or it’ll throw an IllegalStateException.
  5. Prepared State: Before you play any media from a file or a URL, you need to prepare your MediaPlayer by calling either prepare() or prepareAsync(). Once prepared, it reaches this state and calls onPreparedListener().
  6. Started State: Once MediaPlayer is ready, you can play the media by calling start(). While the music or video plays, MediaPlayer is in a started state.
  7. Paused State: When you pause the media, MediaPlayer is in this state. To pause MediaPlayer, call pause().
  8. Stopped State: MediaPlayer is in this state when media stops playing. If MediaPlayer is in this state and you want to play the media again, you have to prepare it again by calling prepare() or prepareAsync().
  9. PlaybackCompleted State: When the playback is complete, MediaPlayer is in this state. Additionally, invokes onCompletion.onCompletion(). If MediaPlayer is in this state you can call the start() and play audio or video again.

Okay, enough theory. It’s time to code!

Let's code

Playing Video From Local Resources

You will start with playing a video file in the raw directory. There’s a video in the starter project named test_video.mp4.

From the states you learned above, you may see that to play the video in your VideoView, you have to:

  1. Set the data source using MediaPlayer
  2. Call the start() function

But you may be wondering where do you add this code? For this, a couple of options may come to your mind.

The most common way to add new code into Android apps is to put it in the onCreate() method, because you know it will be the entry point of your activity. But in the case of Media Player that’s not good practice for two reasons:

  1. First, you don’t know the size of the video or how much time MediaPlayer will take to load it.
  2. Second, MediaPlayer can play a video in VideoView through its surface, which also takes time.
Note: A surface is a low-level drawing area where you can render images and display them on screen.

Take a look at the code inside the onCreate() method of VideoActivity. In there you will see the following line: video_view.holder.addCallback(this), this gets a callback when the VideoView‘s surface is ready for playing video. When this surface is ready, it calls surfaceCreated().

Next, inside surfaceCreated() replace // TODO (1) with:

mediaPlayer.apply {
 setDataSource(applicationContext, 
    // 1
    Uri.parse("android.resource://$packageName/raw/test_video"))
 // 2
 setDisplay(surfaceHolder)
 // 3
 prepareAsync()
}

In this code, you perform three tasks:

  1. First, you pass the location, URI, of the video.
  2. Then, you set MediaPlayer‘s display to the VideoView‘s surface by calling setDisplay(surfaceHolder).
    Note: If you started the MediaPlayer without calling this function, you wouldn’t see any video because MediaPlayer wouldn’t know where to display the video.
  3. Finally, you call prepare(). This function prepares MediaPlayer to playback the video synchronously on the main thread.
Note: If you started the MediaPlayer without calling this function, you wouldn’t see any video because MediaPlayer wouldn’t know where to display the video.