Monday, October 24, 2011

A simple exercise of Video Capture using MediaRecorder, for Android 2.3 or higher

Refer to my old exercise "A simple exercise of Video Capture using MediaRecorder" for SDK Level 8 Android 2.2. But it fail to run on Android 2.3!!! So I re-write it for SDK Level 10, Android 2.3.3. Tested on Nexus One running Android 2.3.6.

A simple exercise of Video Capture using MediaRecorder, run on Nexus One running 2.3.6

Main Code:
package com.exercise.AndroidVideoCapture;

import java.io.IOException;

import android.app.Activity;
import android.content.Context;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.Toast;

public class AndroidVideoCapture extends Activity{

private Camera myCamera;
private MyCameraSurfaceView myCameraSurfaceView;
private MediaRecorder mediaRecorder;

Button myButton;
SurfaceHolder surfaceHolder;
boolean recording;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

recording = false;

setContentView(R.layout.main);

//Get Camera for preview
myCamera = getCameraInstance();
if(myCamera == null){
Toast.makeText(AndroidVideoCapture.this,
"Fail to get Camera",
Toast.LENGTH_LONG).show();
}

myCameraSurfaceView = new MyCameraSurfaceView(this, myCamera);
FrameLayout myCameraPreview = (FrameLayout)findViewById(R.id.videoview);
myCameraPreview.addView(myCameraSurfaceView);

myButton = (Button)findViewById(R.id.mybutton);
myButton.setOnClickListener(myButtonOnClickListener);
}

Button.OnClickListener myButtonOnClickListener
= new Button.OnClickListener(){

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(recording){
// stop recording and release camera
mediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object

//Exit after saved
finish();
}else{

//Release Camera before MediaRecorder start
releaseCamera();

if(!prepareMediaRecorder()){
Toast.makeText(AndroidVideoCapture.this,
"Fail in prepareMediaRecorder()!\n - Ended -",
Toast.LENGTH_LONG).show();
finish();
}

mediaRecorder.start();
recording = true;
myButton.setText("STOP");
}
}};

private Camera getCameraInstance(){
// TODO Auto-generated method stub
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}

private boolean prepareMediaRecorder(){
myCamera = getCameraInstance();
mediaRecorder = new MediaRecorder();

myCamera.unlock();
mediaRecorder.setCamera(myCamera);

mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

mediaRecorder.setOutputFile("/sdcard/myvideo.mp4");
mediaRecorder.setMaxDuration(60000); // Set max duration 60 sec.
mediaRecorder.setMaxFileSize(5000000); // Set max file size 5M

mediaRecorder.setPreviewDisplay(myCameraSurfaceView.getHolder().getSurface());

try {
mediaRecorder.prepare();
} catch (IllegalStateException e) {
releaseMediaRecorder();
return false;
} catch (IOException e) {
releaseMediaRecorder();
return false;
}
return true;

}

@Override
protected void onPause() {
super.onPause();
releaseMediaRecorder(); // if you are using MediaRecorder, release it first
releaseCamera(); // release the camera immediately on pause event
}

private void releaseMediaRecorder(){
if (mediaRecorder != null) {
mediaRecorder.reset(); // clear recorder configuration
mediaRecorder.release(); // release the recorder object
mediaRecorder = null;
myCamera.lock(); // lock camera for later use
}
}

private void releaseCamera(){
if (myCamera != null){
myCamera.release(); // release the camera for other applications
myCamera = null;
}
}

public class MyCameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback{

private SurfaceHolder mHolder;
private Camera mCamera;

public MyCameraSurfaceView(Context context, Camera camera) {
super(context);
mCamera = camera;

// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int weight,
int height) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.

if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}

// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}

// make any resize, rotate or reformatting changes here

// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();

} catch (Exception e){
}
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
}
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub

}
}
}


main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<FrameLayout
android:id="@+id/videoview"
android:layout_width="720px"
android:layout_height="480px"/>
<Button
android:id="@+id/mybutton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="REC"
android:textSize="12dp"/>
</LinearLayout>
</LinearLayout>


AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.exercise.AndroidVideoCapture"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission>
<uses-permission android:name="android.permission.CAMERA"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".AndroidVideoCapture"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

</application>
</manifest>


Download the files.

next:
- Video Capture using MediaRecorder with Flash Light

Reference:
- Android Dev Guide: Camera

25 comments:

chilltime said...

Sweet post android-er the preview is working now, but when I press the record button it stops. Im trying to fix it now, its probably because I have a lot of things that go on when the video records.

I wanted to ask how would you implement on flash while the video is recording, i tried implementing on the last tutorial u put on here but It never worked for me. I am guessing i have to let it know the camera instance at any point it it toggling between flash on and flash off?

Thanks again,

chilltime

Erik said...

hello chilltime,

For the flash:
Are you using Sony device?

chilltime said...

No i have htc, but i want the flash to work on all android phones. Your flash example "http://android-er.blogspot.com/2011/02/control-flash-light-function-as-torch.html" works but it crashes either when the flash is on and I am recording or the when I am recording and I press the flash button. Any help will suffice. Thank in advance.

Erik said...

hello chilltime,

I tried your case and have the same result! because the camera is being locked when video recording. I think we cannot change flash setting while recording, even the build-in Camera app cannot do that.

Anyway, we can set flash mode before video recording start: Video Capture using MediaRecorder with Flash Light.

रचना said...

Hello,
I implemented this code n it is working fine.
But my problem is onClick of record button the size of surface is getting changed.It becomes very small i.e. imagine the size of 4*4 square n rest screen is blank.

