The wonder world of Android’s video recording

More than a year ago I started to develop an an app that looked very simple and straight forward to do: The user starts a timer that counts down the time and and when the timer reaches zero the app records a video whose maximum file size and length can be preconfigured. Sounds easy, doesn’t it? I can tell you it was not. But I finally got an app who does that (see here), runs on all Android versions from 2.1 on and seems to work even well with the newest generation of Samsung devices (here I still keep my fingers crossed). But it was a bunch of work to find out how to do it. Here is the story.

As this was my first video recording app I started with reading the guide on Android Developers. This guide tells you the steps that you have to follow. It does not tell you about the caveats. So please read this guide first (if you haven’t already) and then continue reading here.

Opening the camera with contains already a small trap. The guide does not mention that returns a null pointer in case that the device has only a front facing camera which is for example true for the first generation Nexus 7. In this case you have to use with the correct camera id. But was only introduced with Android 2.3 (API level 9). This was the first case where I was forced to write version dependent code. This code snippet opens the first back facing camera it finds and opens the first camera it can get otherwise.

Camera cam = null;

  Camera.CameraInfo info = new Camera.CameraInfo();
  for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
    Camera.getCameraInfo(i, info);
    if (info.facing == CameraInfo.CAMERA_FACING_BACK){
    	cam =;
  if (cam == null){
    cam =;
else {
  camera =;

When it comes to setting up the media recorder, setting up the video output format and encoding is to my experience the main source of trouble for recording a video in Android. The guide on Android Developer says here:

Set the video output format and encoding. For Android 2.2 (API Level 8) and higher, use the MediaRecorder.setProfile method, and get a profile instance using CamcorderProfile.get(). For versions of Android prior to 2.2, you must set the video output format and encoding parameters: …

This leaves a bunch of problems unmentioned:

  • Android 2.2 (API Level 8) did not bring the full class with all its methods:
    • CamcorderProfile.get(quality) was already available with Android 2.2 (API Level 8), but CamcorderProfile.get(cameraId, quality) came with Android 2.3 (API Level 9).
    • Initially only constants for CamcorderProfile.QUALITY_HIGH and CamcorderProfile.QUALITY_LOW were defined. Most other constants came with Android 3.0 (API Level 11), CamcorderProfile.QUALITY_QVGA and CamcorderProfile.QUALITY_TIME_LAPSE_QVGA came with Android 4.0.3 (API Level 15). I used Java’s introspection API on CamcorderProfile to get the available profile constant in order be prepared for future extensions like e.g. 4k.
    • Checking, which profiles are actually supported with CamcorderProfile.hasProfile (cameraId, quality) came with Android 3.0 (API Level 11).
  • I know at least of one device (Sony Ericsson Xperia Ray with Android 4.0.4) where setting up the MediaRecorder with  MediaRecorder.setProfile() results in an exception when starting the MediaRecorder.
  • On some devices some possible output formats are not available through MediaRecorder profiles, but only by manually setting the output format parameters. For example the Intenso Tab 814 (Android 4.1.1) offers a 320×240 video format which is QVGA for which there is no profile constant in Android 4.1.1.
  • The guide mentions nowhere that you must specify width and height of the video with MediaRecoder.setVideoSize and the video frame rate with MediaRecorder.setVideoFrameRate in case you don’t use camcorder profiles.

So using camcorder profiles is only really well suited for devices with Android 3.0 (API Level 11) at minimum. Nevertheless it seems as if for the newest Generation of Samsung phones (Galaxy Note 3, Galaxy S4, etc.) using camcorder profiles is the only way to get the MediaRecorder up and running. Setting up the video output format values manually resulted either in a completely failed start of the recorder (e.g. on a Galaxy Note 3) or in a low quality video (e.g. on a Galaxy Tab 3 7.1).

In parallel to this approach I implemented two other ways to set up the video output format values:

The “automatic” approach

1) Get the preview size from the camera object (which can e.g on the Xperia Ray be different from the size of the holder of the preview surface!):

videoWidth = cam.getParameters().getPreviewSize().width; 
videoHeight = cam.getParameters().getPreviewSize().height;

This must be done after the preview surface has been created and the surface holder of the preview has been set in the camera object but before unlocking the camera when starting to set up theMediaRecorder.

2) Use these values and some parameters that officially every Android device with a camera must support to set up the media recorder

recorder = new MediaRecorder();
videoFramesPerSecond = 20;
recorder.setVideoSize(videoWidth, videoHeight);

Version 1.0 of my app published more than a year ago used only this approach for video recording and at that time I had next to no crash reports. Interestingly it worked even on the Samsung Galaxy S3. The videoFramesPerSecond parameter is a “high enough” value. From my experience it seems that the cameras take this only as a maximum value that they decrease for the given conditions during the recording.

The “explicit frame size” approach

This method requires Android 3.0 (API Level 11) and above.

1) Let the user choose one of the supported video sizes that you get from Camera.getParameters().getSupportedVideoSizes() if this function does not return null (!!!). If it does return null (an example is here again the Xperia Ray) this means that the size of the preview and the frame size of the recorded video must be identical and you can let the user choose one of the video sizes from Camera.getParameters().getSupportedPreviewSizes(). What does not work is to use one of the supported preview sizes without checking whether or not it is a supported video size. For example the Nexus 7 (first generation with Android 4.4.2) does support a preview size of 480×480 which makes the MediaRecorder start fail when used as a video size. The same Nexus 7 produces by the way some supported video sizes that are way beyond the known resolution of the camera, for example 1280×720. In this case the recording starts but stops after a few seconds and produces a corrupted video.

