qq_33623384
Kason Wong
2019-03-05 15:25

Camera2 如何同时开启前后摄像头Preview并进行录像?

  • java
  • android-studio
  • android

我按照camera2 谷歌的demo,同时开启两个线程进行相同操作,但是运行时最后一个摄像头能preview出来,前一个停在最后一帧,不能两个同时动。请问如何进行多线程同时操作?本人新手,多线程不太熟悉,求指教!

@Override
public void onResume() {
    super.onResume();

    if (texture_front.isAvailable()) {
        openCamera(false,texture_front.getWidth(), texture_front.getHeight());
    } else {
        texture_front.setSurfaceTextureListener(mFrontTextureListener);
    }
    if (texture_back.isAvailable()) {
        openCamera(true,texture_back.getWidth(), texture_back.getHeight());
    } else {
        texture_back.setSurfaceTextureListener(mBackTextureListener);
    }
    startBackgroundThread();

}

        private void startBackgroundThread() {
    mBackgroundThread_front = new HandlerThread("Camera_front");
    mBackgroundThread_front.start();
    mHandler_front = new Handler(mBackgroundThread_front.getLooper());

    mBackgroundThread_back=new HandlerThread("Camera_back");
    mBackgroundThread_back.start();
    mHandler_back=new Handler(mBackgroundThread_back.getLooper());
}

    接下来OpenCamera方法
    private void openCamera(boolean isBack,int width, int height) {
    if (!hasPermissionsGranted(VIDEO_PERMISSIONS)) {
        requestVideoPermissions();
        return;
    }
    final Activity activity = getActivity();
    if (null == activity || activity.isFinishing()) {
        return;
    }
    CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
    try {
        L.d("tryAcquire");
        if (!getSemaphore(isBack).tryAcquire(2500, TimeUnit.MILLISECONDS)) {
            throw new RuntimeException("Time out waiting to lock camera opening.");
        }
        String cameraId;
        if (isBack){
            cameraId = manager.getCameraIdList()[0];      //0后   1前
            // Choose the sizes for camera preview and video recording
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
            StreamConfigurationMap map = characteristics
                    .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
            if (map == null) {
                throw new RuntimeException("Cannot get available preview/video sizes");
            }
            mVideoSize = chooseVideoSize(map.getOutputSizes(MediaRecorder.class));
            mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
                    width, height, mVideoSize);

            int orientation = getResources().getConfiguration().orientation;
            if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
                texture_back.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
            } else {
                texture_back.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
            }
            configureTransform(true,width, height);
            mMediaRecorder = new MediaRecorder();
            manager.openCamera(cameraId, mStateCallback_back, null);
        }else {
            cameraId = manager.getCameraIdList()[1];     //0后   1前
        // Choose the sizes for camera preview and video recording
        CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
        StreamConfigurationMap map = characteristics
                .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
        mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
        if (map == null) {
            throw new RuntimeException("Cannot get available preview/video sizes");
        }
        mVideoSize = chooseVideoSize(map.getOutputSizes(MediaRecorder.class));
        mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
                width, height, mVideoSize);
        int orientation = getResources().getConfiguration().orientation;
        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            texture_front.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
        } else {
            texture_front.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
        }
        configureTransform(false,width, height);
        mMediaRecorder = new MediaRecorder();
        manager.openCamera(cameraId, mStateCallback_front, null);
        }

    } catch (CameraAccessException e) {
       showTip("Cannot access the camera.");
        activity.finish();
    } catch (NullPointerException e) {
        // Currently an NPE is thrown when the Camera2API is used but not supported on the
        // device this code runs.
        ErrorDialog.newInstance(getString(R.string.camera_error))
                .show(getChildFragmentManager(), FRAGMENT_DIALOG);
    } catch (InterruptedException e) {
        throw new RuntimeException("Interrupted while trying to lock camera opening.");
    }
}

#然后到StateCallBack,我分成前后摄像头两个callback
private CameraDevice.StateCallback mStateCallback_back = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice cameraDevice) {
mCameraDevice = cameraDevice;
startPreview(true);
mCameraOpenCloseLock.release();
if (null != texture_back) {
configureTransform(true,texture_back.getWidth(), texture_back.getHeight());
}
}

    @Override
    public void onDisconnected(@NonNull CameraDevice cameraDevice) {
        mCameraOpenCloseLock.release();
        cameraDevice.close();
        mCameraDevice = null;
    }

    @Override
    public void onError(@NonNull CameraDevice cameraDevice, int error) {
        mCameraOpenCloseLock.release();
        cameraDevice.close();
        mCameraDevice = null;
        Activity activity = getActivity();
        if (null != activity) {
            activity.finish();
        }
    }

};


    private CameraDevice.StateCallback mStateCallback_front = new CameraDevice.StateCallback() {

    @Override
    public void onOpened(@NonNull CameraDevice cameraDevice) {
        mCameraDevice = cameraDevice;
        startPreview(false);
        mCameraOpenCloseLock_front.release();
        if (null != texture_front) {
            configureTransform(false,texture_front.getWidth(), texture_front.getHeight());
        }
    }

    @Override
    public void onDisconnected(@NonNull CameraDevice cameraDevice) {
        mCameraOpenCloseLock_front.release();
        cameraDevice.close();
        mCameraDevice = null;
    }

    @Override
    public void onError(@NonNull CameraDevice cameraDevice, int error) {
        mCameraOpenCloseLock_front.release();
        cameraDevice.close();
        mCameraDevice = null;
        Activity activity = getActivity();
        if (null != activity) {
            activity.finish();
        }
    }

};

Callback成功后会返回startPreview()方法

private void startPreview(final Boolean isBack) {
if (null == mCameraDevice || !getTexture(isBack).isAvailable() || null == mPreviewSize) {
return;
}
final String threadName;
if (isBack){
threadName="Camera_back";
}else {
threadName="Camera_front";
}

        try {
            closePreviewSession();
            SurfaceTexture texture = getTexture(isBack).getSurfaceTexture();
            assert texture != null;
            texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
            mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            Surface previewSurface = new Surface(texture);
            mPreviewBuilder.addTarget(previewSurface);
            mCameraDevice.createCaptureSession(Collections.singletonList(previewSurface),
                    new CameraCaptureSession.StateCallback() {

                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession session) {
                            mPreviewSession = session;
                            //updatePreview
                            if (null == mCameraDevice) {
                                return;
                            }
                            try {
                                setUpCaptureRequestBuilder(mPreviewBuilder);
                                HandlerThread thread = new HandlerThread(threadName);
                                thread.start();
                                mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, mHandler_back);
                            } catch (CameraAccessException e) {
                                e.printStackTrace();
                            }
                        }

                        @Override
                        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                            Activity activity = getActivity();
                            if (null != activity) {
                                Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
                            }
                        }
                    }, mHandler_back);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

}

    private AutoFitTextureView getTexture(boolean isBack){
    if (isBack){
        return texture_back;
    }else {
        return texture_front;
    }

}

以上是预览的核心代码,录像部分就不贴上去了。试了很多方法,始终不能两个摄像头同时previeew,只能其中一个单独预览。求教

图片说明

  • 点赞
  • 回答
  • 收藏
  • 复制链接分享

3条回答

为你推荐