Merge "Supply the sensor-to-buffer transform in SurfaceOutput" into androidx-main
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt
index b1020d6..6321d77 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt
@@ -16,8 +16,10 @@
package androidx.camera.core.processing
+import android.graphics.Bitmap.createBitmap
import android.graphics.BitmapFactory
import android.graphics.ImageFormat
+import android.graphics.Matrix
import android.graphics.Rect
import android.graphics.SurfaceTexture
import android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW
@@ -427,7 +429,8 @@
Rect(0, 0, WIDTH, HEIGHT),
/*rotationDegrees=*/0,
/*mirroring=*/false,
- FakeCamera()
+ FakeCamera(),
+ Matrix()
)
private fun createCustomShaderProvider(
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/SurfaceOutput.java b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceOutput.java
index 0cde5ad..a41d1a7 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/SurfaceOutput.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceOutput.java
@@ -18,7 +18,9 @@
import static androidx.camera.core.impl.ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE;
+import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
+import android.hardware.camera2.CameraCharacteristics;
import android.util.Size;
import android.view.Surface;
@@ -150,6 +152,33 @@
void updateTransformMatrix(@NonNull float[] updated, @NonNull float[] original);
/**
+ * Returns the sensor to image buffer transform matrix.
+ *
+ * <p>The value is a mapping from sensor coordinates to buffer coordinates, which is,
+ * from the rect of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE} to the
+ * rect defined by {@code (0, 0, SurfaceRequest#getResolution#getWidth(),
+ * SurfaceRequest#getResolution#getHeight())}. The matrix can
+ * be used to map the coordinates from one {@link UseCase} to another. For example,
+ * detecting face with {@link ImageAnalysis}, and then highlighting the face in
+ * {@link Preview}.
+ *
+ * <p>Code sample
+ * <code><pre>
+ * // Get the transformation from sensor to effect output.
+ * Matrix sensorToEffect = surfaceOutput.getSensorToBufferTransform();
+ * // Get the transformation from sensor to ImageAnalysis.
+ * Matrix sensorToAnalysis = imageProxy.getSensorToBufferTransform();
+ * // Concatenate the two matrices to get the transformation from ImageAnalysis to effect.
+ * Matrix analysisToEffect = Matrix()
+ * sensorToAnalysis.invert(analysisToEffect);
+ * analysisToEffect.postConcat(sensorToEffect);
+ * </pre></code>
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @NonNull
+ Matrix getSensorToBufferTransform();
+
+ /**
* Events of the {@link Surface} retrieved from
* {@link SurfaceOutput#getSurface(Executor, Consumer)}.
*/
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEdge.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEdge.java
index a7c936a..d237eda 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEdge.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEdge.java
@@ -320,7 +320,7 @@
}
SurfaceOutputImpl surfaceOutputImpl = new SurfaceOutputImpl(surface,
getTargets(), format, mStreamSpec.getResolution(), inputSize, cropRect,
- rotationDegrees, mirroring, cameraInternal);
+ rotationDegrees, mirroring, cameraInternal, mSensorToBufferTransform);
surfaceOutputImpl.getCloseFuture().addListener(
settableSurface::decrementUseCount,
directExecutor());
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOutputImpl.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOutputImpl.java
index 8038235..aae6698 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOutputImpl.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOutputImpl.java
@@ -95,6 +95,8 @@
private CallbackToFutureAdapter.Completer<Void> mCloseFutureCompleter;
@Nullable
private CameraInternal mCameraInternal;
+ @NonNull
+ private android.graphics.Matrix mSensorToBufferTransform;
SurfaceOutputImpl(
@NonNull Surface surface,
@@ -105,7 +107,8 @@
@NonNull Rect inputCropRect,
int rotationDegree,
boolean mirroring,
- @Nullable CameraInternal cameraInternal) {
+ @Nullable CameraInternal cameraInternal,
+ @NonNull android.graphics.Matrix sensorToBufferTransform) {
mSurface = surface;
mTargets = targets;
mFormat = format;
@@ -115,6 +118,7 @@
mMirroring = mirroring;
mRotationDegrees = rotationDegree;
mCameraInternal = cameraInternal;
+ mSensorToBufferTransform = sensorToBufferTransform;
calculateAdditionalTransform();
mCloseFuture = CallbackToFutureAdapter.getFuture(
completer -> {
@@ -264,6 +268,15 @@
}
/**
+ * @inheritDoc
+ */
+ @NonNull
+ @Override
+ public android.graphics.Matrix getSensorToBufferTransform() {
+ return new android.graphics.Matrix(mSensorToBufferTransform);
+ }
+
+ /**
* Calculates the additional GL transform and saves it to {@link #mAdditionalTransform}.
*
* <p>The effect implementation needs to apply this value on top of texture transform obtained
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceEdgeTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceEdgeTest.kt
index eeda779..ad6dbd7 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceEdgeTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceEdgeTest.kt
@@ -293,25 +293,26 @@
@Test
fun createSurfaceOutputWithDisconnectedEdge_surfaceOutputNotCreated() {
- // Arrange: create a SurfaceOutput future from a closed LinkableSurface
+ // Arrange: create a SurfaceOutput future from a closed Edge
+ surfaceEdge.setProvider(provider)
+ provider.setSurface(fakeSurface)
surfaceEdge.disconnect()
- val surfaceOutput = createSurfaceOutputFuture(surfaceEdge)
-
// Act: wait for the SurfaceOutput to return.
- var successful: Boolean? = null
- Futures.addCallback(surfaceOutput, object : FutureCallback<SurfaceOutput> {
- override fun onSuccess(result: SurfaceOutput?) {
- successful = true
- }
-
- override fun onFailure(t: Throwable) {
- successful = false
- }
- }, mainThreadExecutor())
- shadowOf(getMainLooper()).idle()
+ val surfaceOutput = getSurfaceOutputFromFuture(createSurfaceOutputFuture(surfaceEdge))
// Assert: the SurfaceOutput is not created.
- assertThat(successful!!).isEqualTo(false)
+ assertThat(surfaceOutput).isNull()
+ }
+
+ @Test
+ fun createSurfaceOutput_inheritSurfaceEdgeTransformation() {
+ // Arrange: set the provider and create a SurfaceOutput future.
+ surfaceEdge.setProvider(provider)
+ provider.setSurface(fakeSurface)
+ // Act: create a SurfaceOutput from the SurfaceEdge
+ val surfaceOutput = getSurfaceOutputFromFuture(createSurfaceOutputFuture(surfaceEdge))
+ // Assert: the SurfaceOutput inherits the transformation from the SurfaceEdge.
+ assertThat(surfaceOutput!!.sensorToBufferTransform).isEqualTo(SENSOR_TO_BUFFER)
}
@Test
@@ -542,6 +543,22 @@
assertThat(transformationInfo!!.rotationDegrees).isEqualTo(90)
}
+ private fun getSurfaceOutputFromFuture(
+ future: ListenableFuture<SurfaceOutput>
+ ): SurfaceOutput? {
+ var surfaceOutput: SurfaceOutput? = null
+ Futures.addCallback(future, object : FutureCallback<SurfaceOutput> {
+ override fun onSuccess(result: SurfaceOutput?) {
+ surfaceOutput = result
+ }
+
+ override fun onFailure(t: Throwable) {
+ }
+ }, mainThreadExecutor())
+ shadowOf(getMainLooper()).idle()
+ return surfaceOutput
+ }
+
private fun createSurfaceOutputFuture(surfaceEdge: SurfaceEdge) =
surfaceEdge.createSurfaceOutputFuture(
INPUT_SIZE,
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceOutputImplTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceOutputImplTest.kt
index 21dd66c..2603f35 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceOutputImplTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceOutputImplTest.kt
@@ -186,7 +186,8 @@
sizeToRect(INPUT_SIZE),
/*rotationDegrees=*/180,
/*mirroring=*/false,
- camera
+ camera,
+ android.graphics.Matrix()
).apply {
surfaceOutputsToCleanup.add(this)
}