Effect: Add GlTextureInfo release() and accessor methods.
This allows us to disallow access after release. PiperOrigin-RevId: 534046475
This commit is contained in:
parent
438ae0ed6a
commit
a6897aedaa
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user