mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
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)
This commit is contained in:
parent
a7102992ba
commit
09e0dd8505
@ -356,12 +356,15 @@ public final class GlUtil {
|
|||||||
// TODO(b/201293185): Consider handling adjustments for sizes > GL_MAX_TEXTURE_SIZE
|
// TODO(b/201293185): Consider handling adjustments for sizes > GL_MAX_TEXTURE_SIZE
|
||||||
// (ex. downscaling appropriately) in a texture processor instead of asserting incorrect
|
// (ex. downscaling appropriately) in a texture processor instead of asserting incorrect
|
||||||
// values.
|
// values.
|
||||||
|
|
||||||
// For valid GL sizes, see:
|
// For valid GL sizes, see:
|
||||||
// https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glTexImage2D.xml
|
// https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glTexImage2D.xml
|
||||||
int[] maxTextureSizeBuffer = new int[1];
|
int[] maxTextureSizeBuffer = new int[1];
|
||||||
GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxTextureSizeBuffer, 0);
|
GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxTextureSizeBuffer, 0);
|
||||||
int maxTextureSize = 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) {
|
if (width < 0 || height < 0) {
|
||||||
throw new GlException("width or height is less than 0");
|
throw new GlException("width or height is less than 0");
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package androidx.media3.effect;
|
package androidx.media3.effect;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import androidx.annotation.WorkerThread;
|
||||||
import androidx.media3.common.FrameProcessingException;
|
import androidx.media3.common.FrameProcessingException;
|
||||||
import androidx.media3.common.util.GlUtil;
|
import androidx.media3.common.util.GlUtil;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
@ -40,7 +41,9 @@ public interface ColorLut extends GlEffect {
|
|||||||
/** Releases the OpenGL texture of the LUT. */
|
/** Releases the OpenGL texture of the LUT. */
|
||||||
void release() throws GlUtil.GlException;
|
void release() throws GlUtil.GlException;
|
||||||
|
|
||||||
|
/** This method must be executed on the same thread as other GL commands. */
|
||||||
@Override
|
@Override
|
||||||
|
@WorkerThread
|
||||||
default ColorLutProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
default ColorLutProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
||||||
throws FrameProcessingException {
|
throws FrameProcessingException {
|
||||||
return new ColorLutProcessor(context, /* colorLut= */ this, useHdr);
|
return new ColorLutProcessor(context, /* colorLut= */ this, useHdr);
|
||||||
|
@ -23,6 +23,7 @@ import android.content.Context;
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.opengl.GLES20;
|
import android.opengl.GLES20;
|
||||||
import android.opengl.GLUtils;
|
import android.opengl.GLUtils;
|
||||||
|
import androidx.media3.common.Format;
|
||||||
import androidx.media3.common.FrameProcessingException;
|
import androidx.media3.common.FrameProcessingException;
|
||||||
import androidx.media3.common.util.GlUtil;
|
import androidx.media3.common.util.GlUtil;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
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. */
|
/** Transforms the colors of a frame by applying the same color lookup table to each frame. */
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
public class SingleColorLut implements ColorLut {
|
public class SingleColorLut implements ColorLut {
|
||||||
private final int lutTextureId;
|
private final Bitmap lut;
|
||||||
private final int length;
|
private int lutTextureId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
@ -40,7 +41,7 @@ public class SingleColorLut implements ColorLut {
|
|||||||
* <p>{@code lutCube} needs to be a {@code N x N x N} cube and each element is an integer
|
* <p>{@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.
|
* 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(
|
checkArgument(
|
||||||
lutCube.length > 0 && lutCube[0].length > 0 && lutCube[0][0].length > 0,
|
lutCube.length > 0 && lutCube[0].length > 0 && lutCube[0][0].length > 0,
|
||||||
"LUT must have three dimensions.");
|
"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
|
* N^2}. Each element must be an integer representing a color using the {@link
|
||||||
* Bitmap.Config#ARGB_8888} format.
|
* Bitmap.Config#ARGB_8888} format.
|
||||||
*/
|
*/
|
||||||
public static SingleColorLut createFromBitmap(Bitmap lut) throws GlUtil.GlException {
|
public static SingleColorLut createFromBitmap(Bitmap lut) {
|
||||||
checkArgument(
|
checkArgument(
|
||||||
lut.getWidth() * lut.getWidth() == lut.getHeight(),
|
lut.getWidth() * lut.getWidth() == lut.getHeight(),
|
||||||
Util.formatInvariant(
|
Util.formatInvariant(
|
||||||
@ -72,18 +73,9 @@ public class SingleColorLut implements ColorLut {
|
|||||||
return new SingleColorLut(lut);
|
return new SingleColorLut(lut);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SingleColorLut(Bitmap lut) throws GlUtil.GlException {
|
private SingleColorLut(Bitmap lut) {
|
||||||
length = lut.getWidth();
|
this.lut = lut;
|
||||||
lutTextureId = storeLutAsTexture(lut);
|
lutTextureId = Format.NO_VALUE;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -136,14 +128,19 @@ public class SingleColorLut implements ColorLut {
|
|||||||
Bitmap.Config.ARGB_8888);
|
Bitmap.Config.ARGB_8888);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Must be called after {@link #toGlTextureProcessor(Context, boolean)}. */
|
||||||
@Override
|
@Override
|
||||||
public int getLutTextureId(long presentationTimeUs) {
|
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;
|
return lutTextureId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getLength(long presentationTimeUs) {
|
public int getLength(long presentationTimeUs) {
|
||||||
return length;
|
return lut.getWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -155,6 +152,22 @@ public class SingleColorLut implements ColorLut {
|
|||||||
public ColorLutProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
public ColorLutProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
||||||
throws FrameProcessingException {
|
throws FrameProcessingException {
|
||||||
checkState(!useHdr, "HDR is currently not supported.");
|
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);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user