如何基于Camera2 Api同时运行两个不同的相机预览?
Hey there! I’ve helped many developers work through dual camera preview setups, so let’s break this down step by step—covering both the framework-side code and whether you’ll need to touch the HAL layer.
First: Confirm Hardware Support
Before writing any code, make sure your device can actually run two camera streams at the same time:
- Use the
CameraManagerto check concurrent camera groups:val cameraManager = getSystemService(CAMERA_SERVICE) as CameraManager val concurrentGroups = cameraManager.getConcurrentCameraIds() // Verify your target camera IDs (e.g., front + back) are in the same group - Also, check the camera’s characteristics for
REQUEST_AVAILABLE_CAPABILITIES_CONCURRENT_STREAMS—this flag confirms the camera can participate in concurrent sessions.
Framework-Side Implementation Steps
1. Set Up Dual Preview UI
Use two TextureView widgets (or SurfaceView if you prefer) in your layout to display each camera’s feed:
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <TextureView android:id="@+id/frontCameraPreview" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1"/> <TextureView android:id="@+id/backCameraPreview" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1"/> </LinearLayout>
2. Open and Configure Both Cameras
Camera operations are asynchronous, so you’ll need to handle each camera’s setup separately:
// Helper to open a camera and start preview fun initCameraPreview(cameraId: String, targetSurface: Surface) { val cameraManager = getSystemService(CAMERA_SERVICE) as CameraManager cameraManager.openCamera(cameraId, object : CameraDevice.StateCallback() { override fun onOpened(camera: CameraDevice) { // Create a capture session for this camera val surfaces = listOf(targetSurface) camera.createCaptureSession(surfaces, object : CameraCaptureSession.StateCallback() { override fun onConfigured(session: CameraCaptureSession) { val previewRequest = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW).apply { addTarget(targetSurface) } // Start repeating preview session.setRepeatingRequest(previewRequest.build(), null, null) } override fun onConfigureFailed(session: CameraCaptureSession) { // Handle configuration failure (e.g., incompatible surface format) } }, null) } override fun onDisconnected(camera: CameraDevice) = camera.close() override fun onError(camera: CameraDevice, error: Int) = camera.close() }, null) } // Initialize front camera when its TextureView is ready frontCameraPreview.surfaceTextureListener = object : TextureView.SurfaceTextureListener { override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) { val frontCameraId = getCameraIdByLensFacing(CameraCharacteristics.LENS_FACING_FRONT) initCameraPreview(frontCameraId, Surface(surface)) } // Implement other required listener methods (onSurfaceTextureSizeChanged, etc.) } // Initialize back camera similarly backCameraPreview.surfaceTextureListener = object : TextureView.SurfaceTextureListener { override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) { val backCameraId = getCameraIdByLensFacing(CameraCharacteristics.LENS_FACING_BACK) initCameraPreview(backCameraId, Surface(surface)) } // Implement other required listener methods } // Helper to get camera ID by lens facing fun getCameraIdByLensFacing(lensFacing: Int): String { val cameraManager = getSystemService(CAMERA_SERVICE) as CameraManager for (cameraId in cameraManager.cameraIdList) { val characteristics = cameraManager.getCameraCharacteristics(cameraId) if (characteristics.get(CameraCharacteristics.LENS_FACING) == lensFacing) { return cameraId } } throw IllegalArgumentException("No camera found with lens facing: $lensFacing") }
3. Critical Tips to Avoid Issues
- Match Preview Formats: Ensure both cameras use compatible preview resolutions and image formats (e.g.,
ImageFormat.YUV_420_888). Mismatches will break capture session configuration. - Permission Handling: Don’t forget to request the
CAMERApermission (and handle runtime permissions on Android 6.0+). - Resource Cleanup: Always close
CameraDeviceandCameraCaptureSessionwhen your activity/fragment is destroyed to prevent memory leaks. - Performance Tuning: Dual preview uses more system resources—test on target devices and lower preview resolutions if you see lag or crashes.
HAL Layer Modifications: Do You Need Them?
Short answer: Almost never, unless you’re building custom hardware.
- If your device’s hardware (ISP, camera sensors, bus bandwidth) supports concurrent camera streams, the stock HAL implementation will handle it automatically. The Android Framework communicates with the HAL via standard interfaces to enable concurrent sessions.
- If the hardware doesn’t support concurrent streams (e.g., a single ISP that can’t process two feeds at once), no HAL modification can fix this—it’s a fundamental hardware limitation.
To confirm, check your device’s official specs or reach out to the chipset manufacturer (like Qualcomm or MediaTek) to verify concurrent stream support.
内容的提问来源于stack exchange,提问作者Akshit Agarwal

