[automerger skipped] Merge "AndroidCommonTests minsdk bump feom 19 to 21" into main am: 767551ebc1 -s ours am skip reason: Merged-In I05a2a7de81d8202f0f996f599bd91da80501abf6 with SHA-1 c949d0c00d is already in history Original change: https://android-review.googlesource.com/c/platform/frameworks/ex/+/3148017 Change-Id: Iba77c7d773d0729a4dcac72f9c0a8d9691701273 Signed-off-by: Automerger Merge Worker <[email protected]>
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java index 821b11f..dc99339 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
@@ -18,6 +18,7 @@ import android.annotation.SuppressLint; import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraExtensionCharacteristics; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.util.Pair; @@ -230,6 +231,13 @@ * * <p>For example, an extension may limit the zoom ratio range. In this case, an OEM can return * a new zoom ratio range for the key {@link CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE}. + * + * <p> Currently, the only synthetic keys supported for override are + * {@link CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES} and + * {@link CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES}. To enable them, an OEM + * should override the respective native keys + * {@link CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP} and + * {@link CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP}. * @since 1.5 */ List<Pair<CameraCharacteristics.Key, Object>> getAvailableCharacteristicsKeyValues();
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java index 06c8c44..c818386 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
@@ -33,6 +33,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -62,6 +64,39 @@ AWB_MODE_DAYLIGHT); } + @Override + public boolean isPostviewAvailable() { + return true; + } + + @Override + public Map<Integer, List<Size>> getSupportedPostviewResolutions(Size captureSize) { + Map<Integer, List<Size>> res = new HashMap<>(); + Map<Integer, List<Size>> captureSupportedResolutions = + getSupportedCaptureOutputResolutions(mCameraId); + float targetAr = ((float) captureSize.getWidth()) / captureSize.getHeight(); + + List<Size> currFormatSizes = captureSupportedResolutions.get(ImageFormat.YUV_420_888); + if (currFormatSizes != null) { + List<Size> postviewSizes = new ArrayList<>(); + + for (Size s : currFormatSizes) { + if ((s.equals(captureSize)) || (s.getWidth() > captureSize.getWidth()) + || (s.getHeight() > captureSize.getHeight())) continue; + float currentAr = ((float) s.getWidth()) / s.getHeight(); + if (Math.abs(targetAr - currentAr) < 0.01) { + postviewSizes.add(s); + } + } + + if (!postviewSizes.isEmpty()) { + res.put(ImageFormat.YUV_420_888, postviewSizes); + } + } + + return res; + } + public class AutoAdvancedSessionProcessor extends BaseAdvancedSessionProcessor { public AutoAdvancedSessionProcessor() { @@ -78,6 +113,11 @@ RequestBuilder build = new RequestBuilder(mCaptureOutputConfig.getId(), CameraDevice.TEMPLATE_STILL_CAPTURE, DEFAULT_CAPTURE_ID); build.setParameters(CaptureRequest.CONTROL_AWB_MODE, AWB_MODE_DAYLIGHT); + + if (mPostviewOutputSurfaceConfig.getSurface() != null) { + build.addTargetOutputConfigIds(mPostviewOutputConfig.getId()); + } + applyParameters(build); requestList.add(build.build());
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BaseAdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BaseAdvancedExtenderImpl.java index b97fdbd..1b61d93 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BaseAdvancedExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BaseAdvancedExtenderImpl.java
@@ -23,14 +23,18 @@ import android.annotation.SuppressLint; import android.content.Context; +import android.graphics.ColorSpace; import android.graphics.ImageFormat; import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraCharacteristics.Key; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CaptureFailure; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.ColorSpaceProfiles; +import android.hardware.camera2.params.DynamicRangeProfiles; import android.hardware.camera2.params.StreamConfigurationMap; import android.hardware.DataSpace; import android.media.Image; @@ -57,6 +61,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; @SuppressLint("UnknownNullness") public abstract class BaseAdvancedExtenderImpl implements AdvancedExtenderImpl { @@ -70,6 +75,12 @@ } protected CameraCharacteristics mCameraCharacteristics; + protected String mCameraId; + + protected static final Key REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP = + new Key<long[]>("android.request.availableDynamicRangeProfilesMap", long[].class); + protected static final Key REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP = + new Key<long[]>("android.request.availableColorSpaceProfilesMap", long[].class); public BaseAdvancedExtenderImpl() { } @@ -82,6 +93,7 @@ public void init(String cameraId, Map<String, CameraCharacteristics> characteristicsMap) { mCameraCharacteristics = characteristicsMap.get(cameraId); + mCameraId = cameraId; } @Override @@ -115,12 +127,12 @@ @Override public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(String cameraId) { return filterOutputResolutions(Arrays.asList(ImageFormat.JPEG, ImageFormat.YUV_420_888, - ImageFormat.JPEG_R)); + ImageFormat.JPEG_R, ImageFormat.YCBCR_P010)); } @Override public Map<Integer, List<Size>> getSupportedPostviewResolutions(Size captureSize) { - return new HashMap<>(); + return new HashMap<Integer, List<Size>>(); } @Override @@ -138,22 +150,31 @@ protected Camera2OutputConfigImpl mPreviewOutputConfig; protected Camera2OutputConfigImpl mCaptureOutputConfig; + protected Camera2OutputConfigImpl mPostviewOutputConfig; protected OutputSurfaceImpl mPreviewOutputSurfaceConfig; protected OutputSurfaceImpl mCaptureOutputSurfaceConfig; + protected OutputSurfaceImpl mPostviewOutputSurfaceConfig; protected final Object mLock = new Object(); @GuardedBy("mLock") protected Map<CaptureRequest.Key<?>, Object> mParameters = new LinkedHashMap<>(); - protected final Object mLockCaptureSurfaceImageWriter = new Object(); - @GuardedBy("mLockCaptureSurfaceImageWriter") + protected final Object mLockImageWriter = new Object(); + @GuardedBy("mLockImageWriter") protected ImageWriter mCaptureSurfaceImageWriter; + @GuardedBy("mLockImageWriter") + protected ImageWriter mPostviewSurfaceImageWriter; + protected CaptureResultImageMatcher mImageCaptureCaptureResultImageMatcher = new CaptureResultImageMatcher(); + protected CaptureResultImageMatcher mPostviewCaptureCaptureResultImageMatcher = + new CaptureResultImageMatcher(); protected HashMap<Integer, Pair<ImageReferenceImpl, TotalCaptureResult>> mCaptureResults = new HashMap<>(); + protected HashMap<Integer, Pair<ImageReferenceImpl, TotalCaptureResult>> mPostviewResults = + new HashMap<>(); protected RequestProcessorImpl mRequestProcessor; protected List<Integer> mCaptureIdList = List.of(DEFAULT_CAPTURE_ID); @@ -177,6 +198,7 @@ mPreviewOutputSurfaceConfig = surfaceConfigs.getPreviewOutputSurface(); mCaptureOutputSurfaceConfig = surfaceConfigs.getImageCaptureOutputSurface(); + mPostviewOutputSurfaceConfig = surfaceConfigs.getPostviewOutputSurface(); Camera2SessionConfigImplBuilder builder = new Camera2SessionConfigImplBuilder() @@ -190,6 +212,9 @@ Camera2OutputConfigImplBuilder.newSurfaceConfig( mPreviewOutputSurfaceConfig.getSurface()); + previewOutputConfigBuilder.setDynamicRangeProfile( + mPreviewOutputSurfaceConfig.getDynamicRangeProfile()); + mPreviewOutputConfig = previewOutputConfigBuilder.build(); builder.addOutputConfig(mPreviewOutputConfig); @@ -198,7 +223,7 @@ // Image Capture if (mCaptureOutputSurfaceConfig.getSurface() != null) { - // For this sample, JPEG_R will not be processed + // For this sample, JPEG_R or YCBCR_P010 will not be processed if (isJpegR(mCaptureOutputSurfaceConfig)) { Camera2OutputConfigImplBuilder captureOutputConfigBuilder; @@ -210,6 +235,20 @@ builder.addOutputConfig(mCaptureOutputConfig); mProcessCapture = false; + } else if (mCaptureOutputSurfaceConfig.getImageFormat() == ImageFormat.YCBCR_P010) { + Camera2OutputConfigImplBuilder captureOutputConfigBuilder; + + captureOutputConfigBuilder = + Camera2OutputConfigImplBuilder.newSurfaceConfig( + mCaptureOutputSurfaceConfig.getSurface()); + + captureOutputConfigBuilder.setDynamicRangeProfile( + mCaptureOutputSurfaceConfig.getDynamicRangeProfile()); + + mCaptureOutputConfig = captureOutputConfigBuilder.build(); + + builder.addOutputConfig(mCaptureOutputConfig); + mProcessCapture = false; } else { Camera2OutputConfigImplBuilder captureOutputConfigBuilder; @@ -226,6 +265,23 @@ } } + // Postview + if (mPostviewOutputSurfaceConfig.getSurface() != null) { + Camera2OutputConfigImplBuilder postviewOutputConfigBuilder; + + postviewOutputConfigBuilder = + Camera2OutputConfigImplBuilder.newImageReaderConfig( + mPostviewOutputSurfaceConfig.getSize(), + ImageFormat.YUV_420_888, + BASIC_CAPTURE_PROCESS_MAX_IMAGES, + mPostviewOutputSurfaceConfig.getUsage()); + + mPostviewOutputConfig = postviewOutputConfigBuilder.build(); + + builder.addOutputConfig(mPostviewOutputConfig); + } + + builder.setColorSpace(surfaceConfigs.getColorSpace()); addSessionParameter(builder); return builder.build(); @@ -255,11 +311,16 @@ @Override public void deInitSession() { - synchronized (mLockCaptureSurfaceImageWriter) { + synchronized (mLockImageWriter) { if (mCaptureSurfaceImageWriter != null) { mCaptureSurfaceImageWriter.close(); mCaptureSurfaceImageWriter = null; } + + if (mPostviewSurfaceImageWriter != null) { + mPostviewSurfaceImageWriter.close(); + mPostviewSurfaceImageWriter = null; + } } } @@ -373,30 +434,39 @@ mRequestProcessor = requestProcessor; if (mCaptureOutputSurfaceConfig.getSurface() != null) { - synchronized (mLockCaptureSurfaceImageWriter) { - if (isJpegR(mCaptureOutputSurfaceConfig)) { - return; + synchronized (mLockImageWriter) { + if (mProcessCapture) { + if (isJpeg(mCaptureOutputSurfaceConfig)) { + mCaptureSurfaceImageWriter = new ImageWriter + .Builder(mCaptureOutputSurfaceConfig.getSurface()) + .setImageFormat(ImageFormat.JPEG) + .setMaxImages(MAX_NUM_IMAGES) + // For JPEG format, width x height should be set to (w*h) x 1 + // since the JPEG image is returned as a 1D byte array + .setWidthAndHeight( + mCaptureOutputSurfaceConfig.getSize().getWidth() + * mCaptureOutputSurfaceConfig.getSize().getHeight(), + 1) + .build(); + } else { + mCaptureSurfaceImageWriter = new ImageWriter + .Builder(mCaptureOutputSurfaceConfig.getSurface()) + .setImageFormat(mCaptureOutputSurfaceConfig.getImageFormat()) + .setMaxImages(MAX_NUM_IMAGES) + .build(); + } } + } + } - if (isJpeg(mCaptureOutputSurfaceConfig)) { - mCaptureSurfaceImageWriter = new ImageWriter - .Builder(mCaptureOutputSurfaceConfig.getSurface()) - .setImageFormat(ImageFormat.JPEG) - .setMaxImages(MAX_NUM_IMAGES) - // For JPEG format, width x height should be set to (w*h) x 1 - // since the JPEG image is returned as a 1D byte array - .setWidthAndHeight( - mCaptureOutputSurfaceConfig.getSize().getWidth() - * mCaptureOutputSurfaceConfig.getSize().getHeight(), - 1) - .build(); - } else { - mCaptureSurfaceImageWriter = new ImageWriter - .Builder(mCaptureOutputSurfaceConfig.getSurface()) - .setImageFormat(mCaptureOutputSurfaceConfig.getImageFormat()) - .setMaxImages(MAX_NUM_IMAGES) - .build(); - } + if (mPostviewOutputSurfaceConfig != null + && mPostviewOutputSurfaceConfig.getSurface() != null) { + synchronized (mLockImageWriter) { + mPostviewSurfaceImageWriter = new ImageWriter + .Builder(mPostviewOutputSurfaceConfig.getSurface()) + .setImageFormat(mPostviewOutputSurfaceConfig.getImageFormat()) + .setMaxImages(MAX_NUM_IMAGES) + .build(); } } } @@ -405,6 +475,7 @@ public void onCaptureSessionEnd() { synchronized (this) { mImageCaptureCaptureResultImageMatcher.clear(); + mPostviewCaptureCaptureResultImageMatcher.clear(); } mRequestProcessor = null; @@ -498,6 +569,7 @@ @Override public int startCaptureWithPostview(@NonNull CaptureCallback captureCallback) { + Log.d(TAG, "startCaptureWithPostview"); return startCapture(captureCallback); } @@ -529,6 +601,12 @@ addCaptureResultKeys(seqId, totalCaptureResult, captureCallback); + if (mPostviewOutputSurfaceConfig != null) { + mPostviewCaptureCaptureResultImageMatcher.setCameraCaptureCallback( + totalCaptureResult, + requestProcessorRequest.getCaptureStageId()); + } + if (!mProcessCapture) { captureCallback.onCaptureProcessStarted(seqId); } else { @@ -566,6 +644,33 @@ mRequestProcessor.submit(requestList, callback); + if (mPostviewOutputSurfaceConfig != null && + mPostviewOutputSurfaceConfig.getSurface() != null) { + mRequestProcessor.setImageProcessor(mPostviewOutputConfig.getId(), + new ImageProcessorImpl() { + @Override + public void onNextImageAvailable(int outputStreamId, + long timestampNs, + @NonNull ImageReferenceImpl imgReferenceImpl, + @Nullable String physicalCameraId) { + mPostviewCaptureCaptureResultImageMatcher + .setInputImage(imgReferenceImpl); + } + }); + + mPostviewCaptureCaptureResultImageMatcher.setImageReferenceListener( + new CaptureResultImageMatcher.ImageReferenceListener() { + @Override + public void onImageReferenceIncoming( + @NonNull ImageReferenceImpl imageReferenceImpl, + @NonNull TotalCaptureResult totalCaptureResult, + int captureId) { + processImageCapture(imageReferenceImpl, totalCaptureResult, + captureId, true /*isPostview*/); + } + }); + } + if (mCaptureOutputSurfaceConfig.getSurface() != null && mProcessCapture) { mRequestProcessor.setImageProcessor(mCaptureOutputConfig.getId(), new ImageProcessorImpl() { @@ -588,7 +693,7 @@ int captureId) { captureCallback.onCaptureProcessStarted(seqId); processImageCapture(imageReferenceImpl, totalCaptureResult, - captureId); + captureId, false /*isPostview*/); } }); } @@ -597,20 +702,25 @@ } protected void processImageCapture(@NonNull ImageReferenceImpl imageReferenceImpl, - @NonNull TotalCaptureResult totalCaptureResult, - int captureId) { + @NonNull TotalCaptureResult totalCaptureResult, int captureId, + boolean isPostview) { - mCaptureResults.put(captureId, new Pair<>(imageReferenceImpl, totalCaptureResult)); + HashMap<Integer, Pair<ImageReferenceImpl, TotalCaptureResult>> captureResults = + isPostview ? mPostviewResults : mCaptureResults; + ImageWriter imageWriter = isPostview ? mPostviewSurfaceImageWriter : + mCaptureSurfaceImageWriter; - if (mCaptureResults.keySet().containsAll(mCaptureIdList)) { + captureResults.put(captureId, new Pair<>(imageReferenceImpl, totalCaptureResult)); + + if (captureResults.keySet().containsAll(mCaptureIdList)) { List<Pair<ImageReferenceImpl, TotalCaptureResult>> imageDataPairs = - new ArrayList<>(mCaptureResults.values()); + new ArrayList<>(captureResults.values()); Image resultImage = null; int captureSurfaceWriterImageFormat = ImageFormat.UNKNOWN; - synchronized (mLockCaptureSurfaceImageWriter) { - resultImage = mCaptureSurfaceImageWriter.dequeueInputImage(); - captureSurfaceWriterImageFormat = mCaptureSurfaceImageWriter.getFormat(); + synchronized (mLockImageWriter) { + resultImage = imageWriter.dequeueInputImage(); + captureSurfaceWriterImageFormat = imageWriter.getFormat(); } if (captureSurfaceWriterImageFormat == ImageFormat.JPEG) { @@ -648,11 +758,11 @@ DEFAULT_CAPTURE_ID).first.get().getTimestamp()); } - synchronized (mLockCaptureSurfaceImageWriter) { - mCaptureSurfaceImageWriter.queueInputImage(resultImage); + synchronized (mLockImageWriter) { + imageWriter.queueInputImage(resultImage); } - for (Pair<ImageReferenceImpl, TotalCaptureResult> val : mCaptureResults.values()) { + for (Pair<ImageReferenceImpl, TotalCaptureResult> val : captureResults.values()) { val.first.decrement(); } } else { @@ -742,18 +852,62 @@ @Override public List<Pair<CameraCharacteristics.Key, Object>> getAvailableCharacteristicsKeyValues() { + int[] caps = mCameraCharacteristics + .get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); + + Set<Integer> unsupportedCapabilities = new HashSet<>(Arrays.asList( + CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT, + CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_RAW, + CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING, + CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING, + CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO, + CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING, + CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING, + CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME, + CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA, + CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA, + CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR + )); + + List<Integer> filtered = new ArrayList<>(); + for (int c : caps) { + if (unsupportedCapabilities.contains(c)) { + continue; + } + filtered.add(c); + } + int[] extensionsCaps = new int[filtered.size()]; + for (int i = 0; i < filtered.size(); i++) { + extensionsCaps[i] = filtered.get(i); + } + + long[] dynamicRangeProfileArray = new long[]{ + DynamicRangeProfiles.HLG10, + DynamicRangeProfiles.HLG10 | DynamicRangeProfiles.STANDARD, + 0L}; + long[] colorSpacesProfileArray = new long[]{ + ColorSpace.Named.BT2020_HLG.ordinal(), + ImageFormat.YCBCR_P010, + DynamicRangeProfiles.HLG10}; + Range<Float> zoomRange = mCameraCharacteristics .get(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE); float zoomRangeLower = Math.max(1f, zoomRange.getLower()); float zoomRangeUpper = Math.min(10f, zoomRange.getUpper()); return Arrays.asList( + Pair.create(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES, + extensionsCaps), Pair.create(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE, Range.create(zoomRangeLower, zoomRangeUpper)), Pair.create(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES, new int[]{ CameraMetadata.CONTROL_AF_MODE_OFF, CameraMetadata.CONTROL_AF_MODE_AUTO - }) + }), + Pair.create(REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP, + dynamicRangeProfileArray), + Pair.create(REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP, + colorSpacesProfileArray) ); } }
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java index 68de01b..fe0cddf 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java
@@ -17,6 +17,7 @@ package androidx.camera.extensions.impl.advanced; import android.annotation.SuppressLint; +import android.hardware.camera2.params.DynamicRangeProfiles; import java.util.List; @@ -44,6 +45,15 @@ String getPhysicalCameraId(); /** + * Gets the dynamic range profile. + * + * @since 1.5 + */ + default long getDynamicRangeProfile() { + return DynamicRangeProfiles.STANDARD; + } + + /** * If non-null, enable surface sharing and add the surface constructed by the return * Camera2OutputConfig. */
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java index 9ae5f83..95cd48d 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
@@ -17,6 +17,7 @@ package androidx.camera.extensions.impl.advanced; import android.annotation.SuppressLint; +import android.hardware.camera2.params.DynamicRangeProfiles; import android.hardware.camera2.params.OutputConfiguration; import android.util.Size; import android.view.Surface; @@ -35,6 +36,7 @@ private int mSurfaceGroupId = OutputConfiguration.SURFACE_GROUP_ID_NONE; private String mPhysicalCameraId; private List<Camera2OutputConfigImpl> mSurfaceSharingConfigs; + private long mDynamicRangeProfile = DynamicRangeProfiles.STANDARD; private Camera2OutputConfigImplBuilder(OutputConfigImplImpl outputConfig) { mOutputConfig = outputConfig; @@ -93,6 +95,14 @@ } /** + * Set dynamic range profile. + */ + public Camera2OutputConfigImplBuilder setDynamicRangeProfile(long dynamicRangeProfile) { + mDynamicRangeProfile = dynamicRangeProfile; + return this; + } + + /** * Sets surface group id. */ public Camera2OutputConfigImplBuilder setSurfaceGroupId(int surfaceGroupId) { @@ -108,6 +118,7 @@ mOutputConfig.setPhysicalCameraId(mPhysicalCameraId); mOutputConfig.setSurfaceGroup(mSurfaceGroupId); mOutputConfig.setSurfaceSharingConfigs(mSurfaceSharingConfigs); + mOutputConfig.setDynamicRangeProfile(mDynamicRangeProfile); return mOutputConfig; } @@ -115,6 +126,7 @@ private int mId; private int mSurfaceGroup; private String mPhysicalCameraId; + private long mDynamicRangeProfile; private List<Camera2OutputConfigImpl> mSurfaceSharingConfigs; OutputConfigImplImpl() { @@ -122,6 +134,7 @@ mSurfaceGroup = 0; mPhysicalCameraId = null; mSurfaceSharingConfigs = null; + mDynamicRangeProfile = DynamicRangeProfiles.STANDARD; } @Override @@ -140,6 +153,11 @@ } @Override + public long getDynamicRangeProfile() { + return mDynamicRangeProfile; + } + + @Override public List<Camera2OutputConfigImpl> getSurfaceSharingOutputConfigs() { return mSurfaceSharingConfigs; } @@ -156,6 +174,10 @@ mPhysicalCameraId = physicalCameraId; } + public void setDynamicRangeProfile(long dynamicRangeProfile) { + mDynamicRangeProfile = dynamicRangeProfile; + } + public void setSurfaceSharingConfigs( List<Camera2OutputConfigImpl> surfaceSharingConfigs) { mSurfaceSharingConfigs = surfaceSharingConfigs;
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java index 6fb45bc..0b7d59b 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java
@@ -18,6 +18,7 @@ import android.annotation.SuppressLint; import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.params.ColorSpaceProfiles; import java.util.List; import java.util.Map; @@ -54,4 +55,14 @@ * will be configured to use the default regular type. */ int getSessionType(); + + /** + * Gets the color space. + * + * @since 1.5 + * @return {@link android.graphics#ColorSpace.Named} set for session configuration + */ + default int getColorSpace() { + return ColorSpaceProfiles.UNSPECIFIED; + } }
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java index dc1fecc..e745624 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java
@@ -20,6 +20,7 @@ import android.annotation.SuppressLint; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.params.ColorSpaceProfiles; import android.hardware.camera2.params.SessionConfiguration; import java.util.ArrayList; @@ -33,6 +34,7 @@ @SuppressLint("UnknownNullness") public class Camera2SessionConfigImplBuilder { private int mSessionTemplateId = CameraDevice.TEMPLATE_PREVIEW; + private int mColorSpace = ColorSpaceProfiles.UNSPECIFIED; private int mSessionType = SessionConfiguration.SESSION_REGULAR; Map<CaptureRequest.Key<?>, Object> mSessionParameters = new HashMap<>(); List<Camera2OutputConfigImpl> mCamera2OutputConfigs = new ArrayList<>(); @@ -67,6 +69,21 @@ } /** + * Sets the color space. + */ + public Camera2SessionConfigImplBuilder setColorSpace(int colorSpace) { + mColorSpace = colorSpace; + return this; + } + + /** + * Gets the color space. + */ + public int getColorSpace() { + return mColorSpace; + } + + /** * Gets the session template id. */ public int getSessionTemplateId() { @@ -105,12 +122,14 @@ Camera2SessionConfigImpl { int mSessionTemplateId; int mSessionType; + int mColorSpace = ColorSpaceProfiles.UNSPECIFIED; Map<CaptureRequest.Key<?>, Object> mSessionParameters; List<Camera2OutputConfigImpl> mCamera2OutputConfigs; Camera2SessionConfigImplImpl(Camera2SessionConfigImplBuilder builder) { mSessionTemplateId = builder.getSessionTemplateId(); mSessionParameters = builder.getSessionParameters(); + mColorSpace = builder.getColorSpace(); mCamera2OutputConfigs = builder.getCamera2OutputConfigs(); mSessionType = builder.getSessionType(); } @@ -134,6 +153,11 @@ public int getSessionType() { return mSessionType; } + + @Override + public int getColorSpace() { + return mColorSpace; + } } }
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java index 68a84b7..1a3a099 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
@@ -247,7 +247,7 @@ Image resultImage = null; int captureSurfaceWriterImageFormat = ImageFormat.UNKNOWN; - synchronized (mLockCaptureSurfaceImageWriter) { + synchronized (mLockImageWriter) { resultImage = mCaptureSurfaceImageWriter.dequeueInputImage(); captureSurfaceWriterImageFormat = mCaptureSurfaceImageWriter.getFormat(); } @@ -290,7 +290,7 @@ UNDER_EXPOSED_CAPTURE_ID).first.get().getTimestamp()); } - synchronized (mLockCaptureSurfaceImageWriter) { + synchronized (mLockImageWriter) { mCaptureSurfaceImageWriter.queueInputImage(resultImage); }
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java index ba4ea4c..86ea363 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
@@ -27,6 +27,7 @@ import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.DynamicRangeProfiles; import android.media.Image; import android.media.Image.Plane; import android.media.ImageWriter; @@ -39,6 +40,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -70,6 +72,8 @@ public class NightAdvancedSessionProcessor extends BaseAdvancedSessionProcessor { + protected boolean mProcessPreview = true; + public NightAdvancedSessionProcessor() { appendTag("::Night"); } @@ -101,12 +105,23 @@ if (mPreviewOutputSurfaceConfig.getSurface() != null) { Camera2OutputConfigImplBuilder previewOutputConfigBuilder; - previewOutputConfigBuilder = - Camera2OutputConfigImplBuilder.newImageReaderConfig( - mPreviewOutputSurfaceConfig.getSize(), - ImageFormat.YUV_420_888, - BASIC_CAPTURE_PROCESS_MAX_IMAGES, - mPreviewOutputSurfaceConfig.getUsage()); + if (mPreviewOutputSurfaceConfig.getDynamicRangeProfile() == + DynamicRangeProfiles.STANDARD) { + previewOutputConfigBuilder = + Camera2OutputConfigImplBuilder.newImageReaderConfig( + mPreviewOutputSurfaceConfig.getSize(), + ImageFormat.YUV_420_888, + BASIC_CAPTURE_PROCESS_MAX_IMAGES, + mPreviewOutputSurfaceConfig.getUsage()); + } else { + previewOutputConfigBuilder = + Camera2OutputConfigImplBuilder.newSurfaceConfig( + mPreviewOutputSurfaceConfig.getSurface()); + previewOutputConfigBuilder.setDynamicRangeProfile( + mPreviewOutputSurfaceConfig.getDynamicRangeProfile()); + + mProcessPreview = false; + } mPreviewOutputConfig = previewOutputConfigBuilder.build(); @@ -116,7 +131,7 @@ // Image Capture if (mCaptureOutputSurfaceConfig.getSurface() != null) { - // For this sample, JPEG_R will not be processed + // For this sample, JPEG_R or YCBCR_P010 will not be processed if (isJpegR(mCaptureOutputSurfaceConfig)) { Camera2OutputConfigImplBuilder captureOutputConfigBuilder; @@ -128,6 +143,20 @@ builder.addOutputConfig(mCaptureOutputConfig); mProcessCapture = false; + } else if (mCaptureOutputSurfaceConfig.getImageFormat() == ImageFormat.YCBCR_P010) { + Camera2OutputConfigImplBuilder captureOutputConfigBuilder; + + captureOutputConfigBuilder = + Camera2OutputConfigImplBuilder.newSurfaceConfig( + mCaptureOutputSurfaceConfig.getSurface()); + + captureOutputConfigBuilder.setDynamicRangeProfile( + mCaptureOutputSurfaceConfig.getDynamicRangeProfile()); + + mCaptureOutputConfig = captureOutputConfigBuilder.build(); + + builder.addOutputConfig(mCaptureOutputConfig); + mProcessCapture = false; } else { Camera2OutputConfigImplBuilder captureOutputConfigBuilder; @@ -144,6 +173,7 @@ } } + builder.setColorSpace(surfaceConfigs.getColorSpace()); addSessionParameter(builder); return builder.build(); @@ -170,6 +200,10 @@ public void onCaptureSessionStart(@NonNull RequestProcessorImpl requestProcessor) { super.onCaptureSessionStart(requestProcessor); + if (!mProcessPreview) { + return; + } + if (mPreviewOutputSurfaceConfig.getSurface() != null) { synchronized (mLockPreviewSurfaceImageWriter) { mPreviewSurfaceImageWriter = new ImageWriter @@ -246,8 +280,10 @@ addCaptureResultKeys(seqId, totalCaptureResult, captureCallback); - mCaptureResultImageMatcher.setCameraCaptureCallback( - totalCaptureResult); + if (mProcessPreview) { + mCaptureResultImageMatcher.setCameraCaptureCallback( + totalCaptureResult); + } captureCallback.onCaptureProcessStarted(seqId); } @@ -295,4 +331,22 @@ public SessionProcessorImpl createSessionProcessor() { return new NightAdvancedSessionProcessor(); } + + @Override + public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() { + final CaptureRequest.Key [] CAPTURE_REQUEST_SET = {CaptureRequest.CONTROL_ZOOM_RATIO, + CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_REGIONS, + CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.JPEG_QUALITY, + CaptureRequest.JPEG_ORIENTATION}; + return Arrays.asList(CAPTURE_REQUEST_SET); + } + + @Override + public List<CaptureResult.Key> getAvailableCaptureResultKeys() { + final CaptureResult.Key [] CAPTURE_RESULT_SET = {CaptureResult.CONTROL_ZOOM_RATIO, + CaptureResult.CONTROL_AF_MODE, CaptureResult.CONTROL_AF_REGIONS, + CaptureResult.CONTROL_AF_TRIGGER, CaptureResult.CONTROL_AF_STATE, + CaptureResult.JPEG_QUALITY, CaptureResult.JPEG_ORIENTATION}; + return Arrays.asList(CAPTURE_RESULT_SET); + } }
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java index ca3832e..8fe3514 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java
@@ -17,6 +17,7 @@ package androidx.camera.extensions.impl.advanced; import android.annotation.SuppressLint; +import android.hardware.camera2.params.ColorSpaceProfiles; /** * For specifying the output surface configurations for the extension. @@ -32,4 +33,13 @@ public OutputSurfaceImpl getImageAnalysisOutputSurface(); public OutputSurfaceImpl getPostviewOutputSurface(); + + /* + * Gets the color space. + * + * @since 1.5 + */ + default int getColorSpace() { + return ColorSpaceProfiles.UNSPECIFIED; + } }
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java index f173c1b..33759b0 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java
@@ -17,6 +17,7 @@ package androidx.camera.extensions.impl.advanced; import android.annotation.SuppressLint; +import android.hardware.camera2.params.DynamicRangeProfiles; import android.util.Size; import android.view.Surface; @@ -49,4 +50,13 @@ * Get the surface usage bits. */ long getUsage(); + + /** + * Gets the dynamic range profile. + * + * @since 1.5 + */ + default long getDynamicRangeProfile() { + return DynamicRangeProfiles.STANDARD; + } }
diff --git a/camera2/extensions/eyesFreeVidSample/Android.bp b/camera2/extensions/eyesFreeVidSample/Android.bp index 3d9567e..d555190 100644 --- a/camera2/extensions/eyesFreeVidSample/Android.bp +++ b/camera2/extensions/eyesFreeVidSample/Android.bp
@@ -20,8 +20,19 @@ name: "EyesFreeVidService", srcs: ["src/**/*.java"], static_libs: [ - "androidx.annotation_annotation" + "androidx.annotation_annotation", ], platform_apis: true, - system_ext_specific: true + system_ext_specific: true, + required: ["privapp-permissions-efv.xml"], + privileged: true, + certificate: "platform", +} + +prebuilt_etc { + name: "privapp-permissions-efv.xml", + system_ext_specific: true, + sub_dir: "permissions", + src: "privapp-permissions-efv.xml", + filename_from_src: true, }
diff --git a/camera2/extensions/eyesFreeVidSample/AndroidManifest.xml b/camera2/extensions/eyesFreeVidSample/AndroidManifest.xml index 1e53b09..6cf1d91 100644 --- a/camera2/extensions/eyesFreeVidSample/AndroidManifest.xml +++ b/camera2/extensions/eyesFreeVidSample/AndroidManifest.xml
@@ -2,6 +2,9 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.camera.extensions.impl.service"> + <uses-permission android:name="android.permission.SYSTEM_CAMERA" /> + <uses-permission android:name="android.permission.CAMERA" /> + <application android:defaultToDeviceProtectedStorage="true" android:forceQueryable="true"
diff --git a/camera2/extensions/eyesFreeVidSample/privapp-permissions-efv.xml b/camera2/extensions/eyesFreeVidSample/privapp-permissions-efv.xml new file mode 100644 index 0000000..87a5bd6 --- /dev/null +++ b/camera2/extensions/eyesFreeVidSample/privapp-permissions-efv.xml
@@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2016 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<!-- +This XML file declares which signature|privileged permissions should be granted to privileged +applications that come with the platform +--> +<permissions> + <privapp-permissions package="android.camera.extensions.impl.service"> + <permission name="android.permission.SYSTEM_CAMERA"/> + </privapp-permissions> +</permissions> \ No newline at end of file
diff --git a/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidService.java b/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidService.java index d175c1a..496ead1 100644 --- a/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidService.java +++ b/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidService.java
@@ -25,8 +25,10 @@ import java.util.Set; import android.annotation.FlaggedApi; +import android.graphics.ColorSpace; import android.graphics.ImageFormat; import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraCharacteristics.Key; import android.hardware.camera2.CameraExtensionCharacteristics; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata; @@ -38,6 +40,8 @@ import android.hardware.camera2.extension.CameraExtensionService; import android.hardware.camera2.extension.CharacteristicsMap; import android.hardware.camera2.extension.SessionProcessor; +import android.hardware.camera2.params.ColorSpaceProfiles; +import android.hardware.camera2.params.DynamicRangeProfiles; import android.hardware.camera2.params.StreamConfiguration; import android.hardware.camera2.params.StreamConfigurationDuration; import android.hardware.camera2.params.StreamConfigurationMap; @@ -50,7 +54,7 @@ import com.android.internal.camera.flags.Flags; -@FlaggedApi(Flags.FLAG_CONCERT_MODE) +@FlaggedApi(Flags.FLAG_CONCERT_MODE_API) public class EyesFreeVidService extends CameraExtensionService { private static final String TAG = "EyesFreeVidService"; @@ -60,7 +64,12 @@ private final Set<IBinder> mAttachedClients = new HashSet<>(); CameraManager mCameraManager; - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + protected static final Key REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP = + new Key<long[]>("android.request.availableDynamicRangeProfilesMap", long[].class); + protected static final Key REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP = + new Key<long[]>("android.request.availableColorSpaceProfilesMap", long[].class); + + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public boolean onRegisterClient(IBinder token) { synchronized (mLock) { @@ -72,7 +81,7 @@ } } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public void onUnregisterClient(IBinder token) { synchronized (mLock) { @@ -80,7 +89,7 @@ } } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public AdvancedExtender onInitializeAdvancedExtension(int extensionType) { mCameraManager = getSystemService(CameraManager.class); @@ -93,29 +102,29 @@ } } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) public static class AdvancedExtenderEyesFreeImpl extends AdvancedExtender { private CameraCharacteristics mCameraCharacteristics; - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) public AdvancedExtenderEyesFreeImpl(@NonNull CameraManager cameraManager) { super(cameraManager); } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public boolean isExtensionAvailable(String cameraId, CharacteristicsMap charsMap) { return true; } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public void initialize(String cameraId, CharacteristicsMap map) { mCameraCharacteristics = map.get(cameraId); } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions( String cameraId) { @@ -144,21 +153,21 @@ return mCameraCharacteristics; } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions( String cameraId) { return filterOutputResolutions(Arrays.asList(ImageFormat.YUV_420_888, - ImageFormat.JPEG)); + ImageFormat.JPEG, ImageFormat.JPEG_R, ImageFormat.YCBCR_P010)); } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public SessionProcessor getSessionProcessor() { return new EyesFreeVidSessionProcessor(this); } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public List<CaptureRequest.Key> getAvailableCaptureRequestKeys( String cameraId) { @@ -174,7 +183,7 @@ return Arrays.asList(CAPTURE_REQUEST_SET); } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public List<CaptureResult.Key> getAvailableCaptureResultKeys( String cameraId) { @@ -272,6 +281,15 @@ new StreamConfigurationDuration[tmpStallDurations.size()]; filteredStallDurations = tmpStallDurations.toArray(filteredStallDurations); + long[] dynamicRangeProfileArray = new long[]{ + DynamicRangeProfiles.HLG10, + DynamicRangeProfiles.HLG10 | DynamicRangeProfiles.STANDARD, + 0L}; + long[] colorSpacesProfileArray = new long[]{ + ColorSpace.Named.BT2020_HLG.ordinal(), + ImageFormat.YCBCR_P010, + DynamicRangeProfiles.HLG10}; + return Arrays.asList( Pair.create(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS, filteredConfigurations), @@ -293,33 +311,37 @@ .CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION }), Pair.create(CameraExtensionCharacteristics.EFV_PADDING_ZOOM_FACTOR_RANGE, - new Range<Float>(1.0f, 2.0f)) + new Range<Float>(1.0f, 2.0f)), + Pair.create(REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP, + dynamicRangeProfileArray), + Pair.create(REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP, + colorSpacesProfileArray) ); } } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) public static class AdvancedExtenderImpl extends AdvancedExtender { - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) public AdvancedExtenderImpl(@NonNull CameraManager cameraManager) { super(cameraManager); } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public boolean isExtensionAvailable(String cameraId, CharacteristicsMap charsMap) { return false; } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public void initialize(String cameraId, CharacteristicsMap map) { throw new RuntimeException("Extension not supported"); } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions( String cameraId) { @@ -334,20 +356,20 @@ throw new RuntimeException("Extension not supported"); } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions( String cameraId) { throw new RuntimeException("Extension not supported"); } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public SessionProcessor getSessionProcessor() { throw new RuntimeException("Extension not supported"); } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public List<CaptureRequest.Key> getAvailableCaptureRequestKeys( String cameraId) { @@ -355,7 +377,7 @@ } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public List<CaptureResult.Key> getAvailableCaptureResultKeys( String cameraId) {
diff --git a/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidSessionProcessor.java b/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidSessionProcessor.java index 92f371f..9158792 100644 --- a/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidSessionProcessor.java +++ b/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidSessionProcessor.java
@@ -28,6 +28,7 @@ import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.camera.extensions.impl.service.EyesFreeVidService.AdvancedExtenderEyesFreeImpl; +import android.graphics.ImageFormat; import android.graphics.PointF; import android.graphics.Rect; import android.hardware.camera2.CameraAccessException; @@ -61,7 +62,7 @@ import java.util.concurrent.atomic.AtomicBoolean; -@FlaggedApi(Flags.FLAG_CONCERT_MODE) +@FlaggedApi(Flags.FLAG_CONCERT_MODE_API) public class EyesFreeVidSessionProcessor extends SessionProcessor { private static final String TAG = "EyesFreeVidSessionProcessor"; @@ -93,12 +94,12 @@ protected AtomicBoolean mOnCaptureSessionEndStarted = new AtomicBoolean(false); - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) protected EyesFreeVidSessionProcessor(AdvancedExtenderEyesFreeImpl advancedExtender) { mAdvancedExtender = advancedExtender; } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) public ExtensionConfiguration initSession(@NonNull IBinder token, @NonNull String cameraId, @NonNull CharacteristicsMap map, @NonNull CameraOutputSurface previewSurface, @@ -126,9 +127,10 @@ previewSurface.getSize().getHeight(), previewSurface.getImageFormat(), MAX_NUM_IMAGES, SurfaceUtils.getSurfaceUsage(previewSurface.getSurface())); - List<CameraOutputSurface> previewList = new ArrayList<>(List.of( - new CameraOutputSurface(mPreviewImageReader.getSurface(), - previewSurface.getSize()))); + CameraOutputSurface previewOutputSurface = new CameraOutputSurface( + mPreviewImageReader.getSurface(), previewSurface.getSize()); + previewOutputSurface.setDynamicRangeProfile(previewSurface.getDynamicRangeProfile()); + List<CameraOutputSurface> previewList = new ArrayList<>(List.of(previewOutputSurface)); ExtensionOutputConfiguration previewConfig = new ExtensionOutputConfiguration( previewList, PREVIEW_OUTPUT_ID, null, -1); @@ -138,10 +140,15 @@ ExtensionConfiguration res = new ExtensionConfiguration(0 /*session type*/, CameraDevice.TEMPLATE_PREVIEW, outputs, null); + if (imageCaptureSurface != null + && imageCaptureSurface.getImageFormat() == ImageFormat.YCBCR_P010) { + res.setColorSpace(imageCaptureSurface.getColorSpace()); + } + return res; } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public void deInitSession(@NonNull IBinder token) { if (mPreviewImageReader != null) { @@ -163,7 +170,7 @@ } } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public void onCaptureSessionStart(@NonNull RequestProcessor requestProcessor, @NonNull String statsKey) { @@ -188,7 +195,7 @@ mPreviewImageReader.setOnImageAvailableListener(new ImageListener(), mHandler); } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public void onCaptureSessionEnd() { mOnCaptureSessionEndStarted.set(true); @@ -200,7 +207,7 @@ mRequestProcessor = null; } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public int startRepeating(@NonNull Executor executor, @NonNull CaptureCallback captureCallback) { @@ -375,13 +382,13 @@ return mParametersList; } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public void stopRepeating() { mRequestProcessor.stopRepeating(); } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public int startMultiFrameCapture(@NonNull Executor executor, @NonNull CaptureCallback captureCallback) { @@ -446,7 +453,7 @@ return seqId; } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public int startTrigger(@NonNull CaptureRequest captureRequest, @NonNull Executor executor, @NonNull CaptureCallback captureCallback) { @@ -526,7 +533,7 @@ return parameters; } - @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @FlaggedApi(Flags.FLAG_CONCERT_MODE_API) @Override public void setParameters(@NonNull CaptureRequest captureRequest) { synchronized (mParametersLock) {
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java index abf8d45..4386b5e 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
@@ -233,6 +233,13 @@ * {@link CameraCharacteristics#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION} and * {@link CameraCharacteristics#CONTROL_VIDEO_STABILIZATION_MODE_OFF} for the key * {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES}. + * + * <p> Currently, the only synthetic keys supported for override are + * {@link CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES} and + * {@link CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES}. To enable them, an OEM + * should override the respective native keys + * {@link CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP} and + * {@link CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP}. * @since 1.5 */ List<Pair<CameraCharacteristics.Key, Object>> getAvailableCharacteristicsKeyValues();
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java index 68de01b..fe0cddf 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java
@@ -17,6 +17,7 @@ package androidx.camera.extensions.impl.advanced; import android.annotation.SuppressLint; +import android.hardware.camera2.params.DynamicRangeProfiles; import java.util.List; @@ -44,6 +45,15 @@ String getPhysicalCameraId(); /** + * Gets the dynamic range profile. + * + * @since 1.5 + */ + default long getDynamicRangeProfile() { + return DynamicRangeProfiles.STANDARD; + } + + /** * If non-null, enable surface sharing and add the surface constructed by the return * Camera2OutputConfig. */
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java index 365abc3..541ade6 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
@@ -17,6 +17,7 @@ package androidx.camera.extensions.impl.advanced; import android.annotation.SuppressLint; +import android.hardware.camera2.params.DynamicRangeProfiles; import android.hardware.camera2.params.OutputConfiguration; import android.util.Size; import android.view.Surface; @@ -35,6 +36,7 @@ private int mSurfaceGroupId = OutputConfiguration.SURFACE_GROUP_ID_NONE; private String mPhysicalCameraId; private List<Camera2OutputConfigImpl> mSurfaceSharingConfigs; + private long mDynamicRangeProfile = DynamicRangeProfiles.STANDARD; private Camera2OutputConfigImplBuilder(OutputConfigImplImpl outputConfig) { mOutputConfig = outputConfig; @@ -93,6 +95,14 @@ } /** + * Set dynamic range profile. + */ + public Camera2OutputConfigImplBuilder setDynamicRangeProfile(long dynamicRangeProfile) { + mDynamicRangeProfile = dynamicRangeProfile; + return this; + } + + /** * Sets surface group id. */ public Camera2OutputConfigImplBuilder setSurfaceGroupId(int surfaceGroupId) { @@ -108,6 +118,7 @@ mOutputConfig.setPhysicalCameraId(mPhysicalCameraId); mOutputConfig.setSurfaceGroup(mSurfaceGroupId); mOutputConfig.setSurfaceSharingConfigs(mSurfaceSharingConfigs); + mOutputConfig.setDynamicRangeProfile(mDynamicRangeProfile); return mOutputConfig; } @@ -115,6 +126,7 @@ private int mId; private int mSurfaceGroup; private String mPhysicalCameraId; + private long mDynamicRangeProfile; private List<Camera2OutputConfigImpl> mSurfaceSharingConfigs; OutputConfigImplImpl() { @@ -122,6 +134,7 @@ mSurfaceGroup = 0; mPhysicalCameraId = null; mSurfaceSharingConfigs = null; + mDynamicRangeProfile = DynamicRangeProfiles.STANDARD; } @Override @@ -140,6 +153,11 @@ } @Override + public long getDynamicRangeProfile() { + return mDynamicRangeProfile; + } + + @Override public List<Camera2OutputConfigImpl> getSurfaceSharingOutputConfigs() { return mSurfaceSharingConfigs; } @@ -156,6 +174,10 @@ mPhysicalCameraId = physicalCameraId; } + public void setDynamicRangeProfile(long dynamicRangeProfile) { + mDynamicRangeProfile = dynamicRangeProfile; + } + public void setSurfaceSharingConfigs( List<Camera2OutputConfigImpl> surfaceSharingConfigs) { mSurfaceSharingConfigs = surfaceSharingConfigs;
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java index 850f0e1..5d4444f 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java
@@ -18,6 +18,7 @@ import android.annotation.SuppressLint; import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.params.ColorSpaceProfiles; import java.util.List; import java.util.Map; @@ -55,4 +56,14 @@ * will be configured to use the default regular type. */ int getSessionType(); + + /** + * Gets the color space. + * + * @since 1.5 + * @return {@link android.graphics#ColorSpace.Named} set for session configuration + */ + default int getColorSpace() { + return ColorSpaceProfiles.UNSPECIFIED; + } }
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java index dc1fecc..e745624 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java
@@ -20,6 +20,7 @@ import android.annotation.SuppressLint; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.params.ColorSpaceProfiles; import android.hardware.camera2.params.SessionConfiguration; import java.util.ArrayList; @@ -33,6 +34,7 @@ @SuppressLint("UnknownNullness") public class Camera2SessionConfigImplBuilder { private int mSessionTemplateId = CameraDevice.TEMPLATE_PREVIEW; + private int mColorSpace = ColorSpaceProfiles.UNSPECIFIED; private int mSessionType = SessionConfiguration.SESSION_REGULAR; Map<CaptureRequest.Key<?>, Object> mSessionParameters = new HashMap<>(); List<Camera2OutputConfigImpl> mCamera2OutputConfigs = new ArrayList<>(); @@ -67,6 +69,21 @@ } /** + * Sets the color space. + */ + public Camera2SessionConfigImplBuilder setColorSpace(int colorSpace) { + mColorSpace = colorSpace; + return this; + } + + /** + * Gets the color space. + */ + public int getColorSpace() { + return mColorSpace; + } + + /** * Gets the session template id. */ public int getSessionTemplateId() { @@ -105,12 +122,14 @@ Camera2SessionConfigImpl { int mSessionTemplateId; int mSessionType; + int mColorSpace = ColorSpaceProfiles.UNSPECIFIED; Map<CaptureRequest.Key<?>, Object> mSessionParameters; List<Camera2OutputConfigImpl> mCamera2OutputConfigs; Camera2SessionConfigImplImpl(Camera2SessionConfigImplBuilder builder) { mSessionTemplateId = builder.getSessionTemplateId(); mSessionParameters = builder.getSessionParameters(); + mColorSpace = builder.getColorSpace(); mCamera2OutputConfigs = builder.getCamera2OutputConfigs(); mSessionType = builder.getSessionType(); } @@ -134,6 +153,11 @@ public int getSessionType() { return mSessionType; } + + @Override + public int getColorSpace() { + return mColorSpace; + } } }
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java index 723f0f4..217887b 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java
@@ -17,6 +17,7 @@ package androidx.camera.extensions.impl.advanced; import android.annotation.SuppressLint; +import android.hardware.camera2.params.ColorSpaceProfiles; /** * For specifying the output surface configurations for the extension. @@ -32,4 +33,13 @@ public OutputSurfaceImpl getImageAnalysisOutputSurface(); public OutputSurfaceImpl getPostviewOutputSurface(); + + /* + * Gets the color space. + * + * @since 1.5 + */ + default int getColorSpace() { + return ColorSpaceProfiles.UNSPECIFIED; + } }
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java index 7bf8df2..72bc4ab 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java
@@ -17,6 +17,7 @@ package androidx.camera.extensions.impl.advanced; import android.annotation.SuppressLint; +import android.hardware.camera2.params.DynamicRangeProfiles; import android.util.Size; import android.view.Surface; @@ -49,4 +50,13 @@ * Gets the surface usage bits. */ long getUsage(); + + /** + * Gets the dynamic range profile. + * + * @since 1.5 + */ + default long getDynamicRangeProfile() { + return DynamicRangeProfiles.STANDARD; + } }