TextureFrame.java
/*
* Copyright 2023 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.effects.internal;
import static androidx.core.util.Preconditions.checkState;
import static java.util.Objects.requireNonNull;
import android.view.Surface;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.camera.effects.opengl.GlRenderer;
/**
* A GL texture for caching camera frames.
*
* <p>The frame can be empty or filled. A filled frame contains valid information on how to
* render it. An empty frame can be filled with new content.
*/
@RequiresApi(21)
class TextureFrame {
private static final long NO_VALUE = Long.MIN_VALUE;
private final int mTextureId;
private long mTimestampNanos = NO_VALUE;
@Nullable
private Surface mSurface;
@NonNull
private final float[] mTransform = new float[16];
/**
* Creates a frame that is backed by a texture ID.
*/
TextureFrame(int textureId) {
mTextureId = textureId;
}
/**
* Checks if the frame is empty.
*
* <p>An empty frame means that the texture does not have valid content. It can be filled
* with new content.
*/
boolean isEmpty() {
return mTimestampNanos == NO_VALUE;
}
/**
* Marks the frame as empty.
*
* <p>Once the frame is marked as empty, it can be filled with new content.
*/
void markEmpty() {
checkState(!isEmpty(), "Frame is already empty");
mTimestampNanos = NO_VALUE;
mSurface = null;
}
/**
* Marks the frame as filled.
*
* <p>Call this method when a valid camera frame has been copied to the texture with
* {@link GlRenderer#renderInputToQueueTexture}. Once filled, the frame should not be
* written into until it's made empty again.
*
* @param timestampNs the timestamp of the camera frame in nanoseconds.
* @param transform the transform to apply when rendering the frame.
* @param surface the output surface to which the frame should render.
*/
void markFilled(long timestampNs, @NonNull float[] transform, @NonNull Surface surface) {
checkState(isEmpty(), "Frame is already filled");
mTimestampNanos = timestampNs;
System.arraycopy(transform, 0, mTransform, 0, transform.length);
mSurface = surface;
}
/**
* Gets the timestamp of the frame.
*
* <p>This value is used in {@link GlRenderer#renderQueueTextureToSurface}.
*/
long getTimestampNanos() {
return mTimestampNanos;
}
/**
* Gets the 2D texture id of the frame.
*
* <p>This value is used in {@link GlRenderer#renderQueueTextureToSurface} and
* {@link GlRenderer#renderInputToQueueTexture}.
*/
int getTextureId() {
return mTextureId;
}
/**
* Gets the transform of the frame.
*
* <p>This value is used in {@link GlRenderer#renderQueueTextureToSurface}.
*/
@NonNull
float[] getTransform() {
return mTransform;
}
/**
* Gets the output surface to render.
*
* <p>This value is used in {@link GlRenderer#renderQueueTextureToSurface}. A frame should
* always be rendered to the same surface than the one it was originally filled with. If the
* Surface is no longer valid, the frame should be dropped.
*/
@NonNull
Surface getSurface() {
return requireNonNull(mSurface);
}
}