The other day I wanted to add video playback support to Tabris. “Ha!” I thought, “Piece of cake.” My fallback strategy was the normally well documented Android API and, as a last resort, Stackoverflow with the answer to almost any question you can think of. As it turned out, none of these assumptions were correct.
While implementing the new video feature, I ran into some pitfalls that I want to share here.
Get access to a VideoView’s underlying MediaPlayer
Want to play a video on Android? Use the VideoView class from the Android API. The VideoView is a wrapper around the MediaPlayer, which is the central component when it comes to audio or video playback on Android. Take a look at the state diagram of MediaPlayer to get an idea of its life cycle. It is obvious that the VideoView doesn’t provide access to all of the MediaPlayer’s capabilities. So you would expect to somehow get a grip on the VideoView’s underlying MediaPlayer instance. This access is protected by the listener VideoView.setOnPreparedListener(MediaPlayer.OnPreparedListener l). The listener’s callback method onPrepared(MediaPlayer m) provides you with a default MediaPlayer configuration.
Intercept interaction between VideoView and MediaController
Now that we have a reference to the MediaPlayer, the first thing to try might be to add listeners for all these listeners on MediaPlayer. Don’t do it! It breaks the wiring between the VideoView and its MediaPlayer instance, as the VideoView adds its own listeners for most events. The setXYListener methods just drop previously registered listeners. This makes it difficult to intercept the communication between VideoView and MediaPlayer and between MediController and MediaPlayer as well. The VideoView lets you add some listeners directly, but these only cover a subset of the things that are interesting. Instead, I can recommend to take a look at the code of VideoView and MediaPlayer. To intercept calls from the MediaController to the VideoView, you can subclass VideoView and overwrite the play() pause() and skipTo() methods.
Placing controlls over a video
The MediaController is a visual component which provides the well known control widgets you know from the embedded video players used by YouTube and Vimeo. On Android, these controls can be attached to a VideoView with one line of code. Unfortunately, the MediaController uses a strange strategy for placing itself on the screen. Only when the VideoView is displayed in a full screen mode will the MediaController appear at the usual position, as an overlay at the bottom of the video. When embedding the video as a smaller component in a different UI, the controls appear below an anchor view which is usually the VideoView itself. In many cases this is not optimal, as it hides other controls instead of just the lower part of the video. To move the MediaController over the video, you can place an empty anchor view 88 pixels above the bottom line of the VideoView. When attached to this anchor, the MediaController appears at the desired position.
Usually Android’s documentation is well written and detailed. But when it comes to video playback and especially to the VideoView, good documentation is just not available. Have a look at all the completely undocumented methods of VideoView. The developer guide to the MediaPlayer lacks the video topic, too.
If you know of a good guides to video playback, please drop me a line in the comments.