Have you faced this problem?
Do you know any solution on this?
Let me know as soon as possible.
Thank you.

रचना said...

Hi again,
This might sound silly but I wanted to know that this code will also work for 2.2,right??

I am confused as 1 code works on 2.2 and another does not.
Thank you.

रचना said...

Hey there,
I hope to get an answer for this question at least.
I implemented this code but when i say Capture Video, camera gets open but it is not full screen because of width 720px and height 480px.
But i want it full screen n a button at bottom.
how to set parameters for Full Screen inside activity??
Please let me know.

AlCan said...

Hi, I'm using Android 2.3.6 and the MEDIA_RECORDER_INFO_MAX_DURATION_REACHED is not being fired in my onInfo listener, has anyone else noticed something similar?

israel said...

Hi there,

The camera works fine but it's not saving to disk. Everytime I stop recording and go to media library, there is nothing there...

Can you think of anything why this is happening?

Great work though, thanks for putting this online!

RNdo said...

thanks sir this's code helped me ,

but i couldn't save to sd card or my internal memory
how can I determine save the video to sdcard/internal memory as I want

Erik said...

Make sure add "android.permission.WRITE_EXTERNAL_STORAGE" in AndroidManifest.xml

HerbM said...

Like israel said, my video isn't getting save to storage, or maybe not closed properly.

Device: Motorola Droid Bionic which has Android 2.3.4

Symptoms: Video preview works, press record screen blanks. Is that correct behavior?

Press stop.

File is located in storage but is always 0 bytes.

I am working on solving the above and ideas or suggestions are appreciated....

--
HerbM

Akash Singh said...
This comment has been removed by the author.
Akash Singh said...

hiii i have use this code for above 2.3. its work well but i face problem in android 4.0 . please give any idea how to remove this problem ..

eijaz255 said...

Hi,

The codes is not working on android 4.0.3 ICS.. how to solve this?

Unknown said...

Hi,
Thanks for the great sample.
I cannot get it to work with the front-facing camera on my Nexus S, Galaxy Nexus or Nexus 7. Do you know why?

I have posted a StackOverflow:
http://stackoverflow.com/questions/14681703/android-cant-record-video-with-front-facing-camera-mediarecorder-start-failed

Madhavi M said...

Hi,
i have used this code on Android 4.0 when i open the application iam seeing the camera but when i click on record button iam getting black screen on that can anyone please help me how to solve this problem i need it as soon as possible.
thanks,
Madhavi M

ThusharaChaminda said...

Hi ,

Thank you so much.
You save my time.

manfred said...

I got your code working on an SGS2 with 4.1.2. But I have a problem with the preview when recording with the QUALITY_1080P profile: With mediaRecorder.start() the resolution of the preview changes notably and the autofocus does not correctly find the optimal solution. With QUALITY_720P or less everything works seamless.

Any idea?

Uke said...

Hi,

first of all thanks for posting the code for everyone.

When i try to run the code i get the famous error " Camera Error 100" e i can't solv it.

Any idea?

I'm running the code on sdk Nexus One 2.3.3

Rohit Yeole said...

Hi
Code is running smmothly on my device but the issue i am facing is that by default the camera view is rotated in 90 degress. How can i rotate it to the default view.

Anonymous said...

For SDK's that don't support .setProfile(), use the following:

mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setMaxDuration(60000);
mediaRecorder.setVideoSize(720,480);
mediaRecorder.setVideoFrameRate(24);

Unknown said...

Hi there, just wanna inquire that how to add the time lapse function in the video?

Unknown said...

open and storage all function work but in back camera i want to start default front camera in this function but i also try c=camera.open(1); but not work ..

so how can i start front camera instead back camera.

Unknown said...

Hello , when i click record button quickly two times.Then app crash.



11-19 14:44:46.611: E/MediaRecorder(28540): stop failed: -1007
11-19 14:44:46.621: E/AndroidRuntime(28540): FATAL EXCEPTION: main
11-19 14:44:46.621: E/AndroidRuntime(28540): java.lang.RuntimeException: stop failed.
11-19 14:44:46.621: E/AndroidRuntime(28540): at android.media.MediaRecorder.stop(Native Method)
11-19 14:44:46.621: E/AndroidRuntime(28540): at com.exercise.AndroidVideoCapture.AndroidVideoCapture$1.onClick(AndroidVideoCapture.java:61)
11-19 14:44:46.621: E/AndroidRuntime(28540): at android.view.View.performClick(View.java:4117)
11-19 14:44:46.621: E/AndroidRuntime(28540): at android.view.View$PerformClick.run(View.java:17041)
11-19 14:44:46.621: E/AndroidRuntime(28540): at android.os.Handler.handleCallback(Handler.java:615)
11-19 14:44:46.621: E/AndroidRuntime(28540): at android.os.Handler.dispatchMessage(Handler.java:92)
11-19 14:44:46.621: E/AndroidRuntime(28540): at android.os.Looper.loop(Looper.java:137)
11-19 14:44:46.621: E/AndroidRuntime(28540): at android.app.ActivityThread.main(ActivityThread.java:4747)
11-19 14:44:46.621: E/AndroidRuntime(28540): at java.lang.reflect.Method.invokeNative(Native Method)
11-19 14:44:46.621: E/AndroidRuntime(28540): at java.lang.reflect.Method.invoke(Method.java:511)
11-19 14:44:46.621: E/AndroidRuntime(28540): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
11-19 14:44:46.621: E/AndroidRuntime(28540): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
11-19 14:44:46.621: E/AndroidRuntime(28540): at dalvik.system.NativeStart.main(Native Method)