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 @Override
public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) { public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) {
AppTextureFrame appTextureFrame = 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. // TODO(b/238302213): Handle timestamps restarting from 0 when applying effects to a playlist.
// MediaPipe will fail if the timestamps are not monotonically increasing. // MediaPipe will fail if the timestamps are not monotonically increasing.
// Also make sure that a MediaPipe graph producing additional frames only starts producing // Also make sure that a MediaPipe graph producing additional frames only starts producing

View File

@ -15,13 +15,14 @@
*/ */
package androidx.media3.common; package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkState;
import androidx.media3.common.util.GlUtil;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
/** Contains information describing an OpenGL texture. */ /** Contains information describing an OpenGL texture. */
@UnstableApi @UnstableApi
public final class GlTextureInfo { public final class GlTextureInfo {
// TODO: b/262694346 - Add a release() method for GlTextureInfo.
/** A {@link GlTextureInfo} instance with all fields unset. */ /** A {@link GlTextureInfo} instance with all fields unset. */
public static final GlTextureInfo UNSET = public static final GlTextureInfo UNSET =
new GlTextureInfo( new GlTextureInfo(
@ -31,22 +32,13 @@ public final class GlTextureInfo {
/* width= */ C.LENGTH_UNSET, /* width= */ C.LENGTH_UNSET,
/* height= */ C.LENGTH_UNSET); /* height= */ C.LENGTH_UNSET);
/** The OpenGL texture identifier, or {@link C#INDEX_UNSET} if not specified. */ private final int texId;
public final int texId; private final int fboId;
/** private final int rboId;
* Identifier of a framebuffer object associated with the texture, or {@link C#INDEX_UNSET} if not private final int width;
* specified. private final int height;
*/
public final int fboId; private boolean isReleased;
/**
* 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;
/** /**
* Creates a new instance. * Creates a new instance.
@ -66,4 +58,53 @@ public final class GlTextureInfo {
this.width = width; this.width = width;
this.height = height; 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); 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. * Allocates a FloatBuffer with the given data.
* *
@ -656,11 +626,46 @@ public final class GlUtil {
return fboId[0]; 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 { public static void deleteFbo(int fboId) throws GlException {
int[] fboIdArray = new int[1]; GLES20.glDeleteFramebuffers(/* n= */ 1, new int[] {fboId}, /* offset= */ 0);
fboIdArray[0] = fboId; checkGlError();
GLES20.glDeleteFramebuffers(/* n= */ 1, fboIdArray, /* offset= */ 0); }
/** 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(); checkGlError();
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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