0

I have implemented an activity which shows camera preview, it is working fine. Initially on activity start I start activity with front camera. The app works just fine, But Now I am trying to implement the button which switches camera on fly. I mean it should not restart the whole activity but switch the camera from front to back or vice versa. But I am getting following problem:

My Problem is

  • When I switch from front to back camera the preview of front camera gets stuck but the camera back camera starts and its preview never shows up -and When I open the back camera though it is not showing me preview , when I click to take picture and when I navigate to the gallery then I saw the picture it takes with the back camera.
  • So its assure me that the camera is getting switched but the only problem is getting its preview and ends the last one's preview. How can I do that ?

What I have done so far

This is how I switch the camera:

public static Camera getCameraInstance2(Camera camera) {

    if (camera != null) {
        camera.stopPreview();
        camera.release();
        camera = 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_BACK;
    }

    try {
        camera = Camera.open(currentCameraId);
        camera.startPreview();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return camera;
}

it is opening camera but not displaying its preview.

and this is my Surfaceview class

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

private Camera camera;
public static  SurfaceHolder holder;
private Activity activity;


public CameraPreview(Context context, AttributeSet attrs, Activity activity) {
    super(context, attrs);

}

public CameraPreview(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public CameraPreview(Context context) {
    super(context);
}

public void init(Camera camera,Activity activity) {
    this.camera = camera;
    this.activity = activity;
    initSurfaceHolder();
}

@SuppressWarnings("deprecation") // needed for < 3.0
private void initSurfaceHolder() {
    holder = getHolder();
    holder.addCallback(this);
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    initCamera(holder);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);



}

private void initCamera(SurfaceHolder holder) {
    try {

        Camera.Parameters param;
        param = camera.getParameters();

        Camera.Size bestSize = null;
        List<Camera.Size> sizeList = camera.getParameters().getSupportedPreviewSizes();
        bestSize = sizeList.get(0);
        for(int i = 1; i < sizeList.size(); i++){
            if((sizeList.get(i).width * sizeList.get(i).height) > (bestSize.width * bestSize.height)){
                bestSize = sizeList.get(i);
            }
        }

        List<Integer> supportedPreviewFormats = param.getSupportedPreviewFormats();
        Iterator<Integer> supportedPreviewFormatsIterator = supportedPreviewFormats.iterator();
        while(supportedPreviewFormatsIterator.hasNext()){
            Integer previewFormat =supportedPreviewFormatsIterator.next();
            if (previewFormat == ImageFormat.YV12) {
                param.setPreviewFormat(previewFormat);
            }
        }

        param.setPreviewSize(bestSize.width, bestSize.height);
        Log.v("Best Preview Size"+bestSize.width+":/::/:"+bestSize.height);
        param.setPictureSize(bestSize.width, bestSize.height);

        camera.setParameters(param);

        requestLayout();
        camera.setPreviewDisplay(holder);
        camera.startPreview();



    } catch (Exception e) {
        Log.d("Error setting camera preview", e);
    }
}

@Override
public void surfaceChanged(SurfaceHolder mHolder, int format, int width, int height) {


    //new work around

    Camera.Parameters param;
    param = camera.getParameters();

    Camera.Size bestSize = null;
    List<Camera.Size> sizeList = camera.getParameters().getSupportedPreviewSizes();
    bestSize = sizeList.get(0);
    for(int i = 1; i < sizeList.size(); i++){
        if((sizeList.get(i).width * sizeList.get(i).height) > (bestSize.width * bestSize.height)){
            bestSize = sizeList.get(i);
        }
    }

    List<Integer> supportedPreviewFormats = param.getSupportedPreviewFormats();
    Iterator<Integer> supportedPreviewFormatsIterator = supportedPreviewFormats.iterator();
    while(supportedPreviewFormatsIterator.hasNext()){
        Integer previewFormat =supportedPreviewFormatsIterator.next();
        if (previewFormat == ImageFormat.YV12) {
            param.setPreviewFormat(previewFormat);
        }
    }

    param.setPreviewSize(bestSize.width, bestSize.height);

    param.setPictureSize(bestSize.width, bestSize.height);

    camera.setParameters(param);

    Display display = ((WindowManager)activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
    if(display.getRotation() == Surface.ROTATION_0) {
        camera.setDisplayOrientation(90);
        param.setPreviewSize(bestSize.width, bestSize.height);
    } else if(display.getRotation() == Surface.ROTATION_270) {
        camera.setDisplayOrientation(180);
        param.setPreviewSize(bestSize.width, bestSize.height);
    }

    requestLayout();
    try {
        camera.setPreviewDisplay(holder);
    } catch (IOException e) {
        e.printStackTrace();
    }
    camera.startPreview();







}// end surfaceChanged





@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    Log.e("TABACT"+"surfaceDestroyed()");
    camera.stopPreview();
    camera.setPreviewCallback(null);
    camera.release();
    camera = null;

    this.getHolder().removeCallback(this);
  //  camera.release();
  //  camera.stopPreview();

}

public static Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio=(double)h / w;

    if (sizes == null) return null;

    Camera.Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    for (Camera.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 (Camera.Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }
    return optimalSize;
}

I have added my surface preview class named "CameraPreview" .

Edit3

I have examined one thing more and that is when I wrote to get the instance of camera and start preview, its starting camera sucessfully. I mean first time when Activity gets resume its start front camera and when its resume second time its start back camera, and each and every thing is just fine. I am switching the camera by using the code I shared above. Now problem is, when I try this code from activity button the preview stuck whereas the camera toggles in background of that stucked preview of last camera.

So how to remove the last camera preview after switching and start new preview by new opened camera with in the activity.

**What I am thinking **

When user click on the flip camera button , I should show the dialog with a button to switch camera , which will put activity in pause state and on click of yes button simply dismiss the dialog which will resume the activity and as a result it will show the preview of switched camera.

The upper approach would may work , but this is not a good technique. But what could be the solution. Please share with me.

stacy queen
  • 280
  • 1
  • 4
  • 19

2 Answers2

0

You need to remove the previously attached CameraPreview from the root layout and then add this CameraPreview with changed camera. Take for instance I am using a FrameLayout to display the CameraPreview and then if I wish to change the camera preview from front to back to vice-versa, I will remove views attached to FrameLayout (layout.removeAllViews()) and then add CameraPreview with the changed cameraId.

Ishaan
  • 3,658
  • 2
  • 23
  • 39
-1

Base on that answer: Android: Switch camera when button clicked I made this code work for me:

private void switchCamera() {
    if (mCamera != null) {
        mCamera.setPreviewCallback(null);
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
        try {
            if (mCameraFacing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                mCameraFacing = Camera.CameraInfo.CAMERA_FACING_BACK;
            }
            else {
                mCameraFacing = Camera.CameraInfo.CAMERA_FACING_FRONT;
            }
            mCamera = Camera.open(mCameraFacing);
            mCamera.setPreviewDisplay(mPreview.getHolder());
            mCamera.startPreview();
        }
        catch (final Exception e) {
            e.printStackTrace();
        }
    }
}

The key for me here was to stopPreview() and just reset Camera and start a new startPreview().

Aurora0001
  • 13,139
  • 5
  • 50
  • 53
shkschneider
  • 17,833
  • 13
  • 59
  • 112