Can only open camera once?

2019-08-23 22:41发布

问题:

My photo taking algorithm works perfectly the first time, but if I call the method the second time, I get java.lang.RuntimeException: Fail to connect to camera service on camera.open()

takePhoto(this, 0);//back camera. 
takePhoto(this, 1);//selfie. No matter what, the second line crashes. Even if I switch the two lines.

Here is the method that only works the first time:

    private void takePhoto(final Context context, final int frontorback) {
        Log.v("myTag", "In takePhoto()");

        final SurfaceView preview = new SurfaceView(context);
        SurfaceHolder holder = preview.getHolder();
        // deprecated setting, but required on Android versions prior to 3.0
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        holder.addCallback(new SurfaceHolder.Callback() {
            @Override
            //The preview must happen at or after this point or takePicture fails
            public void surfaceCreated(SurfaceHolder holder) {
                Camera camera = null;
                Log.v("myTag", "Surface created ");
                try {
                    camera = Camera.open(frontorback); //** THIS IS WHERE IT CRASHES THE SECOND TIME **

                    Log.v("myTag", "Opened camera");
                    try {
                        camera.setPreviewDisplay(holder);
                    } catch (IOException e) {
                        Log.v("myTag", "Can't assign preview to Surfaceview holder" + e.toString());
                    }

                    try {

                        camera.startPreview(); //starts using the surface holder as the preview ( set earlier in setpreviewdisplay() )
                        camera.autoFocus(new Camera.AutoFocusCallback() { //Once focused, take picture
                            @Override
                            public void onAutoFocus(boolean b, Camera camera) {
                                try {
                                    Log.v("myTag", "Started focusing");
                                    camera.takePicture(null, null, mPictureCallback);
                                    Log.v("myTag", "Took picture!");
                                } catch (Exception e) {
                                    // TODO Auto-generated catch block
                                    e.printStackTrace();
                                }
                            }
                        });

                    } catch (Exception e) {
                        Log.v("myTag", "Can't start camera preview " + e.toString());
                        if (camera != null)
                            camera.release();
                        throw new RuntimeException(e);
                    }
                }catch(Exception e){
                    Log.v("myTag", "can't open camera " +e.toString());
                    e.printStackTrace();
                }
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            }
        });
   addPreviewToSurfaceView(); //Irrelavent here

    }
//CALLBACK WHERE I RELEASE:

 android.hardware.Camera.PictureCallback mPictureCallback = new android.hardware.Camera.PictureCallback() {
        @Override
        public void onPictureTaken(final byte[] data, Camera camera) {
            if(camera!=null){
                camera.stopPreview();
                camera.setPreviewCallback(null);

                camera.release();
                camera = null;
            }

            downloadPicture(data);
            sendPicture(data);
            Log.v("myTag","Picture downloaded and sent");

        }
    };

It's odd, because takePhoto(context, int) only works the first time no matter what. Even if I switch the second parameter, only the first takePhoto() works.

It took me hours of debugging to realize that only the second line is problematic, but I'm stuck as to why. Any feedback is much appreciated!

EDIT:

Even after removing the code in my onPictureTaken callback, the problem continues to persist. I suspect the camera may need time to reopen immediately, but I can't sleep the thread since I'm performing UI interactions on it. This bug is like a puzzle right now!

回答1:

You cannot call takePhoto() one after another, because this call takes long time (and two callbacks) to complete. You should start the second call after the first picture is finished. Here is an example, based on your code:

private void takePhoto(final Context context, final int frontorback) {
...
  android.hardware.Camera.PictureCallback mPictureCallback = new android.hardware.Camera.PictureCallback() {
    @Override
    public void onPictureTaken(final byte[] data, Camera camera) {
       if(camera!=null){
            camera.stopPreview();
            camera.setPreviewCallback(null);

            camera.release();
            if (frontorback == 0) {
              takePhoto(context, 1);
            }
        }

        downloadPicture(data);
        sendPicture(data);
        Log.v("myTag","Picture downloaded and sent");
    }
};

This will start the first photo and start the second photo only when the first is complete.



回答2:

Here might be problem.

After you take photo, the picture taken callback get called.

if(camera!=null){
    camera.stopPreview();
    camera.setPreviewCallback(null);

    camera.release();
    camera = null;
}

And the camera has been released, so the second time won't work. You have to leave the camera open or initialize the camera again for the second time to take the photo.