Hi,
I want to show you here a complete tutorial of making a videorecorder. I just browsed all over the internet, but there is not a fully working code that can record full HD videos or any type of videos.
I faced many issues, like samsung galaxy which dont support full hd resolutions, or the image was green, or some flickeering. This code will fix all this issues.
I hope this will help you.
Code for VideoRecorderActivity:
package com.androidgenuine.videorecorder; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import android.app.Activity; import android.hardware.Camera; import android.hardware.Camera.Size; import android.media.MediaRecorder; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.util.Log; import android.view.SurfaceHolder; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.FrameLayout; import android.widget.Toast; public class VideoRecorderActivity extends Activity implements Camera.ErrorCallback, SurfaceHolder.Callback, OnClickListener { private static final String TAG = "VideoRecording"; Handler handler = new Handler(); private Camera mCamera; private CameraPreview mPreview; private MediaRecorder mMediaRecorder; private Button captureButton; private boolean isRecording = false; private List<Size> sizes; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Create an instance of Camera. if (mCamera == null) { mCamera = getCameraInstance(); // Create preview view and set it as the content of our activity. mPreview = new CameraPreview(this, mCamera); } else { mCamera.release(); mCamera = getCameraInstance(); // Create preview view and set it as the content of our activity. mPreview = new CameraPreview(this, mCamera); } int i = R.id.videoview; Object o = this.findViewById(i); FrameLayout preview = (FrameLayout) o; preview.addView(mPreview); Camera.Parameters params = mCamera.getParameters(); params.set("cam_mode", 1); mCamera.setParameters(params); sizes = params.getSupportedPreviewSizes(); // Add a listener to the Capture button captureButton = (Button) findViewById(R.id.mybutton); captureButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (isRecording) { mMediaRecorder.stop(); // TODO Auto-generated method stub // stop recording and release camera // stop the recording releaseMediaRecorder(); // release the MediaRecorder object mCamera.lock(); // take camera access back from // MediaRecorder // inform the user that recording has stopped setCaptureButtonText("Capture"); isRecording = false; } else { // initialize video camera if (prepareVideoRecorder()) { // Camera is available and unlocked, MediaRecorder is // prepared, // now you can start recording mMediaRecorder.start(); // inform the user that recording has started setCaptureButtonText("Stop"); isRecording = true; } else { // prepare didn't work, release the camera releaseMediaRecorder(); } } } }); } public void setCaptureButtonText(String s) { captureButton.setText(s); } @Override public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, now tell the camera where to draw the // preview. try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); Toast.makeText(this, "Device is not supported!", Toast.LENGTH_LONG) .show(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub } @Override public void surfaceDestroyed(SurfaceHolder holder) { // TODO Auto-generated method stub } private boolean prepareVideoRecorder() { // mCamera = getCameraInstance(); mMediaRecorder = new MediaRecorder(); // Step 1: Unlock and set camera to MediaRecorder mCamera.unlock(); mMediaRecorder.setCamera(mCamera); // Step 2: Set sources // activate this for recording with sound // mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); mMediaRecorder.setVideoSize(getMaxSupportedVideoSize().width, getMaxSupportedVideoSize().height); mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); // mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// // activate this for recording with sound // Step 4: Set output file mMediaRecorder.setOutputFile(getOutputMediaFile("movie")); // Step 5: Set the preview output mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface()); // Step 6: Prepare configured MediaRecorder try { mMediaRecorder.prepare(); } catch (IllegalStateException e) { Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage()); Toast.makeText(this, "Device is not supported!", Toast.LENGTH_LONG) .show(); releaseMediaRecorder(); return false; } catch (IOException e) { Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage()); Toast.makeText(this, "Device is not supported!", Toast.LENGTH_LONG) .show(); releaseMediaRecorder(); return false; } return true; } @Override public void onClick(View v) { /* * Log.i("onClick", "BEGIN"); if(!recording) { recording = * startRecording(); } else { stopRecording(); recording = false; } * Log.i("onClick", "END"); */ } @Override protected void onPause() { super.onPause(); if (isRecording) { mMediaRecorder.stop(); releaseMediaRecorder(); mCamera.lock(); setCaptureButtonText("RECORD"); isRecording = false; } else { releaseMediaRecorder(); } // releaseCamera(); } @Override protected void onDestroy() { super.onDestroy(); if (isRecording) { mMediaRecorder.stop(); releaseMediaRecorder(); mCamera.lock(); setCaptureButtonText("RECORD"); isRecording = false; } else { releaseMediaRecorder(); releaseCamera(); } // releaseCamera(); } private void releaseMediaRecorder() { if (mMediaRecorder != null) { mMediaRecorder.reset(); // clear recorder configuration mMediaRecorder.release(); // release the recorder object mMediaRecorder = null; mCamera.lock(); // lock camera for later use } } private void releaseCamera() { if (mCamera != null) { mCamera.release(); // release the camera for other applications mCamera = null; } } private Camera getCameraInstance() { Camera c = null; try { c = Camera.open(); // attempt to get a Camera instance // c = this.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 } public Camera open() { return Camera.open(); } @Override public void onError(int error, Camera camera) { // TODO Auto-generated method stub if (error == Camera.CAMERA_ERROR_SERVER_DIED || error == Camera.CAMERA_ERROR_UNKNOWN) { releaseCamera(); finish(); Toast.makeText(this, "Camera has died", Toast.LENGTH_LONG).show(); } } public Size getMaxSupportedVideoSize() { int maximum = sizes.get(0).width; int position = 0; for (int i = 0; i < sizes.size() - 1; i++) { if (sizes.get(i).width > maximum) { maximum = sizes.get(i).width; // new maximum position = i - 1; } } if (position == 0) { int secondMax = sizes.get(1).width; position = 1; for (int j = 1; j < sizes.size() - 1; j++) { if (sizes.get(j).width > secondMax) { secondMax = sizes.get(j).width; // new maximum position = j; } } } return sizes.get(position); // end method max } private static String getOutputMediaFile(String sufix) { String mediaFile; File mediaStorageDir = new File( Environment.getExternalStorageDirectory(), "/VideoLogger"); if (!mediaStorageDir.exists()) { if (!mediaStorageDir.mkdirs()) { Log.d("VideoLogger", "failed to create directory"); return null; } } String timeStamp = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss") .format(new Date()); if (!sufix.equals("movie")) { mediaFile = mediaStorageDir.getPath() + File.separator + "output_" + timeStamp + "_" + sufix + ".txt"; } else { mediaFile = mediaStorageDir.getPath() + File.separator + "output_" + timeStamp + ".mp4"; } return mediaFile; } }
Code for main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <FrameLayout android:id="@+id/videoview" android:layout_width="fill_parent" android:layout_height="fill_parent" /> <Button android:id="@+id/mybutton" android:layout_width="150dip" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:text="RECORD" android:textSize="12dp"/> </RelativeLayout>
Code for CameraPreview.java
package com.androidgenuine.videorecorder; import java.io.IOException; import java.util.List; import android.content.Context; import android.hardware.Camera; import android.hardware.Camera.Size; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder mHolder; private Camera mCamera; private List<Size> sizes; public CameraPreview(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 width, 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 Camera.Parameters params = mCamera.getParameters(); sizes = params.getSupportedPreviewSizes(); Log.d("PREVIEW SIZES", String.valueOf(getMaxSupportedVideoSize().width)+":"+String.valueOf(getMaxSupportedVideoSize().height)); params.setPreviewSize(getMaxSupportedVideoSize().width, getMaxSupportedVideoSize().height); mCamera.setParameters(params); // 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 } public Size getMaxSupportedVideoSize() { int maximum = sizes.get(0).width; int position = 0; for (int i = 0; i < sizes.size() - 1; i++) { if (sizes.get(i).width > maximum) { maximum = sizes.get(i).width; // new maximum position = i - 1; } } if (position == 0) { int secondMax = sizes.get(1).width; position = 1; for (int j = 1; j < sizes.size() - 1; j++) { if (sizes.get(j).width > secondMax) { secondMax = sizes.get(j).width; // new maximum position = j; } } } return sizes.get(position); // end method max } }
The permissions are:
<uses-permission android:name="android.permission.RECORD_VIDEO" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" />
Also please use screen orientation landscape in manifest for this to work.
If you have questions please post them in the comment section.
hello developer …………..
that is great post but when i move from video camera to image camera i get java.lang.RuntimeException: Fail to connect to camera service exception . how to resolve this problem i have all permission in manifest file.
thnanx …………………
Hi, thanks for the great example. I want the app to start recording immediately when I launch it, so I tried taking the code in the onClick listener and putting it into the main. But I get an error saying”Application lost the surface” / “Preview surface not available”. Could you please help?
Hello,
Thanks for the example.I have implemented the code accordingly in my project but after running that I can only see a blank screen with a button (text written as “Record” in that button) as per the xml layout.
It does not even opens the camera,and I am completely unable to record the video.
Could you please tell me how will I be able to record the video.
thanxx
please add a logcat error…what logcat says when you click the button?…
Do you added permissions in manifest file?…Do you have a android 4.0 device?