Effect: Rename TextureProcessor to ShaderProgram.

Also, replace instances of "texture processor" to "shader program", with capitalization retained.

PiperOrigin-RevId: 507515655
This commit is contained in:
huangdarwin 2023-02-06 18:19:27 +00:00 committed by microkatz
parent 9224a36add
commit ca4d2be1fa
41 changed files with 531 additions and 550 deletions

View File

@ -23,14 +23,14 @@ import androidx.media3.common.FrameProcessingException;
import androidx.media3.common.util.GlProgram; import androidx.media3.common.util.GlProgram;
import androidx.media3.common.util.GlUtil; import androidx.media3.common.util.GlUtil;
import androidx.media3.common.util.Size; import androidx.media3.common.util.Size;
import androidx.media3.effect.SingleFrameGlTextureProcessor; import androidx.media3.effect.SingleFrameGlShaderProgram;
import java.io.IOException; import java.io.IOException;
/** /**
* A {@link SingleFrameGlTextureProcessor} that periodically dims the frames such that pixels are * A {@link SingleFrameGlShaderProgram} that periodically dims the frames such that pixels are
* darker the further they are away from the frame center. * darker the further they are away from the frame center.
*/ */
/* package */ final class PeriodicVignetteProcessor extends SingleFrameGlTextureProcessor { /* package */ final class PeriodicVignetteShaderProgram extends SingleFrameGlShaderProgram {
private static final String VERTEX_SHADER_PATH = "vertex_shader_copy_es2.glsl"; private static final String VERTEX_SHADER_PATH = "vertex_shader_copy_es2.glsl";
private static final String FRAGMENT_SHADER_PATH = "fragment_shader_vignette_es2.glsl"; private static final String FRAGMENT_SHADER_PATH = "fragment_shader_vignette_es2.glsl";
@ -61,7 +61,7 @@ import java.io.IOException;
* @param outerRadius The radius after which all pixels are black. * @param outerRadius The radius after which all pixels are black.
* @throws FrameProcessingException If a problem occurs while reading shader files. * @throws FrameProcessingException If a problem occurs while reading shader files.
*/ */
public PeriodicVignetteProcessor( public PeriodicVignetteShaderProgram(
Context context, Context context,
boolean useHdr, boolean useHdr,
float centerX, float centerX,

View File

@ -59,7 +59,7 @@ import androidx.media3.effect.BitmapOverlay;
import androidx.media3.effect.Contrast; import androidx.media3.effect.Contrast;
import androidx.media3.effect.DrawableOverlay; import androidx.media3.effect.DrawableOverlay;
import androidx.media3.effect.GlEffect; import androidx.media3.effect.GlEffect;
import androidx.media3.effect.GlTextureProcessor; import androidx.media3.effect.GlShaderProgram;
import androidx.media3.effect.HslAdjustment; import androidx.media3.effect.HslAdjustment;
import androidx.media3.effect.OverlayEffect; import androidx.media3.effect.OverlayEffect;
import androidx.media3.effect.OverlaySettings; import androidx.media3.effect.OverlaySettings;
@ -414,7 +414,7 @@ public final class TransformerActivity extends AppCompatActivity {
(GlEffect) (GlEffect)
(Context context, boolean useHdr) -> { (Context context, boolean useHdr) -> {
try { try {
return (GlTextureProcessor) return (GlShaderProgram)
constructor.newInstance( constructor.newInstance(
context, context,
useHdr, useHdr,
@ -424,7 +424,7 @@ public final class TransformerActivity extends AppCompatActivity {
/* outputStreamName= */ "output_video"); /* outputStreamName= */ "output_video");
} catch (Exception e) { } catch (Exception e) {
runOnUiThread(() -> showToast(R.string.no_media_pipe_error)); runOnUiThread(() -> showToast(R.string.no_media_pipe_error));
throw new RuntimeException("Failed to load MediaPipe processor", e); throw new RuntimeException("Failed to load MediaPipeShaderProgram", e);
} }
}); });
} catch (Exception e) { } catch (Exception e) {
@ -495,7 +495,7 @@ public final class TransformerActivity extends AppCompatActivity {
effects.add( effects.add(
(GlEffect) (GlEffect)
(Context context, boolean useHdr) -> (Context context, boolean useHdr) ->
new PeriodicVignetteProcessor( new PeriodicVignetteShaderProgram(
context, context,
useHdr, useHdr,
bundle.getFloat(ConfigurationActivity.PERIODIC_VIGNETTE_CENTER_X), bundle.getFloat(ConfigurationActivity.PERIODIC_VIGNETTE_CENTER_X),

View File

@ -35,7 +35,7 @@
<string name="select_audio_effects" translatable="false">Add audio effects</string> <string name="select_audio_effects" translatable="false">Add audio effects</string>
<string name="select_video_effects" translatable="false">Add video effects</string> <string name="select_video_effects" translatable="false">Add video effects</string>
<string name="periodic_vignette_options" translatable="false">Periodic vignette options</string> <string name="periodic_vignette_options" translatable="false">Periodic vignette options</string>
<string name="no_media_pipe_error" translatable="false">Failed to load MediaPipe processor. Check the README for instructions.</string> <string name="no_media_pipe_error" translatable="false">Failed to load MediaPipeShaderProgram. Check the README for instructions.</string>
<string name="transform" translatable="false">Transform</string> <string name="transform" translatable="false">Transform</string>
<string name="debug_preview" translatable="false">Debug preview:</string> <string name="debug_preview" translatable="false">Debug preview:</string>
<string name="debug_preview_not_available" translatable="false">No debug preview available.</string> <string name="debug_preview_not_available" translatable="false">No debug preview available.</string>

View File

@ -27,7 +27,7 @@ import androidx.media3.common.C;
import androidx.media3.common.FrameProcessingException; import androidx.media3.common.FrameProcessingException;
import androidx.media3.common.util.LibraryLoader; import androidx.media3.common.util.LibraryLoader;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.effect.GlTextureProcessor; import androidx.media3.effect.GlShaderProgram;
import androidx.media3.effect.TextureInfo; import androidx.media3.effect.TextureInfo;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import com.google.mediapipe.components.FrameProcessor; import com.google.mediapipe.components.FrameProcessor;
@ -43,9 +43,9 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
/** Runs a MediaPipe graph on input frames. */ /** Runs a MediaPipe graph on input frames. */
/* package */ final class MediaPipeProcessor implements GlTextureProcessor { /* package */ final class MediaPipeShaderProgram implements GlShaderProgram {
private static final String THREAD_NAME = "Demo:MediaPipeProcessor"; private static final String THREAD_NAME = "Demo:MediaPipeShaderProgram";
private static final long RELEASE_WAIT_TIME_MS = 100; private static final long RELEASE_WAIT_TIME_MS = 100;
private static final long RETRY_WAIT_TIME_MS = 1; private static final long RETRY_WAIT_TIME_MS = 1;
@ -80,11 +80,11 @@ import java.util.concurrent.Future;
private boolean acceptedFrame; private boolean acceptedFrame;
/** /**
* Creates a new texture processor that wraps a MediaPipe graph. * Creates a new shader program that wraps a MediaPipe graph.
* *
* <p>If {@code isSingleFrameGraph} is {@code false}, the {@code MediaPipeProcessor} may waste CPU * <p>If {@code isSingleFrameGraph} is {@code false}, the {@code MediaPipeShaderProgram} may waste
* time by continuously attempting to queue input frames to MediaPipe until they are accepted or * CPU time by continuously attempting to queue input frames to MediaPipe until they are accepted
* waste memory if MediaPipe accepts and stores many frames internally. * or waste memory if MediaPipe accepts and stores many frames internally.
* *
* @param context The {@link Context}. * @param context The {@link Context}.
* @param useHdr Whether input textures come from an HDR source. If {@code true}, colors will be * @param useHdr Whether input textures come from an HDR source. If {@code true}, colors will be
@ -95,7 +95,7 @@ import java.util.concurrent.Future;
* @param inputStreamName Name of the input video stream in the graph. * @param inputStreamName Name of the input video stream in the graph.
* @param outputStreamName Name of the input video stream in the graph. * @param outputStreamName Name of the input video stream in the graph.
*/ */
public MediaPipeProcessor( public MediaPipeShaderProgram(
Context context, Context context,
boolean useHdr, boolean useHdr,
String graphName, String graphName,
@ -103,8 +103,8 @@ import java.util.concurrent.Future;
String inputStreamName, String inputStreamName,
String outputStreamName) { String outputStreamName) {
checkState(LOADER.isAvailable()); checkState(LOADER.isAvailable());
// TODO(b/227624622): Confirm whether MediaPipeProcessor could support HDR colors. // TODO(b/227624622): Confirm whether MediaPipeShaderProgram could support HDR colors.
checkArgument(!useHdr, "MediaPipeProcessor does not support HDR colors."); checkArgument(!useHdr, "MediaPipeShaderProgram does not support HDR colors.");
this.isSingleFrameGraph = isSingleFrameGraph; this.isSingleFrameGraph = isSingleFrameGraph;
singleThreadExecutorService = singleThreadExecutorService =
@ -233,7 +233,7 @@ import java.util.concurrent.Future;
@Override @Override
public void flush() { public void flush() {
// TODO(b/238302341) Support seeking in MediaPipeProcessor. // TODO(b/238302341) Support seeking in MediaPipeShaderProgram.
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@ -411,7 +411,7 @@ public final class GlUtil {
*/ */
private static void assertValidTextureSize(int width, int height) throws GlException { private static void assertValidTextureSize(int width, int height) throws GlException {
// 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 shader program 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

View File

@ -45,7 +45,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
/** /**
* Pixel test for contrast adjustment via {@link ContrastProcessor}. * Pixel test for contrast adjustment via {@link ContrastShaderProgram}.
* *
* <p>Expected images are taken from an emulator, so tests on different emulators or physical * <p>Expected images are taken from an emulator, so tests on different emulators or physical
* devices may fail. To test on other devices, please increase the {@link * devices may fail. To test on other devices, please increase the {@link
@ -71,7 +71,7 @@ public class ContrastPixelTest {
private @MonotonicNonNull EGLDisplay eglDisplay; private @MonotonicNonNull EGLDisplay eglDisplay;
private @MonotonicNonNull EGLContext eglContext; private @MonotonicNonNull EGLContext eglContext;
private @MonotonicNonNull EGLSurface placeholderEglSurface; private @MonotonicNonNull EGLSurface placeholderEglSurface;
private @MonotonicNonNull SingleFrameGlTextureProcessor contrastProcessor; private @MonotonicNonNull SingleFrameGlShaderProgram contrastShaderProgram;
private int inputTexId; private int inputTexId;
private int inputWidth; private int inputWidth;
private int inputHeight; private int inputHeight;
@ -90,8 +90,8 @@ public class ContrastPixelTest {
@After @After
public void release() throws GlUtil.GlException, FrameProcessingException { public void release() throws GlUtil.GlException, FrameProcessingException {
if (contrastProcessor != null) { if (contrastShaderProgram != null) {
contrastProcessor.release(); contrastShaderProgram.release();
} }
GlUtil.destroyEglContext(eglDisplay, eglContext); GlUtil.destroyEglContext(eglDisplay, eglContext);
} }
@ -99,13 +99,13 @@ public class ContrastPixelTest {
@Test @Test
public void drawFrame_noContrastChange_leavesFrameUnchanged() throws Exception { public void drawFrame_noContrastChange_leavesFrameUnchanged() throws Exception {
String testId = "drawFrame_noContrastChange"; String testId = "drawFrame_noContrastChange";
contrastProcessor = contrastShaderProgram =
new Contrast(/* contrast= */ 0.0f).toGlTextureProcessor(context, /* useHdr= */ false); new Contrast(/* contrast= */ 0.0f).toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = contrastProcessor.configure(inputWidth, inputHeight); Size outputSize = contrastShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
contrastProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); contrastShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -118,9 +118,9 @@ public class ContrastPixelTest {
@Test @Test
public void drawFrame_minimumContrast_producesAllGrayFrame() throws Exception { public void drawFrame_minimumContrast_producesAllGrayFrame() throws Exception {
String testId = "drawFrame_minimumContrast"; String testId = "drawFrame_minimumContrast";
contrastProcessor = contrastShaderProgram =
new Contrast(/* contrast= */ -1.0f).toGlTextureProcessor(context, /* useHdr= */ false); new Contrast(/* contrast= */ -1.0f).toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = contrastProcessor.configure(inputWidth, inputHeight); Size outputSize = contrastShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = Bitmap expectedBitmap =
createArgb8888BitmapWithSolidColor( createArgb8888BitmapWithSolidColor(
@ -129,7 +129,7 @@ public class ContrastPixelTest {
Color.rgb( Color.rgb(
OPENGL_NEUTRAL_RGB_VALUE, OPENGL_NEUTRAL_RGB_VALUE, OPENGL_NEUTRAL_RGB_VALUE)); OPENGL_NEUTRAL_RGB_VALUE, OPENGL_NEUTRAL_RGB_VALUE, OPENGL_NEUTRAL_RGB_VALUE));
contrastProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); contrastShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -143,13 +143,13 @@ public class ContrastPixelTest {
public void drawFrame_decreaseContrast_decreasesPixelsGreaterEqual128IncreasesBelow() public void drawFrame_decreaseContrast_decreasesPixelsGreaterEqual128IncreasesBelow()
throws Exception { throws Exception {
String testId = "drawFrame_decreaseContrast"; String testId = "drawFrame_decreaseContrast";
contrastProcessor = contrastShaderProgram =
new Contrast(/* contrast= */ -0.75f).toGlTextureProcessor(context, /* useHdr= */ false); new Contrast(/* contrast= */ -0.75f).toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = contrastProcessor.configure(inputWidth, inputHeight); Size outputSize = contrastShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(DECREASE_CONTRAST_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(DECREASE_CONTRAST_PNG_ASSET_PATH);
contrastProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); contrastShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -163,13 +163,13 @@ public class ContrastPixelTest {
public void drawFrame_increaseContrast_increasesPixelsGreaterEqual128DecreasesBelow() public void drawFrame_increaseContrast_increasesPixelsGreaterEqual128DecreasesBelow()
throws Exception { throws Exception {
String testId = "drawFrame_increaseContrast"; String testId = "drawFrame_increaseContrast";
contrastProcessor = contrastShaderProgram =
new Contrast(/* contrast= */ 0.75f).toGlTextureProcessor(context, /* useHdr= */ false); new Contrast(/* contrast= */ 0.75f).toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = contrastProcessor.configure(inputWidth, inputHeight); Size outputSize = contrastShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(INCREASE_CONTRAST_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(INCREASE_CONTRAST_PNG_ASSET_PATH);
contrastProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); contrastShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -182,13 +182,13 @@ public class ContrastPixelTest {
@Test @Test
public void drawFrame_maximumContrast_pixelEither0or255() throws Exception { public void drawFrame_maximumContrast_pixelEither0or255() throws Exception {
String testId = "drawFrame_maximumContrast"; String testId = "drawFrame_maximumContrast";
contrastProcessor = contrastShaderProgram =
new Contrast(/* contrast= */ 1.0f).toGlTextureProcessor(context, /* useHdr= */ false); new Contrast(/* contrast= */ 1.0f).toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = contrastProcessor.configure(inputWidth, inputHeight); Size outputSize = contrastShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(MAXIMUM_CONTRAST_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(MAXIMUM_CONTRAST_PNG_ASSET_PATH);
contrastProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); contrastShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());

View File

@ -63,7 +63,7 @@ public final class CropPixelTest {
private @MonotonicNonNull EGLDisplay eglDisplay; private @MonotonicNonNull EGLDisplay eglDisplay;
private @MonotonicNonNull EGLContext eglContext; private @MonotonicNonNull EGLContext eglContext;
private @MonotonicNonNull SingleFrameGlTextureProcessor cropTextureProcessor; private @MonotonicNonNull SingleFrameGlShaderProgram cropShaderProgram;
private @MonotonicNonNull EGLSurface placeholderEglSurface; private @MonotonicNonNull EGLSurface placeholderEglSurface;
private int inputTexId; private int inputTexId;
private int inputWidth; private int inputWidth;
@ -83,8 +83,8 @@ public final class CropPixelTest {
@After @After
public void release() throws GlUtil.GlException, FrameProcessingException { public void release() throws GlUtil.GlException, FrameProcessingException {
if (cropTextureProcessor != null) { if (cropShaderProgram != null) {
cropTextureProcessor.release(); cropShaderProgram.release();
} }
if (eglContext != null && eglDisplay != null) { if (eglContext != null && eglDisplay != null) {
GlUtil.destroyEglContext(eglDisplay, eglContext); GlUtil.destroyEglContext(eglDisplay, eglContext);
@ -94,14 +94,14 @@ public final class CropPixelTest {
@Test @Test
public void drawFrame_noEdits_matchesGoldenFile() throws Exception { public void drawFrame_noEdits_matchesGoldenFile() throws Exception {
String testId = "drawFrame_noEdits"; String testId = "drawFrame_noEdits";
cropTextureProcessor = cropShaderProgram =
new Crop(/* left= */ -1, /* right= */ 1, /* bottom= */ -1, /* top= */ 1) new Crop(/* left= */ -1, /* right= */ 1, /* bottom= */ -1, /* top= */ 1)
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = cropTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = cropShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
cropTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); cropShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -115,14 +115,14 @@ public final class CropPixelTest {
@Test @Test
public void drawFrame_cropSmaller_matchesGoldenFile() throws Exception { public void drawFrame_cropSmaller_matchesGoldenFile() throws Exception {
String testId = "drawFrame_cropSmaller"; String testId = "drawFrame_cropSmaller";
cropTextureProcessor = cropShaderProgram =
new Crop(/* left= */ -.9f, /* right= */ .1f, /* bottom= */ -1f, /* top= */ .5f) new Crop(/* left= */ -.9f, /* right= */ .1f, /* bottom= */ -1f, /* top= */ .5f)
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = cropTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = cropShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(CROP_SMALLER_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(CROP_SMALLER_PNG_ASSET_PATH);
cropTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); cropShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -136,14 +136,14 @@ public final class CropPixelTest {
@Test @Test
public void drawFrame_cropLarger_matchesGoldenFile() throws Exception { public void drawFrame_cropLarger_matchesGoldenFile() throws Exception {
String testId = "drawFrame_cropLarger"; String testId = "drawFrame_cropLarger";
cropTextureProcessor = cropShaderProgram =
new Crop(/* left= */ -2f, /* right= */ 2f, /* bottom= */ -1f, /* top= */ 2f) new Crop(/* left= */ -2f, /* right= */ 2f, /* bottom= */ -1f, /* top= */ 2f)
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = cropTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = cropShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(CROP_LARGER_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(CROP_LARGER_PNG_ASSET_PATH);
cropTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); cropShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());

View File

@ -370,7 +370,7 @@ public final class GlEffectsFrameProcessorFrameReleaseTest {
} }
/** Produces blank frames with the given timestamps. */ /** Produces blank frames with the given timestamps. */
private static final class BlankFrameProducer implements GlTextureProcessor { private static final class BlankFrameProducer implements GlShaderProgram {
private @MonotonicNonNull TextureInfo blankTexture; private @MonotonicNonNull TextureInfo blankTexture;
private @MonotonicNonNull OutputListener outputListener; private @MonotonicNonNull OutputListener outputListener;

View File

@ -17,7 +17,7 @@ package androidx.media3.effect;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkStateNotNull; import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.effect.OverlayTextureProcessorPixelTest.OVERLAY_PNG_ASSET_PATH; import static androidx.media3.effect.OverlayShaderProgramPixelTest.OVERLAY_PNG_ASSET_PATH;
import static androidx.media3.test.utils.BitmapPixelTestUtil.MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE; import static androidx.media3.test.utils.BitmapPixelTestUtil.MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE;
import static androidx.media3.test.utils.BitmapPixelTestUtil.getBitmapAveragePixelAbsoluteDifferenceArgb8888; import static androidx.media3.test.utils.BitmapPixelTestUtil.getBitmapAveragePixelAbsoluteDifferenceArgb8888;
import static androidx.media3.test.utils.BitmapPixelTestUtil.readBitmap; import static androidx.media3.test.utils.BitmapPixelTestUtil.readBitmap;
@ -503,9 +503,9 @@ public final class GlEffectsFrameProcessorPixelTest {
* Wraps a {@link GlEffect} to prevent the {@link GlEffectsFrameProcessor} from detecting its * Wraps a {@link GlEffect} to prevent the {@link GlEffectsFrameProcessor} from detecting its
* class and optimizing it. * class and optimizing it.
* *
* <p>This ensures that {@link GlEffectsFrameProcessor} uses a separate {@link GlTextureProcessor} * <p>This ensures that {@link GlEffectsFrameProcessor} uses a separate {@link GlShaderProgram}
* for the wrapped {@link GlEffect} rather than merging it with preceding or subsequent {@link * for the wrapped {@link GlEffect} rather than merging it with preceding or subsequent {@link
* GlEffect} instances and applying them in one combined {@link GlTextureProcessor}. * GlEffect} instances and applying them in one combined {@link GlShaderProgram}.
*/ */
private static final class GlEffectWrapper implements GlEffect { private static final class GlEffectWrapper implements GlEffect {
@ -516,9 +516,9 @@ public final class GlEffectsFrameProcessorPixelTest {
} }
@Override @Override
public GlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr) public GlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
throws FrameProcessingException { throws FrameProcessingException {
return effect.toGlTextureProcessor(context, useHdr); return effect.toGlShaderProgram(context, useHdr);
} }
} }
} }

View File

@ -75,7 +75,7 @@ public final class HslAdjustmentPixelTest {
private @MonotonicNonNull EGLDisplay eglDisplay; private @MonotonicNonNull EGLDisplay eglDisplay;
private @MonotonicNonNull EGLContext eglContext; private @MonotonicNonNull EGLContext eglContext;
private @MonotonicNonNull SingleFrameGlTextureProcessor hslProcessor; private @MonotonicNonNull SingleFrameGlShaderProgram hslProcessor;
private @MonotonicNonNull EGLSurface placeholderEglSurface; private @MonotonicNonNull EGLSurface placeholderEglSurface;
private int inputTexId; private int inputTexId;
private int inputWidth; private int inputWidth;
@ -111,7 +111,7 @@ public final class HslAdjustmentPixelTest {
public void drawFrame_noOpAdjustment_leavesFrameUnchanged() throws Exception { public void drawFrame_noOpAdjustment_leavesFrameUnchanged() throws Exception {
String testId = "drawFrame_noOpAdjustment"; String testId = "drawFrame_noOpAdjustment";
HslAdjustment noOpAdjustment = new HslAdjustment.Builder().build(); HslAdjustment noOpAdjustment = new HslAdjustment.Builder().build();
hslProcessor = noOpAdjustment.toGlTextureProcessor(context, /* useHdr= */ false); hslProcessor = noOpAdjustment.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = hslProcessor.configure(inputWidth, inputHeight); Size outputSize = hslProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
@ -129,7 +129,7 @@ public final class HslAdjustmentPixelTest {
public void drawFrame_minimumSaturation_producesGrayFrame() throws Exception { public void drawFrame_minimumSaturation_producesGrayFrame() throws Exception {
String testId = "drawFrame_minimumSaturation"; String testId = "drawFrame_minimumSaturation";
HslAdjustment minimumSaturation = new HslAdjustment.Builder().adjustSaturation(-100).build(); HslAdjustment minimumSaturation = new HslAdjustment.Builder().adjustSaturation(-100).build();
hslProcessor = minimumSaturation.toGlTextureProcessor(context, /* useHdr= */ false); hslProcessor = minimumSaturation.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = hslProcessor.configure(inputWidth, inputHeight); Size outputSize = hslProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(MINIMUM_SATURATION_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(MINIMUM_SATURATION_PNG_ASSET_PATH);
@ -147,7 +147,7 @@ public final class HslAdjustmentPixelTest {
public void drawFrame_maximumSaturation_producesHighlySaturatedFrame() throws Exception { public void drawFrame_maximumSaturation_producesHighlySaturatedFrame() throws Exception {
String testId = "drawFrame_maximumSaturation"; String testId = "drawFrame_maximumSaturation";
HslAdjustment maximumSaturation = new HslAdjustment.Builder().adjustSaturation(100).build(); HslAdjustment maximumSaturation = new HslAdjustment.Builder().adjustSaturation(100).build();
hslProcessor = maximumSaturation.toGlTextureProcessor(context, /* useHdr= */ false); hslProcessor = maximumSaturation.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = hslProcessor.configure(inputWidth, inputHeight); Size outputSize = hslProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(MAXIMUM_SATURATION_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(MAXIMUM_SATURATION_PNG_ASSET_PATH);
@ -165,7 +165,7 @@ public final class HslAdjustmentPixelTest {
public void drawFrame_rotateHueByNegative90Degrees_matchesGoldenFile() throws Exception { public void drawFrame_rotateHueByNegative90Degrees_matchesGoldenFile() throws Exception {
String testId = "drawFrame_rotateHueByNegative90Degrees"; String testId = "drawFrame_rotateHueByNegative90Degrees";
HslAdjustment negativeHueRotation90Degrees = new HslAdjustment.Builder().adjustHue(-90).build(); HslAdjustment negativeHueRotation90Degrees = new HslAdjustment.Builder().adjustHue(-90).build();
hslProcessor = negativeHueRotation90Degrees.toGlTextureProcessor(context, /* useHdr= */ false); hslProcessor = negativeHueRotation90Degrees.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = hslProcessor.configure(inputWidth, inputHeight); Size outputSize = hslProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(ROTATE_HUE_BY_NEGATIVE_90_DEGREES_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ROTATE_HUE_BY_NEGATIVE_90_DEGREES_PNG_ASSET_PATH);
@ -183,7 +183,7 @@ public final class HslAdjustmentPixelTest {
public void drawFrame_rotateHueBy60Degrees_matchesGoldenFile() throws Exception { public void drawFrame_rotateHueBy60Degrees_matchesGoldenFile() throws Exception {
String testId = "drawFrame_rotateHueBy60Degrees"; String testId = "drawFrame_rotateHueBy60Degrees";
HslAdjustment hueRotation60Degrees = new HslAdjustment.Builder().adjustHue(60).build(); HslAdjustment hueRotation60Degrees = new HslAdjustment.Builder().adjustHue(60).build();
hslProcessor = hueRotation60Degrees.toGlTextureProcessor(context, /* useHdr= */ false); hslProcessor = hueRotation60Degrees.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = hslProcessor.configure(inputWidth, inputHeight); Size outputSize = hslProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(ROTATE_HUE_BY_60_DEGREES_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ROTATE_HUE_BY_60_DEGREES_PNG_ASSET_PATH);
@ -202,7 +202,7 @@ public final class HslAdjustmentPixelTest {
throws Exception { throws Exception {
String testId = "drawFrame_rotateHueByNegative300Degrees"; String testId = "drawFrame_rotateHueByNegative300Degrees";
HslAdjustment hueRotation420Degrees = new HslAdjustment.Builder().adjustHue(-300).build(); HslAdjustment hueRotation420Degrees = new HslAdjustment.Builder().adjustHue(-300).build();
hslProcessor = hueRotation420Degrees.toGlTextureProcessor(context, /* useHdr= */ false); hslProcessor = hueRotation420Degrees.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = hslProcessor.configure(inputWidth, inputHeight); Size outputSize = hslProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(ROTATE_HUE_BY_60_DEGREES_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ROTATE_HUE_BY_60_DEGREES_PNG_ASSET_PATH);
@ -220,7 +220,7 @@ public final class HslAdjustmentPixelTest {
public void drawFrame_rotateHueBy360Degrees_leavesFrameUnchanged() throws Exception { public void drawFrame_rotateHueBy360Degrees_leavesFrameUnchanged() throws Exception {
String testId = "drawFrame_rotateHueBy360Degrees"; String testId = "drawFrame_rotateHueBy360Degrees";
HslAdjustment hueRotation360Degrees = new HslAdjustment.Builder().adjustHue(360).build(); HslAdjustment hueRotation360Degrees = new HslAdjustment.Builder().adjustHue(360).build();
hslProcessor = hueRotation360Degrees.toGlTextureProcessor(context, /* useHdr= */ false); hslProcessor = hueRotation360Degrees.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = hslProcessor.configure(inputWidth, inputHeight); Size outputSize = hslProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
@ -238,7 +238,7 @@ public final class HslAdjustmentPixelTest {
public void drawFrame_minimumLightness_producesBlackFrame() throws Exception { public void drawFrame_minimumLightness_producesBlackFrame() throws Exception {
String testId = "drawFrame_minimumLightness"; String testId = "drawFrame_minimumLightness";
HslAdjustment minimumLightness = new HslAdjustment.Builder().adjustLightness(-100).build(); HslAdjustment minimumLightness = new HslAdjustment.Builder().adjustLightness(-100).build();
hslProcessor = minimumLightness.toGlTextureProcessor(context, /* useHdr= */ false); hslProcessor = minimumLightness.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = hslProcessor.configure(inputWidth, inputHeight); Size outputSize = hslProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = Bitmap expectedBitmap =
createArgb8888BitmapWithSolidColor(inputWidth, inputHeight, Color.BLACK); createArgb8888BitmapWithSolidColor(inputWidth, inputHeight, Color.BLACK);
@ -257,7 +257,7 @@ public final class HslAdjustmentPixelTest {
public void drawFrame_decreaseLightness_producesDarkerFrame() throws Exception { public void drawFrame_decreaseLightness_producesDarkerFrame() throws Exception {
String testId = "drawFrame_decreaseLightness"; String testId = "drawFrame_decreaseLightness";
HslAdjustment decreasedLightness = new HslAdjustment.Builder().adjustLightness(-50).build(); HslAdjustment decreasedLightness = new HslAdjustment.Builder().adjustLightness(-50).build();
hslProcessor = decreasedLightness.toGlTextureProcessor(context, /* useHdr= */ false); hslProcessor = decreasedLightness.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = hslProcessor.configure(inputWidth, inputHeight); Size outputSize = hslProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(DECREASE_LIGHTNESS_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(DECREASE_LIGHTNESS_PNG_ASSET_PATH);
@ -275,7 +275,7 @@ public final class HslAdjustmentPixelTest {
public void drawFrame_increaseLightness_producesBrighterFrame() throws Exception { public void drawFrame_increaseLightness_producesBrighterFrame() throws Exception {
String testId = "drawFrame_increaseLightness"; String testId = "drawFrame_increaseLightness";
HslAdjustment increasedLightness = new HslAdjustment.Builder().adjustLightness(50).build(); HslAdjustment increasedLightness = new HslAdjustment.Builder().adjustLightness(50).build();
hslProcessor = increasedLightness.toGlTextureProcessor(context, /* useHdr= */ false); hslProcessor = increasedLightness.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = hslProcessor.configure(inputWidth, inputHeight); Size outputSize = hslProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(INCREASE_LIGHTNESS_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(INCREASE_LIGHTNESS_PNG_ASSET_PATH);
@ -293,7 +293,7 @@ public final class HslAdjustmentPixelTest {
public void drawFrame_maximumLightness_producesWhiteFrame() throws Exception { public void drawFrame_maximumLightness_producesWhiteFrame() throws Exception {
String testId = "drawFrame_maximumLightness"; String testId = "drawFrame_maximumLightness";
HslAdjustment maximumLightness = new HslAdjustment.Builder().adjustLightness(100).build(); HslAdjustment maximumLightness = new HslAdjustment.Builder().adjustLightness(100).build();
hslProcessor = maximumLightness.toGlTextureProcessor(context, /* useHdr= */ false); hslProcessor = maximumLightness.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = hslProcessor.configure(inputWidth, inputHeight); Size outputSize = hslProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = Bitmap expectedBitmap =
createArgb8888BitmapWithSolidColor(inputWidth, inputHeight, Color.WHITE); createArgb8888BitmapWithSolidColor(inputWidth, inputHeight, Color.WHITE);
@ -313,7 +313,7 @@ public final class HslAdjustmentPixelTest {
String testId = "drawFrame_adjustAllHslSettings"; String testId = "drawFrame_adjustAllHslSettings";
HslAdjustment allHslSettingsAdjusted = HslAdjustment allHslSettingsAdjusted =
new HslAdjustment.Builder().adjustHue(60).adjustSaturation(30).adjustLightness(50).build(); new HslAdjustment.Builder().adjustHue(60).adjustSaturation(30).adjustLightness(50).build();
hslProcessor = allHslSettingsAdjusted.toGlTextureProcessor(context, /* useHdr= */ false); hslProcessor = allHslSettingsAdjusted.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = hslProcessor.configure(inputWidth, inputHeight); Size outputSize = hslProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(ADJUST_ALL_HSL_SETTINGS_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ADJUST_ALL_HSL_SETTINGS_PNG_ASSET_PATH);

View File

@ -42,7 +42,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
/** /**
* Pixel test for texture processing via {@link MatrixTextureProcessor}. * Pixel test for texture processing via {@link MatrixShaderProgram}.
* *
* <p>Expected images are taken from an emulator, so tests on different emulators or physical * <p>Expected images are taken from an emulator, so tests on different emulators or physical
* devices may fail. To test on other devices, please increase the {@link * devices may fail. To test on other devices, please increase the {@link
@ -50,7 +50,7 @@ import org.junit.runner.RunWith;
* bitmaps as recommended in {@link GlEffectsFrameProcessorPixelTest}. * bitmaps as recommended in {@link GlEffectsFrameProcessorPixelTest}.
*/ */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public final class MatrixTextureProcessorPixelTest { public final class MatrixShaderProgramPixelTest {
public static final String ORIGINAL_PNG_ASSET_PATH = public static final String ORIGINAL_PNG_ASSET_PATH =
"media/bitmap/sample_mp4_first_frame/electrical_colors/original.png"; "media/bitmap/sample_mp4_first_frame/electrical_colors/original.png";
public static final String TRANSLATE_RIGHT_PNG_ASSET_PATH = public static final String TRANSLATE_RIGHT_PNG_ASSET_PATH =
@ -64,7 +64,7 @@ public final class MatrixTextureProcessorPixelTest {
private @MonotonicNonNull EGLDisplay eglDisplay; private @MonotonicNonNull EGLDisplay eglDisplay;
private @MonotonicNonNull EGLContext eglContext; private @MonotonicNonNull EGLContext eglContext;
private @MonotonicNonNull SingleFrameGlTextureProcessor matrixTextureProcessor; private @MonotonicNonNull SingleFrameGlShaderProgram matrixShaderProgram;
private int inputTexId; private int inputTexId;
private int inputWidth; private int inputWidth;
private int inputHeight; private int inputHeight;
@ -88,8 +88,8 @@ public final class MatrixTextureProcessorPixelTest {
@After @After
public void release() throws GlUtil.GlException, FrameProcessingException { public void release() throws GlUtil.GlException, FrameProcessingException {
if (matrixTextureProcessor != null) { if (matrixShaderProgram != null) {
matrixTextureProcessor.release(); matrixShaderProgram.release();
} }
if (eglContext != null && eglDisplay != null) { if (eglContext != null && eglDisplay != null) {
GlUtil.destroyEglContext(eglDisplay, eglContext); GlUtil.destroyEglContext(eglDisplay, eglContext);
@ -101,12 +101,11 @@ public final class MatrixTextureProcessorPixelTest {
String testId = "drawFrame_noEdits"; String testId = "drawFrame_noEdits";
Matrix identityMatrix = new Matrix(); Matrix identityMatrix = new Matrix();
MatrixTransformation noEditsTransformation = (long presentationTimeUs) -> identityMatrix; MatrixTransformation noEditsTransformation = (long presentationTimeUs) -> identityMatrix;
matrixTextureProcessor = matrixShaderProgram = noEditsTransformation.toGlShaderProgram(context, /* useHdr= */ false);
noEditsTransformation.toGlTextureProcessor(context, /* useHdr= */ false); matrixShaderProgram.configure(inputWidth, inputHeight);
matrixTextureProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = createArgb8888BitmapFromCurrentGlFramebuffer(inputWidth, inputHeight); Bitmap actualBitmap = createArgb8888BitmapFromCurrentGlFramebuffer(inputWidth, inputHeight);
maybeSaveTestBitmapToCacheDirectory(testId, /* bitmapLabel= */ "actual", actualBitmap); maybeSaveTestBitmapToCacheDirectory(testId, /* bitmapLabel= */ "actual", actualBitmap);
@ -123,12 +122,12 @@ public final class MatrixTextureProcessorPixelTest {
translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0); translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0);
MatrixTransformation translateRightTransformation = MatrixTransformation translateRightTransformation =
(long presentationTimeUs) -> translateRightMatrix; (long presentationTimeUs) -> translateRightMatrix;
matrixTextureProcessor = matrixShaderProgram =
translateRightTransformation.toGlTextureProcessor(context, /* useHdr= */ false); translateRightTransformation.toGlShaderProgram(context, /* useHdr= */ false);
matrixTextureProcessor.configure(inputWidth, inputHeight); matrixShaderProgram.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(TRANSLATE_RIGHT_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(TRANSLATE_RIGHT_PNG_ASSET_PATH);
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = createArgb8888BitmapFromCurrentGlFramebuffer(inputWidth, inputHeight); Bitmap actualBitmap = createArgb8888BitmapFromCurrentGlFramebuffer(inputWidth, inputHeight);
maybeSaveTestBitmapToCacheDirectory(testId, /* bitmapLabel= */ "actual", actualBitmap); maybeSaveTestBitmapToCacheDirectory(testId, /* bitmapLabel= */ "actual", actualBitmap);
@ -144,12 +143,11 @@ public final class MatrixTextureProcessorPixelTest {
Matrix scaleNarrowMatrix = new Matrix(); Matrix scaleNarrowMatrix = new Matrix();
scaleNarrowMatrix.postScale(.5f, 1.2f); scaleNarrowMatrix.postScale(.5f, 1.2f);
MatrixTransformation scaleNarrowTransformation = (long presentationTimeUs) -> scaleNarrowMatrix; MatrixTransformation scaleNarrowTransformation = (long presentationTimeUs) -> scaleNarrowMatrix;
matrixTextureProcessor = matrixShaderProgram = scaleNarrowTransformation.toGlShaderProgram(context, /* useHdr= */ false);
scaleNarrowTransformation.toGlTextureProcessor(context, /* useHdr= */ false); matrixShaderProgram.configure(inputWidth, inputHeight);
matrixTextureProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(SCALE_NARROW_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(SCALE_NARROW_PNG_ASSET_PATH);
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = createArgb8888BitmapFromCurrentGlFramebuffer(inputWidth, inputHeight); Bitmap actualBitmap = createArgb8888BitmapFromCurrentGlFramebuffer(inputWidth, inputHeight);
maybeSaveTestBitmapToCacheDirectory(testId, /* bitmapLabel= */ "actual", actualBitmap); maybeSaveTestBitmapToCacheDirectory(testId, /* bitmapLabel= */ "actual", actualBitmap);
@ -165,12 +163,11 @@ public final class MatrixTextureProcessorPixelTest {
Matrix rotate90Matrix = new Matrix(); Matrix rotate90Matrix = new Matrix();
rotate90Matrix.postRotate(/* degrees= */ 90); rotate90Matrix.postRotate(/* degrees= */ 90);
MatrixTransformation rotate90Transformation = (long presentationTimeUs) -> rotate90Matrix; MatrixTransformation rotate90Transformation = (long presentationTimeUs) -> rotate90Matrix;
matrixTextureProcessor = matrixShaderProgram = rotate90Transformation.toGlShaderProgram(context, /* useHdr= */ false);
rotate90Transformation.toGlTextureProcessor(context, /* useHdr= */ false); matrixShaderProgram.configure(inputWidth, inputHeight);
matrixTextureProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(ROTATE_90_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ROTATE_90_PNG_ASSET_PATH);
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = createArgb8888BitmapFromCurrentGlFramebuffer(inputWidth, inputHeight); Bitmap actualBitmap = createArgb8888BitmapFromCurrentGlFramebuffer(inputWidth, inputHeight);
maybeSaveTestBitmapToCacheDirectory(testId, /* bitmapLabel= */ "actual", actualBitmap); maybeSaveTestBitmapToCacheDirectory(testId, /* bitmapLabel= */ "actual", actualBitmap);

View File

@ -49,7 +49,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
/** /**
* Pixel test for texture processing via {@link OverlayTextureProcessor}. * Pixel test for texture processing via {@link OverlayShaderProgram}.
* *
* <p>Expected bitmaps are taken from an emulator, so tests on different emulators or physical * <p>Expected bitmaps are taken from an emulator, so tests on different emulators or physical
* devices may fail. To test on other devices, please increase the {@link * devices may fail. To test on other devices, please increase the {@link
@ -57,7 +57,7 @@ import org.junit.runner.RunWith;
* bitmaps as recommended in {@link GlEffectsFrameProcessorPixelTest}. * bitmaps as recommended in {@link GlEffectsFrameProcessorPixelTest}.
*/ */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class OverlayTextureProcessorPixelTest { public class OverlayShaderProgramPixelTest {
public static final String OVERLAY_PNG_ASSET_PATH = "media/bitmap/overlay/media3test.png"; public static final String OVERLAY_PNG_ASSET_PATH = "media/bitmap/overlay/media3test.png";
public static final String ORIGINAL_PNG_ASSET_PATH = public static final String ORIGINAL_PNG_ASSET_PATH =
"media/bitmap/sample_mp4_first_frame/electrical_colors/original.png"; "media/bitmap/sample_mp4_first_frame/electrical_colors/original.png";
@ -82,7 +82,7 @@ public class OverlayTextureProcessorPixelTest {
private @MonotonicNonNull EGLDisplay eglDisplay; private @MonotonicNonNull EGLDisplay eglDisplay;
private @MonotonicNonNull EGLContext eglContext; private @MonotonicNonNull EGLContext eglContext;
private @MonotonicNonNull SingleFrameGlTextureProcessor overlayTextureProcessor; private @MonotonicNonNull SingleFrameGlShaderProgram overlayShaderProgram;
private @MonotonicNonNull EGLSurface placeholderEglSurface; private @MonotonicNonNull EGLSurface placeholderEglSurface;
private int inputTexId; private int inputTexId;
private int inputWidth; private int inputWidth;
@ -102,8 +102,8 @@ public class OverlayTextureProcessorPixelTest {
@After @After
public void release() throws GlUtil.GlException, FrameProcessingException { public void release() throws GlUtil.GlException, FrameProcessingException {
if (overlayTextureProcessor != null) { if (overlayShaderProgram != null) {
overlayTextureProcessor.release(); overlayShaderProgram.release();
} }
GlUtil.destroyEglContext(eglDisplay, eglContext); GlUtil.destroyEglContext(eglDisplay, eglContext);
} }
@ -111,14 +111,14 @@ public class OverlayTextureProcessorPixelTest {
@Test @Test
public void drawFrame_noOverlay_leavesFrameUnchanged() throws Exception { public void drawFrame_noOverlay_leavesFrameUnchanged() throws Exception {
String testId = "drawFrame_noOverlay"; String testId = "drawFrame_noOverlay";
overlayTextureProcessor = overlayShaderProgram =
new OverlayEffect(/* textureOverlays= */ ImmutableList.of()) new OverlayEffect(/* textureOverlays= */ ImmutableList.of())
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -133,14 +133,14 @@ public class OverlayTextureProcessorPixelTest {
String testId = "drawFrame_bitmapOverlay"; String testId = "drawFrame_bitmapOverlay";
Bitmap overlayBitmap = readBitmap(OVERLAY_PNG_ASSET_PATH); Bitmap overlayBitmap = readBitmap(OVERLAY_PNG_ASSET_PATH);
BitmapOverlay bitmapOverlay = BitmapOverlay.createStaticBitmapOverlay(overlayBitmap); BitmapOverlay bitmapOverlay = BitmapOverlay.createStaticBitmapOverlay(overlayBitmap);
overlayTextureProcessor = overlayShaderProgram =
new OverlayEffect(ImmutableList.of(bitmapOverlay)) new OverlayEffect(ImmutableList.of(bitmapOverlay))
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(OVERLAY_BITMAP_DEFAULT); Bitmap expectedBitmap = readBitmap(OVERLAY_BITMAP_DEFAULT);
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -178,14 +178,14 @@ public class OverlayTextureProcessorPixelTest {
return overlaySettings; return overlaySettings;
} }
}; };
overlayTextureProcessor = overlayShaderProgram =
new OverlayEffect(ImmutableList.of(staticBitmapOverlay)) new OverlayEffect(ImmutableList.of(staticBitmapOverlay))
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(OVERLAY_BITMAP_SCALED); Bitmap expectedBitmap = readBitmap(OVERLAY_BITMAP_SCALED);
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -205,14 +205,14 @@ public class OverlayTextureProcessorPixelTest {
new OverlaySettings.Builder().setMatrix(translateMatrix).setAnchor(-1f, 1f).build(); new OverlaySettings.Builder().setMatrix(translateMatrix).setAnchor(-1f, 1f).build();
BitmapOverlay staticBitmapOverlay = BitmapOverlay staticBitmapOverlay =
BitmapOverlay.createStaticBitmapOverlay(overlayBitmap, overlaySettings); BitmapOverlay.createStaticBitmapOverlay(overlayBitmap, overlaySettings);
overlayTextureProcessor = overlayShaderProgram =
new OverlayEffect(ImmutableList.of(staticBitmapOverlay)) new OverlayEffect(ImmutableList.of(staticBitmapOverlay))
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(OVERLAY_BITMAP_ANCHORED); Bitmap expectedBitmap = readBitmap(OVERLAY_BITMAP_ANCHORED);
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -229,14 +229,14 @@ public class OverlayTextureProcessorPixelTest {
OverlaySettings overlaySettings = new OverlaySettings.Builder().setAlpha(0.5f).build(); OverlaySettings overlaySettings = new OverlaySettings.Builder().setAlpha(0.5f).build();
BitmapOverlay translucentBitmapOverlay = BitmapOverlay translucentBitmapOverlay =
BitmapOverlay.createStaticBitmapOverlay(bitmap, overlaySettings); BitmapOverlay.createStaticBitmapOverlay(bitmap, overlaySettings);
overlayTextureProcessor = overlayShaderProgram =
new OverlayEffect(ImmutableList.of(translucentBitmapOverlay)) new OverlayEffect(ImmutableList.of(translucentBitmapOverlay))
.toGlTextureProcessor(context, false); .toGlShaderProgram(context, false);
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(OVERLAY_BITMAP_TRANSLUCENT); Bitmap expectedBitmap = readBitmap(OVERLAY_BITMAP_TRANSLUCENT);
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -258,14 +258,14 @@ public class OverlayTextureProcessorPixelTest {
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
TextOverlay staticTextOverlay = TextOverlay staticTextOverlay =
TextOverlay.createStaticTextOverlay(overlayText, overlaySettings); TextOverlay.createStaticTextOverlay(overlayText, overlaySettings);
overlayTextureProcessor = overlayShaderProgram =
new OverlayEffect(ImmutableList.of(staticTextOverlay)) new OverlayEffect(ImmutableList.of(staticTextOverlay))
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -285,14 +285,14 @@ public class OverlayTextureProcessorPixelTest {
/* end= */ 4, /* end= */ 4,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
TextOverlay staticTextOverlay = TextOverlay.createStaticTextOverlay(overlayText); TextOverlay staticTextOverlay = TextOverlay.createStaticTextOverlay(overlayText);
overlayTextureProcessor = overlayShaderProgram =
new OverlayEffect(ImmutableList.of(staticTextOverlay)) new OverlayEffect(ImmutableList.of(staticTextOverlay))
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(OVERLAY_TEXT_DEFAULT); Bitmap expectedBitmap = readBitmap(OVERLAY_TEXT_DEFAULT);
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -317,14 +317,14 @@ public class OverlayTextureProcessorPixelTest {
new OverlaySettings.Builder().setMatrix(translateMatrix).build(); new OverlaySettings.Builder().setMatrix(translateMatrix).build();
TextOverlay staticTextOverlay = TextOverlay staticTextOverlay =
TextOverlay.createStaticTextOverlay(overlayText, overlaySettings); TextOverlay.createStaticTextOverlay(overlayText, overlaySettings);
overlayTextureProcessor = overlayShaderProgram =
new OverlayEffect(ImmutableList.of(staticTextOverlay)) new OverlayEffect(ImmutableList.of(staticTextOverlay))
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(OVERLAY_TEXT_TRANSLATE); Bitmap expectedBitmap = readBitmap(OVERLAY_TEXT_TRANSLATE);
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -351,14 +351,14 @@ public class OverlayTextureProcessorPixelTest {
Bitmap bitmap = readBitmap(OVERLAY_PNG_ASSET_PATH); Bitmap bitmap = readBitmap(OVERLAY_PNG_ASSET_PATH);
OverlaySettings overlaySettings2 = new OverlaySettings.Builder().setAlpha(0.5f).build(); OverlaySettings overlaySettings2 = new OverlaySettings.Builder().setAlpha(0.5f).build();
BitmapOverlay bitmapOverlay = BitmapOverlay.createStaticBitmapOverlay(bitmap, overlaySettings2); BitmapOverlay bitmapOverlay = BitmapOverlay.createStaticBitmapOverlay(bitmap, overlaySettings2);
overlayTextureProcessor = overlayShaderProgram =
new OverlayEffect(ImmutableList.of(textOverlay, bitmapOverlay)) new OverlayEffect(ImmutableList.of(textOverlay, bitmapOverlay))
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(OVERLAY_MULTIPLE); Bitmap expectedBitmap = readBitmap(OVERLAY_MULTIPLE);
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -388,14 +388,14 @@ public class OverlayTextureProcessorPixelTest {
OverlaySettings overlaySettings2 = new OverlaySettings.Builder().setMatrix(scaleMatrix).build(); OverlaySettings overlaySettings2 = new OverlaySettings.Builder().setMatrix(scaleMatrix).build();
BitmapOverlay bitmapOverlay = BitmapOverlay.createStaticBitmapOverlay(bitmap, overlaySettings2); BitmapOverlay bitmapOverlay = BitmapOverlay.createStaticBitmapOverlay(bitmap, overlaySettings2);
overlayTextureProcessor = overlayShaderProgram =
new OverlayEffect(ImmutableList.of(bitmapOverlay, textOverlay)) new OverlayEffect(ImmutableList.of(bitmapOverlay, textOverlay))
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(OVERLAY_OVERLAP); Bitmap expectedBitmap = readBitmap(OVERLAY_OVERLAP);
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());

View File

@ -72,7 +72,7 @@ public final class PresentationPixelTest {
private @MonotonicNonNull EGLDisplay eglDisplay; private @MonotonicNonNull EGLDisplay eglDisplay;
private @MonotonicNonNull EGLContext eglContext; private @MonotonicNonNull EGLContext eglContext;
private @MonotonicNonNull SingleFrameGlTextureProcessor presentationTextureProcessor; private @MonotonicNonNull SingleFrameGlShaderProgram presentationShaderProgram;
private @MonotonicNonNull EGLSurface placeholderEglSurface; private @MonotonicNonNull EGLSurface placeholderEglSurface;
private int inputTexId; private int inputTexId;
private int inputWidth; private int inputWidth;
@ -92,8 +92,8 @@ public final class PresentationPixelTest {
@After @After
public void release() throws GlUtil.GlException, FrameProcessingException { public void release() throws GlUtil.GlException, FrameProcessingException {
if (presentationTextureProcessor != null) { if (presentationShaderProgram != null) {
presentationTextureProcessor.release(); presentationShaderProgram.release();
} }
if (eglContext != null && eglDisplay != null) { if (eglContext != null && eglDisplay != null) {
GlUtil.destroyEglContext(eglDisplay, eglContext); GlUtil.destroyEglContext(eglDisplay, eglContext);
@ -103,14 +103,14 @@ public final class PresentationPixelTest {
@Test @Test
public void drawFrame_noEdits_matchesGoldenFile() throws Exception { public void drawFrame_noEdits_matchesGoldenFile() throws Exception {
String testId = "drawFrame_noEdits"; String testId = "drawFrame_noEdits";
presentationTextureProcessor = presentationShaderProgram =
Presentation.createForHeight(C.LENGTH_UNSET) Presentation.createForHeight(C.LENGTH_UNSET)
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = presentationShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
presentationTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); presentationShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -124,14 +124,14 @@ public final class PresentationPixelTest {
@Test @Test
public void drawFrame_changeAspectRatio_scaleToFit_narrow_matchesGoldenFile() throws Exception { public void drawFrame_changeAspectRatio_scaleToFit_narrow_matchesGoldenFile() throws Exception {
String testId = "drawFrame_changeAspectRatio_scaleToFit_narrow"; String testId = "drawFrame_changeAspectRatio_scaleToFit_narrow";
presentationTextureProcessor = presentationShaderProgram =
Presentation.createForAspectRatio(/* aspectRatio= */ 1f, Presentation.LAYOUT_SCALE_TO_FIT) Presentation.createForAspectRatio(/* aspectRatio= */ 1f, Presentation.LAYOUT_SCALE_TO_FIT)
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = presentationShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_SCALE_TO_FIT_NARROW_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_SCALE_TO_FIT_NARROW_PNG_ASSET_PATH);
presentationTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); presentationShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -145,14 +145,14 @@ public final class PresentationPixelTest {
@Test @Test
public void drawFrame_changeAspectRatio_scaleToFit_wide_matchesGoldenFile() throws Exception { public void drawFrame_changeAspectRatio_scaleToFit_wide_matchesGoldenFile() throws Exception {
String testId = "drawFrame_changeAspectRatio_scaleToFit_wide"; String testId = "drawFrame_changeAspectRatio_scaleToFit_wide";
presentationTextureProcessor = presentationShaderProgram =
Presentation.createForAspectRatio(/* aspectRatio= */ 2f, Presentation.LAYOUT_SCALE_TO_FIT) Presentation.createForAspectRatio(/* aspectRatio= */ 2f, Presentation.LAYOUT_SCALE_TO_FIT)
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = presentationShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_SCALE_TO_FIT_WIDE_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_SCALE_TO_FIT_WIDE_PNG_ASSET_PATH);
presentationTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); presentationShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -167,15 +167,15 @@ public final class PresentationPixelTest {
public void drawFrame_changeAspectRatio_scaleToFitWithCrop_narrow_matchesGoldenFile() public void drawFrame_changeAspectRatio_scaleToFitWithCrop_narrow_matchesGoldenFile()
throws Exception { throws Exception {
String testId = "drawFrame_changeAspectRatio_scaleToFitWithCrop_narrow"; String testId = "drawFrame_changeAspectRatio_scaleToFitWithCrop_narrow";
presentationTextureProcessor = presentationShaderProgram =
Presentation.createForAspectRatio( Presentation.createForAspectRatio(
/* aspectRatio= */ 1f, Presentation.LAYOUT_SCALE_TO_FIT_WITH_CROP) /* aspectRatio= */ 1f, Presentation.LAYOUT_SCALE_TO_FIT_WITH_CROP)
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = presentationShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_SCALE_TO_FIT_WITH_CROP_NARROW_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_SCALE_TO_FIT_WITH_CROP_NARROW_PNG_ASSET_PATH);
presentationTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); presentationShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -190,15 +190,15 @@ public final class PresentationPixelTest {
public void drawFrame_changeAspectRatio_scaleToFitWithCrop_wide_matchesGoldenFile() public void drawFrame_changeAspectRatio_scaleToFitWithCrop_wide_matchesGoldenFile()
throws Exception { throws Exception {
String testId = "drawFrame_changeAspectRatio_scaleToFitWithCrop_wide"; String testId = "drawFrame_changeAspectRatio_scaleToFitWithCrop_wide";
presentationTextureProcessor = presentationShaderProgram =
Presentation.createForAspectRatio( Presentation.createForAspectRatio(
/* aspectRatio= */ 2f, Presentation.LAYOUT_SCALE_TO_FIT_WITH_CROP) /* aspectRatio= */ 2f, Presentation.LAYOUT_SCALE_TO_FIT_WITH_CROP)
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = presentationShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_SCALE_TO_FIT_WITH_CROP_WIDE_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_SCALE_TO_FIT_WITH_CROP_WIDE_PNG_ASSET_PATH);
presentationTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); presentationShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -212,14 +212,14 @@ public final class PresentationPixelTest {
@Test @Test
public void drawFrame_changeAspectRatio_stretchToFit_narrow_matchesGoldenFile() throws Exception { public void drawFrame_changeAspectRatio_stretchToFit_narrow_matchesGoldenFile() throws Exception {
String testId = "drawFrame_changeAspectRatio_stretchToFit_narrow"; String testId = "drawFrame_changeAspectRatio_stretchToFit_narrow";
presentationTextureProcessor = presentationShaderProgram =
Presentation.createForAspectRatio(/* aspectRatio= */ 1f, Presentation.LAYOUT_STRETCH_TO_FIT) Presentation.createForAspectRatio(/* aspectRatio= */ 1f, Presentation.LAYOUT_STRETCH_TO_FIT)
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = presentationShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_STRETCH_TO_FIT_NARROW_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_STRETCH_TO_FIT_NARROW_PNG_ASSET_PATH);
presentationTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); presentationShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -233,14 +233,14 @@ public final class PresentationPixelTest {
@Test @Test
public void drawFrame_changeAspectRatio_stretchToFit_wide_matchesGoldenFile() throws Exception { public void drawFrame_changeAspectRatio_stretchToFit_wide_matchesGoldenFile() throws Exception {
String testId = "drawFrame_changeAspectRatio_stretchToFit_wide"; String testId = "drawFrame_changeAspectRatio_stretchToFit_wide";
presentationTextureProcessor = presentationShaderProgram =
Presentation.createForAspectRatio(/* aspectRatio= */ 2f, Presentation.LAYOUT_STRETCH_TO_FIT) Presentation.createForAspectRatio(/* aspectRatio= */ 2f, Presentation.LAYOUT_STRETCH_TO_FIT)
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = presentationShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_STRETCH_TO_FIT_WIDE_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_STRETCH_TO_FIT_WIDE_PNG_ASSET_PATH);
presentationTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); presentationShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());

View File

@ -69,7 +69,7 @@ public final class RgbAdjustmentPixelTest {
private @MonotonicNonNull EGLDisplay eglDisplay; private @MonotonicNonNull EGLDisplay eglDisplay;
private @MonotonicNonNull EGLContext eglContext; private @MonotonicNonNull EGLContext eglContext;
private @MonotonicNonNull SingleFrameGlTextureProcessor matrixTextureProcessor; private @MonotonicNonNull SingleFrameGlShaderProgram matrixShaderProgram;
private @MonotonicNonNull EGLSurface placeholderEglSurface; private @MonotonicNonNull EGLSurface placeholderEglSurface;
private int inputTexId; private int inputTexId;
private int inputWidth; private int inputWidth;
@ -100,8 +100,8 @@ public final class RgbAdjustmentPixelTest {
@After @After
public void release() throws GlUtil.GlException, FrameProcessingException { public void release() throws GlUtil.GlException, FrameProcessingException {
if (matrixTextureProcessor != null) { if (matrixShaderProgram != null) {
matrixTextureProcessor.release(); matrixShaderProgram.release();
} }
GlUtil.destroyEglContext(eglDisplay, eglContext); GlUtil.destroyEglContext(eglDisplay, eglContext);
} }
@ -110,11 +110,11 @@ public final class RgbAdjustmentPixelTest {
public void drawFrame_identityMatrix_leavesFrameUnchanged() throws Exception { public void drawFrame_identityMatrix_leavesFrameUnchanged() throws Exception {
String testId = "drawFrame_identityMatrix"; String testId = "drawFrame_identityMatrix";
RgbMatrix identityMatrix = new RgbAdjustment.Builder().build(); RgbMatrix identityMatrix = new RgbAdjustment.Builder().build();
matrixTextureProcessor = identityMatrix.toGlTextureProcessor(context, /* useHdr= */ false); matrixShaderProgram = identityMatrix.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -129,13 +129,13 @@ public final class RgbAdjustmentPixelTest {
String testId = "drawFrame_removeColors"; String testId = "drawFrame_removeColors";
RgbMatrix removeColorMatrix = RgbMatrix removeColorMatrix =
new RgbAdjustment.Builder().setRedScale(0).setGreenScale(0).setBlueScale(0).build(); new RgbAdjustment.Builder().setRedScale(0).setGreenScale(0).setBlueScale(0).build();
matrixTextureProcessor = removeColorMatrix.toGlTextureProcessor(context, /* useHdr= */ false); matrixShaderProgram = removeColorMatrix.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = Bitmap expectedBitmap =
createArgb8888BitmapWithSolidColor( createArgb8888BitmapWithSolidColor(
outputSize.getWidth(), outputSize.getHeight(), Color.BLACK); outputSize.getWidth(), outputSize.getHeight(), Color.BLACK);
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -149,11 +149,11 @@ public final class RgbAdjustmentPixelTest {
public void drawFrame_redOnlyFilter_removeBlueAndGreenValues() throws Exception { public void drawFrame_redOnlyFilter_removeBlueAndGreenValues() throws Exception {
String testId = "drawFrame_redOnlyFilter"; String testId = "drawFrame_redOnlyFilter";
RgbMatrix redOnlyMatrix = new RgbAdjustment.Builder().setBlueScale(0).setGreenScale(0).build(); RgbMatrix redOnlyMatrix = new RgbAdjustment.Builder().setBlueScale(0).setGreenScale(0).build();
matrixTextureProcessor = redOnlyMatrix.toGlTextureProcessor(context, /* useHdr= */ false); matrixShaderProgram = redOnlyMatrix.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(ONLY_RED_CHANNEL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ONLY_RED_CHANNEL_PNG_ASSET_PATH);
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -167,11 +167,11 @@ public final class RgbAdjustmentPixelTest {
public void drawFrame_increaseRedChannel_producesBrighterAndRedderFrame() throws Exception { public void drawFrame_increaseRedChannel_producesBrighterAndRedderFrame() throws Exception {
String testId = "drawFrame_increaseRedChannel"; String testId = "drawFrame_increaseRedChannel";
RgbMatrix increaseRedMatrix = new RgbAdjustment.Builder().setRedScale(5).build(); RgbMatrix increaseRedMatrix = new RgbAdjustment.Builder().setRedScale(5).build();
matrixTextureProcessor = increaseRedMatrix.toGlTextureProcessor(context, /* useHdr= */ false); matrixShaderProgram = increaseRedMatrix.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(INCREASE_RED_CHANNEL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(INCREASE_RED_CHANNEL_PNG_ASSET_PATH);
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -186,12 +186,11 @@ public final class RgbAdjustmentPixelTest {
String testId = "drawFrame_increaseBrightness"; String testId = "drawFrame_increaseBrightness";
RgbMatrix increaseBrightnessMatrix = RgbMatrix increaseBrightnessMatrix =
new RgbAdjustment.Builder().setRedScale(5).setGreenScale(5).setBlueScale(5).build(); new RgbAdjustment.Builder().setRedScale(5).setGreenScale(5).setBlueScale(5).build();
matrixTextureProcessor = matrixShaderProgram = increaseBrightnessMatrix.toGlShaderProgram(context, /* useHdr= */ false);
increaseBrightnessMatrix.toGlTextureProcessor(context, /* useHdr= */ false); Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(INCREASE_BRIGHTNESS_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(INCREASE_BRIGHTNESS_PNG_ASSET_PATH);
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -207,18 +206,18 @@ public final class RgbAdjustmentPixelTest {
RgbMatrix noRed = new RgbAdjustment.Builder().setRedScale(0).build(); RgbMatrix noRed = new RgbAdjustment.Builder().setRedScale(0).build();
RgbMatrix noGreen = new RgbAdjustment.Builder().setGreenScale(0).build(); RgbMatrix noGreen = new RgbAdjustment.Builder().setGreenScale(0).build();
RgbMatrix noBlue = new RgbAdjustment.Builder().setBlueScale(0).build(); RgbMatrix noBlue = new RgbAdjustment.Builder().setBlueScale(0).build();
matrixTextureProcessor = matrixShaderProgram =
MatrixTextureProcessor.create( MatrixShaderProgram.create(
context, context,
/* matrixTransformations= */ ImmutableList.of(), /* matrixTransformations= */ ImmutableList.of(),
/* rgbMatrices= */ ImmutableList.of(noRed, noGreen, noBlue), /* rgbMatrices= */ ImmutableList.of(noRed, noGreen, noBlue),
/* useHdr= */ false); /* useHdr= */ false);
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = Bitmap expectedBitmap =
createArgb8888BitmapWithSolidColor( createArgb8888BitmapWithSolidColor(
outputSize.getWidth(), outputSize.getHeight(), Color.BLACK); outputSize.getWidth(), outputSize.getHeight(), Color.BLACK);
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -233,16 +232,16 @@ public final class RgbAdjustmentPixelTest {
String testId = "drawFrame_removeBlueAndGreenValuesInAChain"; String testId = "drawFrame_removeBlueAndGreenValuesInAChain";
RgbMatrix noGreen = new RgbAdjustment.Builder().setGreenScale(0).build(); RgbMatrix noGreen = new RgbAdjustment.Builder().setGreenScale(0).build();
RgbMatrix noBlue = new RgbAdjustment.Builder().setBlueScale(0).build(); RgbMatrix noBlue = new RgbAdjustment.Builder().setBlueScale(0).build();
matrixTextureProcessor = matrixShaderProgram =
MatrixTextureProcessor.create( MatrixShaderProgram.create(
context, context,
/* matrixTransformations= */ ImmutableList.of(), /* matrixTransformations= */ ImmutableList.of(),
/* rgbMatrices= */ ImmutableList.of(noGreen, noBlue), /* rgbMatrices= */ ImmutableList.of(noGreen, noBlue),
/* useHdr= */ false); /* useHdr= */ false);
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(ONLY_RED_CHANNEL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ONLY_RED_CHANNEL_PNG_ASSET_PATH);
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -259,16 +258,16 @@ public final class RgbAdjustmentPixelTest {
RgbMatrix scaleRedMatrix = new RgbAdjustment.Builder().setRedScale(redScale).build(); RgbMatrix scaleRedMatrix = new RgbAdjustment.Builder().setRedScale(redScale).build();
RgbMatrix scaleRedByInverseMatrix = RgbMatrix scaleRedByInverseMatrix =
new RgbAdjustment.Builder().setRedScale(1 / redScale).build(); new RgbAdjustment.Builder().setRedScale(1 / redScale).build();
matrixTextureProcessor = matrixShaderProgram =
MatrixTextureProcessor.create( MatrixShaderProgram.create(
context, context,
/* matrixTransformations= */ ImmutableList.of(), /* matrixTransformations= */ ImmutableList.of(),
/* rgbMatrices= */ ImmutableList.of(scaleRedMatrix, scaleRedByInverseMatrix), /* rgbMatrices= */ ImmutableList.of(scaleRedMatrix, scaleRedByInverseMatrix),
/* useHdr= */ false); /* useHdr= */ false);
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());

View File

@ -64,7 +64,7 @@ public final class RgbFilterPixelTest {
private @MonotonicNonNull EGLDisplay eglDisplay; private @MonotonicNonNull EGLDisplay eglDisplay;
private @MonotonicNonNull EGLContext eglContext; private @MonotonicNonNull EGLContext eglContext;
private @MonotonicNonNull SingleFrameGlTextureProcessor matrixTextureProcessor; private @MonotonicNonNull SingleFrameGlShaderProgram matrixShaderProgram;
private @MonotonicNonNull EGLSurface placeholderEglSurface; private @MonotonicNonNull EGLSurface placeholderEglSurface;
private int inputTexId; private int inputTexId;
private int inputWidth; private int inputWidth;
@ -95,8 +95,8 @@ public final class RgbFilterPixelTest {
@After @After
public void release() throws GlUtil.GlException, FrameProcessingException { public void release() throws GlUtil.GlException, FrameProcessingException {
if (matrixTextureProcessor != null) { if (matrixShaderProgram != null) {
matrixTextureProcessor.release(); matrixShaderProgram.release();
} }
GlUtil.destroyEglContext(eglDisplay, eglContext); GlUtil.destroyEglContext(eglDisplay, eglContext);
} }
@ -105,11 +105,11 @@ public final class RgbFilterPixelTest {
public void drawFrame_grayscale_producesGrayscaleImage() throws Exception { public void drawFrame_grayscale_producesGrayscaleImage() throws Exception {
String testId = "drawFrame_grayscale"; String testId = "drawFrame_grayscale";
RgbMatrix grayscaleMatrix = RgbFilter.createGrayscaleFilter(); RgbMatrix grayscaleMatrix = RgbFilter.createGrayscaleFilter();
matrixTextureProcessor = grayscaleMatrix.toGlTextureProcessor(context, /* useHdr= */ false); matrixShaderProgram = grayscaleMatrix.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(GRAYSCALE_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(GRAYSCALE_PNG_ASSET_PATH);
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -123,11 +123,11 @@ public final class RgbFilterPixelTest {
public void drawFrame_inverted_producesInvertedFrame() throws Exception { public void drawFrame_inverted_producesInvertedFrame() throws Exception {
String testId = "drawFrame_inverted"; String testId = "drawFrame_inverted";
RgbMatrix invertedMatrix = RgbFilter.createInvertedFilter(); RgbMatrix invertedMatrix = RgbFilter.createInvertedFilter();
matrixTextureProcessor = invertedMatrix.toGlTextureProcessor(context, /* useHdr= */ false); matrixShaderProgram = invertedMatrix.toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
Bitmap expectedBitmap = readBitmap(INVERT_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(INVERT_PNG_ASSET_PATH);
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());

View File

@ -44,7 +44,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
/** /**
* Pixel test for Lookup Tables via {@link ColorLutProcessor}. * Pixel test for Lookup Tables via {@link ColorLutShaderProgram}.
* *
* <p>Expected images are taken from an emulator, so tests on different emulators or physical * <p>Expected images are taken from an emulator, so tests on different emulators or physical
* devices may fail. To test on other devices, please increase the {@link * devices may fail. To test on other devices, please increase the {@link
@ -70,7 +70,7 @@ public class SingleColorLutPixelTest {
private @MonotonicNonNull EGLDisplay eglDisplay; private @MonotonicNonNull EGLDisplay eglDisplay;
private @MonotonicNonNull EGLContext eglContext; private @MonotonicNonNull EGLContext eglContext;
private @MonotonicNonNull EGLSurface placeholderEglSurface; private @MonotonicNonNull EGLSurface placeholderEglSurface;
private @MonotonicNonNull SingleFrameGlTextureProcessor colorLutProcessor; private @MonotonicNonNull SingleFrameGlShaderProgram colorLutShaderProgram;
private int inputTexId; private int inputTexId;
private int inputWidth; private int inputWidth;
private int inputHeight; private int inputHeight;
@ -89,8 +89,8 @@ public class SingleColorLutPixelTest {
@After @After
public void release() throws GlUtil.GlException, FrameProcessingException { public void release() throws GlUtil.GlException, FrameProcessingException {
if (colorLutProcessor != null) { if (colorLutShaderProgram != null) {
colorLutProcessor.release(); colorLutShaderProgram.release();
} }
GlUtil.destroyEglContext(eglDisplay, eglContext); GlUtil.destroyEglContext(eglDisplay, eglContext);
} }
@ -99,14 +99,14 @@ public class SingleColorLutPixelTest {
public void drawFrame_identityCubeLutSize2_leavesFrameUnchanged() throws Exception { public void drawFrame_identityCubeLutSize2_leavesFrameUnchanged() throws Exception {
String testId = "drawFrame_identityLutCubeSize2"; String testId = "drawFrame_identityLutCubeSize2";
int[][][] cubeIdentityLut = createIdentityLutCube(/* length= */ 2); int[][][] cubeIdentityLut = createIdentityLutCube(/* length= */ 2);
colorLutProcessor = colorLutShaderProgram =
SingleColorLut.createFromCube(cubeIdentityLut) SingleColorLut.createFromCube(cubeIdentityLut)
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight); Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -120,14 +120,14 @@ public class SingleColorLutPixelTest {
public void drawFrame_identityCubeLutSize64_leavesFrameUnchanged() throws Exception { public void drawFrame_identityCubeLutSize64_leavesFrameUnchanged() throws Exception {
String testId = "drawFrame_identityLutCubeSize64"; String testId = "drawFrame_identityLutCubeSize64";
int[][][] cubeIdentityLut = createIdentityLutCube(/* length= */ 64); int[][][] cubeIdentityLut = createIdentityLutCube(/* length= */ 64);
colorLutProcessor = colorLutShaderProgram =
SingleColorLut.createFromCube(cubeIdentityLut) SingleColorLut.createFromCube(cubeIdentityLut)
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight); Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -141,14 +141,13 @@ public class SingleColorLutPixelTest {
public void drawFrame_identityBitmapLutSize2_leavesFrameUnchanged() throws Exception { public void drawFrame_identityBitmapLutSize2_leavesFrameUnchanged() throws Exception {
String testId = "drawFrame_identityBitmapLutSize2"; String testId = "drawFrame_identityBitmapLutSize2";
Bitmap bitmapLut = createIdentityLutBitmap(/* length= */ 2); Bitmap bitmapLut = createIdentityLutBitmap(/* length= */ 2);
colorLutProcessor = colorLutShaderProgram =
SingleColorLut.createFromBitmap(bitmapLut) SingleColorLut.createFromBitmap(bitmapLut).toGlShaderProgram(context, /* useHdr= */ false);
.toGlTextureProcessor(context, /* useHdr= */ false); Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -162,14 +161,13 @@ public class SingleColorLutPixelTest {
public void drawFrame_identityBitmapLutSize64_leavesFrameUnchanged() throws Exception { public void drawFrame_identityBitmapLutSize64_leavesFrameUnchanged() throws Exception {
String testId = "drawFrame_identityBitmapLutSize64"; String testId = "drawFrame_identityBitmapLutSize64";
Bitmap bitmapLut = createIdentityLutBitmap(/* length= */ 64); Bitmap bitmapLut = createIdentityLutBitmap(/* length= */ 64);
colorLutProcessor = colorLutShaderProgram =
SingleColorLut.createFromBitmap(bitmapLut) SingleColorLut.createFromBitmap(bitmapLut).toGlShaderProgram(context, /* useHdr= */ false);
.toGlTextureProcessor(context, /* useHdr= */ false); Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -183,14 +181,13 @@ public class SingleColorLutPixelTest {
public void drawFrame_identityLutFromHaldImage_leavesFrameUnchanged() throws Exception { public void drawFrame_identityLutFromHaldImage_leavesFrameUnchanged() throws Exception {
String testId = "drawFrame_identityLutFromHaldImage"; String testId = "drawFrame_identityLutFromHaldImage";
Bitmap bitmapLut = readBitmap(VERTICAL_HALD_IDENTITY_LUT); Bitmap bitmapLut = readBitmap(VERTICAL_HALD_IDENTITY_LUT);
colorLutProcessor = colorLutShaderProgram =
SingleColorLut.createFromBitmap(bitmapLut) SingleColorLut.createFromBitmap(bitmapLut).toGlShaderProgram(context, /* useHdr= */ false);
.toGlTextureProcessor(context, /* useHdr= */ false); Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -206,14 +203,14 @@ public class SingleColorLutPixelTest {
int length = 3; int length = 3;
int[][][] mapWhiteToGreen = createIdentityLutCube(length); int[][][] mapWhiteToGreen = createIdentityLutCube(length);
mapWhiteToGreen[length - 1][length - 1][length - 1] = Color.GREEN; mapWhiteToGreen[length - 1][length - 1][length - 1] = Color.GREEN;
colorLutProcessor = colorLutShaderProgram =
SingleColorLut.createFromCube(mapWhiteToGreen) SingleColorLut.createFromCube(mapWhiteToGreen)
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight); Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(LUT_MAP_WHITE_TO_GREEN_ASSET_PATH); Bitmap expectedBitmap = readBitmap(LUT_MAP_WHITE_TO_GREEN_ASSET_PATH);
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -227,14 +224,14 @@ public class SingleColorLutPixelTest {
public void drawFrame_applyInvertedLut_producesInvertedFrame() throws Exception { public void drawFrame_applyInvertedLut_producesInvertedFrame() throws Exception {
String testId = "drawFrame_applyInvertedLut"; String testId = "drawFrame_applyInvertedLut";
Bitmap invertedLutBitmap = readBitmap(VERTICAL_HALD_INVERTED_LUT); Bitmap invertedLutBitmap = readBitmap(VERTICAL_HALD_INVERTED_LUT);
colorLutProcessor = colorLutShaderProgram =
SingleColorLut.createFromBitmap(invertedLutBitmap) SingleColorLut.createFromBitmap(invertedLutBitmap)
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight); Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(INVERT_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(INVERT_PNG_ASSET_PATH);
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
@ -248,14 +245,14 @@ public class SingleColorLutPixelTest {
public void drawFrame_applyGrayscaleLut_producesGrayscaleFrame() throws Exception { public void drawFrame_applyGrayscaleLut_producesGrayscaleFrame() throws Exception {
String testId = "drawFrame_applyGrayscaleLut"; String testId = "drawFrame_applyGrayscaleLut";
Bitmap grayscaleLutBitmap = readBitmap(VERTICAL_HALD_GRAYSCALE_LUT); Bitmap grayscaleLutBitmap = readBitmap(VERTICAL_HALD_GRAYSCALE_LUT);
colorLutProcessor = colorLutShaderProgram =
SingleColorLut.createFromBitmap(grayscaleLutBitmap) SingleColorLut.createFromBitmap(grayscaleLutBitmap)
.toGlTextureProcessor(context, /* useHdr= */ false); .toGlShaderProgram(context, /* useHdr= */ false);
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight); Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = readBitmap(GRAYSCALE_PNG_ASSET_PATH); Bitmap expectedBitmap = readBitmap(GRAYSCALE_PNG_ASSET_PATH);
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0); colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
Bitmap actualBitmap = Bitmap actualBitmap =
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight()); createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());

View File

@ -19,48 +19,48 @@ import android.util.Pair;
import androidx.annotation.GuardedBy; import androidx.annotation.GuardedBy;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.effect.GlTextureProcessor.InputListener; import androidx.media3.effect.GlShaderProgram.InputListener;
import androidx.media3.effect.GlTextureProcessor.OutputListener; import androidx.media3.effect.GlShaderProgram.OutputListener;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Queue; import java.util.Queue;
/** /**
* Connects a producing and a consuming {@link GlTextureProcessor} instance. * Connects a producing and a consuming {@link GlShaderProgram} instance.
* *
* <p>This listener should be set as {@link InputListener} on the consuming {@link * <p>This listener should be set as {@link InputListener} on the consuming {@link GlShaderProgram}
* GlTextureProcessor} and as {@link OutputListener} on the producing {@link GlTextureProcessor}. * and as {@link OutputListener} on the producing {@link GlShaderProgram}.
*/ */
/* package */ final class ChainingGlTextureProcessorListener /* package */ final class ChainingGlShaderProgramListener
implements GlTextureProcessor.InputListener, GlTextureProcessor.OutputListener { implements GlShaderProgram.InputListener, GlShaderProgram.OutputListener {
private final GlTextureProcessor producingGlTextureProcessor; private final GlShaderProgram producingGlShaderProgram;
private final GlTextureProcessor consumingGlTextureProcessor; private final GlShaderProgram consumingGlShaderProgram;
private final FrameProcessingTaskExecutor frameProcessingTaskExecutor; private final FrameProcessingTaskExecutor frameProcessingTaskExecutor;
@GuardedBy("this") @GuardedBy("this")
private final Queue<Pair<TextureInfo, Long>> availableFrames; private final Queue<Pair<TextureInfo, Long>> availableFrames;
@GuardedBy("this") @GuardedBy("this")
private int consumingGlTextureProcessorInputCapacity; private int consumingGlShaderProgramInputCapacity;
/** /**
* Creates a new instance. * Creates a new instance.
* *
* @param producingGlTextureProcessor The {@link GlTextureProcessor} for which this listener will * @param producingGlShaderProgram The {@link GlShaderProgram} for which this listener will be set
* be set as {@link OutputListener}. * as {@link OutputListener}.
* @param consumingGlTextureProcessor The {@link GlTextureProcessor} for which this listener will * @param consumingGlShaderProgram The {@link GlShaderProgram} for which this listener will be set
* be set as {@link InputListener}. * as {@link InputListener}.
* @param frameProcessingTaskExecutor The {@link FrameProcessingTaskExecutor} that is used for * @param frameProcessingTaskExecutor The {@link FrameProcessingTaskExecutor} that is used for
* OpenGL calls. All calls to the producing/consuming {@link GlTextureProcessor} will be * OpenGL calls. All calls to the producing/consuming {@link GlShaderProgram} will be executed
* executed by the {@link FrameProcessingTaskExecutor}. The caller is responsible for * by the {@link FrameProcessingTaskExecutor}. The caller is responsible for releasing the
* releasing the {@link FrameProcessingTaskExecutor}. * {@link FrameProcessingTaskExecutor}.
*/ */
public ChainingGlTextureProcessorListener( public ChainingGlShaderProgramListener(
GlTextureProcessor producingGlTextureProcessor, GlShaderProgram producingGlShaderProgram,
GlTextureProcessor consumingGlTextureProcessor, GlShaderProgram consumingGlShaderProgram,
FrameProcessingTaskExecutor frameProcessingTaskExecutor) { FrameProcessingTaskExecutor frameProcessingTaskExecutor) {
this.producingGlTextureProcessor = producingGlTextureProcessor; this.producingGlShaderProgram = producingGlShaderProgram;
this.consumingGlTextureProcessor = consumingGlTextureProcessor; this.consumingGlShaderProgram = consumingGlShaderProgram;
this.frameProcessingTaskExecutor = frameProcessingTaskExecutor; this.frameProcessingTaskExecutor = frameProcessingTaskExecutor;
availableFrames = new ArrayDeque<>(); availableFrames = new ArrayDeque<>();
} }
@ -69,18 +69,17 @@ import java.util.Queue;
public synchronized void onReadyToAcceptInputFrame() { public synchronized void onReadyToAcceptInputFrame() {
@Nullable Pair<TextureInfo, Long> pendingFrame = availableFrames.poll(); @Nullable Pair<TextureInfo, Long> pendingFrame = availableFrames.poll();
if (pendingFrame == null) { if (pendingFrame == null) {
consumingGlTextureProcessorInputCapacity++; consumingGlShaderProgramInputCapacity++;
return; return;
} }
long presentationTimeUs = pendingFrame.second; long presentationTimeUs = pendingFrame.second;
if (presentationTimeUs == C.TIME_END_OF_SOURCE) { if (presentationTimeUs == C.TIME_END_OF_SOURCE) {
frameProcessingTaskExecutor.submit( frameProcessingTaskExecutor.submit(consumingGlShaderProgram::signalEndOfCurrentInputStream);
consumingGlTextureProcessor::signalEndOfCurrentInputStream);
} else { } else {
frameProcessingTaskExecutor.submit( frameProcessingTaskExecutor.submit(
() -> () ->
consumingGlTextureProcessor.queueInputFrame( consumingGlShaderProgram.queueInputFrame(
/* inputTexture= */ pendingFrame.first, presentationTimeUs)); /* inputTexture= */ pendingFrame.first, presentationTimeUs));
} }
} }
@ -88,25 +87,25 @@ import java.util.Queue;
@Override @Override
public void onInputFrameProcessed(TextureInfo inputTexture) { public void onInputFrameProcessed(TextureInfo inputTexture) {
frameProcessingTaskExecutor.submit( frameProcessingTaskExecutor.submit(
() -> producingGlTextureProcessor.releaseOutputFrame(inputTexture)); () -> producingGlShaderProgram.releaseOutputFrame(inputTexture));
} }
@Override @Override
public synchronized void onFlush() { public synchronized void onFlush() {
consumingGlTextureProcessorInputCapacity = 0; consumingGlShaderProgramInputCapacity = 0;
availableFrames.clear(); availableFrames.clear();
frameProcessingTaskExecutor.submit(producingGlTextureProcessor::flush); frameProcessingTaskExecutor.submit(producingGlShaderProgram::flush);
} }
@Override @Override
public synchronized void onOutputFrameAvailable( public synchronized void onOutputFrameAvailable(
TextureInfo outputTexture, long presentationTimeUs) { TextureInfo outputTexture, long presentationTimeUs) {
if (consumingGlTextureProcessorInputCapacity > 0) { if (consumingGlShaderProgramInputCapacity > 0) {
frameProcessingTaskExecutor.submit( frameProcessingTaskExecutor.submit(
() -> () ->
consumingGlTextureProcessor.queueInputFrame( consumingGlShaderProgram.queueInputFrame(
/* inputTexture= */ outputTexture, presentationTimeUs)); /* inputTexture= */ outputTexture, presentationTimeUs));
consumingGlTextureProcessorInputCapacity--; consumingGlShaderProgramInputCapacity--;
} else { } else {
availableFrames.add(new Pair<>(outputTexture, presentationTimeUs)); availableFrames.add(new Pair<>(outputTexture, presentationTimeUs));
} }
@ -117,8 +116,7 @@ import java.util.Queue;
if (!availableFrames.isEmpty()) { if (!availableFrames.isEmpty()) {
availableFrames.add(new Pair<>(TextureInfo.UNSET, C.TIME_END_OF_SOURCE)); availableFrames.add(new Pair<>(TextureInfo.UNSET, C.TIME_END_OF_SOURCE));
} else { } else {
frameProcessingTaskExecutor.submit( frameProcessingTaskExecutor.submit(consumingGlShaderProgram::signalEndOfCurrentInputStream);
consumingGlTextureProcessor::signalEndOfCurrentInputStream);
} }
} }
} }

View File

@ -44,8 +44,8 @@ public interface ColorLut extends GlEffect {
/** This method must be executed on the same thread as other GL commands. */ /** This method must be executed on the same thread as other GL commands. */
@Override @Override
@WorkerThread @WorkerThread
default SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr) default SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
throws FrameProcessingException { throws FrameProcessingException {
return new ColorLutProcessor(context, /* colorLut= */ this, useHdr); return new ColorLutShaderProgram(context, /* colorLut= */ this, useHdr);
} }
} }

View File

@ -27,7 +27,7 @@ import androidx.media3.common.util.Size;
import java.io.IOException; import java.io.IOException;
/** Applies a {@link ColorLut} to each frame in the fragment shader. */ /** Applies a {@link ColorLut} to each frame in the fragment shader. */
/* package */ final class ColorLutProcessor extends SingleFrameGlTextureProcessor { /* package */ final class ColorLutShaderProgram extends SingleFrameGlShaderProgram {
private static final String VERTEX_SHADER_PATH = "shaders/vertex_shader_transformation_es2.glsl"; private static final String VERTEX_SHADER_PATH = "shaders/vertex_shader_transformation_es2.glsl";
private static final String FRAGMENT_SHADER_PATH = "shaders/fragment_shader_lut_es2.glsl"; private static final String FRAGMENT_SHADER_PATH = "shaders/fragment_shader_lut_es2.glsl";
@ -43,11 +43,11 @@ import java.io.IOException;
* in linear RGB BT.2020. If {@code false}, colors will be in linear RGB BT.709. * in linear RGB BT.2020. If {@code false}, colors will be in linear RGB BT.709.
* @throws FrameProcessingException If a problem occurs while reading shader files. * @throws FrameProcessingException If a problem occurs while reading shader files.
*/ */
public ColorLutProcessor(Context context, ColorLut colorLut, boolean useHdr) public ColorLutShaderProgram(Context context, ColorLut colorLut, boolean useHdr)
throws FrameProcessingException { throws FrameProcessingException {
super(useHdr); super(useHdr);
// TODO(b/246315245): Add HDR support. // TODO(b/246315245): Add HDR support.
checkArgument(!useHdr, "LutProcessor does not support HDR colors."); checkArgument(!useHdr, "ColorLutShaderProgram does not support HDR colors.");
this.colorLut = colorLut; this.colorLut = colorLut;
try { try {

View File

@ -41,8 +41,8 @@ public class Contrast implements GlEffect {
} }
@Override @Override
public SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr) public SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
throws FrameProcessingException { throws FrameProcessingException {
return new ContrastProcessor(context, this, useHdr); return new ContrastShaderProgram(context, this, useHdr);
} }
} }

View File

@ -25,7 +25,7 @@ import androidx.media3.common.util.Size;
import java.io.IOException; import java.io.IOException;
/** Applies a {@link Contrast} to each frame in the fragment shader. */ /** Applies a {@link Contrast} to each frame in the fragment shader. */
/* package */ final class ContrastProcessor extends SingleFrameGlTextureProcessor { /* package */ final class ContrastShaderProgram extends SingleFrameGlShaderProgram {
private static final String VERTEX_SHADER_PATH = "shaders/vertex_shader_transformation_es2.glsl"; private static final String VERTEX_SHADER_PATH = "shaders/vertex_shader_transformation_es2.glsl";
private static final String FRAGMENT_SHADER_PATH = "shaders/fragment_shader_contrast_es2.glsl"; private static final String FRAGMENT_SHADER_PATH = "shaders/fragment_shader_contrast_es2.glsl";
@ -40,7 +40,7 @@ import java.io.IOException;
* in linear RGB BT.2020. If {@code false}, colors will be in linear RGB BT.709. * in linear RGB BT.2020. If {@code false}, colors will be in linear RGB BT.709.
* @throws FrameProcessingException If a problem occurs while reading shader files. * @throws FrameProcessingException If a problem occurs while reading shader files.
*/ */
public ContrastProcessor(Context context, Contrast contrastEffect, boolean useHdr) public ContrastShaderProgram(Context context, Contrast contrastEffect, boolean useHdr)
throws FrameProcessingException { throws FrameProcessingException {
super(useHdr); super(useHdr);
// Use 1.0001f to avoid division by zero issues. // Use 1.0001f to avoid division by zero issues.

View File

@ -16,12 +16,12 @@
package androidx.media3.effect; package androidx.media3.effect;
/** /**
* Interface for a {@link GlTextureProcessor} that samples from an external texture. * Interface for a {@link GlShaderProgram} that samples from an external texture.
* *
* <p>Use {@link #setTextureTransformMatrix(float[])} to provide the texture's transformation * <p>Use {@link #setTextureTransformMatrix(float[])} to provide the texture's transformation
* matrix. * matrix.
*/ */
/* package */ interface ExternalTextureProcessor extends GlTextureProcessor { /* package */ interface ExternalShaderProgram extends GlShaderProgram {
/** /**
* Sets the texture transform matrix for converting an external surface texture's coordinates to * Sets the texture transform matrix for converting an external surface texture's coordinates to

View File

@ -25,26 +25,26 @@ import androidx.media3.common.FrameInfo;
import androidx.media3.common.FrameProcessingException; import androidx.media3.common.FrameProcessingException;
import androidx.media3.common.FrameProcessor; import androidx.media3.common.FrameProcessor;
import androidx.media3.common.util.GlUtil; import androidx.media3.common.util.GlUtil;
import androidx.media3.effect.GlTextureProcessor.InputListener; import androidx.media3.effect.GlShaderProgram.InputListener;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
/** /**
* Forwards externally produced frames that become available via a {@link SurfaceTexture} to an * Forwards externally produced frames that become available via a {@link SurfaceTexture} to an
* {@link ExternalTextureProcessor} for consumption. * {@link ExternalShaderProgram} for consumption.
*/ */
/* package */ class ExternalTextureManager implements InputListener { /* package */ class ExternalTextureManager implements InputListener {
private final FrameProcessingTaskExecutor frameProcessingTaskExecutor; private final FrameProcessingTaskExecutor frameProcessingTaskExecutor;
private final ExternalTextureProcessor externalTextureProcessor; private final ExternalShaderProgram externalShaderProgram;
private final int externalTexId; private final int externalTexId;
private final SurfaceTexture surfaceTexture; private final SurfaceTexture surfaceTexture;
private final float[] textureTransformMatrix; private final float[] textureTransformMatrix;
private final Queue<FrameInfo> pendingFrames; private final Queue<FrameInfo> pendingFrames;
// Incremented on any thread, decremented on the GL thread only. // Incremented on any thread, decremented on the GL thread only.
private final AtomicInteger externalTextureProcessorInputCapacity; private final AtomicInteger externalShaderProgramInputCapacity;
// Counts the frames that are registered before flush but are made available after flush. // Counts the frames that are registered before flush but are made available after flush.
// Read and written only on GL thread. // Read and written only on GL thread.
private int numberOfFramesToDropOnBecomingAvailable; private int numberOfFramesToDropOnBecomingAvailable;
@ -66,16 +66,16 @@ import java.util.concurrent.atomic.AtomicInteger;
/** /**
* Creates a new instance. * Creates a new instance.
* *
* @param externalTextureProcessor The {@link ExternalTextureProcessor} for which this {@code * @param externalShaderProgram The {@link ExternalShaderProgram} for which this {@code
* ExternalTextureManager} will be set as the {@link InputListener}. * ExternalTextureManager} will be set as the {@link InputListener}.
* @param frameProcessingTaskExecutor The {@link FrameProcessingTaskExecutor}. * @param frameProcessingTaskExecutor The {@link FrameProcessingTaskExecutor}.
* @throws FrameProcessingException If a problem occurs while creating the external texture. * @throws FrameProcessingException If a problem occurs while creating the external texture.
*/ */
public ExternalTextureManager( public ExternalTextureManager(
ExternalTextureProcessor externalTextureProcessor, ExternalShaderProgram externalShaderProgram,
FrameProcessingTaskExecutor frameProcessingTaskExecutor) FrameProcessingTaskExecutor frameProcessingTaskExecutor)
throws FrameProcessingException { throws FrameProcessingException {
this.externalTextureProcessor = externalTextureProcessor; this.externalShaderProgram = externalShaderProgram;
this.frameProcessingTaskExecutor = frameProcessingTaskExecutor; this.frameProcessingTaskExecutor = frameProcessingTaskExecutor;
try { try {
externalTexId = GlUtil.createExternalTexture(); externalTexId = GlUtil.createExternalTexture();
@ -85,7 +85,7 @@ import java.util.concurrent.atomic.AtomicInteger;
surfaceTexture = new SurfaceTexture(externalTexId); surfaceTexture = new SurfaceTexture(externalTexId);
textureTransformMatrix = new float[16]; textureTransformMatrix = new float[16];
pendingFrames = new ConcurrentLinkedQueue<>(); pendingFrames = new ConcurrentLinkedQueue<>();
externalTextureProcessorInputCapacity = new AtomicInteger(); externalShaderProgramInputCapacity = new AtomicInteger();
previousStreamOffsetUs = C.TIME_UNSET; previousStreamOffsetUs = C.TIME_UNSET;
} }
@ -101,7 +101,7 @@ import java.util.concurrent.atomic.AtomicInteger;
maybeExecuteAfterFlushTask(); maybeExecuteAfterFlushTask();
} else { } else {
availableFrameCount++; availableFrameCount++;
maybeQueueFrameToExternalTextureProcessor(); maybeQueueFrameToExternalShaderProgram();
} }
})); }));
return surfaceTexture; return surfaceTexture;
@ -111,8 +111,8 @@ import java.util.concurrent.atomic.AtomicInteger;
public void onReadyToAcceptInputFrame() { public void onReadyToAcceptInputFrame() {
frameProcessingTaskExecutor.submit( frameProcessingTaskExecutor.submit(
() -> { () -> {
externalTextureProcessorInputCapacity.incrementAndGet(); externalShaderProgramInputCapacity.incrementAndGet();
maybeQueueFrameToExternalTextureProcessor(); maybeQueueFrameToExternalShaderProgram();
}); });
} }
@ -121,7 +121,7 @@ import java.util.concurrent.atomic.AtomicInteger;
frameProcessingTaskExecutor.submit( frameProcessingTaskExecutor.submit(
() -> { () -> {
currentFrame = null; currentFrame = null;
maybeQueueFrameToExternalTextureProcessor(); maybeQueueFrameToExternalShaderProgram();
}); });
} }
@ -148,7 +148,7 @@ import java.util.concurrent.atomic.AtomicInteger;
/** /**
* Returns the number of {@linkplain #registerInputFrame(FrameInfo) registered} frames that have * Returns the number of {@linkplain #registerInputFrame(FrameInfo) registered} frames that have
* not been sent to the downstream {@link ExternalTextureProcessor} yet. * not been sent to the downstream {@link ExternalShaderProgram} yet.
* *
* <p>Can be called on any thread. * <p>Can be called on any thread.
*/ */
@ -166,7 +166,7 @@ import java.util.concurrent.atomic.AtomicInteger;
() -> { () -> {
inputStreamEnded = true; inputStreamEnded = true;
if (pendingFrames.isEmpty() && currentFrame == null) { if (pendingFrames.isEmpty() && currentFrame == null) {
externalTextureProcessor.signalEndOfCurrentInputStream(); externalShaderProgram.signalEndOfCurrentInputStream();
} }
}); });
} }
@ -183,7 +183,7 @@ import java.util.concurrent.atomic.AtomicInteger;
availableFrameCount--; availableFrameCount--;
surfaceTexture.updateTexImage(); surfaceTexture.updateTexImage();
} }
externalTextureProcessorInputCapacity.set(0); externalShaderProgramInputCapacity.set(0);
currentFrame = null; currentFrame = null;
pendingFrames.clear(); pendingFrames.clear();
maybeExecuteAfterFlushTask(); maybeExecuteAfterFlushTask();
@ -197,8 +197,8 @@ import java.util.concurrent.atomic.AtomicInteger;
} }
@WorkerThread @WorkerThread
private void maybeQueueFrameToExternalTextureProcessor() { private void maybeQueueFrameToExternalShaderProgram() {
if (externalTextureProcessorInputCapacity.get() == 0 if (externalShaderProgramInputCapacity.get() == 0
|| availableFrameCount == 0 || availableFrameCount == 0
|| currentFrame != null) { || currentFrame != null) {
return; return;
@ -209,28 +209,28 @@ import java.util.concurrent.atomic.AtomicInteger;
this.currentFrame = pendingFrames.peek(); this.currentFrame = pendingFrames.peek();
FrameInfo currentFrame = checkStateNotNull(this.currentFrame); FrameInfo currentFrame = checkStateNotNull(this.currentFrame);
externalTextureProcessorInputCapacity.decrementAndGet(); externalShaderProgramInputCapacity.decrementAndGet();
surfaceTexture.getTransformMatrix(textureTransformMatrix); surfaceTexture.getTransformMatrix(textureTransformMatrix);
externalTextureProcessor.setTextureTransformMatrix(textureTransformMatrix); externalShaderProgram.setTextureTransformMatrix(textureTransformMatrix);
long frameTimeNs = surfaceTexture.getTimestamp(); long frameTimeNs = surfaceTexture.getTimestamp();
long offsetToAddUs = currentFrame.offsetToAddUs; long offsetToAddUs = currentFrame.offsetToAddUs;
long streamOffsetUs = currentFrame.streamOffsetUs; long streamOffsetUs = currentFrame.streamOffsetUs;
if (streamOffsetUs != previousStreamOffsetUs) { if (streamOffsetUs != previousStreamOffsetUs) {
if (previousStreamOffsetUs != C.TIME_UNSET) { if (previousStreamOffsetUs != C.TIME_UNSET) {
externalTextureProcessor.signalEndOfCurrentInputStream(); externalShaderProgram.signalEndOfCurrentInputStream();
} }
previousStreamOffsetUs = streamOffsetUs; previousStreamOffsetUs = streamOffsetUs;
} }
// Correct the presentation time so that processors don't see the stream offset. // Correct the presentation time so that GlShaderPrograms don't see the stream offset.
long presentationTimeUs = (frameTimeNs / 1000) + offsetToAddUs - streamOffsetUs; long presentationTimeUs = (frameTimeNs / 1000) + offsetToAddUs - streamOffsetUs;
externalTextureProcessor.queueInputFrame( externalShaderProgram.queueInputFrame(
new TextureInfo( new TextureInfo(
externalTexId, /* fboId= */ C.INDEX_UNSET, currentFrame.width, currentFrame.height), externalTexId, /* fboId= */ C.INDEX_UNSET, currentFrame.width, currentFrame.height),
presentationTimeUs); presentationTimeUs);
checkStateNotNull(pendingFrames.remove()); checkStateNotNull(pendingFrames.remove());
if (inputStreamEnded && pendingFrames.isEmpty()) { if (inputStreamEnded && pendingFrames.isEmpty()) {
externalTextureProcessor.signalEndOfCurrentInputStream(); externalShaderProgram.signalEndOfCurrentInputStream();
} }
} }
} }

View File

@ -51,19 +51,19 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** /**
* Wrapper around a {@link GlTextureProcessor} that writes to the provided output surface and * Wrapper around a {@link GlShaderProgram} that writes to the provided output surface and optional
* optional debug surface view. * debug surface view.
* *
* <p>The wrapped {@link GlTextureProcessor} applies the {@link GlMatrixTransformation} and {@link * <p>The wrapped {@link GlShaderProgram} applies the {@link GlMatrixTransformation} and {@link
* RgbMatrix} instances passed to the constructor, followed by any transformations needed to convert * RgbMatrix} instances passed to the constructor, followed by any transformations needed to convert
* the frames to the dimensions specified by the provided {@link SurfaceInfo}. * the frames to the dimensions specified by the provided {@link SurfaceInfo}.
* *
* <p>This wrapper is used for the final {@link GlTextureProcessor} instance in the chain of {@link * <p>This wrapper is used for the final {@link GlShaderProgram} instance in the chain of {@link
* GlTextureProcessor} instances used by {@link FrameProcessor}. * GlShaderProgram} instances used by {@link FrameProcessor}.
*/ */
/* package */ final class FinalMatrixTextureProcessorWrapper implements ExternalTextureProcessor { /* package */ final class FinalMatrixShaderProgramWrapper implements ExternalShaderProgram {
private static final String TAG = "FinalProcessorWrapper"; private static final String TAG = "FinalShaderWrapper";
private final Context context; private final Context context;
private final ImmutableList<GlMatrixTransformation> matrixTransformations; private final ImmutableList<GlMatrixTransformation> matrixTransformations;
@ -83,7 +83,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private int inputWidth; private int inputWidth;
private int inputHeight; private int inputHeight;
@Nullable private MatrixTextureProcessor matrixTextureProcessor; @Nullable private MatrixShaderProgram matrixShaderProgram;
@Nullable private SurfaceViewWrapper debugSurfaceViewWrapper; @Nullable private SurfaceViewWrapper debugSurfaceViewWrapper;
private InputListener inputListener; private InputListener inputListener;
private @MonotonicNonNull Size outputSizeBeforeSurfaceTransformation; private @MonotonicNonNull Size outputSizeBeforeSurfaceTransformation;
@ -99,7 +99,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Nullable @Nullable
private EGLSurface outputEglSurface; private EGLSurface outputEglSurface;
public FinalMatrixTextureProcessorWrapper( public FinalMatrixShaderProgramWrapper(
Context context, Context context,
EGLDisplay eglDisplay, EGLDisplay eglDisplay,
EGLContext eglContext, EGLContext eglContext,
@ -167,7 +167,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override @Override
public void releaseOutputFrame(TextureInfo outputTexture) { public void releaseOutputFrame(TextureInfo outputTexture) {
// The final texture processor writes to a surface so there is no texture to release. // The final shader program writes to a surface so there is no texture to release.
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -195,8 +195,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public void flush() { public void flush() {
// Drops all frames that aren't released yet. // Drops all frames that aren't released yet.
availableFrames.clear(); availableFrames.clear();
if (matrixTextureProcessor != null) { if (matrixShaderProgram != null) {
matrixTextureProcessor.flush(); matrixShaderProgram.flush();
} }
inputListener.onFlush(); inputListener.onFlush();
inputListener.onReadyToAcceptInputFrame(); inputListener.onReadyToAcceptInputFrame();
@ -205,8 +205,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override @Override
@WorkerThread @WorkerThread
public synchronized void release() throws FrameProcessingException { public synchronized void release() throws FrameProcessingException {
if (matrixTextureProcessor != null) { if (matrixShaderProgram != null) {
matrixTextureProcessor.release(); matrixShaderProgram.release();
} }
try { try {
GlUtil.destroyEglSurface(eglDisplay, outputEglSurface); GlUtil.destroyEglSurface(eglDisplay, outputEglSurface);
@ -224,8 +224,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/* destPost= */ 0, /* destPost= */ 0,
/* length= */ textureTransformMatrix.length); /* length= */ textureTransformMatrix.length);
if (matrixTextureProcessor != null) { if (matrixShaderProgram != null) {
matrixTextureProcessor.setTextureTransformMatrix(textureTransformMatrix); matrixShaderProgram.setTextureTransformMatrix(textureTransformMatrix);
} }
} }
@ -295,7 +295,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
EGLSurface outputEglSurface = this.outputEglSurface; EGLSurface outputEglSurface = this.outputEglSurface;
SurfaceInfo outputSurfaceInfo = this.outputSurfaceInfo; SurfaceInfo outputSurfaceInfo = this.outputSurfaceInfo;
MatrixTextureProcessor matrixTextureProcessor = this.matrixTextureProcessor; MatrixShaderProgram matrixShaderProgram = this.matrixShaderProgram;
GlUtil.focusEglSurface( GlUtil.focusEglSurface(
eglDisplay, eglDisplay,
@ -304,7 +304,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
outputSurfaceInfo.width, outputSurfaceInfo.width,
outputSurfaceInfo.height); outputSurfaceInfo.height);
GlUtil.clearOutputFrame(); GlUtil.clearOutputFrame();
matrixTextureProcessor.drawFrame(inputTexture.texId, presentationTimeUs); matrixShaderProgram.drawFrame(inputTexture.texId, presentationTimeUs);
EGLExt.eglPresentationTimeANDROID( EGLExt.eglPresentationTimeANDROID(
eglDisplay, eglDisplay,
@ -316,7 +316,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
@EnsuresNonNullIf( @EnsuresNonNullIf(
expression = {"outputSurfaceInfo", "outputEglSurface", "matrixTextureProcessor"}, expression = {"outputSurfaceInfo", "outputEglSurface", "matrixShaderProgram"},
result = true) result = true)
private synchronized boolean ensureConfigured(int inputWidth, int inputHeight) private synchronized boolean ensureConfigured(int inputWidth, int inputHeight)
throws FrameProcessingException, GlUtil.GlException { throws FrameProcessingException, GlUtil.GlException {
@ -340,9 +340,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
if (outputSurfaceInfo == null) { if (outputSurfaceInfo == null) {
if (matrixTextureProcessor != null) { if (matrixShaderProgram != null) {
matrixTextureProcessor.release(); matrixShaderProgram.release();
matrixTextureProcessor = null; matrixShaderProgram = null;
} }
GlUtil.destroyEglSurface(eglDisplay, outputEglSurface); GlUtil.destroyEglSurface(eglDisplay, outputEglSurface);
outputEglSurface = null; outputEglSurface = null;
@ -372,13 +372,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
this.debugSurfaceView = debugSurfaceView; this.debugSurfaceView = debugSurfaceView;
} }
if (matrixTextureProcessor != null && outputSizeOrRotationChanged) { if (matrixShaderProgram != null && outputSizeOrRotationChanged) {
matrixTextureProcessor.release(); matrixShaderProgram.release();
matrixTextureProcessor = null; matrixShaderProgram = null;
outputSizeOrRotationChanged = false; outputSizeOrRotationChanged = false;
} }
if (matrixTextureProcessor == null) { if (matrixShaderProgram == null) {
matrixTextureProcessor = createMatrixTextureProcessorForOutputSurface(outputSurfaceInfo); matrixShaderProgram = createMatrixShaderProgramForOutputSurface(outputSurfaceInfo);
} }
this.outputSurfaceInfo = outputSurfaceInfo; this.outputSurfaceInfo = outputSurfaceInfo;
@ -386,7 +386,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
return true; return true;
} }
private MatrixTextureProcessor createMatrixTextureProcessorForOutputSurface( private MatrixShaderProgram createMatrixShaderProgramForOutputSurface(
SurfaceInfo outputSurfaceInfo) throws FrameProcessingException { SurfaceInfo outputSurfaceInfo) throws FrameProcessingException {
ImmutableList.Builder<GlMatrixTransformation> matrixTransformationListBuilder = ImmutableList.Builder<GlMatrixTransformation> matrixTransformationListBuilder =
new ImmutableList.Builder<GlMatrixTransformation>().addAll(matrixTransformations); new ImmutableList.Builder<GlMatrixTransformation>().addAll(matrixTransformations);
@ -400,46 +400,46 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
Presentation.createForWidthAndHeight( Presentation.createForWidthAndHeight(
outputSurfaceInfo.width, outputSurfaceInfo.height, Presentation.LAYOUT_SCALE_TO_FIT)); outputSurfaceInfo.width, outputSurfaceInfo.height, Presentation.LAYOUT_SCALE_TO_FIT));
MatrixTextureProcessor matrixTextureProcessor; MatrixShaderProgram matrixShaderProgram;
ImmutableList<GlMatrixTransformation> expandedMatrixTransformations = ImmutableList<GlMatrixTransformation> expandedMatrixTransformations =
matrixTransformationListBuilder.build(); matrixTransformationListBuilder.build();
if (sampleFromExternalTexture) { if (sampleFromExternalTexture) {
matrixTextureProcessor = matrixShaderProgram =
MatrixTextureProcessor.createWithExternalSampler( MatrixShaderProgram.createWithExternalSampler(
context, context,
expandedMatrixTransformations, expandedMatrixTransformations,
rgbMatrices, rgbMatrices,
/* inputColorInfo= */ inputColorInfo, /* inputColorInfo= */ inputColorInfo,
/* outputColorInfo= */ outputColorInfo); /* outputColorInfo= */ outputColorInfo);
} else { } else {
matrixTextureProcessor = matrixShaderProgram =
MatrixTextureProcessor.createApplyingOetf( MatrixShaderProgram.createApplyingOetf(
context, expandedMatrixTransformations, rgbMatrices, outputColorInfo); context, expandedMatrixTransformations, rgbMatrices, outputColorInfo);
} }
matrixTextureProcessor.setTextureTransformMatrix(textureTransformMatrix); matrixShaderProgram.setTextureTransformMatrix(textureTransformMatrix);
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight); Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
checkState(outputSize.getWidth() == outputSurfaceInfo.width); checkState(outputSize.getWidth() == outputSurfaceInfo.width);
checkState(outputSize.getHeight() == outputSurfaceInfo.height); checkState(outputSize.getHeight() == outputSurfaceInfo.height);
return matrixTextureProcessor; return matrixShaderProgram;
} }
private void maybeRenderFrameToDebugSurface(TextureInfo inputTexture, long presentationTimeUs) { private void maybeRenderFrameToDebugSurface(TextureInfo inputTexture, long presentationTimeUs) {
if (debugSurfaceViewWrapper == null || this.matrixTextureProcessor == null) { if (debugSurfaceViewWrapper == null || this.matrixShaderProgram == null) {
return; return;
} }
MatrixTextureProcessor matrixTextureProcessor = this.matrixTextureProcessor; MatrixShaderProgram matrixShaderProgram = this.matrixShaderProgram;
try { try {
debugSurfaceViewWrapper.maybeRenderToSurfaceView( debugSurfaceViewWrapper.maybeRenderToSurfaceView(
() -> { () -> {
GlUtil.clearOutputFrame(); GlUtil.clearOutputFrame();
@C.ColorTransfer @C.ColorTransfer
int configuredColorTransfer = matrixTextureProcessor.getOutputColorTransfer(); int configuredColorTransfer = matrixShaderProgram.getOutputColorTransfer();
matrixTextureProcessor.setOutputColorTransfer( matrixShaderProgram.setOutputColorTransfer(
checkNotNull(debugSurfaceViewWrapper).outputColorTransfer); checkNotNull(debugSurfaceViewWrapper).outputColorTransfer);
matrixTextureProcessor.drawFrame(inputTexture.texId, presentationTimeUs); matrixShaderProgram.drawFrame(inputTexture.texId, presentationTimeUs);
matrixTextureProcessor.setOutputColorTransfer(configuredColorTransfer); matrixShaderProgram.setOutputColorTransfer(configuredColorTransfer);
}); });
} catch (FrameProcessingException | GlUtil.GlException e) { } catch (FrameProcessingException | GlUtil.GlException e) {
Log.d(TAG, "Error rendering to debug preview", e); Log.d(TAG, "Error rendering to debug preview", e);

View File

@ -50,8 +50,8 @@ public class FrameCache implements GlEffect {
} }
@Override @Override
public GlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr) public GlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
throws FrameProcessingException { throws FrameProcessingException {
return new FrameCacheTextureProcessor(context, capacity, useHdr); return new FrameCacheShaderProgram(context, capacity, useHdr);
} }
} }

View File

@ -35,7 +35,7 @@ import java.util.concurrent.Executor;
* *
* <p>Implements {@link FrameCache}. * <p>Implements {@link FrameCache}.
*/ */
/* package */ class FrameCacheTextureProcessor implements GlTextureProcessor { /* package */ class FrameCacheShaderProgram implements GlShaderProgram {
private static final String VERTEX_SHADER_TRANSFORMATION_ES2_PATH = private static final String VERTEX_SHADER_TRANSFORMATION_ES2_PATH =
"shaders/vertex_shader_transformation_es2.glsl"; "shaders/vertex_shader_transformation_es2.glsl";
private static final String FRAGMENT_SHADER_TRANSFORMATION_ES2_PATH = private static final String FRAGMENT_SHADER_TRANSFORMATION_ES2_PATH =
@ -53,7 +53,7 @@ import java.util.concurrent.Executor;
private Executor errorListenerExecutor; private Executor errorListenerExecutor;
/** Creates a new instance. */ /** Creates a new instance. */
public FrameCacheTextureProcessor(Context context, int capacity, boolean useHdr) public FrameCacheShaderProgram(Context context, int capacity, boolean useHdr)
throws FrameProcessingException { throws FrameProcessingException {
freeOutputTextures = new ArrayDeque<>(); freeOutputTextures = new ArrayDeque<>();
inUseOutputTextures = new ArrayDeque<>(); inUseOutputTextures = new ArrayDeque<>();

View File

@ -21,24 +21,23 @@ import androidx.media3.common.FrameProcessingException;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
/** /**
* Interface for a video frame effect with a {@link GlTextureProcessor} implementation. * Interface for a video frame effect with a {@link GlShaderProgram} implementation.
* *
* <p>Implementations contain information specifying the effect and can be {@linkplain * <p>Implementations contain information specifying the effect and can be {@linkplain
* #toGlTextureProcessor(Context, boolean) converted} to a {@link GlTextureProcessor} which applies * #toGlShaderProgram(Context, boolean) converted} to a {@link GlShaderProgram} which applies the
* the effect. * effect.
*/ */
@UnstableApi @UnstableApi
public interface GlEffect extends Effect { public interface GlEffect extends Effect {
/** /**
* Returns a {@link GlTextureProcessor} that applies the effect. * Returns a {@link GlShaderProgram} that applies the effect.
* *
* @param context A {@link Context}. * @param context A {@link Context}.
* @param useHdr Whether input textures come from an HDR source. If {@code true}, colors will be * @param useHdr Whether input textures come from an HDR source. If {@code true}, colors will be
* in linear RGB BT.2020. If {@code false}, colors will be in linear RGB BT.709. * in linear RGB BT.2020. If {@code false}, colors will be in linear RGB BT.709.
* @throws FrameProcessingException If an error occurs while creating the {@link * @throws FrameProcessingException If an error occurs while creating the {@link GlShaderProgram}.
* GlTextureProcessor}.
*/ */
GlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr) GlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
throws FrameProcessingException; throws FrameProcessingException;
} }

View File

@ -152,8 +152,8 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
/** /**
* Creates the OpenGL context, surfaces, textures, and frame buffers, initializes {@link * Creates the OpenGL context, surfaces, textures, and frame buffers, initializes {@link
* GlTextureProcessor} instances corresponding to the {@link GlEffect} instances, and returns a * GlShaderProgram} instances corresponding to the {@link GlEffect} instances, and returns a new
* new {@code GlEffectsFrameProcessor}. * {@code GlEffectsFrameProcessor}.
* *
* <p>All {@link Effect} instances must be {@link GlEffect} instances. * <p>All {@link Effect} instances must be {@link GlEffect} instances.
* *
@ -199,8 +199,8 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
} }
} }
ImmutableList<GlTextureProcessor> textureProcessors = ImmutableList<GlShaderProgram> shaderPrograms =
getGlTextureProcessorsForGlEffects( getGlShaderProgramsForGlEffects(
context, context,
effects, effects,
eglDisplay, eglDisplay,
@ -213,29 +213,29 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
listener); listener);
FrameProcessingTaskExecutor frameProcessingTaskExecutor = FrameProcessingTaskExecutor frameProcessingTaskExecutor =
new FrameProcessingTaskExecutor(singleThreadExecutorService, listener); new FrameProcessingTaskExecutor(singleThreadExecutorService, listener);
chainTextureProcessorsWithListeners( chainShaderProgramsWithListeners(
textureProcessors, frameProcessingTaskExecutor, listener, executor); shaderPrograms, frameProcessingTaskExecutor, listener, executor);
return new GlEffectsFrameProcessor( return new GlEffectsFrameProcessor(
eglDisplay, eglDisplay,
eglContext, eglContext,
frameProcessingTaskExecutor, frameProcessingTaskExecutor,
textureProcessors, shaderPrograms,
releaseFramesAutomatically); releaseFramesAutomatically);
} }
/** /**
* Combines consecutive {@link GlMatrixTransformation} and {@link RgbMatrix} instances into a * Combines consecutive {@link GlMatrixTransformation} and {@link RgbMatrix} instances into a
* single {@link MatrixTextureProcessor} and converts all other {@link GlEffect} instances to * single {@link MatrixShaderProgram} and converts all other {@link GlEffect} instances to
* separate {@link GlTextureProcessor} instances. * separate {@link GlShaderProgram} instances.
* *
* <p>All {@link Effect} instances must be {@link GlEffect} instances. * <p>All {@link Effect} instances must be {@link GlEffect} instances.
* *
* @return A non-empty list of {@link GlTextureProcessor} instances to apply in the given order. * @return A non-empty list of {@link GlShaderProgram} instances to apply in the given order. The
* The first is an {@link ExternalTextureProcessor} and the last is a {@link * first is an {@link ExternalShaderProgram} and the last is a {@link
* FinalMatrixTextureProcessorWrapper}. * FinalMatrixShaderProgramWrapper}.
*/ */
private static ImmutableList<GlTextureProcessor> getGlTextureProcessorsForGlEffects( private static ImmutableList<GlShaderProgram> getGlShaderProgramsForGlEffects(
Context context, Context context,
List<Effect> effects, List<Effect> effects,
EGLDisplay eglDisplay, EGLDisplay eglDisplay,
@ -247,8 +247,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
Executor executor, Executor executor,
Listener listener) Listener listener)
throws FrameProcessingException { throws FrameProcessingException {
ImmutableList.Builder<GlTextureProcessor> textureProcessorListBuilder = ImmutableList.Builder<GlShaderProgram> shaderProgramListBuilder = new ImmutableList.Builder<>();
new ImmutableList.Builder<>();
ImmutableList.Builder<GlMatrixTransformation> matrixTransformationListBuilder = ImmutableList.Builder<GlMatrixTransformation> matrixTransformationListBuilder =
new ImmutableList.Builder<>(); new ImmutableList.Builder<>();
ImmutableList.Builder<RgbMatrix> rgbMatrixListBuilder = new ImmutableList.Builder<>(); ImmutableList.Builder<RgbMatrix> rgbMatrixListBuilder = new ImmutableList.Builder<>();
@ -277,30 +276,30 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
ImmutableList<RgbMatrix> rgbMatrices = rgbMatrixListBuilder.build(); ImmutableList<RgbMatrix> rgbMatrices = rgbMatrixListBuilder.build();
boolean isOutputTransferHdr = ColorInfo.isTransferHdr(outputColorInfo); boolean isOutputTransferHdr = ColorInfo.isTransferHdr(outputColorInfo);
if (!matrixTransformations.isEmpty() || !rgbMatrices.isEmpty() || sampleFromExternalTexture) { if (!matrixTransformations.isEmpty() || !rgbMatrices.isEmpty() || sampleFromExternalTexture) {
MatrixTextureProcessor matrixTextureProcessor; MatrixShaderProgram matrixShaderProgram;
if (sampleFromExternalTexture) { if (sampleFromExternalTexture) {
matrixTextureProcessor = matrixShaderProgram =
MatrixTextureProcessor.createWithExternalSampler( MatrixShaderProgram.createWithExternalSampler(
context, context,
matrixTransformations, matrixTransformations,
rgbMatrices, rgbMatrices,
/* inputColorInfo= */ inputColorInfo, /* inputColorInfo= */ inputColorInfo,
/* outputColorInfo= */ linearColorInfo); /* outputColorInfo= */ linearColorInfo);
} else { } else {
matrixTextureProcessor = matrixShaderProgram =
MatrixTextureProcessor.create( MatrixShaderProgram.create(
context, matrixTransformations, rgbMatrices, isOutputTransferHdr); context, matrixTransformations, rgbMatrices, isOutputTransferHdr);
} }
textureProcessorListBuilder.add(matrixTextureProcessor); shaderProgramListBuilder.add(matrixShaderProgram);
matrixTransformationListBuilder = new ImmutableList.Builder<>(); matrixTransformationListBuilder = new ImmutableList.Builder<>();
rgbMatrixListBuilder = new ImmutableList.Builder<>(); rgbMatrixListBuilder = new ImmutableList.Builder<>();
sampleFromExternalTexture = false; sampleFromExternalTexture = false;
} }
textureProcessorListBuilder.add(glEffect.toGlTextureProcessor(context, isOutputTransferHdr)); shaderProgramListBuilder.add(glEffect.toGlShaderProgram(context, isOutputTransferHdr));
} }
textureProcessorListBuilder.add( shaderProgramListBuilder.add(
new FinalMatrixTextureProcessorWrapper( new FinalMatrixShaderProgramWrapper(
context, context,
eglDisplay, eglDisplay,
eglContext, eglContext,
@ -313,30 +312,28 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
releaseFramesAutomatically, releaseFramesAutomatically,
executor, executor,
listener)); listener));
return textureProcessorListBuilder.build(); return shaderProgramListBuilder.build();
} }
/** /**
* Chains the given {@link GlTextureProcessor} instances using {@link * Chains the given {@link GlShaderProgram} instances using {@link
* ChainingGlTextureProcessorListener} instances. * ChainingGlShaderProgramListener} instances.
*/ */
private static void chainTextureProcessorsWithListeners( private static void chainShaderProgramsWithListeners(
ImmutableList<GlTextureProcessor> textureProcessors, ImmutableList<GlShaderProgram> shaderPrograms,
FrameProcessingTaskExecutor frameProcessingTaskExecutor, FrameProcessingTaskExecutor frameProcessingTaskExecutor,
Listener frameProcessorListener, Listener frameProcessorListener,
Executor frameProcessorListenerExecutor) { Executor frameProcessorListenerExecutor) {
for (int i = 0; i < textureProcessors.size() - 1; i++) { for (int i = 0; i < shaderPrograms.size() - 1; i++) {
GlTextureProcessor producingGlTextureProcessor = textureProcessors.get(i); GlShaderProgram producingGlShaderProgram = shaderPrograms.get(i);
GlTextureProcessor consumingGlTextureProcessor = textureProcessors.get(i + 1); GlShaderProgram consumingGlShaderProgram = shaderPrograms.get(i + 1);
ChainingGlTextureProcessorListener chainingGlTextureProcessorListener = ChainingGlShaderProgramListener chainingGlShaderProgramListener =
new ChainingGlTextureProcessorListener( new ChainingGlShaderProgramListener(
producingGlTextureProcessor, producingGlShaderProgram, consumingGlShaderProgram, frameProcessingTaskExecutor);
consumingGlTextureProcessor, producingGlShaderProgram.setOutputListener(chainingGlShaderProgramListener);
frameProcessingTaskExecutor); producingGlShaderProgram.setErrorListener(
producingGlTextureProcessor.setOutputListener(chainingGlTextureProcessorListener);
producingGlTextureProcessor.setErrorListener(
frameProcessorListenerExecutor, frameProcessorListener::onFrameProcessingError); frameProcessorListenerExecutor, frameProcessorListener::onFrameProcessingError);
consumingGlTextureProcessor.setInputListener(chainingGlTextureProcessorListener); consumingGlShaderProgram.setInputListener(chainingGlShaderProgramListener);
} }
} }
@ -349,8 +346,8 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
private final ExternalTextureManager inputExternalTextureManager; private final ExternalTextureManager inputExternalTextureManager;
private final Surface inputSurface; private final Surface inputSurface;
private final boolean releaseFramesAutomatically; private final boolean releaseFramesAutomatically;
private final FinalMatrixTextureProcessorWrapper finalTextureProcessorWrapper; private final FinalMatrixShaderProgramWrapper finalShaderProgramWrapper;
private final ImmutableList<GlTextureProcessor> allTextureProcessors; private final ImmutableList<GlShaderProgram> allShaderPrograms;
/** /**
* Offset compared to original media presentation time that has been added to incoming frame * Offset compared to original media presentation time that has been added to incoming frame
@ -365,7 +362,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
EGLDisplay eglDisplay, EGLDisplay eglDisplay,
EGLContext eglContext, EGLContext eglContext,
FrameProcessingTaskExecutor frameProcessingTaskExecutor, FrameProcessingTaskExecutor frameProcessingTaskExecutor,
ImmutableList<GlTextureProcessor> textureProcessors, ImmutableList<GlShaderProgram> shaderPrograms,
boolean releaseFramesAutomatically) boolean releaseFramesAutomatically)
throws FrameProcessingException { throws FrameProcessingException {
@ -374,17 +371,17 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
this.frameProcessingTaskExecutor = frameProcessingTaskExecutor; this.frameProcessingTaskExecutor = frameProcessingTaskExecutor;
this.releaseFramesAutomatically = releaseFramesAutomatically; this.releaseFramesAutomatically = releaseFramesAutomatically;
checkState(!textureProcessors.isEmpty()); checkState(!shaderPrograms.isEmpty());
checkState(textureProcessors.get(0) instanceof ExternalTextureProcessor); checkState(shaderPrograms.get(0) instanceof ExternalShaderProgram);
checkState(getLast(textureProcessors) instanceof FinalMatrixTextureProcessorWrapper); checkState(getLast(shaderPrograms) instanceof FinalMatrixShaderProgramWrapper);
ExternalTextureProcessor inputExternalTextureProcessor = ExternalShaderProgram inputExternalShaderProgram =
(ExternalTextureProcessor) textureProcessors.get(0); (ExternalShaderProgram) shaderPrograms.get(0);
inputExternalTextureManager = inputExternalTextureManager =
new ExternalTextureManager(inputExternalTextureProcessor, frameProcessingTaskExecutor); new ExternalTextureManager(inputExternalShaderProgram, frameProcessingTaskExecutor);
inputExternalTextureProcessor.setInputListener(inputExternalTextureManager); inputExternalShaderProgram.setInputListener(inputExternalTextureManager);
inputSurface = new Surface(inputExternalTextureManager.getSurfaceTexture()); inputSurface = new Surface(inputExternalTextureManager.getSurfaceTexture());
finalTextureProcessorWrapper = (FinalMatrixTextureProcessorWrapper) getLast(textureProcessors); finalShaderProgramWrapper = (FinalMatrixShaderProgramWrapper) getLast(shaderPrograms);
allTextureProcessors = textureProcessors; allShaderPrograms = shaderPrograms;
previousStreamOffsetUs = C.TIME_UNSET; previousStreamOffsetUs = C.TIME_UNSET;
} }
@ -423,7 +420,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
nextInputFrameInfo = adjustForPixelWidthHeightRatio(inputFrameInfo); nextInputFrameInfo = adjustForPixelWidthHeightRatio(inputFrameInfo);
if (nextInputFrameInfo.streamOffsetUs != previousStreamOffsetUs) { if (nextInputFrameInfo.streamOffsetUs != previousStreamOffsetUs) {
finalTextureProcessorWrapper.appendStream(nextInputFrameInfo.streamOffsetUs); finalShaderProgramWrapper.appendStream(nextInputFrameInfo.streamOffsetUs);
previousStreamOffsetUs = nextInputFrameInfo.streamOffsetUs; previousStreamOffsetUs = nextInputFrameInfo.streamOffsetUs;
} }
} }
@ -444,7 +441,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
@Override @Override
public void setOutputSurfaceInfo(@Nullable SurfaceInfo outputSurfaceInfo) { public void setOutputSurfaceInfo(@Nullable SurfaceInfo outputSurfaceInfo) {
finalTextureProcessorWrapper.setOutputSurfaceInfo(outputSurfaceInfo); finalShaderProgramWrapper.setOutputSurfaceInfo(outputSurfaceInfo);
} }
@Override @Override
@ -453,7 +450,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
!releaseFramesAutomatically, !releaseFramesAutomatically,
"Calling this method is not allowed when releaseFramesAutomatically is enabled"); "Calling this method is not allowed when releaseFramesAutomatically is enabled");
frameProcessingTaskExecutor.submitWithHighPriority( frameProcessingTaskExecutor.submitWithHighPriority(
() -> finalTextureProcessorWrapper.releaseOutputFrame(releaseTimeNs)); () -> finalShaderProgramWrapper.releaseOutputFrame(releaseTimeNs));
} }
@Override @Override
@ -469,7 +466,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
frameProcessingTaskExecutor.flush(); frameProcessingTaskExecutor.flush();
CountDownLatch latch = new CountDownLatch(1); CountDownLatch latch = new CountDownLatch(1);
inputExternalTextureManager.setOnFlushCompleteListener(latch::countDown); inputExternalTextureManager.setOnFlushCompleteListener(latch::countDown);
frameProcessingTaskExecutor.submit(finalTextureProcessorWrapper::flush); frameProcessingTaskExecutor.submit(finalShaderProgramWrapper::flush);
latch.await(); latch.await();
inputExternalTextureManager.setOnFlushCompleteListener(null); inputExternalTextureManager.setOnFlushCompleteListener(null);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -481,8 +478,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
public void release() { public void release() {
try { try {
frameProcessingTaskExecutor.release( frameProcessingTaskExecutor.release(
/* releaseTask= */ this::releaseTextureProcessorsAndDestroyGlContext, /* releaseTask= */ this::releaseShaderProgramsAndDestroyGlContext, RELEASE_WAIT_TIME_MS);
RELEASE_WAIT_TIME_MS);
} catch (InterruptedException unexpected) { } catch (InterruptedException unexpected) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
throw new IllegalStateException(unexpected); throw new IllegalStateException(unexpected);
@ -513,15 +509,15 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
} }
/** /**
* Releases the {@link GlTextureProcessor} instances and destroys the OpenGL context. * Releases the {@link GlShaderProgram} instances and destroys the OpenGL context.
* *
* <p>This method must be called on the {@linkplain #THREAD_NAME background thread}. * <p>This method must be called on the {@linkplain #THREAD_NAME background thread}.
*/ */
@WorkerThread @WorkerThread
private void releaseTextureProcessorsAndDestroyGlContext() private void releaseShaderProgramsAndDestroyGlContext()
throws GlUtil.GlException, FrameProcessingException { throws GlUtil.GlException, FrameProcessingException {
for (int i = 0; i < allTextureProcessors.size(); i++) { for (int i = 0; i < allShaderPrograms.size(); i++) {
allTextureProcessors.get(i).release(); allShaderPrograms.get(i).release();
} }
GlUtil.destroyEglContext(eglDisplay, eglContext); GlUtil.destroyEglContext(eglDisplay, eglContext);
} }

View File

@ -53,9 +53,9 @@ public interface GlMatrixTransformation extends GlEffect {
float[] getGlMatrixArray(long presentationTimeUs); float[] getGlMatrixArray(long presentationTimeUs);
@Override @Override
default SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr) default SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
throws FrameProcessingException { throws FrameProcessingException {
return MatrixTextureProcessor.create( return MatrixShaderProgram.create(
context, context,
/* matrixTransformations= */ ImmutableList.of(this), /* matrixTransformations= */ ImmutableList.of(this),
/* rgbMatrices= */ ImmutableList.of(), /* rgbMatrices= */ ImmutableList.of(),

View File

@ -22,29 +22,29 @@ import java.util.concurrent.Executor;
/** /**
* Processes frames from one OpenGL 2D texture to another. * Processes frames from one OpenGL 2D texture to another.
* *
* <p>The {@code GlTextureProcessor} consumes input frames it accepts via {@link * <p>The {@code GlShaderProgram} consumes input frames it accepts via {@link
* #queueInputFrame(TextureInfo, long)} and surrenders each texture back to the caller via its * #queueInputFrame(TextureInfo, long)} and surrenders each texture back to the caller via its
* {@linkplain InputListener#onInputFrameProcessed(TextureInfo) listener} once the texture's * {@linkplain InputListener#onInputFrameProcessed(TextureInfo) listener} once the texture's
* contents have been processed. * contents have been processed.
* *
* <p>The {@code GlTextureProcessor} produces output frames asynchronously and notifies its owner * <p>The {@code GlShaderProgram} produces output frames asynchronously and notifies its owner when
* when they are available via its {@linkplain OutputListener#onOutputFrameAvailable(TextureInfo, * they are available via its {@linkplain OutputListener#onOutputFrameAvailable(TextureInfo, long)
* long) listener}. The {@code GlTextureProcessor} instance's owner must surrender the texture back * listener}. The {@code GlShaderProgram} instance's owner must surrender the texture back to the
* to the {@code GlTextureProcessor} via {@link #releaseOutputFrame(TextureInfo)} when it has * {@code GlShaderProgram} via {@link #releaseOutputFrame(TextureInfo)} when it has finished
* finished processing it. * processing it.
* *
* <p>{@code GlTextureProcessor} implementations can choose to produce output frames before * <p>{@code GlShaderProgram} implementations can choose to produce output frames before receiving
* receiving input frames or process several input frames before producing an output frame. However, * input frames or process several input frames before producing an output frame. However, {@code
* {@code GlTextureProcessor} implementations cannot assume that they will receive more than one * GlShaderProgram} implementations cannot assume that they will receive more than one input frame
* input frame at a time, so they must process each input frame they accept even if they cannot * at a time, so they must process each input frame they accept even if they cannot produce output
* produce output yet. * yet.
* *
* <p>The methods in this interface must be called on the thread that owns the parent OpenGL * <p>The methods in this interface must be called on the thread that owns the parent OpenGL
* context. If the implementation uses another OpenGL context, e.g., on another thread, it must * context. If the implementation uses another OpenGL context, e.g., on another thread, it must
* configure it to share data with the context of thread the interface methods are called on. * configure it to share data with the context of thread the interface methods are called on.
*/ */
@UnstableApi @UnstableApi
public interface GlTextureProcessor { public interface GlShaderProgram {
/** /**
* Listener for input-related frame processing events. * Listener for input-related frame processing events.
@ -53,7 +53,7 @@ public interface GlTextureProcessor {
*/ */
interface InputListener { interface InputListener {
/** /**
* Called when the {@link GlTextureProcessor} is ready to accept another input frame. * Called when the {@link GlShaderProgram} is ready to accept another input frame.
* *
* <p>For each time this method is called, {@link #queueInputFrame(TextureInfo, long)} can be * <p>For each time this method is called, {@link #queueInputFrame(TextureInfo, long)} can be
* called once. * called once.
@ -61,9 +61,9 @@ public interface GlTextureProcessor {
default void onReadyToAcceptInputFrame() {} default void onReadyToAcceptInputFrame() {}
/** /**
* Called when the {@link GlTextureProcessor} has processed an input frame. * Called when the {@link GlShaderProgram} has processed an input frame.
* *
* <p>The implementation shall not assume the {@link GlTextureProcessor} is {@linkplain * <p>The implementation shall not assume the {@link GlShaderProgram} is {@linkplain
* #onReadyToAcceptInputFrame ready to accept another input frame} when this method is called. * #onReadyToAcceptInputFrame ready to accept another input frame} when this method is called.
* *
* @param inputTexture The {@link TextureInfo} that was used to {@linkplain * @param inputTexture The {@link TextureInfo} that was used to {@linkplain
@ -72,9 +72,9 @@ public interface GlTextureProcessor {
default void onInputFrameProcessed(TextureInfo inputTexture) {} default void onInputFrameProcessed(TextureInfo inputTexture) {}
/** /**
* Called when the {@link GlTextureProcessor} has been flushed. * Called when the {@link GlShaderProgram} has been flushed.
* *
* <p>The implementation shall not assume the {@link GlTextureProcessor} is {@linkplain * <p>The implementation shall not assume the {@link GlShaderProgram} is {@linkplain
* #onReadyToAcceptInputFrame ready to accept another input frame} when this method is called. * #onReadyToAcceptInputFrame ready to accept another input frame} when this method is called.
*/ */
default void onFlush() {} default void onFlush() {}
@ -87,12 +87,12 @@ public interface GlTextureProcessor {
*/ */
interface OutputListener { interface OutputListener {
/** /**
* Called when the {@link GlTextureProcessor} has produced an output frame. * Called when the {@link GlShaderProgram} has produced an output frame.
* *
* <p>After the listener's owner has processed the output frame, it must call {@link * <p>After the listener's owner has processed the output frame, it must call {@link
* #releaseOutputFrame(TextureInfo)}. The output frame should be released as soon as possible, * #releaseOutputFrame(TextureInfo)}. The output frame should be released as soon as possible,
* as there is no guarantee that the {@link GlTextureProcessor} will produce further output * as there is no guarantee that the {@link GlShaderProgram} will produce further output frames
* frames before this output frame is released. * before this output frame is released.
* *
* @param outputTexture A {@link TextureInfo} describing the texture containing the output * @param outputTexture A {@link TextureInfo} describing the texture containing the output
* frame. * frame.
@ -101,8 +101,8 @@ public interface GlTextureProcessor {
default void onOutputFrameAvailable(TextureInfo outputTexture, long presentationTimeUs) {} default void onOutputFrameAvailable(TextureInfo outputTexture, long presentationTimeUs) {}
/** /**
* Called when the {@link GlTextureProcessor} will not produce further output frames belonging * Called when the {@link GlShaderProgram} will not produce further output frames belonging to
* to the current output stream. * the current output stream.
*/ */
default void onCurrentOutputStreamEnded() {} default void onCurrentOutputStreamEnded() {}
} }
@ -117,7 +117,7 @@ public interface GlTextureProcessor {
* Called when an exception occurs during asynchronous frame processing. * Called when an exception occurs during asynchronous frame processing.
* *
* <p>If an error occurred, consuming and producing further frames will not work as expected and * <p>If an error occurred, consuming and producing further frames will not work as expected and
* the {@link GlTextureProcessor} should be released. * the {@link GlShaderProgram} should be released.
*/ */
void onFrameProcessingError(FrameProcessingException e); void onFrameProcessingError(FrameProcessingException e);
} }
@ -150,11 +150,11 @@ public interface GlTextureProcessor {
/** /**
* Processes an input frame if possible. * Processes an input frame if possible.
* *
* <p>The {@code GlTextureProcessor} owns the accepted frame until it calls {@link * <p>The {@code GlShaderProgram} owns the accepted frame until it calls {@link
* InputListener#onInputFrameProcessed(TextureInfo)}. The caller should not overwrite or release * InputListener#onInputFrameProcessed(TextureInfo)}. The caller should not overwrite or release
* the texture before the {@code GlTextureProcessor} has finished processing it. * the texture before the {@code GlShaderProgram} has finished processing it.
* *
* <p>This method must only be called when the {@code GlTextureProcessor} can {@linkplain * <p>This method must only be called when the {@code GlShaderProgram} can {@linkplain
* InputListener#onReadyToAcceptInputFrame() accept an input frame}. * InputListener#onReadyToAcceptInputFrame() accept an input frame}.
* *
* @param inputTexture A {@link TextureInfo} describing the texture containing the input frame. * @param inputTexture A {@link TextureInfo} describing the texture containing the input frame.
@ -163,13 +163,13 @@ public interface GlTextureProcessor {
void queueInputFrame(TextureInfo inputTexture, long presentationTimeUs); void queueInputFrame(TextureInfo inputTexture, long presentationTimeUs);
/** /**
* Notifies the texture processor that the frame on the given output texture is no longer used and * Notifies the {@code GlShaderProgram} that the frame on the given output texture is no longer
* can be overwritten. * used and can be overwritten.
*/ */
void releaseOutputFrame(TextureInfo outputTexture); void releaseOutputFrame(TextureInfo outputTexture);
/** /**
* Notifies the {@code GlTextureProcessor} that no further input frames belonging to the current * Notifies the {@code GlShaderProgram} that no further input frames belonging to the current
* input stream will be queued. * input stream will be queued.
* *
* <p>Input frames that are queued after this method is called belong to a different input stream, * <p>Input frames that are queued after this method is called belong to a different input stream,
@ -179,11 +179,11 @@ public interface GlTextureProcessor {
void signalEndOfCurrentInputStream(); void signalEndOfCurrentInputStream();
/** /**
* Flushes the {@code GlTextureProcessor}. * Flushes the {@code GlShaderProgram}.
* *
* <p>The texture processor should reclaim the ownership of its allocated textures, {@linkplain * <p>The {@code GlShaderProgram} should reclaim the ownership of its allocated textures,
* InputListener#onFlush notify} its {@link InputListener} about the flush event, and {@linkplain * {@linkplain InputListener#onFlush notify} its {@link InputListener} about the flush event, and
* InputListener#onReadyToAcceptInputFrame report its availability} if necessary. * {@linkplain InputListener#onReadyToAcceptInputFrame report its availability} if necessary.
*/ */
void flush(); void flush();

View File

@ -113,8 +113,8 @@ public class HslAdjustment implements GlEffect {
} }
@Override @Override
public SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr) public SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
throws FrameProcessingException { throws FrameProcessingException {
return new HslProcessor(context, /* hslAdjustment= */ this, useHdr); return new HslShaderProgram(context, /* hslAdjustment= */ this, useHdr);
} }
} }

View File

@ -27,7 +27,7 @@ import androidx.media3.common.util.Size;
import java.io.IOException; import java.io.IOException;
/** Applies the {@link HslAdjustment} to each frame in the fragment shader. */ /** Applies the {@link HslAdjustment} to each frame in the fragment shader. */
/* package */ final class HslProcessor extends SingleFrameGlTextureProcessor { /* package */ final class HslShaderProgram extends SingleFrameGlShaderProgram {
private static final String VERTEX_SHADER_PATH = "shaders/vertex_shader_transformation_es2.glsl"; private static final String VERTEX_SHADER_PATH = "shaders/vertex_shader_transformation_es2.glsl";
private static final String FRAGMENT_SHADER_PATH = "shaders/fragment_shader_hsl_es2.glsl"; private static final String FRAGMENT_SHADER_PATH = "shaders/fragment_shader_hsl_es2.glsl";
@ -42,7 +42,7 @@ import java.io.IOException;
* in linear RGB BT.2020. If {@code false}, colors will be in linear RGB BT.709. * in linear RGB BT.2020. If {@code false}, colors will be in linear RGB BT.709.
* @throws FrameProcessingException If a problem occurs while reading shader files. * @throws FrameProcessingException If a problem occurs while reading shader files.
*/ */
public HslProcessor(Context context, HslAdjustment hslAdjustment, boolean useHdr) public HslShaderProgram(Context context, HslAdjustment hslAdjustment, boolean useHdr)
throws FrameProcessingException { throws FrameProcessingException {
super(useHdr); super(useHdr);
// TODO(b/241241680): Check if HDR <-> HSL works the same or not. // TODO(b/241241680): Check if HDR <-> HSL works the same or not.

View File

@ -52,8 +52,8 @@ import java.util.List;
*/ */
@UnstableApi @UnstableApi
@SuppressWarnings("FunctionalInterfaceClash") // b/228192298 @SuppressWarnings("FunctionalInterfaceClash") // b/228192298
/* package */ final class MatrixTextureProcessor extends SingleFrameGlTextureProcessor /* package */ final class MatrixShaderProgram extends SingleFrameGlShaderProgram
implements ExternalTextureProcessor { implements ExternalShaderProgram {
private static final String VERTEX_SHADER_TRANSFORMATION_PATH = private static final String VERTEX_SHADER_TRANSFORMATION_PATH =
"shaders/vertex_shader_transformation_es2.glsl"; "shaders/vertex_shader_transformation_es2.glsl";
@ -144,7 +144,7 @@ import java.util.List;
* @throws FrameProcessingException If a problem occurs while reading shader files or an OpenGL * @throws FrameProcessingException If a problem occurs while reading shader files or an OpenGL
* operation fails or is unsupported. * operation fails or is unsupported.
*/ */
public static MatrixTextureProcessor create( public static MatrixShaderProgram create(
Context context, Context context,
List<GlMatrixTransformation> matrixTransformations, List<GlMatrixTransformation> matrixTransformations,
List<RgbMatrix> rgbMatrices, List<RgbMatrix> rgbMatrices,
@ -155,7 +155,7 @@ import java.util.List;
context, VERTEX_SHADER_TRANSFORMATION_PATH, FRAGMENT_SHADER_TRANSFORMATION_PATH); context, VERTEX_SHADER_TRANSFORMATION_PATH, FRAGMENT_SHADER_TRANSFORMATION_PATH);
// No transfer functions needed, because input and output are both optical colors. // No transfer functions needed, because input and output are both optical colors.
return new MatrixTextureProcessor( return new MatrixShaderProgram(
glProgram, glProgram,
ImmutableList.copyOf(matrixTransformations), ImmutableList.copyOf(matrixTransformations),
ImmutableList.copyOf(rgbMatrices), ImmutableList.copyOf(rgbMatrices),
@ -171,7 +171,7 @@ import java.util.List;
* external texture. * external texture.
* *
* <p>Applies the {@linkplain ColorInfo#colorTransfer inputColorInfo EOTF} to convert from * <p>Applies the {@linkplain ColorInfo#colorTransfer inputColorInfo EOTF} to convert from
* electrical color input, to intermediate optical {@link GlTextureProcessor} color output, before * electrical color input, to intermediate optical {@link GlShaderProgram} color output, before
* {@code matrixTransformations} and {@code rgbMatrices} are applied. Also applies the {@linkplain * {@code matrixTransformations} and {@code rgbMatrices} are applied. Also applies the {@linkplain
* ColorInfo#colorTransfer outputColorInfo OETF}, if needed, to convert back to an electrical * ColorInfo#colorTransfer outputColorInfo OETF}, if needed, to convert back to an electrical
* color output. * color output.
@ -188,7 +188,7 @@ import java.util.List;
* @throws FrameProcessingException If a problem occurs while reading shader files or an OpenGL * @throws FrameProcessingException If a problem occurs while reading shader files or an OpenGL
* operation fails or is unsupported. * operation fails or is unsupported.
*/ */
public static MatrixTextureProcessor createWithExternalSampler( public static MatrixShaderProgram createWithExternalSampler(
Context context, Context context,
List<GlMatrixTransformation> matrixTransformations, List<GlMatrixTransformation> matrixTransformations,
List<RgbMatrix> rgbMatrices, List<RgbMatrix> rgbMatrices,
@ -242,7 +242,7 @@ import java.util.List;
glProgram.setIntUniform("uOutputColorTransfer", outputColorTransfer); glProgram.setIntUniform("uOutputColorTransfer", outputColorTransfer);
} }
return new MatrixTextureProcessor( return new MatrixShaderProgram(
glProgram, glProgram,
ImmutableList.copyOf(matrixTransformations), ImmutableList.copyOf(matrixTransformations),
ImmutableList.copyOf(rgbMatrices), ImmutableList.copyOf(rgbMatrices),
@ -254,7 +254,7 @@ import java.util.List;
* Creates a new instance. * Creates a new instance.
* *
* <p>Applies the {@linkplain ColorInfo#colorTransfer outputColorInfo OETF} to convert from * <p>Applies the {@linkplain ColorInfo#colorTransfer outputColorInfo OETF} to convert from
* intermediate optical {@link GlTextureProcessor} color input, to electrical color output, after * intermediate optical {@link GlShaderProgram} color input, to electrical color output, after
* {@code matrixTransformations} and {@code rgbMatrices} are applied. * {@code matrixTransformations} and {@code rgbMatrices} are applied.
* *
* <p>Intermediate optical/linear colors are RGB BT.2020 if {@code outputColorInfo} is {@linkplain * <p>Intermediate optical/linear colors are RGB BT.2020 if {@code outputColorInfo} is {@linkplain
@ -269,7 +269,7 @@ import java.util.List;
* @throws FrameProcessingException If a problem occurs while reading shader files or an OpenGL * @throws FrameProcessingException If a problem occurs while reading shader files or an OpenGL
* operation fails or is unsupported. * operation fails or is unsupported.
*/ */
public static MatrixTextureProcessor createApplyingOetf( public static MatrixShaderProgram createApplyingOetf(
Context context, Context context,
List<GlMatrixTransformation> matrixTransformations, List<GlMatrixTransformation> matrixTransformations,
List<RgbMatrix> rgbMatrices, List<RgbMatrix> rgbMatrices,
@ -297,7 +297,7 @@ import java.util.List;
glProgram.setIntUniform("uOutputColorTransfer", outputColorTransfer); glProgram.setIntUniform("uOutputColorTransfer", outputColorTransfer);
} }
return new MatrixTextureProcessor( return new MatrixShaderProgram(
glProgram, glProgram,
ImmutableList.copyOf(matrixTransformations), ImmutableList.copyOf(matrixTransformations),
ImmutableList.copyOf(rgbMatrices), ImmutableList.copyOf(rgbMatrices),
@ -317,7 +317,7 @@ import java.util.List;
* @param useHdr Whether to process the input as an HDR signal. Using HDR requires the {@code * @param useHdr Whether to process the input as an HDR signal. Using HDR requires the {@code
* EXT_YUV_target} OpenGL extension. * EXT_YUV_target} OpenGL extension.
*/ */
private MatrixTextureProcessor( private MatrixShaderProgram(
GlProgram glProgram, GlProgram glProgram,
ImmutableList<GlMatrixTransformation> matrixTransformations, ImmutableList<GlMatrixTransformation> matrixTransformations,
ImmutableList<RgbMatrix> rgbMatrices, ImmutableList<RgbMatrix> rgbMatrices,
@ -403,7 +403,7 @@ import java.util.List;
/** /**
* Sets the output {@link C.ColorTransfer}. * Sets the output {@link C.ColorTransfer}.
* *
* <p>This method must not be called on {@code MatrixTextureProcessor} instances that output * <p>This method must not be called on {@code MatrixShaderProgram} instances that output
* {@linkplain C#COLOR_TRANSFER_LINEAR linear colors}. * {@linkplain C#COLOR_TRANSFER_LINEAR linear colors}.
*/ */
public void setOutputColorTransfer(@C.ColorTransfer int colorTransfer) { public void setOutputColorTransfer(@C.ColorTransfer int colorTransfer) {

View File

@ -39,8 +39,8 @@ public final class OverlayEffect implements GlEffect {
} }
@Override @Override
public SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr) public SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
throws FrameProcessingException { throws FrameProcessingException {
return new OverlayTextureProcessor(context, useHdr, overlays); return new OverlayShaderProgram(context, useHdr, overlays);
} }
} }

View File

@ -29,7 +29,7 @@ import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
/** Applies zero or more {@link TextureOverlay}s onto each frame. */ /** Applies zero or more {@link TextureOverlay}s onto each frame. */
/* package */ final class OverlayTextureProcessor extends SingleFrameGlTextureProcessor { /* package */ final class OverlayShaderProgram extends SingleFrameGlShaderProgram {
private static final int MATRIX_OFFSET = 0; private static final int MATRIX_OFFSET = 0;
@ -51,16 +51,16 @@ import com.google.common.collect.ImmutableList;
* in linear RGB BT.2020. If {@code false}, colors will be in linear RGB BT.709. * in linear RGB BT.2020. If {@code false}, colors will be in linear RGB BT.709.
* @throws FrameProcessingException If a problem occurs while reading shader files. * @throws FrameProcessingException If a problem occurs while reading shader files.
*/ */
public OverlayTextureProcessor( public OverlayShaderProgram(
Context context, boolean useHdr, ImmutableList<TextureOverlay> overlays) Context context, boolean useHdr, ImmutableList<TextureOverlay> overlays)
throws FrameProcessingException { throws FrameProcessingException {
super(useHdr); super(useHdr);
checkArgument(!useHdr, "OverlayTextureProcessor does not support HDR colors yet."); checkArgument(!useHdr, "OverlayShaderProgram does not support HDR colors yet.");
// The maximum number of samplers allowed in a single GL program is 16. // The maximum number of samplers allowed in a single GL program is 16.
// We use one for every overlay and one for the video. // We use one for every overlay and one for the video.
checkArgument( checkArgument(
overlays.size() <= 15, overlays.size() <= 15,
"OverlayTextureProcessor does not support more than 15 overlays in the same processor."); "OverlayShaderProgram does not support more than 15 overlays in the same instance.");
this.overlays = overlays; this.overlays = overlays;
aspectRatioMatrix = GlUtil.create4x4IdentityMatrix(); aspectRatioMatrix = GlUtil.create4x4IdentityMatrix();
overlayMatrix = GlUtil.create4x4IdentityMatrix(); overlayMatrix = GlUtil.create4x4IdentityMatrix();

View File

@ -91,9 +91,9 @@ public class RgbFilter implements RgbMatrix {
} }
@Override @Override
public SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr) public SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
throws FrameProcessingException { throws FrameProcessingException {
checkForConsistentHdrSetting(useHdr); checkForConsistentHdrSetting(useHdr);
return RgbMatrix.super.toGlTextureProcessor(context, useHdr); return RgbMatrix.super.toGlShaderProgram(context, useHdr);
} }
} }

View File

@ -34,15 +34,15 @@ public interface RgbMatrix extends GlEffect {
* @param presentationTimeUs The timestamp of the frame to apply the matrix on. * @param presentationTimeUs The timestamp of the frame to apply the matrix on.
* @param useHdr If {@code true}, colors will be in linear RGB BT.2020. If {@code false}, colors * @param useHdr If {@code true}, colors will be in linear RGB BT.2020. If {@code false}, colors
* will be in linear RGB BT.709. Must be consistent with {@code useHdr} in {@link * will be in linear RGB BT.709. Must be consistent with {@code useHdr} in {@link
* #toGlTextureProcessor(Context, boolean)}. * #toGlShaderProgram(Context, boolean)}.
* @return The {@code RgbMatrix} to apply to the frame. * @return The {@code RgbMatrix} to apply to the frame.
*/ */
float[] getMatrix(long presentationTimeUs, boolean useHdr); float[] getMatrix(long presentationTimeUs, boolean useHdr);
@Override @Override
default SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr) default SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
throws FrameProcessingException { throws FrameProcessingException {
return MatrixTextureProcessor.create( return MatrixShaderProgram.create(
context, context,
/* matrixTransformations= */ ImmutableList.of(), /* matrixTransformations= */ ImmutableList.of(),
/* rgbMatrices= */ ImmutableList.of(this), /* rgbMatrices= */ ImmutableList.of(this),

View File

@ -128,13 +128,13 @@ public class SingleColorLut implements ColorLut {
Bitmap.Config.ARGB_8888); Bitmap.Config.ARGB_8888);
} }
/** Must be called after {@link #toGlTextureProcessor(Context, boolean)}. */ /** Must be called after {@link #toGlShaderProgram(Context, boolean)}. */
@Override @Override
public int getLutTextureId(long presentationTimeUs) { public int getLutTextureId(long presentationTimeUs) {
checkState( checkState(
lutTextureId != Format.NO_VALUE, lutTextureId != Format.NO_VALUE,
"The LUT has not been stored as a texture in OpenGL yet. You must to call" "The LUT has not been stored as a texture in OpenGL yet. You must to call"
+ " #toGlTextureProcessor() first."); + " #toGlShaderProgram() first.");
return lutTextureId; return lutTextureId;
} }
@ -149,7 +149,7 @@ public class SingleColorLut implements ColorLut {
} }
@Override @Override
public SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr) public SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
throws FrameProcessingException { throws FrameProcessingException {
checkState(!useHdr, "HDR is currently not supported."); checkState(!useHdr, "HDR is currently not supported.");
@ -159,7 +159,7 @@ public class SingleColorLut implements ColorLut {
throw new FrameProcessingException("Could not store the LUT as a texture.", e); throw new FrameProcessingException("Could not store the LUT as a texture.", e);
} }
return new ColorLutProcessor(context, /* colorLut= */ this, useHdr); return new ColorLutShaderProgram(context, /* colorLut= */ this, useHdr);
} }
private static int storeLutAsTexture(Bitmap bitmap) throws GlUtil.GlException { private static int storeLutAsTexture(Bitmap bitmap) throws GlUtil.GlException {

View File

@ -31,14 +31,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* Manages a GLSL shader program for processing a frame. Implementations generally copy input pixels * Manages a GLSL shader program for processing a frame. Implementations generally copy input pixels
* into an output frame, with changes to pixels specific to the implementation. * into an output frame, with changes to pixels specific to the implementation.
* *
* <p>{@code SingleFrameGlTextureProcessor} implementations must produce exactly one output frame * <p>{@code SingleFrameGlShaderProgram} implementations must produce exactly one output frame per
* per input frame with the same presentation timestamp. For more flexibility, implement {@link * input frame with the same presentation timestamp. For more flexibility, implement {@link
* GlTextureProcessor} directly. * GlShaderProgram} directly.
* *
* <p>All methods in this class must be called on the thread that owns the OpenGL context. * <p>All methods in this class must be called on the thread that owns the OpenGL context.
*/ */
@UnstableApi @UnstableApi
public abstract class SingleFrameGlTextureProcessor implements GlTextureProcessor { public abstract class SingleFrameGlShaderProgram implements GlShaderProgram {
private final boolean useHdr; private final boolean useHdr;
@ -52,12 +52,12 @@ public abstract class SingleFrameGlTextureProcessor implements GlTextureProcesso
private boolean outputTextureInUse; private boolean outputTextureInUse;
/** /**
* Creates a {@code SingleFrameGlTextureProcessor} instance. * Creates a {@code SingleFrameGlShaderProgram} instance.
* *
* @param useHdr Whether input textures come from an HDR source. If {@code true}, colors will be * @param useHdr Whether input textures come from an HDR source. If {@code true}, colors will be
* in linear RGB BT.2020. If {@code false}, colors will be in linear RGB BT.709. * in linear RGB BT.2020. If {@code false}, colors will be in linear RGB BT.709.
*/ */
public SingleFrameGlTextureProcessor(boolean useHdr) { public SingleFrameGlShaderProgram(boolean useHdr) {
this.useHdr = useHdr; this.useHdr = useHdr;
inputListener = new InputListener() {}; inputListener = new InputListener() {};
outputListener = new OutputListener() {}; outputListener = new OutputListener() {};
@ -66,7 +66,7 @@ public abstract class SingleFrameGlTextureProcessor implements GlTextureProcesso
} }
/** /**
* Configures the texture processor based on the input dimensions. * Configures the instance based on the input dimensions.
* *
* <p>This method must be called before {@linkplain #drawFrame(int,long) drawing} the first frame * <p>This method must be called before {@linkplain #drawFrame(int,long) drawing} the first frame
* and before drawing subsequent frames with different input dimensions. * and before drawing subsequent frames with different input dimensions.
@ -81,9 +81,9 @@ public abstract class SingleFrameGlTextureProcessor implements GlTextureProcesso
/** /**
* Draws one frame. * Draws one frame.
* *
* <p>This method may only be called after the texture processor has been {@link #configure(int, * <p>This method may only be called after the shader program has been {@link #configure(int, int)
* int) configured}. The caller is responsible for focussing the correct render target before * configured}. The caller is responsible for focussing the correct render target before calling
* calling this method. * this method.
* *
* <p>A minimal implementation should tell OpenGL to use its shader program, bind the shader * <p>A minimal implementation should tell OpenGL to use its shader program, bind the shader
* program's vertex attributes and uniforms, and issue a drawing command. * program's vertex attributes and uniforms, and issue a drawing command.
@ -118,7 +118,7 @@ public abstract class SingleFrameGlTextureProcessor implements GlTextureProcesso
public final void queueInputFrame(TextureInfo inputTexture, long presentationTimeUs) { public final void queueInputFrame(TextureInfo inputTexture, long presentationTimeUs) {
checkState( checkState(
!outputTextureInUse, !outputTextureInUse,
"The texture processor does not currently accept input frames. Release prior output frames" "The shader program does not currently accept input frames. Release prior output frames"
+ " first."); + " first.");
try { try {

View File

@ -25,9 +25,9 @@ import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
/** Tests for {@link ChainingGlTextureProcessorListener}. */ /** Tests for {@link ChainingGlShaderProgramListener}. */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public final class ChainingGlTextureProcessorListenerTest { public final class ChainingGlShaderProgramListenerTest {
private static final long EXECUTOR_WAIT_TIME_MS = 100; private static final long EXECUTOR_WAIT_TIME_MS = 100;
private final FrameProcessor.Listener mockFrameProcessorListener = private final FrameProcessor.Listener mockFrameProcessorListener =
@ -35,13 +35,11 @@ public final class ChainingGlTextureProcessorListenerTest {
private final FrameProcessingTaskExecutor frameProcessingTaskExecutor = private final FrameProcessingTaskExecutor frameProcessingTaskExecutor =
new FrameProcessingTaskExecutor( new FrameProcessingTaskExecutor(
Util.newSingleThreadExecutor("Test"), mockFrameProcessorListener); Util.newSingleThreadExecutor("Test"), mockFrameProcessorListener);
private final GlTextureProcessor mockProducingGlTextureProcessor = mock(GlTextureProcessor.class); private final GlShaderProgram mockProducingGlShaderProgram = mock(GlShaderProgram.class);
private final GlTextureProcessor mockConsumingGlTextureProcessor = mock(GlTextureProcessor.class); private final GlShaderProgram mockConsumingGlShaderProgram = mock(GlShaderProgram.class);
private final ChainingGlTextureProcessorListener chainingGlTextureProcessorListener = private final ChainingGlShaderProgramListener chainingGlShaderProgramListener =
new ChainingGlTextureProcessorListener( new ChainingGlShaderProgramListener(
mockProducingGlTextureProcessor, mockProducingGlShaderProgram, mockConsumingGlShaderProgram, frameProcessingTaskExecutor);
mockConsumingGlTextureProcessor,
frameProcessingTaskExecutor);
@After @After
public void release() throws InterruptedException { public void release() throws InterruptedException {
@ -49,47 +47,47 @@ public final class ChainingGlTextureProcessorListenerTest {
} }
@Test @Test
public void onInputFrameProcessed_surrendersFrameToPreviousGlTextureProcessor() public void onInputFrameProcessed_surrendersFrameToPreviousGlShaderProgram()
throws InterruptedException { throws InterruptedException {
TextureInfo texture = TextureInfo texture =
new TextureInfo(/* texId= */ 1, /* fboId= */ 1, /* width= */ 100, /* height= */ 100); new TextureInfo(/* texId= */ 1, /* fboId= */ 1, /* width= */ 100, /* height= */ 100);
chainingGlTextureProcessorListener.onInputFrameProcessed(texture); chainingGlShaderProgramListener.onInputFrameProcessed(texture);
Thread.sleep(EXECUTOR_WAIT_TIME_MS); Thread.sleep(EXECUTOR_WAIT_TIME_MS);
verify(mockProducingGlTextureProcessor).releaseOutputFrame(texture); verify(mockProducingGlShaderProgram).releaseOutputFrame(texture);
} }
@Test @Test
public void onOutputFrameAvailable_afterAcceptsInputFrame_passesFrameToNextGlTextureProcessor() public void onOutputFrameAvailable_afterAcceptsInputFrame_passesFrameToNextGlShaderProgram()
throws InterruptedException { throws InterruptedException {
TextureInfo texture = TextureInfo texture =
new TextureInfo(/* texId= */ 1, /* fboId= */ 1, /* width= */ 100, /* height= */ 100); new TextureInfo(/* texId= */ 1, /* fboId= */ 1, /* width= */ 100, /* height= */ 100);
long presentationTimeUs = 123; long presentationTimeUs = 123;
chainingGlTextureProcessorListener.onReadyToAcceptInputFrame(); chainingGlShaderProgramListener.onReadyToAcceptInputFrame();
chainingGlTextureProcessorListener.onOutputFrameAvailable(texture, presentationTimeUs); chainingGlShaderProgramListener.onOutputFrameAvailable(texture, presentationTimeUs);
Thread.sleep(EXECUTOR_WAIT_TIME_MS); Thread.sleep(EXECUTOR_WAIT_TIME_MS);
verify(mockConsumingGlTextureProcessor).queueInputFrame(texture, presentationTimeUs); verify(mockConsumingGlShaderProgram).queueInputFrame(texture, presentationTimeUs);
} }
@Test @Test
public void onOutputFrameAvailable_beforeAcceptsInputFrame_passesFrameToNextGlTextureProcessor() public void onOutputFrameAvailable_beforeAcceptsInputFrame_passesFrameToNextGlShaderProgram()
throws InterruptedException { throws InterruptedException {
TextureInfo texture = TextureInfo texture =
new TextureInfo(/* texId= */ 1, /* fboId= */ 1, /* width= */ 100, /* height= */ 100); new TextureInfo(/* texId= */ 1, /* fboId= */ 1, /* width= */ 100, /* height= */ 100);
long presentationTimeUs = 123; long presentationTimeUs = 123;
chainingGlTextureProcessorListener.onOutputFrameAvailable(texture, presentationTimeUs); chainingGlShaderProgramListener.onOutputFrameAvailable(texture, presentationTimeUs);
chainingGlTextureProcessorListener.onReadyToAcceptInputFrame(); chainingGlShaderProgramListener.onReadyToAcceptInputFrame();
Thread.sleep(EXECUTOR_WAIT_TIME_MS); Thread.sleep(EXECUTOR_WAIT_TIME_MS);
verify(mockConsumingGlTextureProcessor).queueInputFrame(texture, presentationTimeUs); verify(mockConsumingGlShaderProgram).queueInputFrame(texture, presentationTimeUs);
} }
@Test @Test
public void onOutputFrameAvailable_twoFrames_passesFirstBeforeSecondToNextGlTextureProcessor() public void onOutputFrameAvailable_twoFrames_passesFirstBeforeSecondToNextGlShaderProgram()
throws InterruptedException { throws InterruptedException {
TextureInfo firstTexture = TextureInfo firstTexture =
new TextureInfo(/* texId= */ 1, /* fboId= */ 1, /* width= */ 100, /* height= */ 100); new TextureInfo(/* texId= */ 1, /* fboId= */ 1, /* width= */ 100, /* height= */ 100);
@ -98,25 +96,22 @@ public final class ChainingGlTextureProcessorListenerTest {
new TextureInfo(/* texId= */ 2, /* fboId= */ 2, /* width= */ 100, /* height= */ 100); new TextureInfo(/* texId= */ 2, /* fboId= */ 2, /* width= */ 100, /* height= */ 100);
long secondPresentationTimeUs = 567; long secondPresentationTimeUs = 567;
chainingGlTextureProcessorListener.onOutputFrameAvailable( chainingGlShaderProgramListener.onOutputFrameAvailable(firstTexture, firstPresentationTimeUs);
firstTexture, firstPresentationTimeUs); chainingGlShaderProgramListener.onOutputFrameAvailable(secondTexture, secondPresentationTimeUs);
chainingGlTextureProcessorListener.onOutputFrameAvailable( chainingGlShaderProgramListener.onReadyToAcceptInputFrame();
secondTexture, secondPresentationTimeUs); chainingGlShaderProgramListener.onReadyToAcceptInputFrame();
chainingGlTextureProcessorListener.onReadyToAcceptInputFrame();
chainingGlTextureProcessorListener.onReadyToAcceptInputFrame();
Thread.sleep(EXECUTOR_WAIT_TIME_MS); Thread.sleep(EXECUTOR_WAIT_TIME_MS);
verify(mockConsumingGlTextureProcessor).queueInputFrame(firstTexture, firstPresentationTimeUs); verify(mockConsumingGlShaderProgram).queueInputFrame(firstTexture, firstPresentationTimeUs);
verify(mockConsumingGlTextureProcessor) verify(mockConsumingGlShaderProgram).queueInputFrame(secondTexture, secondPresentationTimeUs);
.queueInputFrame(secondTexture, secondPresentationTimeUs);
} }
@Test @Test
public void onOutputStreamEnded_signalsInputStreamEndedToNextGlTextureProcessor() public void onOutputStreamEnded_signalsInputStreamEndedToNextGlShaderProgram()
throws InterruptedException { throws InterruptedException {
chainingGlTextureProcessorListener.onCurrentOutputStreamEnded(); chainingGlShaderProgramListener.onCurrentOutputStreamEnded();
Thread.sleep(EXECUTOR_WAIT_TIME_MS); Thread.sleep(EXECUTOR_WAIT_TIME_MS);
verify(mockConsumingGlTextureProcessor).signalEndOfCurrentInputStream(); verify(mockConsumingGlShaderProgram).signalEndOfCurrentInputStream();
} }
} }

View File

@ -25,8 +25,8 @@ import org.junit.runner.RunWith;
/** /**
* Unit tests for {@link ScaleToFitTransformation}. * Unit tests for {@link ScaleToFitTransformation}.
* *
* <p>See {@code MatrixTextureProcessorPixelTest} for pixel tests testing {@link * <p>See {@code MatrixShaderProgramPixelTest} for pixel tests testing {@link MatrixShaderProgram}
* MatrixTextureProcessor} given a transformation matrix. * given a transformation matrix.
*/ */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public final class ScaleToFitTransformationTest { public final class ScaleToFitTransformationTest {