2) My app chooses values from Camera.getParameters().getSupportedPreviewSizes() that are as close as possible (which means normally identical) to the selected video sizes and sets them as preview sizes in the camera parameters directly after opening the camera, which means before you attach the camera to the surface view holder for the preview:

int previewWidth = ...
previewHeight = ...
Camera.Parameters  camPara = cam.getParameters();
camPara.setPreviewSize(previewWidth, previewHeight);

Just leaving the preview size parameters in the camera as it is would probably work as well but I did not test it.

3) Set up the video recorder in the same way as with the “automatic” approach but use the selected width and height parameters instead.

The advantage of this method is that you get access to all available video sizes. The downside is that even on devices where this method works in principal there can be sizes that don’t work.

My app supports all three methods. Any feedback on which parameters work on which device would be highly welcome.

Finally one last hint that – if I had know this before – would have saved me some hours of debugging. In Android’s Media Framework the process running the app communicates via Interprocess Communication with a another process who runs the media recorder. Detailed warnings and error message (for example “Unsupported video size: 480×480”) come mostly from this other process, the Media Framework layers of the app quite often throw only a run time exception with an integer parameter like -19 whose meaning is nowhere documented. This means that on a Development System like Eclipse it may be sometimes extremely helpful to look at the complete LogCat without the filter set for the messages of your app.

Warning: count(): Parameter must be an array or an object that implements Countable in /homepages/38/d73375733/htdocs/wordpress/wp-includes/class-wp-comment-query.php on line 405

10 thoughts on “The wonder world of Android’s video recording

  1. Very useful. Thanks for this info.

    Another approach that I’m playing with is to also use getParameters().flatten and pick out “video-size-values” for Pre API 11 devices.

  2. Hello there! Thank you for sharing such information, it kinda helped me getting around my problem. I’m trying to achieve exactly what you’re describing here but using the front-facing camera, have you tried so?

    Looks like you’re no longer maintaining this blog, so if you get to read this and if you please, answer me via e-mail cause i’m really really interested in getting my code working.

    Thanks you in advice!

    • Yes, this blog is still maintained by me. I have only been busy with other things recently. 🙂

      I have tested my video app with tablets that have only front facing cameras and it worked. If you want your app to work in general with front facing cameras, changing CameraInfo.CAMERA_FACING_BACK into CAMERA_FACING_FRONT in the first code snippet should do the job.

      If you run your software on a device that has only a front facing camera you could install my video timer app and see what settings work there. Based on that you could implement the method that worked in my app in your app as well.

  3. I’m wondering if you’ve seen an issue where if you stop recording a video and then immediately start again, the media server will sometimes crash. I can, mostly, avoid this happening by inserting a 300ms pause between videos, but this is pretty unsatisfying as an answer. Without the pause the MediaRecorder the media server is increasingly likely to crash. I think this crash is the result of a race condition, possibly with the video codec or somewhere else in the media framework. Any thoughts? Pointers?

    • This is a “feature” of Android’s media recorder. It is documented in the description of the stop() function in :

      … Note that a RuntimeException is intentionally thrown to the application, if no valid audio/video data has been received when stop() is called. This happens if stop() is called immediately after start(). …

      The only thing you can do here is to catch the exception and do whatever your app can do in this situation. My app for example simply tells the user that the recording has failed.

  4. Jörg, do you know Not all, but most of the device idiosyncrasies is coded into that library already. It’s probably worth replacing your camera logic to make it work on most devices. Funny, your story starts like mine. I started in April and was sure I could finish my app within 3-6 months. I’m still futzing with Android 🙁

  5. Pingback: IllegalStateException with MediaRecorder.start() : null

Leave a Reply to Joerg Cancel reply

Your email address will not be published. Required fields are marked *