Android (Camera) - How to synchronize stopPreview(

2020-02-14 08:18发布

问题:

I have an app in which the client uses the camera to take a picture. The preview of the image is being shown in the tablet using a SurfaceView, before the person hits my "click" button. When the person hits the click button, the method onPictureTaken is called, and, in that method, I save the image and also call the camera.stopPreview() method (so the user can see the picture that was taken).

There is an issue, however... If the user is moving around the tablet at the moment that the picture is taken, the still picture actually shown after the stopPreview method is called DOES NOT correspond to the one that I get in the byte array of the onPictureTaken method. There is a delay of some miliseconds there in which make that difference to stand out when the user is moving around the tablet just before the picture is taken (I know that 99% of the people will not move the tablet around while taken the picture, but my client actually noticed this issue and want it fixed...). I have tried to move the save operation to a separete thread, as shown below, so the onPictureTaken method can execute as fast as possible. Still, it had no effect at all...

private PictureCallback pictureCallback = new PictureCallback() {

    public void onPictureTaken(byte[] data, Camera camera) {

        camera.stopPreview();
        reference = data;

        new PictureCallbackHeavy().execute();
    }
};

I have also trield to call camera.stopPreview() just BEFORE I call the takePicture method (and not inside the onPictureTaken() method). But the result is the same.

What can I do to sync the stopPreview method so I can show EXACTLY the image that was taken and that is in the byte array of the onPictureTaken() callback?

Thank you in advance!! =)

回答1:

Unfortunately you can't acquire a reasonable good preview image just by calling stopPreview() because between the moment the picture is taken and the moment onPictureTaken() is called there can pass quite some time because it works like this:

  • The camera actually takes the picture (that's what you want to preview)
  • onShutter() is called
  • onPictureTaken() for the raw image data is called (on some devices)
  • onPictureTaken() for a scaled preview image is called (on some devices)
  • onPictureTaken() for the final compressed image data is called (the one we are talking about here)

So you have to convert the byte[] data in your onPictureTaken() callback into a Bitmap and map that Bitmap onto an ImageView that you should position above your SurfaceView to show the still preview image. The code will probably look something like this:

public void onPictureTaken(byte[] data, Camera camera) {
    camera.stopPreview();
    final Bitmap image = BitmapFactory.decodeByteArray(data, 0, data.length);
    surfaceView.setVisibility(SurfaceView.GONE);
    imageView.setVisibility(ImageView.VISIBLE);
    imageView.setImageBitmap(image);
    reference = data;
    new PictureCallbackHeavy().execute();
}