Showing posts with label Android Camera And SurfaceView. Show all posts
Showing posts with label Android Camera And SurfaceView. Show all posts

Saturday, December 1, 2012

Video recording application in android

We can take video from android default intent also but customization becomes impossible as it has its own limitation. So we need to make our own camera application in android to capture video. It will work as camcorder also. Making camera application in android , is bit complicated task if we do not understand it step by step

It need these three thing


  • SurfaceView to give one platform to show material
  • Camera to show material on surface provided by surfaceview
  • And a media recorder to record the video provided by camera and surface view

So let make one layout, which have one surfaceview class inside it and start with surfaceview


  • surfaceview called surfaceCreated(SurfaceHolder arg0) very first time. So we need to open camera here. Handle the case where camera is not able to work properly
 @Override
public void surfaceCreated(SurfaceHolder arg0) {
camera = openFrontFacingCamera();
if (camera != null) {
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
camera.release();
camera = null;
}
} else {
Toast.makeText(act, "Problem in opening Camera.", Toast.LENGTH_LONG)
.show();
act.finish();
}
}

  • Now camera is ready. Once surfaceChanged(SurfaceHolder arg0, int format, int height,int width), we will instantiate the MediaRecorder and attach all thing to capture video properly. It important to remember that camera attribute is need to be set in a order but their value may differ

 @Override
public void surfaceChanged(SurfaceHolder arg0, int format, int height,
int width) {
Camera.Size previewSize = null;
try {
Camera.Parameters parameters = camera.getParameters();
List<Camera.Size> supportSize = parameters
.getSupportedPreviewSizes();
if (supportSize != null) {
previewSize = getOptimalPreviewSize(supportSize, width, height);
}
parameters.setPreviewSize(previewSize.width, previewSize.height);
parameters.set("orientation", "portrait");
camera.setPreviewDisplay(arg0);
camera.setParameters(parameters);
camera.startPreview();
camera.unlock();
m_recorder.setPreviewDisplay(arg0.getSurface());
m_recorder.setCamera(camera);
m_recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
m_recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
m_recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
m_recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
m_recorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
m_recorder.setMaxDuration(90000);
m_recorder.setOnInfoListener(oninfoLis);
m_recorder.setVideoSize(previewSize.width, previewSize.height);
m_recorder.setVideoFrameRate(30);

m_recorder.setVideoEncodingBitRate(500);
m_recorder.setAudioEncodingBitRate(128);
m_recorder.setOutputFile("/mnt/sdcard/myfile"
+ SystemClock.elapsedRealtime() + ".mp4");
m_recorder.prepare();
m_recorder.start();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.getMessage();
}
}
  • But most important is to get optimal preview display to camera. For one device there may be more than one preview display so we need use best among them to capture good quality video


         private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null)
return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}

So this article shows how to capture video with out default intent. Video quality may vary according to device resolution. and you need to set Video Frame Rate according to you device type. I have found this limit on android developer site



SD (Low quality)SD (High quality)HD (Not available on all devices)
Video codecH.264 Baseline ProfileH.264 Baseline ProfileH.264 Baseline Profile
Video resolution176 x 144 px480 x 360 px1280 x 720 px
Video frame rate12 fps30 fps30 fps
Video bitrate56 Kbps500 Kbps2 Mbps
Audio codecAAC-LCAAC-LCAAC-LC
Audio channels1 (mono)2 (stereo)2 (stereo)
Audio bitrate24 Kbps128 Kbps192 Kbps

 Download Source Code

Wednesday, January 18, 2012

Android Camera : Taking picture through android camera and surfaceview example





Camera Integration with Surface View provide you a way to take photo in android application. You can Intent Activity for taking photo. But Surface View provide a way to take photo in Customization way. This article address about SurfaceView and Android Phone camera integration

Make one XML file path res/layout which Include on simple SurfaceView


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent" android:layout_height="fill_parent"

android:orientation="vertical">

<SurfaceView android:id="@+id/surface_camera"

android:layout_width="fill_parent" android:layout_height="10dip"

android:layout_weight="1">

</SurfaceView>

</LinearLayout>



Camera Implementation code

Create an activity called CameraView that implements the interface SurfaceHolder.Callback. This will overide some method which control life cycle of Surface which later will be associated with Camera.
public class CamaraView extends Activity implements SurfaceHolder.Callback

  • This interface “SurfaceHolder.Callback” is used to receive information about changes that occur in the surface (in this case, the camera preview). SurfaceHolder.Callback implements three methods:
  • SurfaceChanged   - This method is called when the size or the format of the surface changes.
  • SurfaceCreated - When, in the first instance, the surface is created, this method is called.
  • SurfaceDestroyed - This is called when the surface is destroyed.

Camera Code

We'll use the onCreate() method in our activity.

super.onCreate(icicle);

setContentView(R.layout.camera_surface);

mSurfaceView = (SurfaceView) findViewById(R.id.surface_camera);

mSurfaceHolder = mSurfaceView.getHolder();

mSurfaceHolder.addCallback(this);

mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

}


We set the layout to the Activity with the setContentView to the camera_surface (the one we created some lines above!) and we create a SurfaceView object, getting it from the xml file.

mSurfaceHolder = mSurfaceView.getHolder();

mSurfaceHolder.addCallback(this);

mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);


With these lines, we get the holder from the surfaceview, and we add the callback function to “this”. This means that our activity is going to manage the surfaceview.
Now see how the callback functions are implemented.

public void surfaceCreated(SurfaceHolder holder) {

mCamera = Camera.open();

mCamera is an Object of the class “Camera”. In the surfaceCreated we “open” the camera. This is how to start it!!

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {

if (mPreviewRunning) {

mCamera.stopPreview();

}

Camera.Parameters p = mCamera.getParameters();

p.setPreviewSize(w, h);

mCamera.setParameters(p);

try {

mCamera.setPreviewDisplay(holder);

} catch (IOException e) {

e.printStackTrace();

}

mCamera.startPreview();

mPreviewRunning = true;

}


This is the method that prepares the camera, sets parameters and starts the preview of the image in our Android screen. I have used a “semaphore” parameter to prevent crashing: when the mPreviewRunning is true, it means that the camera is active and has not “closed”, so this way we can work with it.

public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mPreviewRunning = false;
mCamera.release();
}

This is the method where we stop the camera and release the resources associated to the camera. See, that here we set the mPreviewRunning flat to “false”, with this, we prevent crashing in the surfaceChanged method. Why? Because this means that we have “closed” the camera, and we cannot set parameters or start image previews in our camera (stuff that the surfaceChanged method does) if it is closed!.
And let's finish with the most important method:

Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] imageData, Camera c) {
}
};

This method is called when a picture is taken. For example, you could create an OnClickListener on the screen that calls the PictureCallBack method when you click on the screen. This method just gives you thebyte[] of the image. So, just convert it from byte[] to some image format you want, using the Bitmap and BitmapFactory class that Android offers us.