diff options
author | Xin Li <delphij@google.com> | 2023-08-14 15:40:28 -0700 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2023-08-14 15:40:28 -0700 |
commit | 824677fd594bc9442ff7e0b32bb0572d60d56471 (patch) | |
tree | da0417ebd1cd17c2ec214fb4e75bfb8c80d5b089 | |
parent | ed86b838842d3b3b111450ef47de08d588e82964 (diff) | |
parent | 036ec921b1119ea9796d996e642ed28d8723d40c (diff) | |
download | ex-824677fd594bc9442ff7e0b32bb0572d60d56471.tar.gz |
Merge Android U (ab/10368041)
Bug: 291102124
Merged-In: I7dac45bdf2c5c00004f39a274f981c2c242c26a2
Change-Id: I582fccbfdd95520e0be118afda1a1436bce6d8e0
65 files changed, 1735 insertions, 47 deletions
diff --git a/camera2/extensions/advancedSample/Android.bp b/camera2/extensions/advancedSample/Android.bp index bf5ca793..9f0df8e4 100644 --- a/camera2/extensions/advancedSample/Android.bp +++ b/camera2/extensions/advancedSample/Android.bp @@ -22,9 +22,11 @@ java_library { static_libs: [ "androidx.annotation_annotation" ], + exclude_kotlinc_generated_files: true, srcs: ["src/**/*.java"], sdk_version: "current", vendor: true, + jarjar_rules: "jarjar-rules.txt", } prebuilt_etc { diff --git a/camera2/extensions/advancedSample/jarjar-rules.txt b/camera2/extensions/advancedSample/jarjar-rules.txt new file mode 100644 index 00000000..7442cef5 --- /dev/null +++ b/camera2/extensions/advancedSample/jarjar-rules.txt @@ -0,0 +1 @@ +rule kotlin.** androidx.camera.extensions.impl.advanced.@0
\ No newline at end of file diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java index ccb0dacf..bd605708 100755 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java @@ -95,6 +95,11 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI throw new RuntimeException("Stub, replace with implementation."); } + @Override + public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + @Nullable @Override public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) { @@ -113,4 +118,23 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI throw new RuntimeException("Stub, replace with implementation."); } + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isCaptureProcessProgressAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isPostviewAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java index 100f6658..0c4577a4 100755 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java @@ -93,4 +93,9 @@ public final class AutoPreviewExtenderImpl implements PreviewExtenderImpl { public List<Pair<Integer, Size[]>> getSupportedResolutions() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java index 2d266390..50c80407 100755 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java @@ -95,6 +95,11 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende throw new RuntimeException("Stub, replace with implementation."); } + @Override + public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + @Nullable @Override public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) { @@ -112,4 +117,24 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende public List<CaptureResult.Key> getAvailableCaptureResultKeys() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isCaptureProcessProgressAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isPostviewAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java index bc3e48dd..1f501745 100755 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java @@ -93,4 +93,9 @@ public final class BeautyPreviewExtenderImpl implements PreviewExtenderImpl { public List<Pair<Integer, Size[]>> getSupportedResolutions() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java index 66c5839d..ee777cf9 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java @@ -95,6 +95,11 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender throw new RuntimeException("Stub, replace with implementation."); } + @Override + public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + @Nullable @Override public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) { @@ -113,4 +118,23 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender throw new RuntimeException("Stub, replace with implementation."); } + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isCaptureProcessProgressAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isPostviewAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java index ff588623..1dc5ed79 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java @@ -91,4 +91,9 @@ public final class BokehPreviewExtenderImpl implements PreviewExtenderImpl { public List<Pair<Integer, Size[]>> getSupportedResolutions() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java index 3eee146a..f4719b8b 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java @@ -21,6 +21,7 @@ import android.graphics.ImageFormat; import android.hardware.camera2.TotalCaptureResult; import android.media.Image; import android.util.Pair; +import android.util.Size; import android.view.Surface; import java.util.Map; @@ -46,6 +47,29 @@ public interface CaptureProcessorImpl extends ProcessorImpl { void process(Map<Integer, Pair<Image, TotalCaptureResult>> results); /** + * Informs the CaptureProcessorImpl where it should write the postview output to. + * This will only be invoked once if a valid postview surface was set. + * + * @param surface A valid {@link ImageFormat#YUV_420_888} {@link Surface} + * that the CaptureProcessorImpl should write data into. + * @since 1.4 + */ + void onPostviewOutputSurface(Surface surface); + + /** + * Invoked when the Camera Framework changes the configured output resolution for + * still capture and postview. + * + * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as + * input for still capture and postview to be at the specified resolutions. + * + * @param size for the surface for still capture. + * @param postviewSize for the surface for postview. + * @since 1.4 + */ + void onResolutionUpdate(Size size, Size postviewSize); + + /** * Process a set images captured that were requested. * * <p> The result of the processing step should be written to the {@link Surface} that was @@ -63,4 +87,30 @@ public interface CaptureProcessorImpl extends ProcessorImpl { */ void process(Map<Integer, Pair<Image, TotalCaptureResult>> results, ProcessResultImpl resultCallback, Executor executor); + + /** + * Process a set images captured that were requested for both postview and + * still capture. + * + * <p> This processing method will be called if a postview was requested, therefore the + * processed postview should be written to the + * {@link Surface} received by {@link #onPostviewOutputSurface(Surface, int)}. + * The final result of the processing step should be written to the {@link Surface} that was + * received by {@link #onOutputSurface(Surface, int)}. Since postview should be available + * before the capture, it should be processed and written to the surface before + * the final capture is processed. + * + * @param results The map of {@link ImageFormat#YUV_420_888} format images and + * metadata to process. The {@link Image} that are contained within + * the map will become invalid after this method completes, so no + * references to them should be kept. + * @param resultCallback Capture result callback to be called once the capture result + * values of the processed image are ready. + * @param executor The executor to run the callback on. If null then the callback + * will run on any arbitrary executor. + * @throws RuntimeException if postview feature is not supported + * @since 1.4 + */ + void processWithPostview(Map<Integer, Pair<Image, TotalCaptureResult>> results, + ProcessResultImpl resultCallback, Executor executor); } diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java index 2879568f..3a88ab2e 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java @@ -80,4 +80,21 @@ public interface ExtenderStateListener { * @return The request information to customize the session. */ CaptureStageImpl onDisableSession(); + + /** + * This will be invoked before the {@link android.hardware.camera2.CameraCaptureSession} is + * initialized and must return a valid camera session type + * {@link android.hardware.camera2.params.SessionConfiguration#getSessionType} + * to be used to configure camera capture session. Both the preview and the image capture + * extender must return the same session type value for a specific extension type. If there + * is inconsistency between the session type values from preview and image extenders, then + * the session configuration will fail. + * + * + * @since 1.4 + * @return Camera capture session type. Regular and vendor specific types are supported but + * not high speed values. The extension can return -1 in which case the camera capture session + * will be configured to use the default regular type. + */ + int onSessionType(); } diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java index e3dc9932..1f285720 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java @@ -29,7 +29,7 @@ import android.util.Log; */ public class ExtensionVersionImpl { private static final String TAG = "ExtenderVersionImpl"; - private static final String VERSION = "1.3.0"; + private static final String VERSION = "1.4.0"; /** * @hide @@ -71,4 +71,4 @@ public class ExtensionVersionImpl { public boolean isAdvancedExtenderImplemented() { return true; } -}
\ No newline at end of file +} diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java index f1191dcf..f3fd2f3b 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java @@ -95,6 +95,11 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm throw new RuntimeException("Stub, replace with implementation."); } + @Override + public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + @Nullable @Override public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) { @@ -112,4 +117,24 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm public List<CaptureResult.Key> getAvailableCaptureResultKeys() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isCaptureProcessProgressAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isPostviewAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java index 0eb4a610..af484646 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java @@ -93,4 +93,9 @@ public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl { public List<Pair<Integer, Size[]>> getSupportedResolutions() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java index 88bd105a..70c1804e 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java @@ -85,6 +85,21 @@ public interface ImageCaptureExtenderImpl extends ExtenderStateListener { List<Pair<Integer, Size[]>> getSupportedResolutions(); /** + * Returns the customized supported postview resolutions for a still capture using + * its size. + * + * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned. + * + * <p>The returned resolutions should be subset of the supported sizes retrieved from + * {@link android.hardware.camera2.params.StreamConfigurationMap} for the camera device. + * + * @return the customized supported resolutions, or null to support all sizes retrieved from + * {@link android.hardware.camera2.params.StreamConfigurationMap}. + * @since 1.4 + */ + List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize); + + /** * Returns the estimated capture latency range in milliseconds for the target capture * resolution. * @@ -159,4 +174,44 @@ public interface ImageCaptureExtenderImpl extends ExtenderStateListener { * @since 1.3 */ List<CaptureResult.Key> getAvailableCaptureResultKeys(); + + /** + * Advertise support for {@link ProcessResultImpl#onCaptureProcessProgressed}. + * + * @return {@code true} in case the process progress callback is supported and is expected to + * be triggered, {@code false} otherwise. + * @since 1.4 + */ + boolean isCaptureProcessProgressAvailable(); + + /** + * Returns the dynamically calculated capture latency pair in milliseconds. + * + * <p>In contrast to {@link #getEstimatedCaptureLatencyRange} this method is guaranteed to be + * called after the camera capture session is initialized and camera preview is enabled. + * The measurement is expected to take in to account dynamic parameters such as the current + * scene, the state of 3A algorithms, the state of internal HW modules and return a more + * accurate assessment of the still capture latency.</p> + * + * @return pair that includes the estimated input frame/frames camera capture latency as the + * first field and the estimated post-processing latency {@link CaptureProcessorImpl#process} + * as the second pair field. Both first and second fields will be in milliseconds. The total + * still capture latency will be the sum of both the first and second values. + * The pair is expected to be null if the dynamic latency estimation is not supported. + * If clients have not configured a still capture output, then this method can also return a + * null pair. + * @since 1.4 + */ + Pair<Long, Long> getRealtimeCaptureLatency(); + + /** + * Indicates whether the extension supports the postview for still capture feature. + * If the extension is using HAL processing, false should be returned since the + * postview feature is not currently supported for this case. + * + * @return {@code true} in case postview for still capture is supported + * {@code false} otherwise. + * @since 1.4 + */ + boolean isPostviewAvailable(); } diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java index c8ac9788..6f0eaef9 100755 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java @@ -95,6 +95,11 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender throw new RuntimeException("Stub, replace with implementation."); } + @Override + public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + @Nullable @Override public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) { @@ -112,4 +117,24 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender public List<CaptureResult.Key> getAvailableCaptureResultKeys() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isCaptureProcessProgressAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isPostviewAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java index a5809f6b..825994f5 100755 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java @@ -93,4 +93,9 @@ public final class NightPreviewExtenderImpl implements PreviewExtenderImpl { public List<Pair<Integer, Size[]>> getSupportedResolutions() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java index d0e3605d..0e154450 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java @@ -25,7 +25,6 @@ import java.util.List; /** * Allows clients to receive information about the capture result values of processed frames. * - * @since 1.3 */ @SuppressLint("UnknownNullness") public interface ProcessResultImpl { @@ -40,6 +39,22 @@ public interface ProcessResultImpl { * must also be passed as part of this callback. Both Camera2 and * CameraX guarantee that those two settings and results are always * supported and applied by the corresponding framework. + * @since 1.3 */ void onCaptureCompleted(long shutterTimestamp, List<Pair<CaptureResult.Key, Object>> result); + + /** + * Capture progress callback that needs to be called when the process capture is + * ongoing and includes the estimated progress of the processing. + * + * <p>Extensions must ensure that they always call this callback with monotonically increasing + * values.</p> + * + * <p>Extensions are allowed to trigger this callback multiple times but at the minimum the + * callback is expected to be called once when processing is done with value 100.</p> + * + * @param progress Value between 0 and 100. + * @since 1.4 + */ + void onCaptureProcessProgressed(int progress); } 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 f5335e05..abcbf5fd 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 @@ -124,6 +124,17 @@ public interface AdvancedExtenderImpl { Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(String cameraId); /** + * Returns supported output format/size map for postview image. OEM is required to support + * both JPEG and YUV_420_888 format output. + * + * <p>The surface created with this supported format/size could configure + * intermediate surfaces(YUV/RAW..) and write the output to the output surface.</p> + * + * @since 1.4 + */ + Map<Integer, List<Size>> getSupportedPostviewResolutions(Size captureSize); + + /** * Returns supported output sizes for Image Analysis (YUV_420_888 format). * * <p>OEM can optionally support a YUV surface for ImageAnalysis along with Preview/ImageCapture @@ -185,4 +196,24 @@ public interface AdvancedExtenderImpl { * @since 1.3 */ List<CaptureResult.Key> getAvailableCaptureResultKeys(); + + /** + * Advertise support for {@link SessionProcessorImpl#onCaptureProcessProgressed}. + * + * @return {@code true} in case the process progress callback is supported and is expected to + * be triggered, {@code false} otherwise. + * @since 1.4 + */ + boolean isCaptureProcessProgressAvailable(); + + /** + * Indicates whether the extension supports the postview for still capture feature. + * If the extension is using HAL processing, false should be returned since the + * postview feature is not currently supported for this case. + * + * @return {@code true} in case postview for still capture is supported + * {@code false} otherwise. + * @since 1.4 + */ + boolean isPostviewAvailable(); } 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 6758a325..00b57058 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 @@ -116,6 +116,11 @@ public abstract class BaseAdvancedExtenderImpl implements AdvancedExtenderImpl { } @Override + public Map<Integer, List<Size>> getSupportedPostviewResolutions(Size captureSize) { + return new HashMap<>(); + } + + @Override public List<Size> getSupportedYuvAnalysisResolutions( String cameraId) { return null; @@ -161,14 +166,12 @@ public abstract class BaseAdvancedExtenderImpl implements AdvancedExtenderImpl { public Camera2SessionConfigImpl initSession(@NonNull String cameraId, @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap, @NonNull Context context, - @NonNull OutputSurfaceImpl previewSurfaceConfig, - @NonNull OutputSurfaceImpl imageCaptureSurfaceConfig, - @Nullable OutputSurfaceImpl imageAnalysisSurfaceConfig) { + @NonNull OutputSurfaceConfigurationImpl surfaceConfigs) { Log.d(TAG, "initSession cameraId=" + cameraId); - mPreviewOutputSurfaceConfig = previewSurfaceConfig; - mCaptureOutputSurfaceConfig = imageCaptureSurfaceConfig; + mPreviewOutputSurfaceConfig = surfaceConfigs.getPreviewOutputSurface(); + mCaptureOutputSurfaceConfig = surfaceConfigs.getImageCaptureOutputSurface(); Camera2SessionConfigImplBuilder builder = new Camera2SessionConfigImplBuilder() @@ -180,7 +183,7 @@ public abstract class BaseAdvancedExtenderImpl implements AdvancedExtenderImpl { previewOutputConfigBuilder = Camera2OutputConfigImplBuilder.newSurfaceConfig( - previewSurfaceConfig.getSurface()); + mPreviewOutputSurfaceConfig.getSurface()); mPreviewOutputConfig = previewOutputConfigBuilder.build(); @@ -193,7 +196,7 @@ public abstract class BaseAdvancedExtenderImpl implements AdvancedExtenderImpl { captureOutputConfigBuilder = Camera2OutputConfigImplBuilder.newImageReaderConfig( - imageCaptureSurfaceConfig.getSize(), + mCaptureOutputSurfaceConfig.getSize(), ImageFormat.YUV_420_888, BASIC_CAPTURE_PROCESS_MAX_IMAGES); @@ -207,6 +210,24 @@ public abstract class BaseAdvancedExtenderImpl implements AdvancedExtenderImpl { return builder.build(); } + @Override + public Camera2SessionConfigImpl initSession(@NonNull String cameraId, + @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap, + @NonNull Context context, + @NonNull OutputSurfaceImpl previewSurfaceConfig, + @NonNull OutputSurfaceImpl imageCaptureSurfaceConfig, + @Nullable OutputSurfaceImpl imageAnalysisSurfaceConfig) { + + // Since this sample impl uses version 1.4, the other initSession method will be + // called. This is just a sample for earlier versions if wanting to redirect this call. + OutputSurfaceConfigurationImplImpl surfaceConfigs = + new OutputSurfaceConfigurationImplImpl(previewSurfaceConfig, + imageCaptureSurfaceConfig, imageAnalysisSurfaceConfig, + null /*postviewSurfaceConfig*/); + + return initSession(cameraId, cameraCharacteristicsMap, context, surfaceConfigs); + } + protected void addSessionParameter(Camera2SessionConfigImplBuilder builder) { // default empty implementation } @@ -437,6 +458,11 @@ public abstract class BaseAdvancedExtenderImpl implements AdvancedExtenderImpl { } @Override + public int startCaptureWithPostview(@NonNull CaptureCallback captureCallback) { + return startCapture(captureCallback); + } + + @Override public int startCapture(@NonNull CaptureCallback captureCallback) { List<RequestProcessorImpl.Request> requestList = new ArrayList<>(); addCaptureRequestParameters(requestList); @@ -484,6 +510,7 @@ public abstract class BaseAdvancedExtenderImpl implements AdvancedExtenderImpl { @Override public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) { captureCallback.onCaptureSequenceCompleted(seqId); + captureCallback.onCaptureProcessProgressed(100); } @Override @@ -599,6 +626,48 @@ public abstract class BaseAdvancedExtenderImpl implements AdvancedExtenderImpl { public void abortCapture(int captureSequenceId) { } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + return null; + } + } + + public static class OutputSurfaceConfigurationImplImpl implements OutputSurfaceConfigurationImpl { + private OutputSurfaceImpl mOutputPreviewSurfaceImpl; + private OutputSurfaceImpl mOutputImageCaptureSurfaceImpl; + private OutputSurfaceImpl mOutputImageAnalysisSurfaceImpl; + private OutputSurfaceImpl mOutputPostviewSurfaceImpl; + + public OutputSurfaceConfigurationImplImpl(OutputSurfaceImpl previewSurfaceConfig, + OutputSurfaceImpl imageCaptureSurfaceConfig, + OutputSurfaceImpl imageAnalysisSurfaceConfig, + OutputSurfaceImpl postviewSurfaceConfig) { + mOutputPreviewSurfaceImpl = previewSurfaceConfig; + mOutputImageCaptureSurfaceImpl = imageCaptureSurfaceConfig; + mOutputImageAnalysisSurfaceImpl = imageAnalysisSurfaceConfig; + mOutputPostviewSurfaceImpl = postviewSurfaceConfig; + } + + @Override + public OutputSurfaceImpl getPreviewOutputSurface() { + return mOutputPreviewSurfaceImpl; + } + + @Override + public OutputSurfaceImpl getImageCaptureOutputSurface() { + return mOutputImageCaptureSurfaceImpl; + } + + @Override + public OutputSurfaceImpl getImageAnalysisOutputSurface() { + return mOutputImageAnalysisSurfaceImpl; + } + + @Override + public OutputSurfaceImpl getPostviewOutputSurface() { + return mOutputPostviewSurfaceImpl; + } } @Override @@ -617,4 +686,14 @@ public abstract class BaseAdvancedExtenderImpl implements AdvancedExtenderImpl { CaptureResult.JPEG_ORIENTATION}; return Arrays.asList(CAPTURE_RESULT_SET); } + + @Override + public boolean isCaptureProcessProgressAvailable() { + return true; + } + + @Override + public boolean isPostviewAvailable() { + return false; + } } 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 47a0d226..6fb45bca 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 @@ -43,4 +43,15 @@ public interface Camera2SessionConfigImpl { * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters}. */ int getSessionTemplateId(); + + /** + * Retrieves the session type to be used when initializing the + * {@link android.hardware.camera2.CameraCaptureSession}. + * + * @since 1.4 + * @return Camera capture session type. Regular and vendor specific types are supported but + * not high speed values. The extension can return -1 in which case the camera capture session + * will be configured to use the default regular type. + */ + int getSessionType(); } 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 a3011666..dc1feccd 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 @@ package androidx.camera.extensions.impl.advanced; import android.annotation.SuppressLint; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.params.SessionConfiguration; import java.util.ArrayList; import java.util.HashMap; @@ -32,6 +33,7 @@ import java.util.Map; @SuppressLint("UnknownNullness") public class Camera2SessionConfigImplBuilder { private int mSessionTemplateId = CameraDevice.TEMPLATE_PREVIEW; + private int mSessionType = SessionConfiguration.SESSION_REGULAR; Map<CaptureRequest.Key<?>, Object> mSessionParameters = new HashMap<>(); List<Camera2OutputConfigImpl> mCamera2OutputConfigs = new ArrayList<>(); @@ -86,6 +88,13 @@ public class Camera2SessionConfigImplBuilder { } /** + * Gets the camera capture session type. + */ + public int getSessionType() { + return mSessionType; + } + + /** * Builds a {@link Camera2SessionConfigImpl} instance. */ public Camera2SessionConfigImpl build() { @@ -95,6 +104,7 @@ public class Camera2SessionConfigImplBuilder { private static class Camera2SessionConfigImplImpl implements Camera2SessionConfigImpl { int mSessionTemplateId; + int mSessionType; Map<CaptureRequest.Key<?>, Object> mSessionParameters; List<Camera2OutputConfigImpl> mCamera2OutputConfigs; @@ -102,6 +112,7 @@ public class Camera2SessionConfigImplBuilder { mSessionTemplateId = builder.getSessionTemplateId(); mSessionParameters = builder.getSessionParameters(); mCamera2OutputConfigs = builder.getCamera2OutputConfigs(); + mSessionType = builder.getSessionType(); } @Override @@ -118,6 +129,11 @@ public class Camera2SessionConfigImplBuilder { public int getSessionTemplateId() { return mSessionTemplateId; } + + @Override + public int getSessionType() { + return mSessionType; + } } } 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 6d9e013d..d8b99289 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 @@ -176,6 +176,7 @@ public class HdrAdvancedExtenderImpl extends BaseAdvancedExtenderImpl { @Override public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) { captureCallback.onCaptureSequenceCompleted(seqId); + captureCallback.onCaptureProcessProgressed(100); } @Override 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 31c79404..82940635 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 @@ -86,14 +86,12 @@ public class NightAdvancedExtenderImpl extends BaseAdvancedExtenderImpl { public Camera2SessionConfigImpl initSession(@NonNull String cameraId, @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap, @NonNull Context context, - @NonNull OutputSurfaceImpl previewSurfaceConfig, - @NonNull OutputSurfaceImpl imageCaptureSurfaceConfig, - @Nullable OutputSurfaceImpl imageAnalysisSurfaceConfig) { + @NonNull OutputSurfaceConfigurationImpl surfaceConfigs) { Log.d(TAG, "initSession cameraId=" + cameraId); - mPreviewOutputSurfaceConfig = previewSurfaceConfig; - mCaptureOutputSurfaceConfig = imageCaptureSurfaceConfig; + mPreviewOutputSurfaceConfig = surfaceConfigs.getPreviewOutputSurface(); + mCaptureOutputSurfaceConfig = surfaceConfigs.getImageCaptureOutputSurface(); Camera2SessionConfigImplBuilder builder = new Camera2SessionConfigImplBuilder() @@ -105,7 +103,7 @@ public class NightAdvancedExtenderImpl extends BaseAdvancedExtenderImpl { previewOutputConfigBuilder = Camera2OutputConfigImplBuilder.newImageReaderConfig( - previewSurfaceConfig.getSize(), + mPreviewOutputSurfaceConfig.getSize(), ImageFormat.YUV_420_888, BASIC_CAPTURE_PROCESS_MAX_IMAGES); @@ -120,7 +118,7 @@ public class NightAdvancedExtenderImpl extends BaseAdvancedExtenderImpl { captureOutputConfigBuilder = Camera2OutputConfigImplBuilder.newImageReaderConfig( - imageCaptureSurfaceConfig.getSize(), + mCaptureOutputSurfaceConfig.getSize(), ImageFormat.YUV_420_888, BASIC_CAPTURE_PROCESS_MAX_IMAGES); 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 new file mode 100644 index 00000000..ca3832e3 --- /dev/null +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java @@ -0,0 +1,35 @@ +/* + * Copyright 2022 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. + */ + +package androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; + +/** + * For specifying the output surface configurations for the extension. + * + * since 1.4 + */ +@SuppressLint("UnknownNullness") +public interface OutputSurfaceConfigurationImpl { + public OutputSurfaceImpl getPreviewOutputSurface(); + + public OutputSurfaceImpl getImageCaptureOutputSurface(); + + public OutputSurfaceImpl getImageAnalysisOutputSurface(); + + public OutputSurfaceImpl getPostviewOutputSurface(); +} diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java index fabfc2bf..8dbfadc2 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java @@ -21,6 +21,7 @@ import android.content.Context; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; +import android.util.Pair; import android.view.Surface; import java.util.Map; @@ -64,9 +65,59 @@ public interface SessionProcessorImpl { * preparing a CameraCaptureSession. After initSession() is called, the camera ID, * cameraCharacteristics and context will not change until deInitSession() has been called. * - * <p>CameraX specifies the output surface configurations for preview, image capture and image - * analysis[optional]. And OEM returns a {@link Camera2SessionConfigImpl} which consists of a - * list of {@link Camera2OutputConfigImpl} and session parameters. The + * <p>CameraX / Camera2 specifies the output surface configurations for preview using + * {@link OutputSurfaceConfigurationImpl#getPreviewOutputSurface}, image capture using + * {@link OutputSurfaceConfigurationImpl#getImageCaptureOutputSurface}, and image analysis + * [optional] using {@link OutputSurfaceConfigurationImpl#getImageAnalysisOutputSurface}. + * And OEM returns a {@link Camera2SessionConfigImpl} which consists of a list of + * {@link Camera2OutputConfigImpl} and session parameters. The {@link Camera2SessionConfigImpl} + * will be used to configure the CameraCaptureSession. + * + * <p>OEM is responsible for outputting correct camera images output to these output surfaces. + * OEM can have the following options to enable the output: + * <pre> + * (1) Add these output surfaces in CameraCaptureSession directly using + * {@link Camera2OutputConfigImplBuilder#newSurfaceConfig(Surface)} }. Processing is done in + * HAL. + * + * (2) Use surface sharing with other surface by calling + * {@link Camera2OutputConfigImplBuilder#addSurfaceSharingOutputConfig(Camera2OutputConfigImpl)} + * to add the output surface to the other {@link Camera2OutputConfigImpl}. + * + * (3) Process output from other surfaces (RAW, YUV..) and write the result to the output + * surface. The output surface won't be contained in the returned + * {@link Camera2SessionConfigImpl}. + * </pre> + * + * <p>{@link Camera2OutputConfigImplBuilder} and {@link Camera2SessionConfigImplBuilder} + * implementations are provided in the stub for OEM to construct the + * {@link Camera2OutputConfigImpl} and {@link Camera2SessionConfigImpl} instances. + * + * @param surfaceConfigs contains output surfaces for preview, image capture, and an + * optional output config for image analysis (YUV_420_888). + * @return a {@link Camera2SessionConfigImpl} consisting of a list of + * {@link Camera2OutputConfigImpl} and session parameters which will decide the + * {@link android.hardware.camera2.params.SessionConfiguration} for configuring the + * CameraCaptureSession. Please note that the OutputConfiguration list may not be part of any + * supported or mandatory stream combination BUT OEM must ensure this list will always + * produce a valid camera capture session. + * + * @since 1.4 + */ + Camera2SessionConfigImpl initSession( + String cameraId, + Map<String, CameraCharacteristics> cameraCharacteristicsMap, + Context context, + OutputSurfaceConfigurationImpl surfaceConfigs); + + /** + * Initializes the session for the extension. This is where the OEMs allocate resources for + * preparing a CameraCaptureSession. After initSession() is called, the camera ID, + * cameraCharacteristics and context will not change until deInitSession() has been called. + * + * <p>CameraX / Camera2 specifies the output surface configurations for preview, image capture + * and image analysis[optional]. And OEM returns a {@link Camera2SessionConfigImpl} which + * consists of a list of {@link Camera2OutputConfigImpl} and session parameters. The * {@link Camera2SessionConfigImpl} will be used to configure the CameraCaptureSession. * * <p>OEM is responsible for outputting correct camera images output to these output surfaces. @@ -173,6 +224,26 @@ public interface SessionProcessorImpl { void stopRepeating(); /** + * Start a multi-frame capture with a postview. {@link #startCapture(CaptureCallback)} + * will be used for captures without a postview request. + * + * Postview will be available before the capture. Upon postview completion, + * {@code OnImageAvailableListener#onImageAvailable} will be called on the ImageReader + * that creates the postview output surface. When the capture is completed, + * {@link CaptureCallback#onCaptureSequenceCompleted} is called and + * {@code OnImageAvailableListener#onImageAvailable} will also be called on the ImageReader + * that creates the image capture output surface. + * + * <p>Only one capture can perform at a time. Starting a capture when another capture is + * running will cause onCaptureFailed to be called immediately. + * + * @param callback a callback to report the status. + * @return the id of the capture sequence. + * @since 1.4 + */ + int startCaptureWithPostview(CaptureCallback callback); + + /** * Start a multi-frame capture. * * When the capture is completed, {@link CaptureCallback#onCaptureSequenceCompleted} @@ -193,6 +264,29 @@ public interface SessionProcessorImpl { void abortCapture(int captureSequenceId); /** + * Returns the dynamically calculated capture latency pair in milliseconds. + * + * <p>In contrast to {@link AdvancedExtenderImpl#getEstimatedCaptureLatencyRange} this method is + * guaranteed to be called after {@link #onCaptureSessionStart}. + * The measurement is expected to take in to account dynamic parameters such as the current + * scene, the state of 3A algorithms, the state of internal HW modules and return a more + * accurate assessment of the still capture latency.</p> + * + * @return pair that includes the estimated input frame/frames camera capture latency as the + * first field. This is the time between {@link #onCaptureStarted} and + * {@link #onCaptureProcessStarted}. The second field value includes the estimated + * post-processing latency. This is the time between {@link #onCaptureProcessStarted} until + * the processed frame returns back to the client registered surface. + * Both first and second values will be in milliseconds. The total still capture latency will be + * the sum of both the first and second values of the pair. + * The pair is expected to be null if the dynamic latency estimation is not supported. + * If clients have not configured a still capture output, then this method can also return a + * null pair. + * @since 1.4 + */ + Pair<Long, Long> getRealtimeCaptureLatency(); + + /** * Callback for notifying the status of {@link #startCapture(CaptureCallback)} and * {@link #startRepeating(CaptureCallback)}. */ @@ -277,5 +371,20 @@ public interface SessionProcessorImpl { */ void onCaptureCompleted(long timestamp, int captureSequenceId, Map<CaptureResult.Key, Object> result); + + /** + * Capture progress callback that needs to be called when the process capture is + * ongoing and includes the estimated progress of the processing. + * + * <p>Extensions must ensure that they always call this callback with monotonically + * increasing values.</p> + * + * <p>Extensions are allowed to trigger this callback multiple times but at the minimum the + * callback is expected to be called once when processing is done with value 100.</p> + * + * @param progress Value between 0 and 100. + * @since 1.4 + */ + void onCaptureProcessProgressed(int progress); } } diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java index 5f6cb2ba..30a79a6b 100755 --- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java +++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java @@ -20,6 +20,7 @@ import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.SessionConfiguration; import android.media.Image; import android.media.ImageWriter; import android.os.Build; @@ -116,6 +117,26 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI } @Override + public void onPostviewOutputSurface(Surface surface) { + + } + + @Override + public void processWithPostview( + Map<Integer, Pair<Image, TotalCaptureResult>> results, + ProcessResultImpl resultCallback, Executor executor) { + if (!isPostviewAvailable()) { + throw new RuntimeException("The extension doesn't support postview"); + } + + if (resultCallback != null) { + process(results, resultCallback, executor); + } else { + process(results); + } + } + + @Override public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results, ProcessResultImpl resultCallback, Executor executor) { throw new RuntimeException("The extension doesn't support capture " + @@ -164,6 +185,11 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI } @Override + public void onResolutionUpdate(Size size, Size postviewSize) { + + } + + @Override public void onImageFormatUpdate(int imageFormat) { } @@ -244,6 +270,11 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI } @Override + public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) { + return new ArrayList<>(); + } + + @Override public Range<Long> getEstimatedCaptureLatencyRange(Size captureOutputSize) { return null; } @@ -257,4 +288,24 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI public List<CaptureResult.Key> getAvailableCaptureResultKeys() { return new ArrayList<>(); } + + @Override + public int onSessionType() { + return SessionConfiguration.SESSION_REGULAR; + } + + @Override + public boolean isCaptureProcessProgressAvailable() { + return false; + } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + return null; + } + + @Override + public boolean isPostviewAvailable() { + return false; + } } diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java index 5018df8a..aa95a4a7 100755 --- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java +++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java @@ -18,6 +18,7 @@ package androidx.camera.extensions.impl; import android.content.Context; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.params.SessionConfiguration; import android.util.Pair; import android.util.Size; @@ -162,4 +163,9 @@ public final class AutoPreviewExtenderImpl implements PreviewExtenderImpl { return captureStage; } + + @Override + public int onSessionType() { + return SessionConfiguration.SESSION_REGULAR; + } } diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java index 5c9b2d39..c9b24206 100755 --- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java +++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java @@ -21,6 +21,7 @@ import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.Image; import android.media.ImageWriter; @@ -118,6 +119,26 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende } @Override + public void onPostviewOutputSurface(Surface surface) { + + } + + @Override + public void processWithPostview( + Map<Integer, Pair<Image, TotalCaptureResult>> results, + ProcessResultImpl resultCallback, Executor executor) { + if (!isPostviewAvailable()) { + throw new RuntimeException("The extension doesn't support postview"); + } + + if (resultCallback != null) { + process(results, resultCallback, executor); + } else { + process(results); + } + } + + @Override public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results, ProcessResultImpl resultCallback, Executor executor) { throw new RuntimeException("The extension doesn't support capture " + @@ -166,6 +187,11 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende } @Override + public void onResolutionUpdate(Size size, Size postviewSize) { + + } + + @Override public void onImageFormatUpdate(int imageFormat) { } @@ -267,6 +293,11 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende } @Override + public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) { + return new ArrayList<>(); + } + + @Override public Range<Long> getEstimatedCaptureLatencyRange(Size captureOutputSize) { return null; } @@ -280,4 +311,24 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende public List<CaptureResult.Key> getAvailableCaptureResultKeys() { return new ArrayList<>(); } + + @Override + public int onSessionType() { + return SessionConfiguration.SESSION_REGULAR; + } + + @Override + public boolean isCaptureProcessProgressAvailable() { + return false; + } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + return null; + } + + @Override + public boolean isPostviewAvailable() { + return false; + } } diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java index fcc78d55..2ef357c3 100755 --- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java +++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java @@ -19,6 +19,7 @@ import android.content.Context; import android.graphics.ImageFormat; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.params.StreamConfigurationMap; import android.util.Pair; import android.util.Size; @@ -183,4 +184,9 @@ public final class BeautyPreviewExtenderImpl implements PreviewExtenderImpl { return captureStage; } + + @Override + public int onSessionType() { + return SessionConfiguration.SESSION_REGULAR; + } } diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java index 5c3882b8..a72deef6 100644 --- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java +++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java @@ -16,10 +16,13 @@ package androidx.camera.extensions.impl; import android.content.Context; +import android.graphics.ImageFormat; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.SessionConfiguration; +import android.hardware.camera2.params.StreamConfigurationMap; import android.media.Image; import android.media.ImageWriter; import android.os.Build; @@ -51,6 +54,8 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender private static final int SESSION_STAGE_ID = 101; private static final int MODE = CaptureRequest.CONTROL_AWB_MODE_SHADE; + private CameraCharacteristics mCameraCharacteristics; + /** * @hide */ @@ -62,6 +67,7 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender */ @Override public void init(String cameraId, CameraCharacteristics cameraCharacteristics) { + mCameraCharacteristics = cameraCharacteristics; } /** @@ -104,6 +110,7 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender CaptureProcessorImpl captureProcessor = new CaptureProcessorImpl() { private ImageWriter mImageWriter; + private ImageWriter mImageWriterPostview; @Override public void onOutputSurface(Surface surface, int imageFormat) { @@ -113,6 +120,61 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender } @Override + public void onPostviewOutputSurface(Surface surface) { + if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) && + mImageWriterPostview == null) { + mImageWriterPostview = ImageWriter.newInstance(surface, 1); + } + } + + @Override + public void processWithPostview( + Map<Integer, Pair<Image, TotalCaptureResult>> results, + ProcessResultImpl resultCallback, Executor executor) { + + Pair<Image, TotalCaptureResult> result = results.get(DEFAULT_STAGE_ID); + if (result == null) { + Log.w(TAG, + "Unable to process since images does not contain all " + + "stages."); + return; + } else { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + Image image = mImageWriterPostview.dequeueInputImage(); + + // Postview processing here + ByteBuffer yByteBuffer = image.getPlanes()[0].getBuffer(); + ByteBuffer uByteBuffer = image.getPlanes()[2].getBuffer(); + ByteBuffer vByteBuffer = image.getPlanes()[1].getBuffer(); + + // For sample, allocate empty buffer to match postview size + yByteBuffer.put(ByteBuffer.allocate(image.getPlanes()[0] + .getBuffer().capacity())); + uByteBuffer.put(ByteBuffer.allocate(image.getPlanes()[2] + .getBuffer().capacity())); + vByteBuffer.put(ByteBuffer.allocate(image.getPlanes()[1] + .getBuffer().capacity())); + Long sensorTimestamp = + result.second.get(CaptureResult.SENSOR_TIMESTAMP); + if (sensorTimestamp != null) { + image.setTimestamp(sensorTimestamp); + } else { + Log.e(TAG, "Sensor timestamp absent using default!"); + } + + mImageWriterPostview.queueInputImage(image); + } + } + + // Process still capture + if (resultCallback != null) { + process(results, resultCallback, executor); + } else { + process(results); + } + } + + @Override public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results, ProcessResultImpl resultCallback, Executor executor) { Pair<Image, TotalCaptureResult> result = results.get(DEFAULT_STAGE_ID); @@ -241,6 +303,11 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender } @Override + public void onResolutionUpdate(Size size, Size postviewSize) { + + } + + @Override public void onImageFormatUpdate(int imageFormat) { } @@ -317,7 +384,59 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender */ @Override public List<Pair<Integer, Size[]>> getSupportedResolutions() { - return null; + List<Pair<Integer, Size[]>> formatResolutionsPairList = new ArrayList<>(); + + StreamConfigurationMap map = + mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); + + if (map != null) { + // The sample implementation only retrieves originally supported resolutions from + // CameraCharacteristics for JPEG and YUV_420_888 formats to return. + Size[] outputSizes = map.getOutputSizes(ImageFormat.JPEG); + + if (outputSizes != null) { + formatResolutionsPairList.add(Pair.create(ImageFormat.JPEG, outputSizes)); + } + + outputSizes = map.getOutputSizes(ImageFormat.YUV_420_888); + + if (outputSizes != null) { + formatResolutionsPairList.add(Pair.create(ImageFormat.YUV_420_888, outputSizes)); + } + } + + return formatResolutionsPairList; + } + + @Override + public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) { + // Sample for supported postview sizes, returns subset of supported resolutions for + // still capture that are less than its size and match the aspect ratio + List<Pair<Integer, Size[]>> res = new ArrayList<>(); + List<Pair<Integer, Size[]>> captureSupportedResolutions = getSupportedResolutions(); + float targetAr = ((float) captureSize.getWidth()) / captureSize.getHeight(); + + for (Pair<Integer, Size[]> elem : captureSupportedResolutions) { + Integer currFormat = elem.first; + Size[] currFormatSizes = elem.second; + 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.add(new Pair<Integer, Size[]>(currFormat, + postviewSizes.toArray(new Size[postviewSizes.size()]))); + } + } + + return res; } @Override @@ -341,4 +460,24 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender CaptureResult.FLASH_STATE}; return Arrays.asList(CAPTURE_RESULT_SET); } + + @Override + public int onSessionType() { + return SessionConfiguration.SESSION_REGULAR; + } + + @Override + public boolean isCaptureProcessProgressAvailable() { + return false; + } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + return null; + } + + @Override + public boolean isPostviewAvailable() { + return true; + } } diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java index 45c7f47c..ace54c8b 100644 --- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java +++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java @@ -19,6 +19,7 @@ import android.content.Context; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.SessionConfiguration; import android.util.Pair; import android.util.Size; import android.view.Surface; @@ -202,4 +203,9 @@ public final class BokehPreviewExtenderImpl implements PreviewExtenderImpl { return captureStage; } + + @Override + public int onSessionType() { + return SessionConfiguration.SESSION_REGULAR; + } } diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java index 3eee146a..f4719b8b 100644 --- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java +++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java @@ -21,6 +21,7 @@ import android.graphics.ImageFormat; import android.hardware.camera2.TotalCaptureResult; import android.media.Image; import android.util.Pair; +import android.util.Size; import android.view.Surface; import java.util.Map; @@ -46,6 +47,29 @@ public interface CaptureProcessorImpl extends ProcessorImpl { void process(Map<Integer, Pair<Image, TotalCaptureResult>> results); /** + * Informs the CaptureProcessorImpl where it should write the postview output to. + * This will only be invoked once if a valid postview surface was set. + * + * @param surface A valid {@link ImageFormat#YUV_420_888} {@link Surface} + * that the CaptureProcessorImpl should write data into. + * @since 1.4 + */ + void onPostviewOutputSurface(Surface surface); + + /** + * Invoked when the Camera Framework changes the configured output resolution for + * still capture and postview. + * + * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as + * input for still capture and postview to be at the specified resolutions. + * + * @param size for the surface for still capture. + * @param postviewSize for the surface for postview. + * @since 1.4 + */ + void onResolutionUpdate(Size size, Size postviewSize); + + /** * Process a set images captured that were requested. * * <p> The result of the processing step should be written to the {@link Surface} that was @@ -63,4 +87,30 @@ public interface CaptureProcessorImpl extends ProcessorImpl { */ void process(Map<Integer, Pair<Image, TotalCaptureResult>> results, ProcessResultImpl resultCallback, Executor executor); + + /** + * Process a set images captured that were requested for both postview and + * still capture. + * + * <p> This processing method will be called if a postview was requested, therefore the + * processed postview should be written to the + * {@link Surface} received by {@link #onPostviewOutputSurface(Surface, int)}. + * The final result of the processing step should be written to the {@link Surface} that was + * received by {@link #onOutputSurface(Surface, int)}. Since postview should be available + * before the capture, it should be processed and written to the surface before + * the final capture is processed. + * + * @param results The map of {@link ImageFormat#YUV_420_888} format images and + * metadata to process. The {@link Image} that are contained within + * the map will become invalid after this method completes, so no + * references to them should be kept. + * @param resultCallback Capture result callback to be called once the capture result + * values of the processed image are ready. + * @param executor The executor to run the callback on. If null then the callback + * will run on any arbitrary executor. + * @throws RuntimeException if postview feature is not supported + * @since 1.4 + */ + void processWithPostview(Map<Integer, Pair<Image, TotalCaptureResult>> results, + ProcessResultImpl resultCallback, Executor executor); } diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java index f926cff9..23570c4b 100644 --- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java +++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java @@ -84,4 +84,21 @@ public interface ExtenderStateListener { * @hide */ CaptureStageImpl onDisableSession(); + + /** + * This will be invoked before the {@link android.hardware.camera2.CameraCaptureSession} is + * initialized and must return a valid camera session type + * {@link android.hardware.camera2.params.SessionConfiguration#getSessionType} + * to be used to configure camera capture session. Both the preview and the image capture + * extender must return the same session type value for a specific extension type. If there + * is inconsistency between the session type values from preview and image extenders, then + * the session configuration will fail. + * + * + * @since 1.4 + * @return Camera capture session type. Regular and vendor specific types are supported but + * not high speed values. The extension can return -1 in which case the camera capture session + * will be configured to use the default regular type. + */ + int onSessionType(); } diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java index af147ed7..75739ce0 100644 --- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java +++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java @@ -29,7 +29,7 @@ import android.util.Log; */ public class ExtensionVersionImpl { private static final String TAG = "ExtenderVersionImpl"; - private static final String VERSION = "1.3.0"; + private static final String VERSION = "1.4.0"; /** * @hide diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java index 57b7fe65..25232635 100644 --- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java +++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java @@ -17,10 +17,12 @@ package androidx.camera.extensions.impl; import android.content.Context; import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraExtensionCharacteristics; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; import android.hardware.camera2.params.MeteringRectangle; +import android.hardware.camera2.params.SessionConfiguration; import android.media.Image; import android.media.ImageWriter; import android.os.Build; @@ -130,6 +132,26 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm } @Override + public void onPostviewOutputSurface(Surface surface) { + + } + + @Override + public void processWithPostview( + Map<Integer, Pair<Image, TotalCaptureResult>> results, + ProcessResultImpl resultCallback, Executor executor) { + if (!isPostviewAvailable()) { + throw new RuntimeException("The extension doesn't support postview"); + } + + if (resultCallback != null) { + process(results, resultCallback, executor); + } else { + process(results); + } + } + + @Override public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results, ProcessResultImpl resultCallback, Executor executor) { Pair<Image, TotalCaptureResult> result = results.get(NORMAL_STAGE_ID); @@ -184,12 +206,25 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm jpegOrientation)); } + Integer strength = result.second.get( + CaptureResult.EXTENSION_STRENGTH); + if (strength != null) { + captureResults.add(new Pair<>(CaptureResult.EXTENSION_STRENGTH, + strength)); + } + + captureResults.add(new Pair<>(CaptureResult.EXTENSION_CURRENT_TYPE, + CameraExtensionCharacteristics.EXTENSION_HDR)); + if (executor != null) { executor.execute(() -> resultCallback.onCaptureCompleted( shutterTimestamp, captureResults)); + executor.execute(() -> + resultCallback.onCaptureProcessProgressed(100)); } else { resultCallback.onCaptureCompleted(shutterTimestamp, captureResults); + resultCallback.onCaptureProcessProgressed(100); } } } @@ -264,6 +299,11 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm } @Override + public void onResolutionUpdate(Size size, Size postviewSize) { + + } + + @Override public void onImageFormatUpdate(int imageFormat) { } @@ -332,6 +372,11 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm } @Override + public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) { + return new ArrayList<>(); + } + + @Override public Range<Long> getEstimatedCaptureLatencyRange(Size captureOutputSize) { return null; } @@ -340,7 +385,7 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm 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.CONTROL_AF_TRIGGER, CaptureRequest.EXTENSION_STRENGTH}; return Arrays.asList(CAPTURE_REQUEST_SET); } @@ -348,7 +393,28 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm 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.CONTROL_AF_TRIGGER, CaptureResult.CONTROL_AF_STATE, + CaptureResult.EXTENSION_CURRENT_TYPE, CaptureResult.EXTENSION_STRENGTH}; return Arrays.asList(CAPTURE_RESULT_SET); } + + @Override + public int onSessionType() { + return SessionConfiguration.SESSION_REGULAR; + } + + @Override + public boolean isCaptureProcessProgressAvailable() { + return true; + } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + return null; + } + + @Override + public boolean isPostviewAvailable() { + return false; + } } diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java index 78b0a9d0..7777bfa2 100644 --- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java +++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java @@ -18,15 +18,18 @@ package androidx.camera.extensions.impl; import android.content.Context; import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraExtensionCharacteristics; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; import android.hardware.camera2.params.MeteringRectangle; +import android.hardware.camera2.params.SessionConfiguration; import android.media.ImageWriter; import android.media.Image; import android.util.Pair; import android.util.Size; import android.view.Surface; +import java.io.Closeable; import java.util.ArrayList; import java.util.concurrent.Executor; import java.util.List; @@ -43,8 +46,6 @@ import java.util.List; public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl { private static final int DEFAULT_STAGE_ID = 0; - ImageWriter mWriter; - /** * @hide */ @@ -109,17 +110,32 @@ public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl { return null; } - private PreviewImageProcessorImpl mProcessor = new PreviewImageProcessorImpl() { + private HdrPreviewProcessor mProcessor = new HdrPreviewProcessor(); + + private static class HdrPreviewProcessor implements PreviewImageProcessorImpl, Closeable { Surface mSurface; int mFormat = -1; + final Object mLock = new Object(); // Synchronize access to 'mWriter' + ImageWriter mWriter; - private void setWindowSurface() { - if (mSurface != null && mFormat >= 0) { + public void close() { + synchronized(mLock) { if (mWriter != null) { mWriter.close(); + mWriter = null; } + } + } - mWriter = ImageWriter.newInstance(mSurface, 2, mFormat); + private void setWindowSurface() { + synchronized(mLock) { + if (mSurface != null && mFormat >= 0) { + if (mWriter != null) { + mWriter.close(); + } + + mWriter = ImageWriter.newInstance(mSurface, 2, mFormat); + } } } @@ -132,7 +148,11 @@ public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl { @Override public void process(Image image, TotalCaptureResult result) { - mWriter.queueInputImage(image); + synchronized(mLock) { + if (mWriter != null) { + mWriter.queueInputImage(image); + } + } } @Override @@ -175,6 +195,14 @@ public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl { jpegOrientation)); } + Integer strength = result.get(CaptureResult.EXTENSION_STRENGTH); + if (strength != null) { + captureResults.add(new Pair<>(CaptureResult.EXTENSION_STRENGTH, strength)); + } + + captureResults.add(new Pair<>(CaptureResult.EXTENSION_CURRENT_TYPE, + CameraExtensionCharacteristics.EXTENSION_HDR)); + if (executor != null) { executor.execute(() -> resultCallback.onCaptureCompleted(shutterTimestamp, captureResults)); @@ -209,10 +237,7 @@ public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl { */ @Override public void onDeInit() { - if (mWriter != null) { - mWriter.close(); - mWriter = null; - } + mProcessor.close(); } /** @@ -238,4 +263,9 @@ public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl { public CaptureStageImpl onDisableSession() { return null; } + + @Override + public int onSessionType() { + return SessionConfiguration.SESSION_REGULAR; + } } diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java index c27a5dbb..37e7baf3 100644 --- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java +++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java @@ -91,6 +91,21 @@ public interface ImageCaptureExtenderImpl extends ExtenderStateListener { List<Pair<Integer, Size[]>> getSupportedResolutions(); /** + * Returns the customized supported postview resolutions for a still capture using + * its size. + * + * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned. + * + * <p>The returned resolutions should be subset of the supported sizes retrieved from + * {@link android.hardware.camera2.params.StreamConfigurationMap} for the camera device. + * + * @return the customized supported resolutions, or null to support all sizes retrieved from + * {@link android.hardware.camera2.params.StreamConfigurationMap}. + * @since 1.4 + */ + List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize); + + /** * Returns the estimated capture latency range in milliseconds for the target capture * resolution. * @@ -138,5 +153,44 @@ public interface ImageCaptureExtenderImpl extends ExtenderStateListener { * @since 1.3 */ List<CaptureResult.Key> getAvailableCaptureResultKeys(); -} + /** + * Advertise support for {@link ProcessResultImpl#onCaptureProcessProgressed}. + * + * @return {@code true} in case the process progress callback is supported and is expected to + * be triggered, {@code false} otherwise. + * @since 1.4 + */ + boolean isCaptureProcessProgressAvailable(); + + /** + * Returns the dynamically calculated capture latency pair in milliseconds. + * + * <p>In contrast to {@link #getEstimatedCaptureLatencyRange} this method is guaranteed to be + * called after the camera capture session is initialized and camera preview is enabled. + * The measurement is expected to take in to account dynamic parameters such as the current + * scene, the state of 3A algorithms, the state of internal HW modules and return a more + * accurate assessment of the still capture latency.</p> + * + * @return pair that includes the estimated input frame/frames camera capture latency as the + * first field and the estimated post-processing latency {@link CaptureProcessorImpl#process} + * as the second pair field. Both first and second fields will be in milliseconds. The total + * still capture latency will be the sum of both the first and second values. + * The pair is expected to be null if the dynamic latency estimation is not supported. + * If clients have not configured a still capture output, then this method can also return a + * null pair. + * @since 1.4 + */ + Pair<Long, Long> getRealtimeCaptureLatency(); + + /** + * Indicates whether the extension supports the postview for still capture feature. + * If the extension is using HAL processing, false should be returned since the + * postview feature is not currently supported for this case. + * + * @return {@code true} in case postview for still capture is supported + * {@code false} otherwise. + * @since 1.4 + */ + boolean isPostviewAvailable(); +} diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java index f0821ed7..e3317d94 100755 --- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java +++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java @@ -20,6 +20,7 @@ import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.SessionConfiguration; import android.media.Image; import android.media.ImageWriter; import android.os.Build; @@ -116,6 +117,26 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender } @Override + public void onPostviewOutputSurface(Surface surface) { + + } + + @Override + public void processWithPostview( + Map<Integer, Pair<Image, TotalCaptureResult>> results, + ProcessResultImpl resultCallback, Executor executor) { + if (!isPostviewAvailable()) { + throw new RuntimeException("The extension doesn't support postview"); + } + + if (resultCallback != null) { + process(results, resultCallback, executor); + } else { + process(results); + } + } + + @Override public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results, ProcessResultImpl resultCallback, Executor executor) { throw new RuntimeException("The extension doesn't support capture " + @@ -164,6 +185,11 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender } @Override + public void onResolutionUpdate(Size size, Size postviewSize) { + + } + + @Override public void onImageFormatUpdate(int imageFormat) { } @@ -244,6 +270,11 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender } @Override + public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) { + return new ArrayList<>(); + } + + @Override public Range<Long> getEstimatedCaptureLatencyRange(Size captureOutputSize) { return null; } @@ -257,4 +288,24 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender public List<CaptureResult.Key> getAvailableCaptureResultKeys() { return new ArrayList<>(); } + + @Override + public int onSessionType() { + return SessionConfiguration.SESSION_REGULAR; + } + + @Override + public boolean isCaptureProcessProgressAvailable() { + return false; + } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + return null; + } + + @Override + public boolean isPostviewAvailable() { + return false; + } } diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java index e29abec1..46be86ab 100755 --- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java +++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java @@ -18,6 +18,7 @@ package androidx.camera.extensions.impl; import android.content.Context; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.params.SessionConfiguration; import android.util.Pair; import android.util.Size; @@ -162,4 +163,9 @@ public final class NightPreviewExtenderImpl implements PreviewExtenderImpl { return captureStage; } + + @Override + public int onSessionType() { + return SessionConfiguration.SESSION_REGULAR; + } } diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java index d4c2014d..518942e9 100644 --- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java +++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java @@ -24,7 +24,6 @@ import java.util.List; /** * Allows clients to receive information about the capture result values of processed frames. * - * @since 1.3 */ public interface ProcessResultImpl { /** @@ -38,6 +37,23 @@ public interface ProcessResultImpl { * must also be passed as part of this callback. Both Camera2 and * CameraX guarantee that those two settings and results are always * supported and applied by the corresponding framework. + * @since 1.3 */ void onCaptureCompleted(long shutterTimestamp, List<Pair<CaptureResult.Key, Object>> result); + + + /** + * Capture progress callback that needs to be called when the process capture is + * ongoing and includes the estimated progress of the processing. + * + * <p>Extensions must ensure that they always call this callback with monotonically increasing + * values.</p> + * + * <p>Extensions are allowed to trigger this callback multiple times but at the minimum the + * callback is expected to be called once when processing is done with value 100.</p> + * + * @param progress Value between 0 and 100. + * @since 1.4 + */ + void onCaptureProcessProgressed(int progress); } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java index ccb0dacf..bd605708 100755 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java @@ -95,6 +95,11 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI throw new RuntimeException("Stub, replace with implementation."); } + @Override + public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + @Nullable @Override public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) { @@ -113,4 +118,23 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI throw new RuntimeException("Stub, replace with implementation."); } + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isCaptureProcessProgressAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isPostviewAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java index 100f6658..0c4577a4 100755 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java @@ -93,4 +93,9 @@ public final class AutoPreviewExtenderImpl implements PreviewExtenderImpl { public List<Pair<Integer, Size[]>> getSupportedResolutions() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java index 2d266390..50c80407 100755 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java @@ -95,6 +95,11 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende throw new RuntimeException("Stub, replace with implementation."); } + @Override + public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + @Nullable @Override public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) { @@ -112,4 +117,24 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende public List<CaptureResult.Key> getAvailableCaptureResultKeys() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isCaptureProcessProgressAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isPostviewAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java index bc3e48dd..1f501745 100755 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java @@ -93,4 +93,9 @@ public final class BeautyPreviewExtenderImpl implements PreviewExtenderImpl { public List<Pair<Integer, Size[]>> getSupportedResolutions() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java index 66c5839d..ee777cf9 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java @@ -95,6 +95,11 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender throw new RuntimeException("Stub, replace with implementation."); } + @Override + public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + @Nullable @Override public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) { @@ -113,4 +118,23 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender throw new RuntimeException("Stub, replace with implementation."); } + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isCaptureProcessProgressAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isPostviewAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java index ff588623..1dc5ed79 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java @@ -91,4 +91,9 @@ public final class BokehPreviewExtenderImpl implements PreviewExtenderImpl { public List<Pair<Integer, Size[]>> getSupportedResolutions() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java index 3eee146a..f4719b8b 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java @@ -21,6 +21,7 @@ import android.graphics.ImageFormat; import android.hardware.camera2.TotalCaptureResult; import android.media.Image; import android.util.Pair; +import android.util.Size; import android.view.Surface; import java.util.Map; @@ -46,6 +47,29 @@ public interface CaptureProcessorImpl extends ProcessorImpl { void process(Map<Integer, Pair<Image, TotalCaptureResult>> results); /** + * Informs the CaptureProcessorImpl where it should write the postview output to. + * This will only be invoked once if a valid postview surface was set. + * + * @param surface A valid {@link ImageFormat#YUV_420_888} {@link Surface} + * that the CaptureProcessorImpl should write data into. + * @since 1.4 + */ + void onPostviewOutputSurface(Surface surface); + + /** + * Invoked when the Camera Framework changes the configured output resolution for + * still capture and postview. + * + * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as + * input for still capture and postview to be at the specified resolutions. + * + * @param size for the surface for still capture. + * @param postviewSize for the surface for postview. + * @since 1.4 + */ + void onResolutionUpdate(Size size, Size postviewSize); + + /** * Process a set images captured that were requested. * * <p> The result of the processing step should be written to the {@link Surface} that was @@ -63,4 +87,30 @@ public interface CaptureProcessorImpl extends ProcessorImpl { */ void process(Map<Integer, Pair<Image, TotalCaptureResult>> results, ProcessResultImpl resultCallback, Executor executor); + + /** + * Process a set images captured that were requested for both postview and + * still capture. + * + * <p> This processing method will be called if a postview was requested, therefore the + * processed postview should be written to the + * {@link Surface} received by {@link #onPostviewOutputSurface(Surface, int)}. + * The final result of the processing step should be written to the {@link Surface} that was + * received by {@link #onOutputSurface(Surface, int)}. Since postview should be available + * before the capture, it should be processed and written to the surface before + * the final capture is processed. + * + * @param results The map of {@link ImageFormat#YUV_420_888} format images and + * metadata to process. The {@link Image} that are contained within + * the map will become invalid after this method completes, so no + * references to them should be kept. + * @param resultCallback Capture result callback to be called once the capture result + * values of the processed image are ready. + * @param executor The executor to run the callback on. If null then the callback + * will run on any arbitrary executor. + * @throws RuntimeException if postview feature is not supported + * @since 1.4 + */ + void processWithPostview(Map<Integer, Pair<Image, TotalCaptureResult>> results, + ProcessResultImpl resultCallback, Executor executor); } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java index 2879568f..4a3b01cd 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java @@ -80,4 +80,20 @@ public interface ExtenderStateListener { * @return The request information to customize the session. */ CaptureStageImpl onDisableSession(); + + /** + * This will be invoked before the {@link android.hardware.camera2.CameraCaptureSession} is + * initialized and must return a valid camera session type + * {@link android.hardware.camera2.params.SessionConfiguration#getSessionType} + * to be used to configure camera capture session. Both the preview and the image capture + * extender must return the same session type value for a specific extension type. If there + * is inconsistency between the session type values from preview and image extenders, then + * the session configuration will fail. + * + * @since 1.4 + * @return Camera capture session type. Regular and vendor specific types are supported but + * not high speed values. The extension can return -1 in which case the camera capture session + * will be configured to use the default regular type. + */ + int onSessionType(); } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java index f1191dcf..f3fd2f3b 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java @@ -95,6 +95,11 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm throw new RuntimeException("Stub, replace with implementation."); } + @Override + public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + @Nullable @Override public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) { @@ -112,4 +117,24 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm public List<CaptureResult.Key> getAvailableCaptureResultKeys() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isCaptureProcessProgressAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isPostviewAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java index 0eb4a610..af484646 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java @@ -93,4 +93,9 @@ public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl { public List<Pair<Integer, Size[]>> getSupportedResolutions() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java index 88bd105a..70c1804e 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java @@ -85,6 +85,21 @@ public interface ImageCaptureExtenderImpl extends ExtenderStateListener { List<Pair<Integer, Size[]>> getSupportedResolutions(); /** + * Returns the customized supported postview resolutions for a still capture using + * its size. + * + * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned. + * + * <p>The returned resolutions should be subset of the supported sizes retrieved from + * {@link android.hardware.camera2.params.StreamConfigurationMap} for the camera device. + * + * @return the customized supported resolutions, or null to support all sizes retrieved from + * {@link android.hardware.camera2.params.StreamConfigurationMap}. + * @since 1.4 + */ + List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize); + + /** * Returns the estimated capture latency range in milliseconds for the target capture * resolution. * @@ -159,4 +174,44 @@ public interface ImageCaptureExtenderImpl extends ExtenderStateListener { * @since 1.3 */ List<CaptureResult.Key> getAvailableCaptureResultKeys(); + + /** + * Advertise support for {@link ProcessResultImpl#onCaptureProcessProgressed}. + * + * @return {@code true} in case the process progress callback is supported and is expected to + * be triggered, {@code false} otherwise. + * @since 1.4 + */ + boolean isCaptureProcessProgressAvailable(); + + /** + * Returns the dynamically calculated capture latency pair in milliseconds. + * + * <p>In contrast to {@link #getEstimatedCaptureLatencyRange} this method is guaranteed to be + * called after the camera capture session is initialized and camera preview is enabled. + * The measurement is expected to take in to account dynamic parameters such as the current + * scene, the state of 3A algorithms, the state of internal HW modules and return a more + * accurate assessment of the still capture latency.</p> + * + * @return pair that includes the estimated input frame/frames camera capture latency as the + * first field and the estimated post-processing latency {@link CaptureProcessorImpl#process} + * as the second pair field. Both first and second fields will be in milliseconds. The total + * still capture latency will be the sum of both the first and second values. + * The pair is expected to be null if the dynamic latency estimation is not supported. + * If clients have not configured a still capture output, then this method can also return a + * null pair. + * @since 1.4 + */ + Pair<Long, Long> getRealtimeCaptureLatency(); + + /** + * Indicates whether the extension supports the postview for still capture feature. + * If the extension is using HAL processing, false should be returned since the + * postview feature is not currently supported for this case. + * + * @return {@code true} in case postview for still capture is supported + * {@code false} otherwise. + * @since 1.4 + */ + boolean isPostviewAvailable(); } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java index c8ac9788..6f0eaef9 100755 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java @@ -95,6 +95,11 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender throw new RuntimeException("Stub, replace with implementation."); } + @Override + public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + @Nullable @Override public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) { @@ -112,4 +117,24 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender public List<CaptureResult.Key> getAvailableCaptureResultKeys() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isCaptureProcessProgressAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public Pair<Long, Long> getRealtimeCaptureLatency() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isPostviewAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java index a5809f6b..825994f5 100755 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java @@ -93,4 +93,9 @@ public final class NightPreviewExtenderImpl implements PreviewExtenderImpl { public List<Pair<Integer, Size[]>> getSupportedResolutions() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public int onSessionType() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ProcessResultImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ProcessResultImpl.java index d0e3605d..0e154450 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ProcessResultImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ProcessResultImpl.java @@ -25,7 +25,6 @@ import java.util.List; /** * Allows clients to receive information about the capture result values of processed frames. * - * @since 1.3 */ @SuppressLint("UnknownNullness") public interface ProcessResultImpl { @@ -40,6 +39,22 @@ public interface ProcessResultImpl { * must also be passed as part of this callback. Both Camera2 and * CameraX guarantee that those two settings and results are always * supported and applied by the corresponding framework. + * @since 1.3 */ void onCaptureCompleted(long shutterTimestamp, List<Pair<CaptureResult.Key, Object>> result); + + /** + * Capture progress callback that needs to be called when the process capture is + * ongoing and includes the estimated progress of the processing. + * + * <p>Extensions must ensure that they always call this callback with monotonically increasing + * values.</p> + * + * <p>Extensions are allowed to trigger this callback multiple times but at the minimum the + * callback is expected to be called once when processing is done with value 100.</p> + * + * @param progress Value between 0 and 100. + * @since 1.4 + */ + void onCaptureProcessProgressed(int progress); } 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 465bfe88..d13efc85 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 @@ -124,6 +124,17 @@ public interface AdvancedExtenderImpl { Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(String cameraId); /** + * Returns supported output format/size map for postview image. OEM is required to support + * both JPEG and YUV_420_888 format output. + * + * <p>The surface created with this supported format/size could configure + * intermediate surfaces(YUV/RAW..) and write the output to the output surface.</p> + * + * @since 1.4 + */ + Map<Integer, List<Size>> getSupportedPostviewResolutions(Size captureSize); + + /** * Returns supported output sizes for Image Analysis (YUV_420_888 format). * * <p>OEM can optionally support a YUV surface for ImageAnalysis along with Preview/ImageCapture @@ -185,4 +196,24 @@ public interface AdvancedExtenderImpl { * @since 1.3 */ List<CaptureResult.Key> getAvailableCaptureResultKeys(); + + /** + * Advertise support for {@link SessionProcessorImpl#onCaptureProcessProgressed}. + * + * @return {@code true} in case the process progress callback is supported and is expected to + * be triggered, {@code false} otherwise. + * @since 1.4 + */ + public boolean isCaptureProcessProgressAvailable(); + + /** + * Indicates whether the extension supports the postview for still capture feature. + * If the extension is using HAL processing, false should be returned since the + * postview feature is not currently supported for this case. + * + * @return {@code true} in case postview for still capture is supported + * {@code false} otherwise. + * @since 1.4 + */ + boolean isPostviewAvailable(); } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java index 0d3bd4a0..8c3ac11c 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java @@ -69,6 +69,12 @@ public class AutoAdvancedExtenderImpl implements AdvancedExtenderImpl { } @Override + public Map<Integer, List<Size>> getSupportedPostviewResolutions( + Size captureSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override public List<Size> getSupportedYuvAnalysisResolutions( String cameraId) { throw new RuntimeException("Stub, replace with implementation."); @@ -88,4 +94,14 @@ public class AutoAdvancedExtenderImpl implements AdvancedExtenderImpl { public List<CaptureResult.Key> getAvailableCaptureResultKeys() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public boolean isCaptureProcessProgressAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isPostviewAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java index 1dec3266..135306c8 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java @@ -69,6 +69,12 @@ public class BeautyAdvancedExtenderImpl implements AdvancedExtenderImpl { } @Override + public Map<Integer, List<Size>> getSupportedPostviewResolutions( + Size captureSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override public List<Size> getSupportedYuvAnalysisResolutions( String cameraId) { throw new RuntimeException("Stub, replace with implementation."); @@ -88,4 +94,14 @@ public class BeautyAdvancedExtenderImpl implements AdvancedExtenderImpl { public List<CaptureResult.Key> getAvailableCaptureResultKeys() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public boolean isCaptureProcessProgressAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isPostviewAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java index bc41b4e0..fa4ad0dc 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java @@ -69,6 +69,12 @@ public class BokehAdvancedExtenderImpl implements AdvancedExtenderImpl { } @Override + public Map<Integer, List<Size>> getSupportedPostviewResolutions( + Size captureSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override public List<Size> getSupportedYuvAnalysisResolutions( String cameraId) { throw new RuntimeException("Stub, replace with implementation."); @@ -88,4 +94,14 @@ public class BokehAdvancedExtenderImpl implements AdvancedExtenderImpl { public List<CaptureResult.Key> getAvailableCaptureResultKeys() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public boolean isCaptureProcessProgressAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isPostviewAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } } 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 d1217177..850f0e1b 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 @@ -43,4 +43,16 @@ public interface Camera2SessionConfigImpl { * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters}. */ int getSessionTemplateId(); + + + /** + * Retrieves the session type to be used when initializing the + * {@link android.hardware.camera2.CameraCaptureSession}. + * + * @since 1.4 + * @return Camera capture session type. Regular and vendor specific types are supported but + * not high speed values. The extension can return -1 in which case the camera capture session + * will be configured to use the default regular type. + */ + int getSessionType(); } 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 a3011666..dc1feccd 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 @@ package androidx.camera.extensions.impl.advanced; import android.annotation.SuppressLint; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.params.SessionConfiguration; import java.util.ArrayList; import java.util.HashMap; @@ -32,6 +33,7 @@ import java.util.Map; @SuppressLint("UnknownNullness") public class Camera2SessionConfigImplBuilder { private int mSessionTemplateId = CameraDevice.TEMPLATE_PREVIEW; + private int mSessionType = SessionConfiguration.SESSION_REGULAR; Map<CaptureRequest.Key<?>, Object> mSessionParameters = new HashMap<>(); List<Camera2OutputConfigImpl> mCamera2OutputConfigs = new ArrayList<>(); @@ -86,6 +88,13 @@ public class Camera2SessionConfigImplBuilder { } /** + * Gets the camera capture session type. + */ + public int getSessionType() { + return mSessionType; + } + + /** * Builds a {@link Camera2SessionConfigImpl} instance. */ public Camera2SessionConfigImpl build() { @@ -95,6 +104,7 @@ public class Camera2SessionConfigImplBuilder { private static class Camera2SessionConfigImplImpl implements Camera2SessionConfigImpl { int mSessionTemplateId; + int mSessionType; Map<CaptureRequest.Key<?>, Object> mSessionParameters; List<Camera2OutputConfigImpl> mCamera2OutputConfigs; @@ -102,6 +112,7 @@ public class Camera2SessionConfigImplBuilder { mSessionTemplateId = builder.getSessionTemplateId(); mSessionParameters = builder.getSessionParameters(); mCamera2OutputConfigs = builder.getCamera2OutputConfigs(); + mSessionType = builder.getSessionType(); } @Override @@ -118,6 +129,11 @@ public class Camera2SessionConfigImplBuilder { public int getSessionTemplateId() { return mSessionTemplateId; } + + @Override + public int getSessionType() { + return mSessionType; + } } } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java index 06157dc3..dc5b2b60 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java @@ -70,6 +70,12 @@ public class HdrAdvancedExtenderImpl implements AdvancedExtenderImpl { } @Override + public Map<Integer, List<Size>> getSupportedPostviewResolutions( + Size captureSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override public List<Size> getSupportedYuvAnalysisResolutions( String cameraId) { throw new RuntimeException("Stub, replace with implementation."); @@ -89,4 +95,14 @@ public class HdrAdvancedExtenderImpl implements AdvancedExtenderImpl { public List<CaptureResult.Key> getAvailableCaptureResultKeys() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public boolean isCaptureProcessProgressAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isPostviewAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } } diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java index 97da5c14..5b0ed8ee 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java @@ -69,6 +69,12 @@ public class NightAdvancedExtenderImpl implements AdvancedExtenderImpl { } @Override + public Map<Integer, List<Size>> getSupportedPostviewResolutions( + Size captureSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override public List<Size> getSupportedYuvAnalysisResolutions( String cameraId) { throw new RuntimeException("Stub, replace with implementation."); @@ -88,4 +94,14 @@ public class NightAdvancedExtenderImpl implements AdvancedExtenderImpl { public List<CaptureResult.Key> getAvailableCaptureResultKeys() { throw new RuntimeException("Stub, replace with implementation."); } + + @Override + public boolean isCaptureProcessProgressAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public boolean isPostviewAvailable() { + throw new RuntimeException("Stub, replace with implementation."); + } } 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 new file mode 100644 index 00000000..723f0f4e --- /dev/null +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java @@ -0,0 +1,35 @@ +/* + * Copyright 2022 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. + */ + +package androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; + +/** + * For specifying the output surface configurations for the extension. + * + * @since 1.4 + */ +@SuppressLint("UnknownNullness") +public interface OutputSurfaceConfigurationImpl { + public OutputSurfaceImpl getPreviewOutputSurface(); + + public OutputSurfaceImpl getImageCaptureOutputSurface(); + + public OutputSurfaceImpl getImageAnalysisOutputSurface(); + + public OutputSurfaceImpl getPostviewOutputSurface(); +} diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java index fabfc2bf..06270812 100644 --- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java +++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java @@ -21,6 +21,7 @@ import android.content.Context; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; +import android.util.Pair; import android.view.Surface; import java.util.Map; @@ -64,9 +65,59 @@ public interface SessionProcessorImpl { * preparing a CameraCaptureSession. After initSession() is called, the camera ID, * cameraCharacteristics and context will not change until deInitSession() has been called. * - * <p>CameraX specifies the output surface configurations for preview, image capture and image - * analysis[optional]. And OEM returns a {@link Camera2SessionConfigImpl} which consists of a - * list of {@link Camera2OutputConfigImpl} and session parameters. The + * <p>CameraX / Camera2 specifies the output surface configurations for preview using + * {@link OutputSurfaceConfigurationImpl#getPreviewOutputSurface}, image capture using + * {@link OutputSurfaceConfigurationImpl#getImageCaptureOutputSurface}, and image analysis + * [optional] using {@link OutputSurfaceConfigurationImpl#getImageAnalysisOutputSurface}. + * And OEM returns a {@link Camera2SessionConfigImpl} which consists of a list of + * {@link Camera2OutputConfigImpl} and session parameters. The {@link Camera2SessionConfigImpl} + * will be used to configure the CameraCaptureSession. + * + * <p>OEM is responsible for outputting correct camera images output to these output surfaces. + * OEM can have the following options to enable the output: + * <pre> + * (1) Add these output surfaces in CameraCaptureSession directly using + * {@link Camera2OutputConfigImplBuilder#newSurfaceConfig(Surface)} }. Processing is done in + * HAL. + * + * (2) Use surface sharing with other surface by calling + * {@link Camera2OutputConfigImplBuilder#addSurfaceSharingOutputConfig(Camera2OutputConfigImpl)} + * to add the output surface to the other {@link Camera2OutputConfigImpl}. + * + * (3) Process output from other surfaces (RAW, YUV..) and write the result to the output + * surface. The output surface won't be contained in the returned + * {@link Camera2SessionConfigImpl}. + * </pre> + * + * <p>{@link Camera2OutputConfigImplBuilder} and {@link Camera2SessionConfigImplBuilder} + * implementations are provided in the stub for OEM to construct the + * {@link Camera2OutputConfigImpl} and {@link Camera2SessionConfigImpl} instances. + * + * @param surfaceConfigs contains output surfaces for preview, image capture, and an + * optional output config for image analysis (YUV_420_888). + * @return a {@link Camera2SessionConfigImpl} consisting of a list of + * {@link Camera2OutputConfigImpl} and session parameters which will decide the + * {@link android.hardware.camera2.params.SessionConfiguration} for configuring the + * CameraCaptureSession. Please note that the OutputConfiguration list may not be part of any + * supported or mandatory stream combination BUT OEM must ensure this list will always + * produce a valid camera capture session. + * + * @since 1.4 + */ + Camera2SessionConfigImpl initSession( + String cameraId, + Map<String, CameraCharacteristics> cameraCharacteristicsMap, + Context context, + OutputSurfaceConfigurationImpl surfaceConfigs); + + /** + * Initializes the session for the extension. This is where the OEMs allocate resources for + * preparing a CameraCaptureSession. After initSession() is called, the camera ID, + * cameraCharacteristics and context will not change until deInitSession() has been called. + * + * <p>CameraX / Camera 2 specifies the output surface configurations for preview, image capture + * and image analysis[optional]. And OEM returns a {@link Camera2SessionConfigImpl} which + * consists of a list of {@link Camera2OutputConfigImpl} and session parameters. The * {@link Camera2SessionConfigImpl} will be used to configure the CameraCaptureSession. * * <p>OEM is responsible for outputting correct camera images output to these output surfaces. @@ -188,11 +239,54 @@ public interface SessionProcessorImpl { int startCapture(CaptureCallback callback); /** + * Start a multi-frame capture with a postview. {@link #startCapture(CaptureCallback)} + * will be used for captures without a postview request. + * + * Postview will be available before the capture. Upon postview completion, + * {@code OnImageAvailableListener#onImageAvailable} will be called on the ImageReader + * that creates the postview output surface. When the capture is completed, + * {@link CaptureCallback#onCaptureSequenceCompleted} is called and + * {@code OnImageAvailableListener#onImageAvailable} will also be called on the ImageReader + * that creates the image capture output surface. + * + * <p>Only one capture can perform at a time. Starting a capture when another capture is + * running will cause onCaptureFailed to be called immediately. + * + * @param callback a callback to report the status. + * @return the id of the capture sequence. + * @since 1.4 + */ + int startCaptureWithPostview(CaptureCallback callback); + + /** * Abort all capture tasks. */ void abortCapture(int captureSequenceId); /** + * Returns the dynamically calculated capture latency pair in milliseconds. + * + * <p>In contrast to {@link AdvancedExtenderImpl#getEstimatedCaptureLatencyRange} this method is + * guaranteed to be called after {@link #onCaptureSessionStart}. + * The measurement is expected to take in to account dynamic parameters such as the current + * scene, the state of 3A algorithms, the state of internal HW modules and return a more + * accurate assessment of the still capture latency.</p> + * + * @return pair that includes the estimated input frame/frames camera capture latency as the + * first field. This is the time between {@link #onCaptureStarted} and + * {@link #onCaptureProcessStarted}. The second field value includes the estimated + * post-processing latency. This is the time between {@link #onCaptureProcessStarted} until + * the processed frame returns back to the client registered surface. + * Both first and second values will be in milliseconds. The total still capture latency will be + * the sum of both the first and second values of the pair. + * The pair is expected to be null if the dynamic latency estimation is not supported. + * If clients have not configured a still capture output, then this method can also return a + * null pair. + * @since 1.4 + */ + Pair<Long, Long> getRealtimeCaptureLatency(); + + /** * Callback for notifying the status of {@link #startCapture(CaptureCallback)} and * {@link #startRepeating(CaptureCallback)}. */ @@ -277,5 +371,20 @@ public interface SessionProcessorImpl { */ void onCaptureCompleted(long timestamp, int captureSequenceId, Map<CaptureResult.Key, Object> result); + + /** + * Capture progress callback that needs to be called when the process capture is + * ongoing and includes the estimated progress of the processing. + * + * <p>Extensions must ensure that they always call this callback with monotonically + * increasing values.</p> + * + * <p>Extensions are allowed to trigger this callback multiple times but at the minimum the + * callback is expected to be called once when processing is done with value 100.</p> + * + * @param progress Value between 0 and 100. + * @since 1.4 + */ + void onCaptureProcessProgressed(int progress); } } diff --git a/camera2/public/src/com/android/ex/camera2/blocking/BlockingCameraManager.java b/camera2/public/src/com/android/ex/camera2/blocking/BlockingCameraManager.java index 21014d03..5b5a38d9 100644 --- a/camera2/public/src/com/android/ex/camera2/blocking/BlockingCameraManager.java +++ b/camera2/public/src/com/android/ex/camera2/blocking/BlockingCameraManager.java @@ -89,7 +89,7 @@ public class BlockingCameraManager { } } - private final CameraManager mManager; + protected final CameraManager mManager; /** * Create a new blocking camera manager. @@ -168,7 +168,7 @@ public class BlockingCameraManager { * <p>Time out after {@link #OPEN_TIME_OUT_MS} and unblock. Clean up camera if it arrives * later.</p> */ - private class OpenListener extends CameraDevice.StateCallback { + protected class OpenListener extends CameraDevice.StateCallback { private static final int ERROR_UNINITIALIZED = -1; private final String mCameraId; @@ -186,9 +186,13 @@ public class BlockingCameraManager { private boolean mNoReply = true; // Start with no reply until proven otherwise private boolean mTimedOut = false; - OpenListener(CameraManager manager, String cameraId, - CameraDevice.StateCallback listener, Handler handler) - throws CameraAccessException { + protected OpenListener(String cameraId, CameraDevice.StateCallback listener) { + mCameraId = cameraId; + mProxy = listener; + } + + OpenListener(CameraManager manager, String cameraId, CameraDevice.StateCallback listener, + Handler handler) throws CameraAccessException { mCameraId = cameraId; mProxy = listener; manager.openCamera(cameraId, this, handler); @@ -281,7 +285,7 @@ public class BlockingCameraManager { if (mProxy != null) mProxy.onClosed(camera); } - CameraDevice blockUntilOpen() throws BlockingOpenException { + public CameraDevice blockUntilOpen() throws BlockingOpenException { /** * Block until onOpened, onError, or onDisconnected */ |