Search code examples
androidandroid-cameraandroid-memory

Camera onPictureTaken() sometimes not called


I have an app published to Google Play, which at some point takes a picture using the front facing camera from a background service. Now, I've gotten complaints from users that this specific part of the app is not very consistent, that I know is true, because it namely often stops after I call camera.takePicture(). - i.e. the PictureCallback is not not called.

There are several other questions here on SO about this issue, here and here, and I've looked through them all, and their fixes did nothing for me. My situation differs from the others since, in my app, onPictureTaken is usually called, but fails from time to time (something like 1/10).

I've scratched my head for 2 days on this one, without any progress.

I've among other things tried commenting out the Thread i start in PictureCapllback, which seems to make it more consistent, but not completely, so it may be a memory issue of some sort.

    ...
    // Take photo
    takePhoto(new MyPictureCallback());
}

private class MyPictureCallback implements Camera.PictureCallback{
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        Log.d(Constants.TAG_ALERT_PROCESS, "onPictureTaken() called");

        // Release camera
        cameraHandler.release();

        // Continue process
        new Thread(new GotPictureRunnable(data)).start();
    }
}

public void takePhoto(Camera.PictureCallback callback) {

    // Create new cameraInfo object
    cameraInfo = new Camera.CameraInfo();

    // Get camera object
    camera = getCamera();

    // If camera is null bail
    if(camera == null){
        return;
    }

    // Set camera options
    setCameraParameters();
    Log.v(Constants.TAG_ALERT_PROCESS, "Camera parameters set");

    try{
        camera.setPreviewTexture(new SurfaceTexture(0)); // Hack for no preview
        Log.v(Constants.TAG_ALERT_PROCESS, "Preview set");
    } catch (Exception e){
        Log.v(Constants.TAG_ALERT_PROCESS, "Failed to set Preview Texture at camera.takePicture()");
        e.printStackTrace();
        return;
    }

    // Start the preview
    camera.startPreview();
    Log.v(Constants.TAG_ALERT_PROCESS, "Preview started");

    // Preview needs time to start
    Utilities.sleepThread(1000);
    Log.v(Constants.TAG_ALERT_PROCESS, "Thread slept for 1000ms");

    // Take picture and pass our callback
    Log.v(Constants.TAG_ALERT_PROCESS, "Calling takePicture()");
    camera.takePicture(null, null, callback);
}

private void setCameraParameters() {

    // Create parameters object
    Camera.Parameters params = this.camera.getParameters();

    // Set picture size
    setPictureSize(params, context);

    // Set jpeg quality
    params.setJpegQuality(getPictureQuality());

    // Set orientation
    params.setRotation(getRotation());

    // Set Parameters
    this.camera.setParameters(params);
}

public void release(){
    if(camera != null){
        camera.release();
        camera = null;
    }
}

Log on failure

07-06 18:09:38.134     135-1051/? I/CameraClient﹕ Opening camera 1
07-06 18:09:38.134     135-1051/? I/CameraHAL﹕ camera_device open
07-06 18:09:38.149  16009-19806/com...V/myTag﹕ Got front Camera
07-06 18:09:38.157  16009-19806/com...V/myTag﹕ Set camera parameters
07-06 18:09:38.157  16009-19806/com...V/myTag﹕ Preview set
07-06 18:09:38.540  16009-19806/com...V/myTag﹕ Preview started
07-06 18:09:38.548    135-19815/? D/﹕ PPM: Standby to first shot: Sensor Change completed -  :390.137 ms :  1404662978557 ms
07-06 18:09:39.540  16009-19806/com...V/myTag﹕ Thread slept for 1000ms
07-06 18:09:39.540  16009-19806/com...V/myTag﹕ Calling takePicture()
07-06 18:09:39.774    135-19815/? D/﹕ PPM: Shot to snapshot:  :228.852 ms :  1404662979777 ms
07-06 18:09:39.813    135-19815/? D/﹕ PPM: Shot to Jpeg:  :274.231 ms :  1404662979823 ms
07-06 18:09:39.931      135-135/? E/CameraHAL﹕ Adapter state switch PREVIEW_ACTIVE Invalid Op! event = 0x5
07-06 18:09:40.173      135-135/? I/CameraClient﹕ Destroying camera 1

Log on success

07-06 18:13:21.868      135-502/? I/CameraClient﹕ Opening camera 1
07-06 18:13:21.868      135-502/? I/CameraHAL﹕ camera_device open
07-06 18:13:22.048  16009-19890/com...V/myTag﹕ Got front Camera
07-06 18:13:22.056  16009-19890/com...V/myTag﹕ rotation value = Automatic
07-06 18:13:22.063  16009-19890/com...V/myTag﹕ Set camera parameters
07-06 18:13:22.063  16009-19890/com...V/myTag﹕ Preview set
07-06 18:13:22.517  16009-19890/com...V/myTag﹕ Preview started
07-06 18:13:22.524    135-19893/? D/﹕ PPM: Standby to first shot: Sensor Change completed -  :460.845 ms :  1404663202530 ms
07-06 18:13:23.517  16009-19890/com...V/myTag﹕ Thread slept for 1000ms
07-06 18:13:23.517  16009-19890/com...V/myTag﹕ Calling takePicture()
07-06 18:13:23.727    135-19893/? D/﹕ PPM: Shot to snapshot:  :216.3 ms :  1404663203736 ms
07-06 18:13:23.774    135-19893/? D/﹕ PPM: Shot to Jpeg:  :261.688 ms :  1404663203781 ms
07-06 18:13:23.837  16009-16009/com...D/myTag﹕ onPictureTaken() called // <-- This line is only diff from failure log
07-06 18:13:23.837      135-135/? E/CameraHAL﹕ Adapter state switch PREVIEW_ACTIVE Invalid Op! event = 0x5
07-06 18:13:24.001      135-135/? I/CameraClient﹕ Destroying camera 1

Solution

  • Have you used a surface holder? From kitkat onwards, this is a necessity and not an option.

    Also try making your callback as an instance variable of your activity.

    Also look at similar problem I had, which I could fix using the first solution I have proposed here. Camera API not working on KITKAT