Camera not being released properly on Astro Tab A10 running Marshmallow

80 Views Asked by At

I have the some of the following code to use the camera:

@Override
public void surfaceCreated(SurfaceHolder holder) {
    if (mCamera == null) {
        mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
        try {
            mCamera.setPreviewDisplay(mHolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

private void resetCamera() {
    if (!videoReset) {
        if (videoStarted && !videoStopped) {
            mMediaRecorder.stop();
        }
        MediaScannerConnection.scanFile(TherapistActivity.this, new String[]{videoFile.getAbsolutePath()}, null, null);

        mMediaRecorder.reset();
        mMediaRecorder.release();
        mCamera.release();
        mCamera = null;
        mMediaRecorder = null;

        videoReset = true;
        initSuccess = false;

    }
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    surfaceWidth = width;
    surfaceHeight = height;
    try {
        if (!initSuccess)
            startPreview(mHolder.getSurface());
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private void initRecorder(Surface surface) throws IOException {
        Camera.Parameters parameters = mCamera.getParameters();
        Camera.Size previewSize = getOptimalPreviewSize(surfaceWidth, surfaceHeight);

        if (previewSize != null) {
            parameters.setPreviewSize(previewSize.width, previewSize.height);
        }
        parameters.setVideoStabilization(false);
        mCamera.setParameters(parameters);
        mCamera.startPreview();
        mCamera.unlock();

        if (mMediaRecorder == null) mMediaRecorder = new MediaRecorder();
        mMediaRecorder.setCamera(mCamera);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mMediaRecorder.setVideoEncodingBitRate(3072 * 1000);
        mMediaRecorder.setVideoFrameRate(60);
        mMediaRecorder.setVideoSize(1280, 720);
        mMediaRecorder.setOutputFile(videoFile.getAbsolutePath());

        if (!mApp.videoTime) {
            mMediaRecorder.setMaxDuration(30000);
        } else {
            mMediaRecorder.setMaxDuration(Integer.MAX_VALUE);
        }
        mMediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
            @Override
            public void onInfo(MediaRecorder mr, int what, int extra) {
                if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
                      mCameraWrapper.setBackgroundColor(Color.TRANSPARENT);
                    try {     
                        mCamera.stopPreview();
                        videoRecorded = true;
                    } catch (RuntimeException re) {
                        Log.e("Error", "Could not stop camera!");
                    } finally {
                        videoPreviewStarted = false;
                    }
                    btRecord.setTag("stop");
                    btRecord.setBackgroundResource(R.drawable.stop_nobkgrnd_gray);
                    tvVideoCountdown.setVisibility(View.GONE);
                    initSuccess = false;
                }
            }
        });
        try {
            mMediaRecorder.prepare();
            videoPreviewStarted = true;
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
        initSuccess = true;
    }
}

private Camera.Size getOptimalPreviewSize(int w, int h) {
    Camera.Size result = null;
    Camera.Parameters p = mCamera.getParameters();
    for (Camera.Size size : p.getSupportedPreviewSizes()) {
        if (size.width <= w && size.height <= h) {
            if (result == null) {
                result = size;
            } else {
                int resultArea = result.width * result.height;
                int newArea = size.width * size.height;

                if (newArea > resultArea) {
                    result = size;
                }
            }
        }
    }
    return result;
}

On the Astro Tab A10 running Marshmallow, apparently the Camera isn't being released properly when being run the second time, since the camera fails to open until the device is rebooted. I am pretty sure this isn't a permissions problem, since I granted the app permissions to the camera at runtime as well as including camera permissions in the manifest.

Does anyone know what might be the problem?

EDIT: Here is the stack trace:

  E/AndroidRuntime: FATAL EXCEPTION: main
       Process: com.mobilityresearch.treadmill3, PID: 4144
       java.lang.RuntimeException: Fail to connect to camera service
           at android.hardware.Camera.<init>(Camera.java:495)
           at android.hardware.Camera.open(Camera.java:341)
           at com.mobilityresearch.treadmill3.TherapistActivity.surfaceCreated(TherapistActivity.java:8260)
           at android.view.SurfaceView.updateWindow(SurfaceView.java:583)
           at android.view.SurfaceView.setVisibility(SurfaceView.java:257)
           at com.mobilityresearch.treadmill3.TherapistActivity$26.onClick(TherapistActivity.java:1701)
           at android.view.View.performClick(View.java:5204)
           at android.view.View$PerformClick.run(View.java:21153)
           at android.os.Handler.handleCallback(Handler.java:739)
           at android.os.Handler.dispatchMessage(Handler.java:95)
           at android.os.Looper.loop(Looper.java:148)
           at android.app.ActivityThread.main(ActivityThread.java:5417)
           at java.lang.reflect.Method.invoke(Native Method)
           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:742)
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:632)

This doesn't happen on any of our other tablets. In fact, it doesn't happen on the older version of the Astro Tab A10 running Android 5.1 Lollipop. I tried calling resetCamera the camera both in surfaceCreated before opening the preview, and surfacedDestroyed after closing the preview, and it doesn't work.

EDIT 2: I just found out that if I actually record video, it works fine, but if I don't record video and only display the preview, it doesn't work.

EDIT 3: Added surfaceChanged and initRecorder. Updated resetCamera.

1

There are 1 best solutions below

0
Sagar On BEST ANSWER

You are missing call to stopPreview() which stops capturing and drawing preview frames to the surface and setPreviewDisplay(null) which releases the preview display.

Update your resetCamera() as follows:

private void resetCamera() {
        ...
        mCamera.stopPreview();
        mCamera.setPreviewDisplay(null);
        mCamera.release();
        ...

    }
}