From 09e0dd85055829d89c29d80ad5e4fc9a4934c0a5 Mon Sep 17 00:00:00 2001 From: leonwind Date: Fri, 23 Sep 2022 16:19:43 +0000 Subject: [PATCH] Store LUT bitmap as texture with processor creation. * Before this CL, the texture was stored during the construction of the LUT processor. This failed since if one creates a list of GlEffects on the application thread, the texture will get stored in the application thread during the effect creation and not on the GL thread, which executes the FrameProcessors. * This is an issue since the executing thread then can't index from the texture stored on a different thread. PiperOrigin-RevId: 476388021 (cherry picked from commit 44b9aec0b973b1cd5df31df32fff276f340e6ce4) --- .../androidx/media3/common/util/GlUtil.java | 5 +- .../java/androidx/media3/effect/ColorLut.java | 3 ++ .../media3/effect/SingleColorLut.java | 47 ++++++++++++------- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/util/GlUtil.java b/libraries/common/src/main/java/androidx/media3/common/util/GlUtil.java index c89dc8e94c..67c39c576a 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/GlUtil.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/GlUtil.java @@ -356,12 +356,15 @@ public final class GlUtil { // TODO(b/201293185): Consider handling adjustments for sizes > GL_MAX_TEXTURE_SIZE // (ex. downscaling appropriately) in a texture processor instead of asserting incorrect // values. - // For valid GL sizes, see: // https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glTexImage2D.xml int[] maxTextureSizeBuffer = new int[1]; GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxTextureSizeBuffer, 0); int maxTextureSize = maxTextureSizeBuffer[0]; + checkState( + maxTextureSize > 0, + "Create a OpenGL context first or run the GL methods on an OpenGL thread."); + if (width < 0 || height < 0) { throw new GlException("width or height is less than 0"); } diff --git a/libraries/effect/src/main/java/androidx/media3/effect/ColorLut.java b/libraries/effect/src/main/java/androidx/media3/effect/ColorLut.java index 311b6a3e87..ab9db1b9d0 100644 --- a/libraries/effect/src/main/java/androidx/media3/effect/ColorLut.java +++ b/libraries/effect/src/main/java/androidx/media3/effect/ColorLut.java @@ -17,6 +17,7 @@ package androidx.media3.effect; import android.content.Context; +import androidx.annotation.WorkerThread; import androidx.media3.common.FrameProcessingException; import androidx.media3.common.util.GlUtil; import androidx.media3.common.util.UnstableApi; @@ -40,7 +41,9 @@ public interface ColorLut extends GlEffect { /** Releases the OpenGL texture of the LUT. */ void release() throws GlUtil.GlException; + /** This method must be executed on the same thread as other GL commands. */ @Override + @WorkerThread default ColorLutProcessor toGlTextureProcessor(Context context, boolean useHdr) throws FrameProcessingException { return new ColorLutProcessor(context, /* colorLut= */ this, useHdr); diff --git a/libraries/effect/src/main/java/androidx/media3/effect/SingleColorLut.java b/libraries/effect/src/main/java/androidx/media3/effect/SingleColorLut.java index ece986bf48..72c2fec6da 100644 --- a/libraries/effect/src/main/java/androidx/media3/effect/SingleColorLut.java +++ b/libraries/effect/src/main/java/androidx/media3/effect/SingleColorLut.java @@ -23,6 +23,7 @@ import android.content.Context; import android.graphics.Bitmap; import android.opengl.GLES20; import android.opengl.GLUtils; +import androidx.media3.common.Format; import androidx.media3.common.FrameProcessingException; import androidx.media3.common.util.GlUtil; import androidx.media3.common.util.UnstableApi; @@ -31,8 +32,8 @@ import androidx.media3.common.util.Util; /** Transforms the colors of a frame by applying the same color lookup table to each frame. */ @UnstableApi public class SingleColorLut implements ColorLut { - private final int lutTextureId; - private final int length; + private final Bitmap lut; + private int lutTextureId; /** * Creates a new instance. @@ -40,7 +41,7 @@ public class SingleColorLut implements ColorLut { *

{@code lutCube} needs to be a {@code N x N x N} cube and each element is an integer * representing a color using the {@link Bitmap.Config#ARGB_8888} format. */ - public static SingleColorLut createFromCube(int[][][] lutCube) throws GlUtil.GlException { + public static SingleColorLut createFromCube(int[][][] lutCube) { checkArgument( lutCube.length > 0 && lutCube[0].length > 0 && lutCube[0][0].length > 0, "LUT must have three dimensions."); @@ -60,7 +61,7 @@ public class SingleColorLut implements ColorLut { * N^2}. Each element must be an integer representing a color using the {@link * Bitmap.Config#ARGB_8888} format. */ - public static SingleColorLut createFromBitmap(Bitmap lut) throws GlUtil.GlException { + public static SingleColorLut createFromBitmap(Bitmap lut) { checkArgument( lut.getWidth() * lut.getWidth() == lut.getHeight(), Util.formatInvariant( @@ -72,18 +73,9 @@ public class SingleColorLut implements ColorLut { return new SingleColorLut(lut); } - private SingleColorLut(Bitmap lut) throws GlUtil.GlException { - length = lut.getWidth(); - lutTextureId = storeLutAsTexture(lut); - } - - private static int storeLutAsTexture(Bitmap bitmap) throws GlUtil.GlException { - int lutTextureId = - GlUtil.createTexture( - bitmap.getWidth(), bitmap.getHeight(), /* useHighPrecisionColorComponents= */ false); - GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, /* level= */ 0, bitmap, /* border= */ 0); - GlUtil.checkGlError(); - return lutTextureId; + private SingleColorLut(Bitmap lut) { + this.lut = lut; + lutTextureId = Format.NO_VALUE; } /** @@ -136,14 +128,19 @@ public class SingleColorLut implements ColorLut { Bitmap.Config.ARGB_8888); } + /** Must be called after {@link #toGlTextureProcessor(Context, boolean)}. */ @Override public int getLutTextureId(long presentationTimeUs) { + checkState( + lutTextureId != Format.NO_VALUE, + "The LUT has not been stored as a texture in OpenGL yet. You must to call" + + " #toGlTextureProcessor() first."); return lutTextureId; } @Override public int getLength(long presentationTimeUs) { - return length; + return lut.getWidth(); } @Override @@ -155,6 +152,22 @@ public class SingleColorLut implements ColorLut { public ColorLutProcessor toGlTextureProcessor(Context context, boolean useHdr) throws FrameProcessingException { checkState(!useHdr, "HDR is currently not supported."); + + try { + lutTextureId = storeLutAsTexture(lut); + } catch (GlUtil.GlException e) { + throw new FrameProcessingException("Could not store the LUT as a texture.", e); + } + return new ColorLutProcessor(context, /* colorLut= */ this, useHdr); } + + private static int storeLutAsTexture(Bitmap bitmap) throws GlUtil.GlException { + int lutTextureId = + GlUtil.createTexture( + bitmap.getWidth(), bitmap.getHeight(), /* useHighPrecisionColorComponents= */ false); + GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, /* level= */ 0, bitmap, /* border= */ 0); + GlUtil.checkGlError(); + return lutTextureId; + } }