我按照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;
}
}