diff options
author | Ravneet Dhanjal <rdhanjal@google.com> | 2022-12-01 19:50:01 +0000 |
---|---|---|
committer | Ravneet Dhanjal <rdhanjal@google.com> | 2022-12-16 07:00:46 +0000 |
commit | 8e874f79e1a83b1492fe1b78dc658323c3c7e79e (patch) | |
tree | 18d13ecc1c62761f8e85d902dc8f2efd1e6fd4d1 | |
parent | 3b33dca1352e43728d64249818d43d904f4104ad (diff) | |
download | ex-8e874f79e1a83b1492fe1b78dc658323c3c7e79e.tar.gz |
Camera Extensions: Add Postview to sample
- Enable postview in extension samples
- Add sample postview feature to the
basic extension sample
Test: Camera CTS
Bug: 258295487
Change-Id: I98506f0edd6c2e7f2da0740a243bb564db82274d
18 files changed, 536 insertions, 3 deletions
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 49a5a0ef..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) { @@ -127,4 +132,9 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI 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/BeautyImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java index 4a7f9203..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) { @@ -127,4 +132,9 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende 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/BokehImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java index 576029c0..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) { @@ -127,4 +132,9 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender 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/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/HdrImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java index a505cb8b..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) { @@ -127,4 +132,9 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm 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/ImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java index cfc23b11..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. * @@ -188,4 +203,15 @@ public interface ImageCaptureExtenderImpl extends ExtenderStateListener { * @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 829c8a09..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) { @@ -127,4 +132,9 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender 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/advanced/AdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java index fcda9bee..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 @@ -194,4 +205,15 @@ public interface AdvancedExtenderImpl { * @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 7041dae5..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; @@ -217,7 +222,8 @@ public abstract class BaseAdvancedExtenderImpl implements AdvancedExtenderImpl { // called. This is just a sample for earlier versions if wanting to redirect this call. OutputSurfaceConfigurationImplImpl surfaceConfigs = new OutputSurfaceConfigurationImplImpl(previewSurfaceConfig, - imageCaptureSurfaceConfig, imageAnalysisSurfaceConfig); + imageCaptureSurfaceConfig, imageAnalysisSurfaceConfig, + null /*postviewSurfaceConfig*/); return initSession(cameraId, cameraCharacteristicsMap, context, surfaceConfigs); } @@ -452,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); @@ -626,13 +637,16 @@ public abstract class BaseAdvancedExtenderImpl implements AdvancedExtenderImpl { private OutputSurfaceImpl mOutputPreviewSurfaceImpl; private OutputSurfaceImpl mOutputImageCaptureSurfaceImpl; private OutputSurfaceImpl mOutputImageAnalysisSurfaceImpl; + private OutputSurfaceImpl mOutputPostviewSurfaceImpl; public OutputSurfaceConfigurationImplImpl(OutputSurfaceImpl previewSurfaceConfig, OutputSurfaceImpl imageCaptureSurfaceConfig, - OutputSurfaceImpl imageAnalysisSurfaceConfig) { + OutputSurfaceImpl imageAnalysisSurfaceConfig, + OutputSurfaceImpl postviewSurfaceConfig) { mOutputPreviewSurfaceImpl = previewSurfaceConfig; mOutputImageCaptureSurfaceImpl = imageCaptureSurfaceConfig; mOutputImageAnalysisSurfaceImpl = imageAnalysisSurfaceConfig; + mOutputPostviewSurfaceImpl = postviewSurfaceConfig; } @Override @@ -649,6 +663,11 @@ public abstract class BaseAdvancedExtenderImpl implements AdvancedExtenderImpl { public OutputSurfaceImpl getImageAnalysisOutputSurface() { return mOutputImageAnalysisSurfaceImpl; } + + @Override + public OutputSurfaceImpl getPostviewOutputSurface() { + return mOutputPostviewSurfaceImpl; + } } @Override @@ -672,4 +691,9 @@ public abstract class BaseAdvancedExtenderImpl implements AdvancedExtenderImpl { public boolean isCaptureProcessProgressAvailable() { return true; } + + @Override + public boolean isPostviewAvailable() { + return false; + } } diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java index 8e470139..ca3832e3 100644 --- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java +++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java @@ -30,4 +30,6 @@ public interface OutputSurfaceConfigurationImpl { 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 11e63956..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 @@ -224,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} 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 fa19a03a..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 @@ -117,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 " + @@ -165,6 +185,11 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI } @Override + public void onResolutionUpdate(Size size, Size postviewSize) { + + } + + @Override public void onImageFormatUpdate(int imageFormat) { } @@ -245,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; } @@ -273,4 +303,9 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI 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/BeautyImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java index f769549b..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 @@ -119,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 " + @@ -167,6 +187,11 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende } @Override + public void onResolutionUpdate(Size size, Size postviewSize) { + + } + + @Override public void onImageFormatUpdate(int imageFormat) { } @@ -268,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; } @@ -296,4 +326,9 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende 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/BokehImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java index d3412eb0..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,11 +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; @@ -52,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 */ @@ -63,6 +67,7 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender */ @Override public void init(String cameraId, CameraCharacteristics cameraCharacteristics) { + mCameraCharacteristics = cameraCharacteristics; } /** @@ -105,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) { @@ -114,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); @@ -242,6 +303,11 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender } @Override + public void onResolutionUpdate(Size size, Size postviewSize) { + + } + + @Override public void onImageFormatUpdate(int imageFormat) { } @@ -318,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 @@ -357,4 +475,9 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender 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/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/HdrImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java index e0f59558..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 @@ -132,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); @@ -279,6 +299,11 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm } @Override + public void onResolutionUpdate(Size size, Size postviewSize) { + + } + + @Override public void onImageFormatUpdate(int imageFormat) { } @@ -347,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; } @@ -382,4 +412,9 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm 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/ImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java index 8cb64ea2..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. * @@ -167,4 +182,15 @@ public interface ImageCaptureExtenderImpl extends ExtenderStateListener { * @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 c233ef8f..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 @@ -117,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 " + @@ -165,6 +185,11 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender } @Override + public void onResolutionUpdate(Size size, Size postviewSize) { + + } + + @Override public void onImageFormatUpdate(int imageFormat) { } @@ -245,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; } @@ -273,4 +303,9 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender public Pair<Long, Long> getRealtimeCaptureLatency() { return null; } + + @Override + public boolean isPostviewAvailable() { + return false; + } } |