H264 encoder in android?

Bilthon picture Bilthon · Jul 11, 2011 · Viewed 19.3k times · Source

I've been having some problems while trying to fix a simple video recording app*. I think I followed the sequence of steps correctly. The following is a simplification of the part of the code that is giving me problems. This code is executed only as a callback once a button is pressed:

if ( mRecorder != null){
    mRecorder.reset();
    mRecorder.release();
}
mRecorder = new MediaRecorder();
if(mViewer.hasSurface){
    mRecorder.setPreviewDisplay(mViewer.holder.getSurface());
    Log.d(TAG,"Surface has been set");
}
try {
    Log.d(TAG,"Sleeping for 4000 mili");
    Thread.sleep(4000);
    Log.d(TAG,"Waking up");
} catch (InterruptedException e) {
    Log.e(TAG,"InterruptedException");
    e.printStackTrace();
}
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);  
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mRecorder.setVideoFrameRate(12);
mRecorder.setVideoSize(176, 144);
mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setMaxDuration(MAX_DURATION_TEST);

String targetFile = "/sdcard/webcamera/temp.mp4";
File localFile = new File(targetFile);
if(localFile.exists()){
    Log.d(TAG,"Local file exists");
}else{
    Log.d(TAG,"Local file does not exist");
}
mRecorder.setOutputFile(targetFile);
try {
    mRecorder.prepare();
    bPrepared = true;
    Log.i(TAG,"prepared");
    return;
} catch (IllegalStateException e) {
    e.printStackTrace();            
} catch (IOException e) {
    Log.e(TAG ,"IOException");
    Log.e(TAG,"Message: "+e.getMessage());
    StackTraceElement[] array = e.getStackTrace();
    for(StackTraceElement element : array){
        Log.e(TAG,""+element.toString());
    }
}

The important thing which I don't understand here is that whenever I put the video encoder to be MPEG_4_S it works. On the other hand whenever I put the encoder to be H264 it just does not. The problem is that this piece of code is just part of a bigger project, and the rest of it kind of expects this video to be encoded with h264.

I'm testing on a samsung Galaxy I-7500, running on froyo by the way. And I think the Galaxy I-9000 has the same problem.

The puzzling thing for me is that according to this documentation right here: http://developer.android.com/guide/appendix/media-formats.html, MPEG_4_SP encoding should not be supported at all, while H264 is supported since honeycomb. So why is it working with MPEG_4_SP at all? and is it possible to make it work with H264?

The error I get is not really clear.

07-11 00:01:40.626: ERROR/MediaSource(1386): Message: prepare failed.
07-11 00:01:40.766: ERROR/MediaSource(1386): android.media.MediaRecorder._prepare(Native Method)
07-11 00:01:40.766: ERROR/MediaSource(1386): android.media.MediaRecorder.prepare(MediaRecorder.java:508)
07-11 00:01:40.766: ERROR/MediaSource(1386): com.appdh.webcamera.MediaSource.prepareOutput(MediaSource.java:74)
07-11 00:01:40.766: ERROR/MediaSource(1386): com.appdh.webcamera.MainActivity.startDetectCamera(MainActivity.java:312)

*Actually, the app is a little more complicated than just that, as it also does stream the video over LAN, but the part which I am concerned here has nothing to do with that. You can check this interesing project out here: http://code.google.com/p/ipcamera-for-android/

Answer

mattlaabs picture mattlaabs · Sep 7, 2011

As you already wrote H.264 encoding support can be only expected from devices running honeycomb and later, which currently means only tablets. If you need H.264 you should test for prepare failed and either tell the user that the device is not supported or better block devices without H.264 using market filters. Or you can compile ffmpeg for android - like several other projects do. Have a look at these links:

http://odroid.foros-phpbb.com/t338-ffmpeg-compiled-with-android-ndk

http://bambuser.com/opensource

FFmpeg on Android