From ea91d859d3b0112dca6f6192730f88566bfe2786 Mon Sep 17 00:00:00 2001 From: Andrew Gunnerson Date: Sun, 5 Nov 2023 17:12:45 -0500 Subject: [PATCH] Allow --camera-id to specify a physical camera ID With this commit, CameraCapture will search both the logical and physical camera ID lists for a matching camera. If none match, the ID is assumed to be a logical camera. Signed-off-by: Andrew Gunnerson --- .../com/genymobile/scrcpy/CameraCapture.java | 61 ++++++++++++++----- .../java/com/genymobile/scrcpy/LogUtils.java | 2 +- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/server/src/main/java/com/genymobile/scrcpy/CameraCapture.java b/server/src/main/java/com/genymobile/scrcpy/CameraCapture.java index b9da3658fe..7d018ee684 100644 --- a/server/src/main/java/com/genymobile/scrcpy/CameraCapture.java +++ b/server/src/main/java/com/genymobile/scrcpy/CameraCapture.java @@ -20,6 +20,7 @@ import android.os.Build; import android.os.Handler; import android.os.HandlerThread; +import android.util.Pair; import android.util.Range; import android.view.Surface; @@ -43,7 +44,8 @@ public class CameraCapture extends SurfaceCapture { private final int fps; private final boolean highSpeed; - private String cameraId; + private String logicalCameraId; + private String physicalCameraId; private Size size; private HandlerThread cameraThread; @@ -72,34 +74,59 @@ public void init() throws IOException { cameraExecutor = new HandlerExecutor(cameraHandler); try { - cameraId = selectCamera(explicitCameraId, cameraFacing); - if (cameraId == null) { + Pair cameraIdPair = selectCamera(explicitCameraId, cameraFacing); + logicalCameraId = cameraIdPair.first; + physicalCameraId = cameraIdPair.second; + if (logicalCameraId == null) { throw new IOException("No matching camera found"); } - size = selectSize(cameraId, explicitSize, maxSize, aspectRatio, highSpeed); + // Size can be queried against the physical camera. + size = selectSize(physicalCameraId != null ? physicalCameraId : logicalCameraId, + explicitSize, maxSize, aspectRatio, highSpeed); if (size == null) { throw new IOException("Could not select camera size"); } - Ln.i("Using camera '" + cameraId + "'"); - cameraDevice = openCamera(cameraId); + // But the camera must be opened with a logical camera. + Ln.i("Using camera: logical=" + logicalCameraId + ", physical=" + physicalCameraId); + cameraDevice = openCamera(logicalCameraId); } catch (CameraAccessException | InterruptedException e) { throw new IOException(e); } } - private static String selectCamera(String explicitCameraId, CameraFacing cameraFacing) throws CameraAccessException { + private static Pair selectCamera(String explicitCameraId, CameraFacing cameraFacing) throws CameraAccessException { + CameraManager cameraManager = ServiceManager.getCameraManager(); + String[] cameraIds = cameraManager.getCameraIdList(); + if (explicitCameraId != null) { - return explicitCameraId; - } + // The explicit camera ID could be a logical or physical camera. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + for (String cameraId : cameraIds) { + if (cameraId.equals(explicitCameraId)) { + break; + } - CameraManager cameraManager = ServiceManager.getCameraManager(); + CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); + int[] capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); + if (LogUtils.contains(capabilities, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA)) { + for (String phyCameraId : characteristics.getPhysicalCameraIds()) { + if (phyCameraId.equals(explicitCameraId)) { + return new Pair(cameraId, phyCameraId); + } + } + } + } + } + + // Assume it's a logical camera ID. + return new Pair(explicitCameraId, null); + } - String[] cameraIds = cameraManager.getCameraIdList(); if (cameraFacing == null) { // Use the first one - return cameraIds.length > 0 ? cameraIds[0] : null; + return new Pair(cameraIds.length > 0 ? cameraIds[0] : null, null); } for (String cameraId : cameraIds) { @@ -107,7 +134,7 @@ private static String selectCamera(String explicitCameraId, CameraFacing cameraF int facing = characteristics.get(CameraCharacteristics.LENS_FACING); if (cameraFacing.value() == facing) { - return cameraId; + return new Pair(cameraId, null); } } @@ -226,7 +253,8 @@ public boolean setMaxSize(int maxSize) { this.maxSize = maxSize; try { - size = selectSize(cameraId, null, maxSize, aspectRatio, highSpeed); + size = selectSize(physicalCameraId != null ? physicalCameraId : logicalCameraId, + null, maxSize, aspectRatio, highSpeed); return size != null; } catch (CameraAccessException e) { Ln.w("Could not select camera size", e); @@ -286,6 +314,11 @@ public void onError(CameraDevice camera, int error) { private CameraCaptureSession createCaptureSession(CameraDevice camera, Surface surface) throws CameraAccessException, InterruptedException { CompletableFuture future = new CompletableFuture<>(); OutputConfiguration outputConfig = new OutputConfiguration(surface); + + if (physicalCameraId != null) { + outputConfig.setPhysicalCameraId(physicalCameraId); + } + List outputs = Arrays.asList(outputConfig); int sessionType = highSpeed ? SessionConfiguration.SESSION_HIGH_SPEED : SessionConfiguration.SESSION_REGULAR; diff --git a/server/src/main/java/com/genymobile/scrcpy/LogUtils.java b/server/src/main/java/com/genymobile/scrcpy/LogUtils.java index ca97731424..bdfc454959 100644 --- a/server/src/main/java/com/genymobile/scrcpy/LogUtils.java +++ b/server/src/main/java/com/genymobile/scrcpy/LogUtils.java @@ -132,7 +132,7 @@ public static String buildCameraListMessage(boolean includeSizes) { return builder.toString(); } - private static boolean contains(int[] array, int value) { + static boolean contains(int[] array, int value) { for (int i : array) { if (i == value) { return true;