Trying to develop android Camera App with custom preview layout for recording videos.
Folowing this source:
http://developer.android.com/guide/topics/media/camera.html
Camera's preview works fine,
but the problem begins when I try to record video.
After pressing the capture button the App crashes.
During debugging I figured out that problem occurs during the creating of Camera instance. Camera.open() doesn't work (what means that camera is not available) and I receive Camera object = null (getCameraInstance() method returns null).
I tried to specify which camera to open as advised here Camera.open() returns null But it doesn't help.
Also the app crashes after pausing and resuming it (I think the problem is also in onPause() / onResume().
Wery appreciate any piece of advice
My code is here:
Activity:
package com.leo.leoscamera;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
public class CameraActivity extends Activity {
private Camera mCamera;
private CameraPreview mPreview;
private MediaRecorder mMediaRecorder;
private static final int MEDIA_TYPE_VIDEO = 2;
private static final String TAG = "L-Camera";
private boolean isRecording = false;
Button captureButton;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Create an instance of Camera
mCamera = getCameraInstance();
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
// Add a listener to the Capture button
captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isRecording) {
// stop recording and release camera
mMediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object
mCamera.lock(); // take camera access back from MediaRecorder
// inform the user that recording has stopped
captureButton.setText("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
captureButton.setText("Stop");
isRecording = true;
} else {
// prepare didn't work, release the camera
releaseMediaRecorder();
// inform user
}
}
}
}
);
}
/**
* Configuring the MediaRecorder
* @return
*/
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
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
// Step 4: Set output file
mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());
// 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());
releaseMediaRecorder();
return false;
} catch (IOException e) {
Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
releaseMediaRecorder();
return false;
}
return true;
}
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance() {
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)
Log.d(TAG, "Camera is not available");
}
return c; // returns null if camera is unavailable
}
/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_CAMERA)) {
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(int type){
return Uri.fromFile(getOutputMediaFile(type));
}
/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "MyCameraApp");
// This location works best if you want the created images to be shared
// between applications and persist after your app has been uninstalled.
// Create the storage directory if it does not exist
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name (only video files)
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if(type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"VID_"+ timeStamp + ".mp4");
} else {
return null;
}
return mediaFile;
}
@Override
protected void onPause() {
super.onPause();
releaseMediaRecorder(); // if you are using MediaRecorder, release it first
releaseCamera(); // release the camera immediately on pause event
}
@Override
protected void onResume() {
super.onResume();
if(mCamera == null){
mCamera = getCameraInstance();
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
}
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;
}
}
}
Preview:
package com.leo.leoscamera;
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;
import android.view.View;
/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private static final String TAG = "Preview";
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);
}
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());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// 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
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
Manifest:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-feature android:name="android:hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="21" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" >
<activity
android:name=".CameraActivity"
android:label="@string/app_name"
android:screenOrientation="landscape" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Logcat:
07-23 22:22:51.715: W/ActivityThread(17225): Application com.leo.leoscamera is waiting for the debugger on port 8100...
07-23 22:22:51.717: I/System.out(17225): Sending WAIT chunk
07-23 22:22:51.735: I/dalvikvm(17225): Debugger is active
07-23 22:22:51.918: I/System.out(17225): Debugger has connected
07-23 22:22:51.919: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:52.119: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:52.320: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:52.520: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:52.721: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:52.921: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:53.122: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:53.323: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:53.523: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:53.724: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:53.924: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:54.125: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:54.326: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:54.526: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:54.727: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:54.928: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:55.129: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:55.330: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:55.530: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:55.731: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:55.932: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:56.133: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:56.334: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:56.535: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:56.735: I/System.out(17225): waiting for debugger to settle...
07-23 22:22:56.940: I/System.out(17225): debugger has settled (1448)
07-23 22:23:02.545: I/SurfaceView(17225): updateWindow -- onWindowVisibilityChanged, visibility = 0
07-23 22:23:02.615: E/(17225): appName=com.leo.leoscamera, acAppName=/system/bin/surfaceflinger
07-23 22:23:02.615: E/(17225): 0
07-23 22:23:02.621: I/MaliEGL(17225): [Mali]window_type=1, is_framebuffer=0, errnum = 0
07-23 22:23:02.622: I/MaliEGL(17225): [Mali]surface->num_buffers=4, surface->num_frames=3, win_min_undequeued=1
07-23 22:23:02.622: I/MaliEGL(17225): [Mali]max_allowed_dequeued_buffers=3
07-23 22:23:02.674: I/[MALI][Gralloc](17225): dlopen libsec_mem.so fail
07-23 22:23:02.683: I/SurfaceView(17225): updateWindow -- setFrame
07-23 22:23:02.689: I/SurfaceView(17225): updateWindow -- OnPreDrawListener, mHaveFrame = true
07-23 22:23:02.692: I/SurfaceView(17225): Changes: creating=true format=true size=true visible=true left=true top=true mUpdateWindowNeeded=false mReportDrawNeeded=false redrawNeeded=false forceSizeChanged=true mVisible=false mRequestedVisible=true
07-23 22:23:02.699: I/SurfaceView(17225): Cur surface: Surface(name=null)/@0x424b3588
07-23 22:23:02.727: I/SurfaceView(17225): New surface: Surface(name=null)/@0x424b3658, vis=true, frame=Rect(0, 0 - 866, 540)
07-23 22:23:02.728: I/SurfaceView(17225): Callback --> surfaceCreated
07-23 22:23:02.729: I/SurfaceView(17225): surfaceCreated callback +
07-23 22:23:03.318: I/SurfaceView(17225): surfaceCreated callback -
07-23 22:23:03.320: I/SurfaceView(17225): surfaceChanged -- format=4 w=866 h=540
07-23 22:23:03.320: I/SurfaceView(17225): surfaceChanged callback +
07-23 22:23:04.670: I/SurfaceView(17225): surfaceChanged callback -
07-23 22:23:04.670: I/SurfaceView(17225): surfaceRedrawNeeded
07-23 22:23:04.670: I/SurfaceView(17225): finishedDrawing
07-23 22:23:04.683: I/Choreographer(17225): Skipped 136 frames! The application may be doing too much work on its main thread.
07-23 22:23:04.700: I/SurfaceView(17225): updateWindow -- OnPreDrawListener, mHaveFrame = true
07-23 22:23:04.706: I/SurfaceView(17225): Changes: creating=false format=false size=false visible=false left=false top=false mUpdateWindowNeeded=true mReportDrawNeeded=true redrawNeeded=false forceSizeChanged=false mVisible=true mRequestedVisible=true
07-23 22:23:04.709: I/SurfaceView(17225): Cur surface: Surface(name=null)/@0x424b3588
07-23 22:23:04.729: I/SurfaceView(17225): New surface: Surface(name=null)/@0x424b3658, vis=true, frame=Rect(0, 0 - 866, 540)
07-23 22:23:04.730: I/SurfaceView(17225): surfaceRedrawNeeded
07-23 22:23:04.731: I/SurfaceView(17225): finishedDrawing
07-23 22:23:04.871: I/SurfaceView(17225): updateWindow -- UPDATE_WINDOW_MSG
07-23 22:23:04.915: I/SurfaceView(17225): updateWindow -- setFrame
07-23 22:23:04.919: I/SurfaceView(17225): updateWindow -- OnPreDrawListener, mHaveFrame = true
07-23 22:23:07.744: I/View(17225): Touch down dispatch to android.widget.Button{424a2650 VFED..C. ........ 866,234-960,306 #7f090040 app:id/button_capture}, event = MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=20.077026, y[0]=9.548996, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=191289023, downTime=191289023, deviceId=3, source=0x1002 }
07-23 22:23:07.776: I/View(17225): Touch up dispatch to android.widget.Button{424a2650 VFED..C. ...P..ID 866,234-960,306 #7f090040 app:id/button_capture}, event = MotionEvent { action=ACTION_UP, id[0]=0, x[0]=21.075989, y[0]=9.548996, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=191289100, downTime=191289023, deviceId=3, source=0x1002 }
07-23 22:23:07.800: I/SurfaceView(17225): updateWindow -- OnPreDrawListener, mHaveFrame = true
07-23 22:23:09.951: W/CameraBase(17225): An error occurred while connecting to camera: 0
07-23 22:23:13.078: W/dalvikvm(17225): threadid=1: thread exiting with uncaught exception (group=0x41e25cf8)
07-23 22:23:13.078: W/dalvikvm(17225): threadid=1: uncaught exception occurred
07-23 22:23:13.088: W/System.err(17225): java.lang.NullPointerException
07-23 22:23:13.092: W/System.err(17225): at com.leo.leoscamera.CameraActivity.prepareVideoRecorder(CameraActivity.java:95)
07-23 22:23:13.095: W/System.err(17225): at com.leo.leoscamera.CameraActivity.access$5(CameraActivity.java:89)
07-23 22:23:13.097: W/System.err(17225): at com.leo.leoscamera.CameraActivity$1.onClick(CameraActivity.java:64)
07-23 22:23:13.100: W/System.err(17225): at android.view.View.performClick(View.java:4463)
07-23 22:23:13.102: W/System.err(17225): at android.view.View$PerformClick.run(View.java:18770)
07-23 22:23:13.105: W/System.err(17225): at android.os.Handler.handleCallback(Handler.java:808)
07-23 22:23:13.118: W/System.err(17225): at android.os.Handler.dispatchMessage(Handler.java:103)
07-23 22:23:13.120: W/System.err(17225): at android.os.Looper.loop(Looper.java:193)
07-23 22:23:13.123: W/System.err(17225): at android.app.ActivityThread.main(ActivityThread.java:5333)
07-23 22:23:13.125: W/System.err(17225): at java.lang.reflect.Method.invokeNative(Native Method)
07-23 22:23:13.128: W/System.err(17225): at java.lang.reflect.Method.invoke(Method.java:515)
07-23 22:23:13.130: W/System.err(17225): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
07-23 22:23:13.132: W/System.err(17225): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
07-23 22:23:13.134: W/System.err(17225): at dalvik.system.NativeStart.main(Native Method)
07-23 22:23:13.135: W/dalvikvm(17225): threadid=1: calling UncaughtExceptionHandler
07-23 22:23:13.183: E/AndroidRuntime(17225): FATAL EXCEPTION: main
07-23 22:23:13.183: E/AndroidRuntime(17225): Process: com.leo.leoscamera, PID: 17225
07-23 22:23:13.183: E/AndroidRuntime(17225): java.lang.NullPointerException
07-23 22:23:13.183: E/AndroidRuntime(17225): at com.leo.leoscamera.CameraActivity.prepareVideoRecorder(CameraActivity.java:95)
07-23 22:23:13.183: E/AndroidRuntime(17225): at com.leo.leoscamera.CameraActivity.access$5(CameraActivity.java:89)
07-23 22:23:13.183: E/AndroidRuntime(17225): at com.leo.leoscamera.CameraActivity$1.onClick(CameraActivity.java:64)
07-23 22:23:13.183: E/AndroidRuntime(17225): at android.view.View.performClick(View.java:4463)
07-23 22:23:13.183: E/AndroidRuntime(17225): at android.view.View$PerformClick.run(View.java:18770)
07-23 22:23:13.183: E/AndroidRuntime(17225): at android.os.Handler.handleCallback(Handler.java:808)
07-23 22:23:13.183: E/AndroidRuntime(17225): at android.os.Handler.dispatchMessage(Handler.java:103)
07-23 22:23:13.183: E/AndroidRuntime(17225): at android.os.Looper.loop(Looper.java:193)
07-23 22:23:13.183: E/AndroidRuntime(17225): at android.app.ActivityThread.main(ActivityThread.java:5333)
07-23 22:23:13.183: E/AndroidRuntime(17225): at java.lang.reflect.Method.invokeNative(Native Method)
07-23 22:23:13.183: E/AndroidRuntime(17225): at java.lang.reflect.Method.invoke(Method.java:515)
07-23 22:23:13.183: E/AndroidRuntime(17225): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
07-23 22:23:13.183: E/AndroidRuntime(17225): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
07-23 22:23:13.183: E/AndroidRuntime(17225): at dalvik.system.NativeStart.main(Native Method)
07-23 22:23:17.512: I/Process(17225): Sending signal. PID: 17225 SIG: 9