switch back/front camera on fly

2019-01-08 08:01发布

问题:

If I use only CAMERA_FACING_BACK or CAMERA_FACING_FRONT all works fine.

I have trouble with switch from CAMERA_FACING_BACK to CAMERA_FACING_FRONT.

My code snippet:

public class PhotoCameraActivity extends Activity implements OnClickListener {
private SurfaceView cameraView;
private Button turnButton;
private Camera camera = null;
private Callback listener;
private static int camId = Camera.CameraInfo.CAMERA_FACING_BACK;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.photo_camera_main);
    prepareActivity();
}

private void prepareActivity() {
    cameraView = (SurfaceView) findViewById(R.id.photo_camera_surface_view);

    turnButton = (ImageButton) findViewById(R.id.turn_button);
    turnButton.setOnClickListener(this);
}

@Override
public void onClick(View v) {
    if (v.equals(turnButton)) {
        if (Camera.getNumberOfCameras() > 1 && camId < Camera.getNumberOfCameras() - 1) {
            startCamera(camId + 1);
        } else {
            startCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
        }
    } 
}

@Override
protected void onResume() {
    startCamera(camId);
    super.onResume();
}

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

private void startCamera(int cameraId) {
    if (camera != null) {
        stopCamera();
    }       
    holder = cameraView.getHolder();
    listener = new Callback() {

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            try {
                camera.setPreviewDisplay(holder);
                camera.startPreview();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int           width, int height) {}
    };
    holder.addCallback(listener);


    camId = cameraId;
    camera = Camera.open(cameraId);
    Camera.Parameters params = camera.getParameters();
    if (cameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
        params.setPreviewSize(1280, 800);
    } else {
        params.setPreviewSize(640, 480);
    }
    camera.setParameters(params);

}

private void stopCamera(){
    System.out.println("stopCamera method");
    if (camera != null){
        camera.stopPreview();
        camera.setPreviewCallback(null);
        camera.release();
        camera = null;
        holder.removeCallback(listener);
        holder = null;
    }
}

}

回答1:

In onCreate() of my activity I add the following onClick listener to a button overlayed on my Preview SurfaceView (there are numerous example on the web for previewing):

ImageButton useOtherCamera = (ImageButton) findViewById(R.id.useOtherCamera);
//if phone has only one camera, hide "switch camera" button
if(Camera.getNumberOfCameras() == 1){
    useOtherCamera.setVisibility(View.INVISIBLE);
}
else {
    useOtherCamera.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    if (inPreview) {
        camera.stopPreview();
    }
    //NB: if you don't release the current camera before switching, you app will crash
    camera.release();

    //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;
    }
    camera = Camera.open(currentCameraId);
    //Code snippet for this method from somewhere on android developers, i forget where
    setCameraDisplayOrientation(CameraActivity.this, currentCameraId, camera);
    try {
        //this step is critical or preview on new camera will no know where to render to
        camera.setPreviewDisplay(previewHolder);
    } catch (IOException e) {
        e.printStackTrace();
    }
    camera.startPreview();
}

On my test device the back camera has an ID of 0 and the front has an id of 1. I suggest using Camera.CameraInfo static variables for your camera id's rather than hard-coding values. I am sure that will only cause issues on other devices.



回答2:

I restart Activity with cameraId = 2 and this is working.



回答3:

I removed and re-added SurfaceView in my layout and so it worked.

public void switchCamera(int cameraType)
{
    if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT))
    {
        if(Camera.getNumberOfCameras() > cameraType)
        {
            // Set selected camera
            this.cameraType = cameraType;
        }
        else
        {
            // Set default camera (Rear)
            this.cameraType = Camera.CameraInfo.CAMERA_FACING_BACK;
        }

        if(mCamera != null)
        {
            // Destroy previuos Holder
            surfaceDestroyed(holder);
            holder.removeCallback(this);

            // Remove and re-Add SurfaceView
            ViewGroup rootLayout = (ViewGroup) surface.getParent();
            rootLayout.removeView(surface);
            surface = new SurfaceView(context);
            holder = surface.getHolder();
            holder.addCallback(this);
            rootLayout.addView(surface, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        }
    }
}


回答4:

I have to remove the surface preview before adding a new one:

if (mPreview != null) {
        mPreview.surfaceDestroyed(mPreview.getHolder());
        mPreview.getHolder().removeCallback(mPreview);
        mPreview.destroyDrawingCache();
        FrameLayout preview = (FrameLayout) view.findViewById(R.id.camera_frame);
        preview.removeView(mPreview);
        mPreview.mCamera = null;
        mPreview = null;

    }

//then add your preview


回答5:

Use this code:

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_BACK;         

try {                
       mCamera = Camera.open(currentCameraId);   

       mCamera.setDisplayOrientation(90);

       mCamera.setPreviewDisplay(surfaceHolder);               

       mCamera.startPreview();

     } 
catch (Exception e) { e.printStackTrace(); }