Effect: Add GlTextureInfo release() and accessor methods.

This allows us to disallow access after release.

PiperOrigin-RevId: 534046475
This commit is contained in:
huangdarwin 2023-05-22 14:32:43 +01:00 committed by tonihei
parent 438ae0ed6a
commit a6897aedaa
10 changed files with 120 additions and 73 deletions

View File

@ -166,7 +166,8 @@ import java.util.concurrent.Future;
@Override
public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) {
AppTextureFrame appTextureFrame =
new AppTextureFrame(inputTexture.texId, inputTexture.width, inputTexture.height);
new AppTextureFrame(
inputTexture.getTexId(), inputTexture.getWidth(), inputTexture.getHeight());
// TODO(b/238302213): Handle timestamps restarting from 0 when applying effects to a playlist.
// MediaPipe will fail if the timestamps are not monotonically increasing.
// Also make sure that a MediaPipe graph producing additional frames only starts producing

View File

@ -15,13 +15,14 @@
*/
package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkState;
import androidx.media3.common.util.GlUtil;
import androidx.media3.common.util.UnstableApi;
/** Contains information describing an OpenGL texture. */
@UnstableApi
public final class GlTextureInfo {
// TODO: b/262694346 - Add a release() method for GlTextureInfo.
/** A {@link GlTextureInfo} instance with all fields unset. */
public static final GlTextureInfo UNSET =
new GlTextureInfo(
@ -31,22 +32,13 @@ public final class GlTextureInfo {
/* width= */ C.LENGTH_UNSET,
/* height= */ C.LENGTH_UNSET);
/** The OpenGL texture identifier, or {@link C#INDEX_UNSET} if not specified. */
public final int texId;
/**
* Identifier of a framebuffer object associated with the texture, or {@link C#INDEX_UNSET} if not
* specified.
*/
public final int fboId;
/**
* Identifier of a renderbuffer object attached with the framebuffer, or {@link C#INDEX_UNSET} if
* not specified.
*/
public final int rboId;
/** The width of the texture, in pixels, or {@link C#LENGTH_UNSET} if not specified. */
public final int width;
/** The height of the texture, in pixels, or {@link C#LENGTH_UNSET} if not specified. */
public final int height;
private final int texId;
private final int fboId;
private final int rboId;
private final int width;
private final int height;
private boolean isReleased;
/**
* Creates a new instance.
@ -66,4 +58,53 @@ public final class GlTextureInfo {
this.width = width;
this.height = height;
}
/** The OpenGL texture identifier, or {@link C#INDEX_UNSET} if not specified. */
public int getTexId() {
checkState(!isReleased);
return texId;
}
/**
* Identifier of a framebuffer object associated with the texture, or {@link C#INDEX_UNSET} if not
* specified.
*/
public int getFboId() {
checkState(!isReleased);
return fboId;
}
/**
* Identifier of a renderbuffer object attached with the framebuffer, or {@link C#INDEX_UNSET} if
* not specified.
*/
public int getRboId() {
checkState(!isReleased);
return rboId;
}
/** The width of the texture, in pixels, or {@link C#LENGTH_UNSET} if not specified. */
public int getWidth() {
checkState(!isReleased);
return width;
}
/** The height of the texture, in pixels, or {@link C#LENGTH_UNSET} if not specified. */
public int getHeight() {
checkState(!isReleased);
return height;
}
public void release() throws GlUtil.GlException {
isReleased = true;
if (texId != C.INDEX_UNSET) {
GlUtil.deleteTexture(texId);
}
if (fboId != C.INDEX_UNSET) {
GlUtil.deleteFbo(fboId);
}
if (rboId != C.INDEX_UNSET) {
GlUtil.deleteRbo(rboId);
}
}
}

View File

@ -494,36 +494,6 @@ public final class GlUtil {
Api17.focusFramebufferUsingCurrentContext(framebuffer, width, height);
}
/**
* Deletes a GL texture.
*
* @param textureId The ID of the texture to delete.
*/
public static void deleteTexture(int textureId) throws GlException {
GLES20.glDeleteTextures(/* n= */ 1, new int[] {textureId}, /* offset= */ 0);
checkGlError();
}
/**
* Destroys the {@link EGLContext} identified by the provided {@link EGLDisplay} and {@link
* EGLContext}.
*/
@RequiresApi(17)
public static void destroyEglContext(
@Nullable EGLDisplay eglDisplay, @Nullable EGLContext eglContext) throws GlException {
Api17.destroyEglContext(eglDisplay, eglContext);
}
/**
* Destroys the {@link EGLSurface} identified by the provided {@link EGLDisplay} and {@link
* EGLSurface}.
*/
@RequiresApi(17)
public static void destroyEglSurface(
@Nullable EGLDisplay eglDisplay, @Nullable EGLSurface eglSurface) throws GlException {
Api17.destroyEglSurface(eglDisplay, eglSurface);
}
/**
* Allocates a FloatBuffer with the given data.
*
@ -656,11 +626,46 @@ public final class GlUtil {
return fboId[0];
}
/** Deletes a framebuffer. */
/**
* Deletes a GL texture.
*
* @param textureId The ID of the texture to delete.
*/
public static void deleteTexture(int textureId) throws GlException {
GLES20.glDeleteTextures(/* n= */ 1, new int[] {textureId}, /* offset= */ 0);
checkGlError();
}
/**
* Destroys the {@link EGLContext} identified by the provided {@link EGLDisplay} and {@link
* EGLContext}.
*/
@RequiresApi(17)
public static void destroyEglContext(
@Nullable EGLDisplay eglDisplay, @Nullable EGLContext eglContext) throws GlException {
Api17.destroyEglContext(eglDisplay, eglContext);
}
/**
* Destroys the {@link EGLSurface} identified by the provided {@link EGLDisplay} and {@link
* EGLSurface}.
*/
@RequiresApi(17)
public static void destroyEglSurface(
@Nullable EGLDisplay eglDisplay, @Nullable EGLSurface eglSurface) throws GlException {
Api17.destroyEglSurface(eglDisplay, eglSurface);
}
/** Deletes a framebuffer, or silently ignores the method call if {@code fboId} is unused. */
public static void deleteFbo(int fboId) throws GlException {
int[] fboIdArray = new int[1];
fboIdArray[0] = fboId;
GLES20.glDeleteFramebuffers(/* n= */ 1, fboIdArray, /* offset= */ 0);
GLES20.glDeleteFramebuffers(/* n= */ 1, new int[] {fboId}, /* offset= */ 0);
checkGlError();
}
/** Deletes a renderbuffer, or silently ignores the method call if {@code rboId} is unused. */
public static void deleteRbo(int rboId) throws GlException {
GLES20.glDeleteRenderbuffers(
/* n= */ 1, /* renderbuffers= */ new int[] {rboId}, /* offset= */ 0);
checkGlError();
}

View File

@ -129,7 +129,7 @@ public abstract class BaseGlShaderProgram implements GlShaderProgram {
@Override
public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) {
try {
Size outputTextureSize = configure(inputTexture.width, inputTexture.height);
Size outputTextureSize = configure(inputTexture.getWidth(), inputTexture.getHeight());
outputTexturePool.ensureConfigured(
outputTextureSize.getWidth(), outputTextureSize.getHeight());
frameProcessingStarted = true;
@ -139,9 +139,9 @@ public abstract class BaseGlShaderProgram implements GlShaderProgram {
// Copy frame to fbo.
GlUtil.focusFramebufferUsingCurrentContext(
outputTexture.fboId, outputTexture.width, outputTexture.height);
outputTexture.getFboId(), outputTexture.getWidth(), outputTexture.getHeight());
GlUtil.clearOutputFrame();
drawFrame(inputTexture.texId, presentationTimeUs);
drawFrame(inputTexture.getTexId(), presentationTimeUs);
inputListener.onInputFrameProcessed(inputTexture);
outputListener.onOutputFrameAvailable(outputTexture, presentationTimeUs);
} catch (VideoFrameProcessingException | GlUtil.GlException | NoSuchElementException e) {

View File

@ -123,7 +123,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
videoFrameProcessingTaskExecutor.submit(
() -> {
if (currentGlTextureInfo != null) {
GlUtil.deleteTexture(currentGlTextureInfo.texId);
currentGlTextureInfo.release();
}
});
}
@ -160,7 +160,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
int currentTexId;
try {
if (currentGlTextureInfo != null) {
GlUtil.deleteTexture(currentGlTextureInfo.texId);
currentGlTextureInfo.release();
}
currentTexId =
GlUtil.createTexture(

View File

@ -316,7 +316,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
GlTextureInfo inputTexture, long presentationTimeUs, long renderTimeNs) {
try {
if (renderTimeNs == VideoFrameProcessor.DROP_OUTPUT_FRAME
|| !ensureConfigured(inputTexture.width, inputTexture.height)) {
|| !ensureConfigured(inputTexture.getWidth(), inputTexture.getHeight())) {
inputListener.onInputFrameProcessed(inputTexture);
return; // Drop frames when requested, or there is no output surface and output texture.
}
@ -352,7 +352,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
outputSurfaceInfo.width,
outputSurfaceInfo.height);
GlUtil.clearOutputFrame();
defaultShaderProgram.drawFrame(inputTexture.texId, presentationTimeUs);
defaultShaderProgram.drawFrame(inputTexture.getTexId(), presentationTimeUs);
EGLExt.eglPresentationTimeANDROID(
eglDisplay,
@ -369,9 +369,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
GlTextureInfo outputTexture = outputTexturePool.useTexture();
outputTextureTimestamps.add(presentationTimeUs);
GlUtil.focusFramebufferUsingCurrentContext(
outputTexture.fboId, outputTexture.width, outputTexture.height);
outputTexture.getFboId(), outputTexture.getWidth(), outputTexture.getHeight());
GlUtil.clearOutputFrame();
checkNotNull(defaultShaderProgram).drawFrame(inputTexture.texId, presentationTimeUs);
checkNotNull(defaultShaderProgram).drawFrame(inputTexture.getTexId(), presentationTimeUs);
// TODO(b/262694346): If Compositor's VFPs all use the same context, media3 should be able to
// avoid calling glFinish, and require the onTextureRendered listener to decide whether to
// glFinish. Consider removing glFinish and requiring onTextureRendered to handle
@ -519,10 +519,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
int configuredColorTransfer = defaultShaderProgram.getOutputColorTransfer();
defaultShaderProgram.setOutputColorTransfer(
debugSurfaceViewWrapper.outputColorTransfer);
defaultShaderProgram.drawFrame(inputTexture.texId, presentationTimeUs);
defaultShaderProgram.drawFrame(inputTexture.getTexId(), presentationTimeUs);
defaultShaderProgram.setOutputColorTransfer(configuredColorTransfer);
} else {
defaultShaderProgram.drawFrame(inputTexture.texId, presentationTimeUs);
defaultShaderProgram.drawFrame(inputTexture.getTexId(), presentationTimeUs);
}
},
glObjectsProvider);

View File

@ -61,7 +61,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override
public void onInputFrameProcessed(GlTextureInfo inputTexture) {
videoFrameProcessingTaskExecutor.submit(
() -> checkNotNull(frameProcessedListener).onInputFrameProcessed(inputTexture.texId));
() -> checkNotNull(frameProcessedListener).onInputFrameProcessed(inputTexture.getTexId()));
}
@Override

View File

@ -86,7 +86,7 @@ import java.util.Queue;
return;
}
GlTextureInfo texture = getIteratorToAllTextures().next();
if (texture.width != width || texture.height != height) {
if (texture.getWidth() != width || texture.getHeight() != height) {
deleteAllTextures();
createTextures(width, height);
}
@ -141,9 +141,7 @@ import java.util.Queue;
public void deleteAllTextures() throws GlUtil.GlException {
Iterator<GlTextureInfo> allTextures = getIteratorToAllTextures();
while (allTextures.hasNext()) {
GlTextureInfo textureInfo = allTextures.next();
GlUtil.deleteTexture(textureInfo.texId);
GlUtil.deleteFbo(textureInfo.fboId);
allTextures.next().release();
}
freeTextures.clear();
inUseTextures.clear();

View File

@ -353,7 +353,7 @@ public final class VideoFrameProcessorTestRunner {
public void queueInputTexture(GlTextureInfo inputTexture, long pts) {
videoFrameProcessor.setInputFrameInfo(
new FrameInfo.Builder(inputTexture.width, inputTexture.height)
new FrameInfo.Builder(inputTexture.getWidth(), inputTexture.getHeight())
.setPixelWidthHeightRatio(pixelWidthHeightRatio)
.build());
videoFrameProcessor.registerInputStream(INPUT_TYPE_TEXTURE_ID);
@ -365,7 +365,7 @@ public final class VideoFrameProcessorTestRunner {
throw new VideoFrameProcessingException(e);
}
});
videoFrameProcessor.queueInputTexture(inputTexture.texId, pts);
videoFrameProcessor.queueInputTexture(inputTexture.getTexId(), pts);
}
public void endFrameProcessing() throws InterruptedException {

View File

@ -608,10 +608,12 @@ public final class DefaultVideoFrameProcessorTextureOutputPixelTest {
throws VideoFrameProcessingException {
try {
GlUtil.focusFramebufferUsingCurrentContext(
outputTexture.fboId, outputTexture.width, outputTexture.height);
outputTexture.getFboId(), outputTexture.getWidth(), outputTexture.getHeight());
outputBitmap =
createBitmapFromCurrentGlFrameBuffer(
outputTexture.width, outputTexture.height, useHighPrecisionColorComponents);
outputTexture.getWidth(),
outputTexture.getHeight(),
useHighPrecisionColorComponents);
} catch (GlUtil.GlException e) {
throw new VideoFrameProcessingException(e);
}