Mahm00d Mahm00d - 6 months ago 21
Android Question

Android camera preview freezes when switching cameras?

I am writing a custom camera for my app. It's working fine when opening the activity with either of the back or front cameras. But I'm really struggling with switching cameras inside the activity.

When I tap the switching camera button, the preview freezes and nothing happens. I have tried the answers and tips suggested in other questions related to the camera and the preview, but nothing works.

Here is my activity:

public class CameraActivity extends Activity implements SurfaceHolder.Callback {

//================================================================================
// Properties
//================================================================================

// Tag
private final String TAG = "CameraActivity";

// Camera and CameraPreview objects
private Camera mCamera;

// SurfaceHolder object
private SurfaceHolder mSurfaceHolder;
// private CameraPreview mPreview;

// ImageButtons
private ImageButton captureButton;
private ImageButton camSwitchButton;

// Picture previewLayout
FrameLayout previewLayout;
SurfaceView preview;

// Current camera is facing FRONT or BACK
private int currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;

// Picture taking callback
private Camera.PictureCallback mPictureCallback;

//================================================================================
// Methods
//================================================================================

@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Activity with no notification bar
requestWindowFeature(Window.FEATURE_NO_TITLE);

// Set content view
setContentView(R.layout.activity_camera);

// Initialize activity and previews
InitActivity();
InitPreview();

// Set onClicks
}

/**
* Initialize activity views
*/
private void InitActivity() {

// Create an instance of Camera
mCamera = GetCameraInstance(currentCameraId);

// Set the SurfaceView
preview = (SurfaceView) findViewById(R.id.camera_preview);
mSurfaceHolder = preview.getHolder();
mSurfaceHolder.addCallback(this);

}

/**
* Initialize the camera preview
*/
private void InitPreview() {

if (mCamera != null) {

try {
mCamera.setPreviewDisplay(mSurfaceHolder);
} catch (IOException e) {
// log
}

mCamera.startPreview();
}
}

@Override
protected void onPause() {
super.onPause();

if (mCamera != null) {
mCamera.stopPreview();
mCamera.release(); // release the camera for other applications
// mCamera = null;
}
}

@Override
protected void onResume() {
super.onResume();

if (mCamera == null) {
InitActivity();
InitPreview();
}
}

/**
* Get camera instance
* @return Camera instance (null if doesn't exist)
*/
private Camera GetCameraInstance(int camid) {

Camera c = null;

try {

c = Camera.open(camid); // attempt to get a Camera instance

Camera.Parameters campar = c.getParameters();

// Set auto-focus
if (getPackageManager().hasSystemFeature("android.hardware.camera.autofocus")) {
campar.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
}

c.setParameters(campar);

}
catch (Exception e){
// log
}

return c; // returns null if camera is unavailable
}

/**
* Switch the camera from front to back and vica verca
*/
private void SwitchCamera() {

if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
// mCamera = null;
}

//swap the id of the camera to be used
if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
}
else currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;

// Remove the view and re-add it
ViewGroup rootView = (ViewGroup) preview.getParent();
rootView.removeView(previewLayout);

mCamera = GetCameraInstance(currentCameraId);

InitActivity();

}

@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
Logger.Log(TAG, "SurfaceCreated");
InitPreview();
}

@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
// Return if no surface found
if (mSurfaceHolder.getSurface() == null) {
return;
}

// Start preview with new settings
Camera.Parameters params = mCamera.getParameters();
boolean isPortrait = IsPortrait();

// Configure the parameters (so the image is showing correctly)
ConfigureCameraParameters(params, isPortrait);

// Start preview
InitPreview();

}

@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}

/**
* Configure the camer parameters
* @param cameraParams Camera parameters
* @param isPortrait Is the camera in portrait mode?
*/
protected void ConfigureCameraParameters(Camera.Parameters cameraParams, boolean isPortrait) {

int angle;

Display display = getWindowManager().getDefaultDisplay();

// Correct the orientation
switch (display.getRotation()) {

case Surface.ROTATION_0: // This is display orientation
angle = 90; // This is camera orientation
break;
case Surface.ROTATION_90:
angle = 0;
break;
case Surface.ROTATION_180:
angle = 270;
break;
case Surface.ROTATION_270:
angle = 180;
break;
default:
angle = 90;
break;
}

mCamera.setDisplayOrientation(angle);
mCamera.setParameters(cameraParams);
}

/**
* Check whether the camera is in portrait mode
* @return True|False
*/
private boolean IsPortrait() {
return (getResources().getConfiguration().orientation
== Configuration.ORIENTATION_PORTRAIT);
}
}


Permissions in manifest:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />


I really appreciate it if someone could help.

Answer

You are pretty close, you dont need to destroy the surface view everytime you switch the camera, you only need to destroy the camera session and then make sure you re hook up the camera back to the surfaceview so it can be displayed. I was having some trouble with your front facing rear facing logic on a Razr Max so I just switched it to 1 and 0.

    private void SwitchCamera() {

    if (mCamera != null) {
        mCamera.stopPreview();
        mCamera.release();
         mCamera = null;
    }

    //swap the id of the camera to be used
    if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_FRONT) {
        currentCameraId = 0;
    } else  {
        currentCameraId = 1;
    }

    mCamera = GetCameraInstance(currentCameraId);

    InitPreview();
}