[go: nahoru, domu]

blob: 943b069d5d3827e05b77fa9d5c17fee1273f5f3f [file] [log] [blame]
/*
* 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.core;
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;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.core.util.Consumer;
import com.google.auto.value.AutoValue;
import java.io.Closeable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.Executor;
/**
* A {@link Surface} for drawing processed camera frames.
*
* <p>Contains a {@link Surface} and its characteristics along with methods to manage the
* lifecycle of the {@link Surface}.
*
* @see SurfaceProcessor#onOutputSurface(SurfaceOutput)
*/
public interface SurfaceOutput extends Closeable {
/**
* Gets the {@link Surface} for drawing processed frames.
*
* <p> If there are multiple calls to the method, only the {@link Consumer<Event>}
* from the last call will be triggered.
*
* @param executor on which the listener should be invoked.
* @param listener a listener to notify the implementation about the end-of-life of the
* {@link SurfaceOutput}. The implementation should then invoke
* {@link #close()} to mark the {@link Surface} as no longer in use.
*/
@NonNull
Surface getSurface(
@NonNull Executor executor,
@NonNull Consumer<Event> listener);
/**
* This field indicates that what purpose the {@link Surface} will be used for.
*
* <p>{@link CameraEffect#PREVIEW} if the {@link Surface} will be used for {@link Preview}.
*/
@CameraEffect.Targets
int getTargets();
/**
* This field indicates the format of the {@link Surface}.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@CameraEffect.Formats
default int getFormat() {
return INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE;
}
/**
* Gets the size of the {@link Surface}.
*/
@NonNull
Size getSize();
/**
* Call this method to mark the {@link Surface} as no longer in use.
*
* <p>Once the {@link SurfaceProcessor} implementation receives a request to close the
* {@link Surface}, it should call this method to acknowledge after stop writing to the
* {@link Surface}. Writing to the {@link Surface} after calling this method might cause
* errors.
*/
@Override
void close();
/**
* Applies an additional 4x4 transformation on the original matrix.
*
* <p>When the input {@link Surface} of {@link SurfaceProcessor} is backed by a
* {@link SurfaceTexture}, use this method to update the texture transform matrix.
*
* <p>Typically, after retrieving the transform matrix from
* {@link SurfaceTexture#getTransformMatrix}, the {@link SurfaceProcessor} implementation
* should always call this method to update the value. The result is a matrix of the same
* format, which is a transform matrix maps 2D homogeneous texture coordinates of the form
* (s, t, 0, 1) with s and t in the inclusive range [0, 1] to the texture coordinate that
* should be used to sample that location from the texture. The matrix is stored in
* column-major order so that it may be passed directly to OpenGL ES via the {@code
* glLoadMatrixf} or {@code glUniformMatrix4fv} functions.
*
* <p>The additional transformation is calculated based on the target rotation, target
* resolution and the {@link ViewPort} associated with the target {@link UseCase}. The value
* could also include workarounds for device specific bugs. For example, correcting a
* stretched camera output stream.
*
* <p>Code sample:
* <pre><code>
* float[] transform = new float[16];
* float[] updatedTransform = new float[16];
*
* surfaceTexture.setOnFrameAvailableListener(surfaceTexture -> {
* surfaceTexture.getTransformMatrix(transform);
* outputSurface.updateTransformMatrix(updatedTransform, transform);
* // Use the value of updatedTransform for OpenGL rendering.
* });
* </code></pre>
*
* <p>To get the value of the additional transformation, pass in an identity matrix as the
* original value. This is useful when {@link SurfaceTexture#getTransformMatrix} is not
* applied by the implementation.
*
* <p>Code sample:
* <pre><code>
* float[] identity = new float[16];
* Matrix.setIdentityM(identity, 0);
* float[] updatedTransform = new float[16];
*
* surfaceTexture.setOnFrameAvailableListener(surfaceTexture -> {
* outputSurface.updateTransformMatrix(updatedTransform, identity);
* // Use the value of updatedTransform for OpenGL rendering.
* });
* </code></pre>
*
* @param updated the array into which the 4x4 matrix will be stored. The array must
* have exactly 16 elements.
* @param original the original 4x4 matrix. The array must have exactly 16 elements.
* @see SurfaceTexture#getTransformMatrix(float[])
*/
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, #getSize()#getWidth(), #getSize()#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>
*/
@NonNull
default Matrix getSensorToBufferTransform() {
return new Matrix();
}
/**
* Events of the {@link Surface} retrieved from
* {@link SurfaceOutput#getSurface(Executor, Consumer)}.
*/
@AutoValue
abstract class Event {
Event() {
}
/**
* Possible event codes.
*/
@IntDef({EVENT_REQUEST_CLOSE})
@Retention(RetentionPolicy.SOURCE)
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public @interface EventCode {
}
/**
* The {@link Surface} provider is requesting to release the {@link Surface}.
*
* <p> Releasing a {@link Surface} while it's still being written into is not safe on
* some devices. This is why the provider of the {@link Surface} will not release the
* {@link Surface} without the CameraX's permission. Once this event is received, the
* implementation should stop accessing the {@link Surface} as soon as possible, then
* mark the {@link SurfaceOutput} as closed by calling {@link SurfaceOutput#close()}.
* Once closed, CameraX will notify the {@link Surface} provider that it's safe to
* release the {@link Surface}.
*/
public static final int EVENT_REQUEST_CLOSE = 0;
/**
* Returns the event associated with the {@link SurfaceOutput}.
*/
@EventCode
public abstract int getEventCode();
/**
* Gets the {@link SurfaceOutput} associated with this event.
*/
@NonNull
public abstract SurfaceOutput getSurfaceOutput();
/**
* Creates a {@link Event} for sending to the implementation.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@NonNull
public static SurfaceOutput.Event of(@EventCode int code,
@NonNull SurfaceOutput surfaceOutput) {
return new AutoValue_SurfaceOutput_Event(code, surfaceOutput);
}
}
}