From 22d63688cdec8826dfbcac681acf96c110d23ec9 Mon Sep 17 00:00:00 2001 From: Avichal Rakesh Date: Mon, 25 Mar 2024 15:28:30 -0700 Subject: camera2: Ensure SessionCharacteristics and CameraCharactersitics can be used interchangeably CameraDeviceSetup#getSessionCharacteristics documentation says that the returned session characteristics can be used everywhere static charactersitics from CameraManager#getCameraCharacteristics is. However #getCameraCharacteristics sets up a few extra fields and keys in the CameraMetadataNative object returned from cameraservice that SessionCharacteristics was missing. To make the return value of #getSessionCharacteristics completely on par with the return value of #getCameraCharacteristics, this CL ensures that #getSessionCharacteristics and #getCameraCharateristics run the same logic on the CameraMetadataNative object returned from cameraservice before returning it to the caller. Bug: 303645857 Test: atest android.hardware.camera2.cts.CameraDeviceSetupTest passes Change-Id: Ia7ac40c768480a39fe0d1dd9392b5777b0fc2694 --- .../android/hardware/camera2/CameraManager.java | 100 ++++++++++++++++----- .../camera2/impl/CameraDeviceSetupImpl.java | 5 +- 2 files changed, 81 insertions(+), 24 deletions(-) diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 8feb133e832b..3eb5be04b93d 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -112,6 +112,34 @@ public final class CameraManager { private static final int CAMERA_TYPE_BACKWARD_COMPATIBLE = 0; private static final int CAMERA_TYPE_ALL = 1; + /** + * Caches the mapping between a logical camera ID and 'MultiResolutionStreamConfigurationMap' + * that is calculated by {@link #getPhysicalCameraMultiResolutionConfigs} as the calculation + * might take many binder calls. + *

+ * Note, this is a map of maps. The structure is: + *

+     * {
+     *     logicalCameraId_1 -> {
+     *         physicalCameraId_1 -> [
+     *             streamConfiguration_1,
+     *             streamConfiguration_2,
+     *             ...
+     *         ],
+     *         physicalCameraId_2 -> [...],
+     *         ...
+     *     },
+     *     logicalCameraId_2 -> {
+     *         ...
+     *     },
+     *     ...
+     * }
+     * 
+ *

+ */ + private final Map> + mCameraIdToMultiResolutionStreamConfigurationMap = new HashMap<>(); + private final Context mContext; private final Object mLock = new Object(); @@ -566,8 +594,14 @@ public final class CameraManager { private Map getPhysicalCameraMultiResolutionConfigs( String cameraId, CameraMetadataNative info, ICameraService cameraService) throws CameraAccessException { + if (mCameraIdToMultiResolutionStreamConfigurationMap.containsKey(cameraId)) { + return mCameraIdToMultiResolutionStreamConfigurationMap.get(cameraId); + } + HashMap multiResolutionStreamConfigurations = - new HashMap(); + new HashMap<>(); + mCameraIdToMultiResolutionStreamConfigurationMap.put(cameraId, + multiResolutionStreamConfigurations); Boolean multiResolutionStreamSupported = info.get( CameraCharacteristics.SCALER_MULTI_RESOLUTION_STREAM_SUPPORTED); @@ -676,30 +710,10 @@ public final class CameraManager { "Camera service is currently unavailable"); } try { - Size displaySize = getDisplaySize(); - CameraMetadataNative info = cameraService.getCameraCharacteristics(cameraId, mContext.getApplicationInfo().targetSdkVersion, overrideToPortrait, mContext.getDeviceId(), getDevicePolicyFromContext(mContext)); - try { - info.setCameraId(Integer.parseInt(cameraId)); - } catch (NumberFormatException e) { - Log.v(TAG, "Failed to parse camera Id " + cameraId + " to integer"); - } - - boolean hasConcurrentStreams = - CameraManagerGlobal.get().cameraIdHasConcurrentStreamsLocked(cameraId, - mContext.getDeviceId()); - info.setHasMandatoryConcurrentStreams(hasConcurrentStreams); - info.setDisplaySize(displaySize); - - Map multiResolutionSizeMap = - getPhysicalCameraMultiResolutionConfigs(cameraId, info, cameraService); - if (multiResolutionSizeMap.size() > 0) { - info.setMultiResolutionStreamConfigurationMap(multiResolutionSizeMap); - } - - characteristics = new CameraCharacteristics(info); + characteristics = prepareCameraCharacteristics(cameraId, info, cameraService); } catch (ServiceSpecificException e) { throw ExceptionUtils.throwAsPublicException(e); } catch (RemoteException e) { @@ -712,6 +726,48 @@ public final class CameraManager { return characteristics; } + + /** + * Utility method to take a {@link CameraMetadataNative} object and wrap it into a + * {@link CameraCharacteristics} object that has all required fields and keys set and is fit + * for apps to consume. + * + * @param cameraId camera Id that the CameraMetadataNative was fetched for. + * @param metadata base CameraMetadataNative to be wrapped + * @param cameraService remote cameraservice instance to be used if binder calls need + * to be made. + * @return A CameraCharacteristics object that can be used by the apps. + * @hide + */ + @NonNull + public CameraCharacteristics prepareCameraCharacteristics( + @NonNull String cameraId, CameraMetadataNative metadata, ICameraService cameraService) + throws CameraAccessException { + synchronized (mLock) { + try { + metadata.setCameraId(Integer.parseInt(cameraId)); + } catch (NumberFormatException e) { + Log.v(TAG, "Failed to parse camera Id " + cameraId + " to integer"); + } + + boolean hasConcurrentStreams = + CameraManagerGlobal.get().cameraIdHasConcurrentStreamsLocked(cameraId, + mContext.getDeviceId()); + metadata.setHasMandatoryConcurrentStreams(hasConcurrentStreams); + + Size displaySize = getDisplaySize(); + metadata.setDisplaySize(displaySize); + + Map multiResolutionSizeMap = + getPhysicalCameraMultiResolutionConfigs(cameraId, metadata, cameraService); + if (!multiResolutionSizeMap.isEmpty()) { + metadata.setMultiResolutionStreamConfigurationMap(multiResolutionSizeMap); + } + + return new CameraCharacteristics(metadata); + } + } + /** *

Query the camera extension capabilities of a camera device.

* diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java index 24ac0b56a095..81d0976c09bb 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java @@ -132,13 +132,14 @@ public class CameraDeviceSetupImpl extends CameraDevice.CameraDeviceSetup { } try { - CameraMetadataNative metadataNative = cameraService.getSessionCharacteristics( + CameraMetadataNative metadata = cameraService.getSessionCharacteristics( mCameraId, mTargetSdkVersion, CameraManager.shouldOverrideToPortrait(mContext), sessionConfig, mContext.getDeviceId(), mCameraManager.getDevicePolicyFromContext(mContext)); - return new CameraCharacteristics(metadataNative); + return mCameraManager.prepareCameraCharacteristics(mCameraId, metadata, + cameraService); } catch (ServiceSpecificException e) { switch (e.errorCode) { case ICameraService.ERROR_INVALID_OPERATION -> -- cgit v1.2.3-59-g8ed1b