在运行棉花糖的Astro Tab A10上未正确释放相机

时间:2018-04-13 18:55:54

标签: android android-camera surfaceview surfaceholder

我有以下一些代码来使用相机:

@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;
}

在运行Marshmallow的Astro Tab A10上,显然第二次运行时相机未正确释放,因为相机无法打开,直到设备重新启动。我很确定这不是一个权限问题,因为我在运行时将相应权限授予了相机,并在清单中包含了相机权限。

有谁知道可能是什么问题?

编辑:这是堆栈跟踪:

  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)

我们的任何其他平板电脑都不会发生这种情况。事实上,它并没有发生在运行Android 5.1 Lollipop的旧版Astro Tab A10上。我在打开预览之前尝试在resetCamera中调用surfaceCreated相机,在关闭预览后尝试surfacedDestroyed,但它无法正常工作。

编辑2:我刚刚发现,如果我实际录制视频,它可以正常工作,但如果我不录制视频并仅显示预览,则它无法正常工作。

编辑3:添加了surfaceChanged和initRecorder。更新了resetCamera。

1 个答案:

答案 0 :(得分:0)

您缺少对stopPreview()的调用,该调用停止捕获并将预览帧绘制到曲面,setPreviewDisplay(null)会释放预览显示。

按如下方式更新您的resetCamera()

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

    }
}