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:
parent
9224a36add
commit
ca4d2be1fa
@ -23,14 +23,14 @@ import androidx.media3.common.FrameProcessingException;
|
||||
import androidx.media3.common.util.GlProgram;
|
||||
import androidx.media3.common.util.GlUtil;
|
||||
import androidx.media3.common.util.Size;
|
||||
import androidx.media3.effect.SingleFrameGlTextureProcessor;
|
||||
import androidx.media3.effect.SingleFrameGlShaderProgram;
|
||||
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.
|
||||
*/
|
||||
/* 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 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.
|
||||
* @throws FrameProcessingException If a problem occurs while reading shader files.
|
||||
*/
|
||||
public PeriodicVignetteProcessor(
|
||||
public PeriodicVignetteShaderProgram(
|
||||
Context context,
|
||||
boolean useHdr,
|
||||
float centerX,
|
@ -59,7 +59,7 @@ import androidx.media3.effect.BitmapOverlay;
|
||||
import androidx.media3.effect.Contrast;
|
||||
import androidx.media3.effect.DrawableOverlay;
|
||||
import androidx.media3.effect.GlEffect;
|
||||
import androidx.media3.effect.GlTextureProcessor;
|
||||
import androidx.media3.effect.GlShaderProgram;
|
||||
import androidx.media3.effect.HslAdjustment;
|
||||
import androidx.media3.effect.OverlayEffect;
|
||||
import androidx.media3.effect.OverlaySettings;
|
||||
@ -414,7 +414,7 @@ public final class TransformerActivity extends AppCompatActivity {
|
||||
(GlEffect)
|
||||
(Context context, boolean useHdr) -> {
|
||||
try {
|
||||
return (GlTextureProcessor)
|
||||
return (GlShaderProgram)
|
||||
constructor.newInstance(
|
||||
context,
|
||||
useHdr,
|
||||
@ -424,7 +424,7 @@ public final class TransformerActivity extends AppCompatActivity {
|
||||
/* outputStreamName= */ "output_video");
|
||||
} catch (Exception e) {
|
||||
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) {
|
||||
@ -495,7 +495,7 @@ public final class TransformerActivity extends AppCompatActivity {
|
||||
effects.add(
|
||||
(GlEffect)
|
||||
(Context context, boolean useHdr) ->
|
||||
new PeriodicVignetteProcessor(
|
||||
new PeriodicVignetteShaderProgram(
|
||||
context,
|
||||
useHdr,
|
||||
bundle.getFloat(ConfigurationActivity.PERIODIC_VIGNETTE_CENTER_X),
|
||||
|
@ -35,7 +35,7 @@
|
||||
<string name="select_audio_effects" translatable="false">Add audio 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="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="debug_preview" translatable="false">Debug preview:</string>
|
||||
<string name="debug_preview_not_available" translatable="false">No debug preview available.</string>
|
||||
|
@ -27,7 +27,7 @@ import androidx.media3.common.C;
|
||||
import androidx.media3.common.FrameProcessingException;
|
||||
import androidx.media3.common.util.LibraryLoader;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.effect.GlTextureProcessor;
|
||||
import androidx.media3.effect.GlShaderProgram;
|
||||
import androidx.media3.effect.TextureInfo;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import com.google.mediapipe.components.FrameProcessor;
|
||||
@ -43,9 +43,9 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/** 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 RETRY_WAIT_TIME_MS = 1;
|
||||
|
||||
@ -80,11 +80,11 @@ import java.util.concurrent.Future;
|
||||
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
|
||||
* time by continuously attempting to queue input frames to MediaPipe until they are accepted or
|
||||
* waste memory if MediaPipe accepts and stores many frames internally.
|
||||
* <p>If {@code isSingleFrameGraph} is {@code false}, the {@code MediaPipeShaderProgram} may waste
|
||||
* CPU time by continuously attempting to queue input frames to MediaPipe until they are accepted
|
||||
* or waste memory if MediaPipe accepts and stores many frames internally.
|
||||
*
|
||||
* @param context The {@link Context}.
|
||||
* @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 outputStreamName Name of the input video stream in the graph.
|
||||
*/
|
||||
public MediaPipeProcessor(
|
||||
public MediaPipeShaderProgram(
|
||||
Context context,
|
||||
boolean useHdr,
|
||||
String graphName,
|
||||
@ -103,8 +103,8 @@ import java.util.concurrent.Future;
|
||||
String inputStreamName,
|
||||
String outputStreamName) {
|
||||
checkState(LOADER.isAvailable());
|
||||
// TODO(b/227624622): Confirm whether MediaPipeProcessor could support HDR colors.
|
||||
checkArgument(!useHdr, "MediaPipeProcessor does not support HDR colors.");
|
||||
// TODO(b/227624622): Confirm whether MediaPipeShaderProgram could support HDR colors.
|
||||
checkArgument(!useHdr, "MediaPipeShaderProgram does not support HDR colors.");
|
||||
|
||||
this.isSingleFrameGraph = isSingleFrameGraph;
|
||||
singleThreadExecutorService =
|
||||
@ -233,7 +233,7 @@ import java.util.concurrent.Future;
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
// TODO(b/238302341) Support seeking in MediaPipeProcessor.
|
||||
// TODO(b/238302341) Support seeking in MediaPipeShaderProgram.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
@ -411,7 +411,7 @@ public final class GlUtil {
|
||||
*/
|
||||
private static void assertValidTextureSize(int width, int height) throws GlException {
|
||||
// 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.
|
||||
// For valid GL sizes, see:
|
||||
// https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glTexImage2D.xml
|
||||
|
@ -45,7 +45,7 @@ import org.junit.Test;
|
||||
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
|
||||
* 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 EGLContext eglContext;
|
||||
private @MonotonicNonNull EGLSurface placeholderEglSurface;
|
||||
private @MonotonicNonNull SingleFrameGlTextureProcessor contrastProcessor;
|
||||
private @MonotonicNonNull SingleFrameGlShaderProgram contrastShaderProgram;
|
||||
private int inputTexId;
|
||||
private int inputWidth;
|
||||
private int inputHeight;
|
||||
@ -90,8 +90,8 @@ public class ContrastPixelTest {
|
||||
|
||||
@After
|
||||
public void release() throws GlUtil.GlException, FrameProcessingException {
|
||||
if (contrastProcessor != null) {
|
||||
contrastProcessor.release();
|
||||
if (contrastShaderProgram != null) {
|
||||
contrastShaderProgram.release();
|
||||
}
|
||||
GlUtil.destroyEglContext(eglDisplay, eglContext);
|
||||
}
|
||||
@ -99,13 +99,13 @@ public class ContrastPixelTest {
|
||||
@Test
|
||||
public void drawFrame_noContrastChange_leavesFrameUnchanged() throws Exception {
|
||||
String testId = "drawFrame_noContrastChange";
|
||||
contrastProcessor =
|
||||
new Contrast(/* contrast= */ 0.0f).toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = contrastProcessor.configure(inputWidth, inputHeight);
|
||||
contrastShaderProgram =
|
||||
new Contrast(/* contrast= */ 0.0f).toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = contrastShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
|
||||
contrastProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
contrastShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -118,9 +118,9 @@ public class ContrastPixelTest {
|
||||
@Test
|
||||
public void drawFrame_minimumContrast_producesAllGrayFrame() throws Exception {
|
||||
String testId = "drawFrame_minimumContrast";
|
||||
contrastProcessor =
|
||||
new Contrast(/* contrast= */ -1.0f).toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = contrastProcessor.configure(inputWidth, inputHeight);
|
||||
contrastShaderProgram =
|
||||
new Contrast(/* contrast= */ -1.0f).toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = contrastShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap =
|
||||
createArgb8888BitmapWithSolidColor(
|
||||
@ -129,7 +129,7 @@ public class ContrastPixelTest {
|
||||
Color.rgb(
|
||||
OPENGL_NEUTRAL_RGB_VALUE, OPENGL_NEUTRAL_RGB_VALUE, OPENGL_NEUTRAL_RGB_VALUE));
|
||||
|
||||
contrastProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
contrastShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -143,13 +143,13 @@ public class ContrastPixelTest {
|
||||
public void drawFrame_decreaseContrast_decreasesPixelsGreaterEqual128IncreasesBelow()
|
||||
throws Exception {
|
||||
String testId = "drawFrame_decreaseContrast";
|
||||
contrastProcessor =
|
||||
new Contrast(/* contrast= */ -0.75f).toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = contrastProcessor.configure(inputWidth, inputHeight);
|
||||
contrastShaderProgram =
|
||||
new Contrast(/* contrast= */ -0.75f).toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = contrastShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(DECREASE_CONTRAST_PNG_ASSET_PATH);
|
||||
|
||||
contrastProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
contrastShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -163,13 +163,13 @@ public class ContrastPixelTest {
|
||||
public void drawFrame_increaseContrast_increasesPixelsGreaterEqual128DecreasesBelow()
|
||||
throws Exception {
|
||||
String testId = "drawFrame_increaseContrast";
|
||||
contrastProcessor =
|
||||
new Contrast(/* contrast= */ 0.75f).toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = contrastProcessor.configure(inputWidth, inputHeight);
|
||||
contrastShaderProgram =
|
||||
new Contrast(/* contrast= */ 0.75f).toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = contrastShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(INCREASE_CONTRAST_PNG_ASSET_PATH);
|
||||
|
||||
contrastProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
contrastShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -182,13 +182,13 @@ public class ContrastPixelTest {
|
||||
@Test
|
||||
public void drawFrame_maximumContrast_pixelEither0or255() throws Exception {
|
||||
String testId = "drawFrame_maximumContrast";
|
||||
contrastProcessor =
|
||||
new Contrast(/* contrast= */ 1.0f).toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = contrastProcessor.configure(inputWidth, inputHeight);
|
||||
contrastShaderProgram =
|
||||
new Contrast(/* contrast= */ 1.0f).toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = contrastShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(MAXIMUM_CONTRAST_PNG_ASSET_PATH);
|
||||
|
||||
contrastProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
contrastShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
|
@ -63,7 +63,7 @@ public final class CropPixelTest {
|
||||
|
||||
private @MonotonicNonNull EGLDisplay eglDisplay;
|
||||
private @MonotonicNonNull EGLContext eglContext;
|
||||
private @MonotonicNonNull SingleFrameGlTextureProcessor cropTextureProcessor;
|
||||
private @MonotonicNonNull SingleFrameGlShaderProgram cropShaderProgram;
|
||||
private @MonotonicNonNull EGLSurface placeholderEglSurface;
|
||||
private int inputTexId;
|
||||
private int inputWidth;
|
||||
@ -83,8 +83,8 @@ public final class CropPixelTest {
|
||||
|
||||
@After
|
||||
public void release() throws GlUtil.GlException, FrameProcessingException {
|
||||
if (cropTextureProcessor != null) {
|
||||
cropTextureProcessor.release();
|
||||
if (cropShaderProgram != null) {
|
||||
cropShaderProgram.release();
|
||||
}
|
||||
if (eglContext != null && eglDisplay != null) {
|
||||
GlUtil.destroyEglContext(eglDisplay, eglContext);
|
||||
@ -94,14 +94,14 @@ public final class CropPixelTest {
|
||||
@Test
|
||||
public void drawFrame_noEdits_matchesGoldenFile() throws Exception {
|
||||
String testId = "drawFrame_noEdits";
|
||||
cropTextureProcessor =
|
||||
cropShaderProgram =
|
||||
new Crop(/* left= */ -1, /* right= */ 1, /* bottom= */ -1, /* top= */ 1)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = cropTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = cropShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
|
||||
cropTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
cropShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -115,14 +115,14 @@ public final class CropPixelTest {
|
||||
@Test
|
||||
public void drawFrame_cropSmaller_matchesGoldenFile() throws Exception {
|
||||
String testId = "drawFrame_cropSmaller";
|
||||
cropTextureProcessor =
|
||||
cropShaderProgram =
|
||||
new Crop(/* left= */ -.9f, /* right= */ .1f, /* bottom= */ -1f, /* top= */ .5f)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = cropTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = cropShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(CROP_SMALLER_PNG_ASSET_PATH);
|
||||
|
||||
cropTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
cropShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -136,14 +136,14 @@ public final class CropPixelTest {
|
||||
@Test
|
||||
public void drawFrame_cropLarger_matchesGoldenFile() throws Exception {
|
||||
String testId = "drawFrame_cropLarger";
|
||||
cropTextureProcessor =
|
||||
cropShaderProgram =
|
||||
new Crop(/* left= */ -2f, /* right= */ 2f, /* bottom= */ -1f, /* top= */ 2f)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = cropTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = cropShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(CROP_LARGER_PNG_ASSET_PATH);
|
||||
|
||||
cropTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
cropShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
|
@ -370,7 +370,7 @@ public final class GlEffectsFrameProcessorFrameReleaseTest {
|
||||
}
|
||||
|
||||
/** 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 OutputListener outputListener;
|
||||
|
@ -17,7 +17,7 @@ package androidx.media3.effect;
|
||||
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
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.getBitmapAveragePixelAbsoluteDifferenceArgb8888;
|
||||
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
|
||||
* 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
|
||||
* 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 {
|
||||
|
||||
@ -516,9 +516,9 @@ public final class GlEffectsFrameProcessorPixelTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
||||
public GlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
|
||||
throws FrameProcessingException {
|
||||
return effect.toGlTextureProcessor(context, useHdr);
|
||||
return effect.toGlShaderProgram(context, useHdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ public final class HslAdjustmentPixelTest {
|
||||
|
||||
private @MonotonicNonNull EGLDisplay eglDisplay;
|
||||
private @MonotonicNonNull EGLContext eglContext;
|
||||
private @MonotonicNonNull SingleFrameGlTextureProcessor hslProcessor;
|
||||
private @MonotonicNonNull SingleFrameGlShaderProgram hslProcessor;
|
||||
private @MonotonicNonNull EGLSurface placeholderEglSurface;
|
||||
private int inputTexId;
|
||||
private int inputWidth;
|
||||
@ -111,7 +111,7 @@ public final class HslAdjustmentPixelTest {
|
||||
public void drawFrame_noOpAdjustment_leavesFrameUnchanged() throws Exception {
|
||||
String testId = "drawFrame_noOpAdjustment";
|
||||
HslAdjustment noOpAdjustment = new HslAdjustment.Builder().build();
|
||||
hslProcessor = noOpAdjustment.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
hslProcessor = noOpAdjustment.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = hslProcessor.configure(inputWidth, inputHeight);
|
||||
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
|
||||
@ -129,7 +129,7 @@ public final class HslAdjustmentPixelTest {
|
||||
public void drawFrame_minimumSaturation_producesGrayFrame() throws Exception {
|
||||
String testId = "drawFrame_minimumSaturation";
|
||||
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);
|
||||
Bitmap expectedBitmap = readBitmap(MINIMUM_SATURATION_PNG_ASSET_PATH);
|
||||
|
||||
@ -147,7 +147,7 @@ public final class HslAdjustmentPixelTest {
|
||||
public void drawFrame_maximumSaturation_producesHighlySaturatedFrame() throws Exception {
|
||||
String testId = "drawFrame_maximumSaturation";
|
||||
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);
|
||||
Bitmap expectedBitmap = readBitmap(MAXIMUM_SATURATION_PNG_ASSET_PATH);
|
||||
|
||||
@ -165,7 +165,7 @@ public final class HslAdjustmentPixelTest {
|
||||
public void drawFrame_rotateHueByNegative90Degrees_matchesGoldenFile() throws Exception {
|
||||
String testId = "drawFrame_rotateHueByNegative90Degrees";
|
||||
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);
|
||||
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 {
|
||||
String testId = "drawFrame_rotateHueBy60Degrees";
|
||||
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);
|
||||
Bitmap expectedBitmap = readBitmap(ROTATE_HUE_BY_60_DEGREES_PNG_ASSET_PATH);
|
||||
|
||||
@ -202,7 +202,7 @@ public final class HslAdjustmentPixelTest {
|
||||
throws Exception {
|
||||
String testId = "drawFrame_rotateHueByNegative300Degrees";
|
||||
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);
|
||||
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 {
|
||||
String testId = "drawFrame_rotateHueBy360Degrees";
|
||||
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);
|
||||
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
|
||||
@ -238,7 +238,7 @@ public final class HslAdjustmentPixelTest {
|
||||
public void drawFrame_minimumLightness_producesBlackFrame() throws Exception {
|
||||
String testId = "drawFrame_minimumLightness";
|
||||
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);
|
||||
Bitmap expectedBitmap =
|
||||
createArgb8888BitmapWithSolidColor(inputWidth, inputHeight, Color.BLACK);
|
||||
@ -257,7 +257,7 @@ public final class HslAdjustmentPixelTest {
|
||||
public void drawFrame_decreaseLightness_producesDarkerFrame() throws Exception {
|
||||
String testId = "drawFrame_decreaseLightness";
|
||||
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);
|
||||
Bitmap expectedBitmap = readBitmap(DECREASE_LIGHTNESS_PNG_ASSET_PATH);
|
||||
|
||||
@ -275,7 +275,7 @@ public final class HslAdjustmentPixelTest {
|
||||
public void drawFrame_increaseLightness_producesBrighterFrame() throws Exception {
|
||||
String testId = "drawFrame_increaseLightness";
|
||||
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);
|
||||
Bitmap expectedBitmap = readBitmap(INCREASE_LIGHTNESS_PNG_ASSET_PATH);
|
||||
|
||||
@ -293,7 +293,7 @@ public final class HslAdjustmentPixelTest {
|
||||
public void drawFrame_maximumLightness_producesWhiteFrame() throws Exception {
|
||||
String testId = "drawFrame_maximumLightness";
|
||||
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);
|
||||
Bitmap expectedBitmap =
|
||||
createArgb8888BitmapWithSolidColor(inputWidth, inputHeight, Color.WHITE);
|
||||
@ -313,7 +313,7 @@ public final class HslAdjustmentPixelTest {
|
||||
String testId = "drawFrame_adjustAllHslSettings";
|
||||
HslAdjustment allHslSettingsAdjusted =
|
||||
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);
|
||||
Bitmap expectedBitmap = readBitmap(ADJUST_ALL_HSL_SETTINGS_PNG_ASSET_PATH);
|
||||
|
||||
|
@ -42,7 +42,7 @@ import org.junit.Test;
|
||||
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
|
||||
* 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}.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class MatrixTextureProcessorPixelTest {
|
||||
public final class MatrixShaderProgramPixelTest {
|
||||
public static final String ORIGINAL_PNG_ASSET_PATH =
|
||||
"media/bitmap/sample_mp4_first_frame/electrical_colors/original.png";
|
||||
public static final String TRANSLATE_RIGHT_PNG_ASSET_PATH =
|
||||
@ -64,7 +64,7 @@ public final class MatrixTextureProcessorPixelTest {
|
||||
|
||||
private @MonotonicNonNull EGLDisplay eglDisplay;
|
||||
private @MonotonicNonNull EGLContext eglContext;
|
||||
private @MonotonicNonNull SingleFrameGlTextureProcessor matrixTextureProcessor;
|
||||
private @MonotonicNonNull SingleFrameGlShaderProgram matrixShaderProgram;
|
||||
private int inputTexId;
|
||||
private int inputWidth;
|
||||
private int inputHeight;
|
||||
@ -88,8 +88,8 @@ public final class MatrixTextureProcessorPixelTest {
|
||||
|
||||
@After
|
||||
public void release() throws GlUtil.GlException, FrameProcessingException {
|
||||
if (matrixTextureProcessor != null) {
|
||||
matrixTextureProcessor.release();
|
||||
if (matrixShaderProgram != null) {
|
||||
matrixShaderProgram.release();
|
||||
}
|
||||
if (eglContext != null && eglDisplay != null) {
|
||||
GlUtil.destroyEglContext(eglDisplay, eglContext);
|
||||
@ -101,12 +101,11 @@ public final class MatrixTextureProcessorPixelTest {
|
||||
String testId = "drawFrame_noEdits";
|
||||
Matrix identityMatrix = new Matrix();
|
||||
MatrixTransformation noEditsTransformation = (long presentationTimeUs) -> identityMatrix;
|
||||
matrixTextureProcessor =
|
||||
noEditsTransformation.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
matrixTextureProcessor.configure(inputWidth, inputHeight);
|
||||
matrixShaderProgram = noEditsTransformation.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
matrixShaderProgram.configure(inputWidth, inputHeight);
|
||||
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
|
||||
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap = createArgb8888BitmapFromCurrentGlFramebuffer(inputWidth, inputHeight);
|
||||
|
||||
maybeSaveTestBitmapToCacheDirectory(testId, /* bitmapLabel= */ "actual", actualBitmap);
|
||||
@ -123,12 +122,12 @@ public final class MatrixTextureProcessorPixelTest {
|
||||
translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0);
|
||||
MatrixTransformation translateRightTransformation =
|
||||
(long presentationTimeUs) -> translateRightMatrix;
|
||||
matrixTextureProcessor =
|
||||
translateRightTransformation.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
matrixTextureProcessor.configure(inputWidth, inputHeight);
|
||||
matrixShaderProgram =
|
||||
translateRightTransformation.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
matrixShaderProgram.configure(inputWidth, inputHeight);
|
||||
Bitmap expectedBitmap = readBitmap(TRANSLATE_RIGHT_PNG_ASSET_PATH);
|
||||
|
||||
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap = createArgb8888BitmapFromCurrentGlFramebuffer(inputWidth, inputHeight);
|
||||
|
||||
maybeSaveTestBitmapToCacheDirectory(testId, /* bitmapLabel= */ "actual", actualBitmap);
|
||||
@ -144,12 +143,11 @@ public final class MatrixTextureProcessorPixelTest {
|
||||
Matrix scaleNarrowMatrix = new Matrix();
|
||||
scaleNarrowMatrix.postScale(.5f, 1.2f);
|
||||
MatrixTransformation scaleNarrowTransformation = (long presentationTimeUs) -> scaleNarrowMatrix;
|
||||
matrixTextureProcessor =
|
||||
scaleNarrowTransformation.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
matrixTextureProcessor.configure(inputWidth, inputHeight);
|
||||
matrixShaderProgram = scaleNarrowTransformation.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
matrixShaderProgram.configure(inputWidth, inputHeight);
|
||||
Bitmap expectedBitmap = readBitmap(SCALE_NARROW_PNG_ASSET_PATH);
|
||||
|
||||
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap = createArgb8888BitmapFromCurrentGlFramebuffer(inputWidth, inputHeight);
|
||||
|
||||
maybeSaveTestBitmapToCacheDirectory(testId, /* bitmapLabel= */ "actual", actualBitmap);
|
||||
@ -165,12 +163,11 @@ public final class MatrixTextureProcessorPixelTest {
|
||||
Matrix rotate90Matrix = new Matrix();
|
||||
rotate90Matrix.postRotate(/* degrees= */ 90);
|
||||
MatrixTransformation rotate90Transformation = (long presentationTimeUs) -> rotate90Matrix;
|
||||
matrixTextureProcessor =
|
||||
rotate90Transformation.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
matrixTextureProcessor.configure(inputWidth, inputHeight);
|
||||
matrixShaderProgram = rotate90Transformation.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
matrixShaderProgram.configure(inputWidth, inputHeight);
|
||||
Bitmap expectedBitmap = readBitmap(ROTATE_90_PNG_ASSET_PATH);
|
||||
|
||||
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap = createArgb8888BitmapFromCurrentGlFramebuffer(inputWidth, inputHeight);
|
||||
|
||||
maybeSaveTestBitmapToCacheDirectory(testId, /* bitmapLabel= */ "actual", actualBitmap);
|
@ -49,7 +49,7 @@ import org.junit.Test;
|
||||
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
|
||||
* 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}.
|
||||
*/
|
||||
@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 ORIGINAL_PNG_ASSET_PATH =
|
||||
"media/bitmap/sample_mp4_first_frame/electrical_colors/original.png";
|
||||
@ -82,7 +82,7 @@ public class OverlayTextureProcessorPixelTest {
|
||||
|
||||
private @MonotonicNonNull EGLDisplay eglDisplay;
|
||||
private @MonotonicNonNull EGLContext eglContext;
|
||||
private @MonotonicNonNull SingleFrameGlTextureProcessor overlayTextureProcessor;
|
||||
private @MonotonicNonNull SingleFrameGlShaderProgram overlayShaderProgram;
|
||||
private @MonotonicNonNull EGLSurface placeholderEglSurface;
|
||||
private int inputTexId;
|
||||
private int inputWidth;
|
||||
@ -102,8 +102,8 @@ public class OverlayTextureProcessorPixelTest {
|
||||
|
||||
@After
|
||||
public void release() throws GlUtil.GlException, FrameProcessingException {
|
||||
if (overlayTextureProcessor != null) {
|
||||
overlayTextureProcessor.release();
|
||||
if (overlayShaderProgram != null) {
|
||||
overlayShaderProgram.release();
|
||||
}
|
||||
GlUtil.destroyEglContext(eglDisplay, eglContext);
|
||||
}
|
||||
@ -111,14 +111,14 @@ public class OverlayTextureProcessorPixelTest {
|
||||
@Test
|
||||
public void drawFrame_noOverlay_leavesFrameUnchanged() throws Exception {
|
||||
String testId = "drawFrame_noOverlay";
|
||||
overlayTextureProcessor =
|
||||
overlayShaderProgram =
|
||||
new OverlayEffect(/* textureOverlays= */ ImmutableList.of())
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
|
||||
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -133,14 +133,14 @@ public class OverlayTextureProcessorPixelTest {
|
||||
String testId = "drawFrame_bitmapOverlay";
|
||||
Bitmap overlayBitmap = readBitmap(OVERLAY_PNG_ASSET_PATH);
|
||||
BitmapOverlay bitmapOverlay = BitmapOverlay.createStaticBitmapOverlay(overlayBitmap);
|
||||
overlayTextureProcessor =
|
||||
overlayShaderProgram =
|
||||
new OverlayEffect(ImmutableList.of(bitmapOverlay))
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(OVERLAY_BITMAP_DEFAULT);
|
||||
|
||||
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -178,14 +178,14 @@ public class OverlayTextureProcessorPixelTest {
|
||||
return overlaySettings;
|
||||
}
|
||||
};
|
||||
overlayTextureProcessor =
|
||||
overlayShaderProgram =
|
||||
new OverlayEffect(ImmutableList.of(staticBitmapOverlay))
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(OVERLAY_BITMAP_SCALED);
|
||||
|
||||
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -205,14 +205,14 @@ public class OverlayTextureProcessorPixelTest {
|
||||
new OverlaySettings.Builder().setMatrix(translateMatrix).setAnchor(-1f, 1f).build();
|
||||
BitmapOverlay staticBitmapOverlay =
|
||||
BitmapOverlay.createStaticBitmapOverlay(overlayBitmap, overlaySettings);
|
||||
overlayTextureProcessor =
|
||||
overlayShaderProgram =
|
||||
new OverlayEffect(ImmutableList.of(staticBitmapOverlay))
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(OVERLAY_BITMAP_ANCHORED);
|
||||
|
||||
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -229,14 +229,14 @@ public class OverlayTextureProcessorPixelTest {
|
||||
OverlaySettings overlaySettings = new OverlaySettings.Builder().setAlpha(0.5f).build();
|
||||
BitmapOverlay translucentBitmapOverlay =
|
||||
BitmapOverlay.createStaticBitmapOverlay(bitmap, overlaySettings);
|
||||
overlayTextureProcessor =
|
||||
overlayShaderProgram =
|
||||
new OverlayEffect(ImmutableList.of(translucentBitmapOverlay))
|
||||
.toGlTextureProcessor(context, false);
|
||||
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, false);
|
||||
Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(OVERLAY_BITMAP_TRANSLUCENT);
|
||||
|
||||
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -258,14 +258,14 @@ public class OverlayTextureProcessorPixelTest {
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
TextOverlay staticTextOverlay =
|
||||
TextOverlay.createStaticTextOverlay(overlayText, overlaySettings);
|
||||
overlayTextureProcessor =
|
||||
overlayShaderProgram =
|
||||
new OverlayEffect(ImmutableList.of(staticTextOverlay))
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
|
||||
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -285,14 +285,14 @@ public class OverlayTextureProcessorPixelTest {
|
||||
/* end= */ 4,
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
TextOverlay staticTextOverlay = TextOverlay.createStaticTextOverlay(overlayText);
|
||||
overlayTextureProcessor =
|
||||
overlayShaderProgram =
|
||||
new OverlayEffect(ImmutableList.of(staticTextOverlay))
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(OVERLAY_TEXT_DEFAULT);
|
||||
|
||||
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -317,14 +317,14 @@ public class OverlayTextureProcessorPixelTest {
|
||||
new OverlaySettings.Builder().setMatrix(translateMatrix).build();
|
||||
TextOverlay staticTextOverlay =
|
||||
TextOverlay.createStaticTextOverlay(overlayText, overlaySettings);
|
||||
overlayTextureProcessor =
|
||||
overlayShaderProgram =
|
||||
new OverlayEffect(ImmutableList.of(staticTextOverlay))
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(OVERLAY_TEXT_TRANSLATE);
|
||||
|
||||
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -351,14 +351,14 @@ public class OverlayTextureProcessorPixelTest {
|
||||
Bitmap bitmap = readBitmap(OVERLAY_PNG_ASSET_PATH);
|
||||
OverlaySettings overlaySettings2 = new OverlaySettings.Builder().setAlpha(0.5f).build();
|
||||
BitmapOverlay bitmapOverlay = BitmapOverlay.createStaticBitmapOverlay(bitmap, overlaySettings2);
|
||||
overlayTextureProcessor =
|
||||
overlayShaderProgram =
|
||||
new OverlayEffect(ImmutableList.of(textOverlay, bitmapOverlay))
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(OVERLAY_MULTIPLE);
|
||||
|
||||
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -388,14 +388,14 @@ public class OverlayTextureProcessorPixelTest {
|
||||
OverlaySettings overlaySettings2 = new OverlaySettings.Builder().setMatrix(scaleMatrix).build();
|
||||
BitmapOverlay bitmapOverlay = BitmapOverlay.createStaticBitmapOverlay(bitmap, overlaySettings2);
|
||||
|
||||
overlayTextureProcessor =
|
||||
overlayShaderProgram =
|
||||
new OverlayEffect(ImmutableList.of(bitmapOverlay, textOverlay))
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(OVERLAY_OVERLAP);
|
||||
|
||||
overlayTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
@ -72,7 +72,7 @@ public final class PresentationPixelTest {
|
||||
|
||||
private @MonotonicNonNull EGLDisplay eglDisplay;
|
||||
private @MonotonicNonNull EGLContext eglContext;
|
||||
private @MonotonicNonNull SingleFrameGlTextureProcessor presentationTextureProcessor;
|
||||
private @MonotonicNonNull SingleFrameGlShaderProgram presentationShaderProgram;
|
||||
private @MonotonicNonNull EGLSurface placeholderEglSurface;
|
||||
private int inputTexId;
|
||||
private int inputWidth;
|
||||
@ -92,8 +92,8 @@ public final class PresentationPixelTest {
|
||||
|
||||
@After
|
||||
public void release() throws GlUtil.GlException, FrameProcessingException {
|
||||
if (presentationTextureProcessor != null) {
|
||||
presentationTextureProcessor.release();
|
||||
if (presentationShaderProgram != null) {
|
||||
presentationShaderProgram.release();
|
||||
}
|
||||
if (eglContext != null && eglDisplay != null) {
|
||||
GlUtil.destroyEglContext(eglDisplay, eglContext);
|
||||
@ -103,14 +103,14 @@ public final class PresentationPixelTest {
|
||||
@Test
|
||||
public void drawFrame_noEdits_matchesGoldenFile() throws Exception {
|
||||
String testId = "drawFrame_noEdits";
|
||||
presentationTextureProcessor =
|
||||
presentationShaderProgram =
|
||||
Presentation.createForHeight(C.LENGTH_UNSET)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = presentationShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
|
||||
presentationTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
presentationShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -124,14 +124,14 @@ public final class PresentationPixelTest {
|
||||
@Test
|
||||
public void drawFrame_changeAspectRatio_scaleToFit_narrow_matchesGoldenFile() throws Exception {
|
||||
String testId = "drawFrame_changeAspectRatio_scaleToFit_narrow";
|
||||
presentationTextureProcessor =
|
||||
presentationShaderProgram =
|
||||
Presentation.createForAspectRatio(/* aspectRatio= */ 1f, Presentation.LAYOUT_SCALE_TO_FIT)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = presentationShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_SCALE_TO_FIT_NARROW_PNG_ASSET_PATH);
|
||||
|
||||
presentationTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
presentationShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -145,14 +145,14 @@ public final class PresentationPixelTest {
|
||||
@Test
|
||||
public void drawFrame_changeAspectRatio_scaleToFit_wide_matchesGoldenFile() throws Exception {
|
||||
String testId = "drawFrame_changeAspectRatio_scaleToFit_wide";
|
||||
presentationTextureProcessor =
|
||||
presentationShaderProgram =
|
||||
Presentation.createForAspectRatio(/* aspectRatio= */ 2f, Presentation.LAYOUT_SCALE_TO_FIT)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = presentationShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_SCALE_TO_FIT_WIDE_PNG_ASSET_PATH);
|
||||
|
||||
presentationTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
presentationShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -167,15 +167,15 @@ public final class PresentationPixelTest {
|
||||
public void drawFrame_changeAspectRatio_scaleToFitWithCrop_narrow_matchesGoldenFile()
|
||||
throws Exception {
|
||||
String testId = "drawFrame_changeAspectRatio_scaleToFitWithCrop_narrow";
|
||||
presentationTextureProcessor =
|
||||
presentationShaderProgram =
|
||||
Presentation.createForAspectRatio(
|
||||
/* aspectRatio= */ 1f, Presentation.LAYOUT_SCALE_TO_FIT_WITH_CROP)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = presentationShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
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 =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -190,15 +190,15 @@ public final class PresentationPixelTest {
|
||||
public void drawFrame_changeAspectRatio_scaleToFitWithCrop_wide_matchesGoldenFile()
|
||||
throws Exception {
|
||||
String testId = "drawFrame_changeAspectRatio_scaleToFitWithCrop_wide";
|
||||
presentationTextureProcessor =
|
||||
presentationShaderProgram =
|
||||
Presentation.createForAspectRatio(
|
||||
/* aspectRatio= */ 2f, Presentation.LAYOUT_SCALE_TO_FIT_WITH_CROP)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = presentationShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
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 =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -212,14 +212,14 @@ public final class PresentationPixelTest {
|
||||
@Test
|
||||
public void drawFrame_changeAspectRatio_stretchToFit_narrow_matchesGoldenFile() throws Exception {
|
||||
String testId = "drawFrame_changeAspectRatio_stretchToFit_narrow";
|
||||
presentationTextureProcessor =
|
||||
presentationShaderProgram =
|
||||
Presentation.createForAspectRatio(/* aspectRatio= */ 1f, Presentation.LAYOUT_STRETCH_TO_FIT)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = presentationShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_STRETCH_TO_FIT_NARROW_PNG_ASSET_PATH);
|
||||
|
||||
presentationTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
presentationShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -233,14 +233,14 @@ public final class PresentationPixelTest {
|
||||
@Test
|
||||
public void drawFrame_changeAspectRatio_stretchToFit_wide_matchesGoldenFile() throws Exception {
|
||||
String testId = "drawFrame_changeAspectRatio_stretchToFit_wide";
|
||||
presentationTextureProcessor =
|
||||
presentationShaderProgram =
|
||||
Presentation.createForAspectRatio(/* aspectRatio= */ 2f, Presentation.LAYOUT_STRETCH_TO_FIT)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = presentationShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(ASPECT_RATIO_STRETCH_TO_FIT_WIDE_PNG_ASSET_PATH);
|
||||
|
||||
presentationTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
presentationShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
|
@ -69,7 +69,7 @@ public final class RgbAdjustmentPixelTest {
|
||||
|
||||
private @MonotonicNonNull EGLDisplay eglDisplay;
|
||||
private @MonotonicNonNull EGLContext eglContext;
|
||||
private @MonotonicNonNull SingleFrameGlTextureProcessor matrixTextureProcessor;
|
||||
private @MonotonicNonNull SingleFrameGlShaderProgram matrixShaderProgram;
|
||||
private @MonotonicNonNull EGLSurface placeholderEglSurface;
|
||||
private int inputTexId;
|
||||
private int inputWidth;
|
||||
@ -100,8 +100,8 @@ public final class RgbAdjustmentPixelTest {
|
||||
|
||||
@After
|
||||
public void release() throws GlUtil.GlException, FrameProcessingException {
|
||||
if (matrixTextureProcessor != null) {
|
||||
matrixTextureProcessor.release();
|
||||
if (matrixShaderProgram != null) {
|
||||
matrixShaderProgram.release();
|
||||
}
|
||||
GlUtil.destroyEglContext(eglDisplay, eglContext);
|
||||
}
|
||||
@ -110,11 +110,11 @@ public final class RgbAdjustmentPixelTest {
|
||||
public void drawFrame_identityMatrix_leavesFrameUnchanged() throws Exception {
|
||||
String testId = "drawFrame_identityMatrix";
|
||||
RgbMatrix identityMatrix = new RgbAdjustment.Builder().build();
|
||||
matrixTextureProcessor = identityMatrix.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight);
|
||||
matrixShaderProgram = identityMatrix.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
|
||||
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
|
||||
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -129,13 +129,13 @@ public final class RgbAdjustmentPixelTest {
|
||||
String testId = "drawFrame_removeColors";
|
||||
RgbMatrix removeColorMatrix =
|
||||
new RgbAdjustment.Builder().setRedScale(0).setGreenScale(0).setBlueScale(0).build();
|
||||
matrixTextureProcessor = removeColorMatrix.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight);
|
||||
matrixShaderProgram = removeColorMatrix.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
|
||||
Bitmap expectedBitmap =
|
||||
createArgb8888BitmapWithSolidColor(
|
||||
outputSize.getWidth(), outputSize.getHeight(), Color.BLACK);
|
||||
|
||||
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -149,11 +149,11 @@ public final class RgbAdjustmentPixelTest {
|
||||
public void drawFrame_redOnlyFilter_removeBlueAndGreenValues() throws Exception {
|
||||
String testId = "drawFrame_redOnlyFilter";
|
||||
RgbMatrix redOnlyMatrix = new RgbAdjustment.Builder().setBlueScale(0).setGreenScale(0).build();
|
||||
matrixTextureProcessor = redOnlyMatrix.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight);
|
||||
matrixShaderProgram = redOnlyMatrix.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
|
||||
Bitmap expectedBitmap = readBitmap(ONLY_RED_CHANNEL_PNG_ASSET_PATH);
|
||||
|
||||
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -167,11 +167,11 @@ public final class RgbAdjustmentPixelTest {
|
||||
public void drawFrame_increaseRedChannel_producesBrighterAndRedderFrame() throws Exception {
|
||||
String testId = "drawFrame_increaseRedChannel";
|
||||
RgbMatrix increaseRedMatrix = new RgbAdjustment.Builder().setRedScale(5).build();
|
||||
matrixTextureProcessor = increaseRedMatrix.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight);
|
||||
matrixShaderProgram = increaseRedMatrix.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
|
||||
Bitmap expectedBitmap = readBitmap(INCREASE_RED_CHANNEL_PNG_ASSET_PATH);
|
||||
|
||||
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -186,12 +186,11 @@ public final class RgbAdjustmentPixelTest {
|
||||
String testId = "drawFrame_increaseBrightness";
|
||||
RgbMatrix increaseBrightnessMatrix =
|
||||
new RgbAdjustment.Builder().setRedScale(5).setGreenScale(5).setBlueScale(5).build();
|
||||
matrixTextureProcessor =
|
||||
increaseBrightnessMatrix.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight);
|
||||
matrixShaderProgram = increaseBrightnessMatrix.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
|
||||
Bitmap expectedBitmap = readBitmap(INCREASE_BRIGHTNESS_PNG_ASSET_PATH);
|
||||
|
||||
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -207,18 +206,18 @@ public final class RgbAdjustmentPixelTest {
|
||||
RgbMatrix noRed = new RgbAdjustment.Builder().setRedScale(0).build();
|
||||
RgbMatrix noGreen = new RgbAdjustment.Builder().setGreenScale(0).build();
|
||||
RgbMatrix noBlue = new RgbAdjustment.Builder().setBlueScale(0).build();
|
||||
matrixTextureProcessor =
|
||||
MatrixTextureProcessor.create(
|
||||
matrixShaderProgram =
|
||||
MatrixShaderProgram.create(
|
||||
context,
|
||||
/* matrixTransformations= */ ImmutableList.of(),
|
||||
/* rgbMatrices= */ ImmutableList.of(noRed, noGreen, noBlue),
|
||||
/* useHdr= */ false);
|
||||
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight);
|
||||
Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
|
||||
Bitmap expectedBitmap =
|
||||
createArgb8888BitmapWithSolidColor(
|
||||
outputSize.getWidth(), outputSize.getHeight(), Color.BLACK);
|
||||
|
||||
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -233,16 +232,16 @@ public final class RgbAdjustmentPixelTest {
|
||||
String testId = "drawFrame_removeBlueAndGreenValuesInAChain";
|
||||
RgbMatrix noGreen = new RgbAdjustment.Builder().setGreenScale(0).build();
|
||||
RgbMatrix noBlue = new RgbAdjustment.Builder().setBlueScale(0).build();
|
||||
matrixTextureProcessor =
|
||||
MatrixTextureProcessor.create(
|
||||
matrixShaderProgram =
|
||||
MatrixShaderProgram.create(
|
||||
context,
|
||||
/* matrixTransformations= */ ImmutableList.of(),
|
||||
/* rgbMatrices= */ ImmutableList.of(noGreen, noBlue),
|
||||
/* useHdr= */ false);
|
||||
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight);
|
||||
Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
|
||||
Bitmap expectedBitmap = readBitmap(ONLY_RED_CHANNEL_PNG_ASSET_PATH);
|
||||
|
||||
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -259,16 +258,16 @@ public final class RgbAdjustmentPixelTest {
|
||||
RgbMatrix scaleRedMatrix = new RgbAdjustment.Builder().setRedScale(redScale).build();
|
||||
RgbMatrix scaleRedByInverseMatrix =
|
||||
new RgbAdjustment.Builder().setRedScale(1 / redScale).build();
|
||||
matrixTextureProcessor =
|
||||
MatrixTextureProcessor.create(
|
||||
matrixShaderProgram =
|
||||
MatrixShaderProgram.create(
|
||||
context,
|
||||
/* matrixTransformations= */ ImmutableList.of(),
|
||||
/* rgbMatrices= */ ImmutableList.of(scaleRedMatrix, scaleRedByInverseMatrix),
|
||||
/* useHdr= */ false);
|
||||
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight);
|
||||
Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
|
||||
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
|
||||
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
|
@ -64,7 +64,7 @@ public final class RgbFilterPixelTest {
|
||||
|
||||
private @MonotonicNonNull EGLDisplay eglDisplay;
|
||||
private @MonotonicNonNull EGLContext eglContext;
|
||||
private @MonotonicNonNull SingleFrameGlTextureProcessor matrixTextureProcessor;
|
||||
private @MonotonicNonNull SingleFrameGlShaderProgram matrixShaderProgram;
|
||||
private @MonotonicNonNull EGLSurface placeholderEglSurface;
|
||||
private int inputTexId;
|
||||
private int inputWidth;
|
||||
@ -95,8 +95,8 @@ public final class RgbFilterPixelTest {
|
||||
|
||||
@After
|
||||
public void release() throws GlUtil.GlException, FrameProcessingException {
|
||||
if (matrixTextureProcessor != null) {
|
||||
matrixTextureProcessor.release();
|
||||
if (matrixShaderProgram != null) {
|
||||
matrixShaderProgram.release();
|
||||
}
|
||||
GlUtil.destroyEglContext(eglDisplay, eglContext);
|
||||
}
|
||||
@ -105,11 +105,11 @@ public final class RgbFilterPixelTest {
|
||||
public void drawFrame_grayscale_producesGrayscaleImage() throws Exception {
|
||||
String testId = "drawFrame_grayscale";
|
||||
RgbMatrix grayscaleMatrix = RgbFilter.createGrayscaleFilter();
|
||||
matrixTextureProcessor = grayscaleMatrix.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight);
|
||||
matrixShaderProgram = grayscaleMatrix.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
|
||||
Bitmap expectedBitmap = readBitmap(GRAYSCALE_PNG_ASSET_PATH);
|
||||
|
||||
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -123,11 +123,11 @@ public final class RgbFilterPixelTest {
|
||||
public void drawFrame_inverted_producesInvertedFrame() throws Exception {
|
||||
String testId = "drawFrame_inverted";
|
||||
RgbMatrix invertedMatrix = RgbFilter.createInvertedFilter();
|
||||
matrixTextureProcessor = invertedMatrix.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight);
|
||||
matrixShaderProgram = invertedMatrix.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
|
||||
Bitmap expectedBitmap = readBitmap(INVERT_PNG_ASSET_PATH);
|
||||
|
||||
matrixTextureProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
matrixShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
|
@ -44,7 +44,7 @@ import org.junit.Test;
|
||||
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
|
||||
* 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 EGLContext eglContext;
|
||||
private @MonotonicNonNull EGLSurface placeholderEglSurface;
|
||||
private @MonotonicNonNull SingleFrameGlTextureProcessor colorLutProcessor;
|
||||
private @MonotonicNonNull SingleFrameGlShaderProgram colorLutShaderProgram;
|
||||
private int inputTexId;
|
||||
private int inputWidth;
|
||||
private int inputHeight;
|
||||
@ -89,8 +89,8 @@ public class SingleColorLutPixelTest {
|
||||
|
||||
@After
|
||||
public void release() throws GlUtil.GlException, FrameProcessingException {
|
||||
if (colorLutProcessor != null) {
|
||||
colorLutProcessor.release();
|
||||
if (colorLutShaderProgram != null) {
|
||||
colorLutShaderProgram.release();
|
||||
}
|
||||
GlUtil.destroyEglContext(eglDisplay, eglContext);
|
||||
}
|
||||
@ -99,14 +99,14 @@ public class SingleColorLutPixelTest {
|
||||
public void drawFrame_identityCubeLutSize2_leavesFrameUnchanged() throws Exception {
|
||||
String testId = "drawFrame_identityLutCubeSize2";
|
||||
int[][][] cubeIdentityLut = createIdentityLutCube(/* length= */ 2);
|
||||
colorLutProcessor =
|
||||
colorLutShaderProgram =
|
||||
SingleColorLut.createFromCube(cubeIdentityLut)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
|
||||
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -120,14 +120,14 @@ public class SingleColorLutPixelTest {
|
||||
public void drawFrame_identityCubeLutSize64_leavesFrameUnchanged() throws Exception {
|
||||
String testId = "drawFrame_identityLutCubeSize64";
|
||||
int[][][] cubeIdentityLut = createIdentityLutCube(/* length= */ 64);
|
||||
colorLutProcessor =
|
||||
colorLutShaderProgram =
|
||||
SingleColorLut.createFromCube(cubeIdentityLut)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
|
||||
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -141,14 +141,13 @@ public class SingleColorLutPixelTest {
|
||||
public void drawFrame_identityBitmapLutSize2_leavesFrameUnchanged() throws Exception {
|
||||
String testId = "drawFrame_identityBitmapLutSize2";
|
||||
Bitmap bitmapLut = createIdentityLutBitmap(/* length= */ 2);
|
||||
colorLutProcessor =
|
||||
SingleColorLut.createFromBitmap(bitmapLut)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight);
|
||||
colorLutShaderProgram =
|
||||
SingleColorLut.createFromBitmap(bitmapLut).toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
|
||||
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -162,14 +161,13 @@ public class SingleColorLutPixelTest {
|
||||
public void drawFrame_identityBitmapLutSize64_leavesFrameUnchanged() throws Exception {
|
||||
String testId = "drawFrame_identityBitmapLutSize64";
|
||||
Bitmap bitmapLut = createIdentityLutBitmap(/* length= */ 64);
|
||||
colorLutProcessor =
|
||||
SingleColorLut.createFromBitmap(bitmapLut)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight);
|
||||
colorLutShaderProgram =
|
||||
SingleColorLut.createFromBitmap(bitmapLut).toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
|
||||
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -183,14 +181,13 @@ public class SingleColorLutPixelTest {
|
||||
public void drawFrame_identityLutFromHaldImage_leavesFrameUnchanged() throws Exception {
|
||||
String testId = "drawFrame_identityLutFromHaldImage";
|
||||
Bitmap bitmapLut = readBitmap(VERTICAL_HALD_IDENTITY_LUT);
|
||||
colorLutProcessor =
|
||||
SingleColorLut.createFromBitmap(bitmapLut)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight);
|
||||
colorLutShaderProgram =
|
||||
SingleColorLut.createFromBitmap(bitmapLut).toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
|
||||
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -206,14 +203,14 @@ public class SingleColorLutPixelTest {
|
||||
int length = 3;
|
||||
int[][][] mapWhiteToGreen = createIdentityLutCube(length);
|
||||
mapWhiteToGreen[length - 1][length - 1][length - 1] = Color.GREEN;
|
||||
colorLutProcessor =
|
||||
colorLutShaderProgram =
|
||||
SingleColorLut.createFromCube(mapWhiteToGreen)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(LUT_MAP_WHITE_TO_GREEN_ASSET_PATH);
|
||||
|
||||
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -227,14 +224,14 @@ public class SingleColorLutPixelTest {
|
||||
public void drawFrame_applyInvertedLut_producesInvertedFrame() throws Exception {
|
||||
String testId = "drawFrame_applyInvertedLut";
|
||||
Bitmap invertedLutBitmap = readBitmap(VERTICAL_HALD_INVERTED_LUT);
|
||||
colorLutProcessor =
|
||||
colorLutShaderProgram =
|
||||
SingleColorLut.createFromBitmap(invertedLutBitmap)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(INVERT_PNG_ASSET_PATH);
|
||||
|
||||
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
@ -248,14 +245,14 @@ public class SingleColorLutPixelTest {
|
||||
public void drawFrame_applyGrayscaleLut_producesGrayscaleFrame() throws Exception {
|
||||
String testId = "drawFrame_applyGrayscaleLut";
|
||||
Bitmap grayscaleLutBitmap = readBitmap(VERTICAL_HALD_GRAYSCALE_LUT);
|
||||
colorLutProcessor =
|
||||
colorLutShaderProgram =
|
||||
SingleColorLut.createFromBitmap(grayscaleLutBitmap)
|
||||
.toGlTextureProcessor(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutProcessor.configure(inputWidth, inputHeight);
|
||||
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||
Size outputSize = colorLutShaderProgram.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = readBitmap(GRAYSCALE_PNG_ASSET_PATH);
|
||||
|
||||
colorLutProcessor.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
colorLutShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||
Bitmap actualBitmap =
|
||||
createArgb8888BitmapFromCurrentGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
||||
|
@ -19,48 +19,48 @@ import android.util.Pair;
|
||||
import androidx.annotation.GuardedBy;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.effect.GlTextureProcessor.InputListener;
|
||||
import androidx.media3.effect.GlTextureProcessor.OutputListener;
|
||||
import androidx.media3.effect.GlShaderProgram.InputListener;
|
||||
import androidx.media3.effect.GlShaderProgram.OutputListener;
|
||||
import java.util.ArrayDeque;
|
||||
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
|
||||
* GlTextureProcessor} and as {@link OutputListener} on the producing {@link GlTextureProcessor}.
|
||||
* <p>This listener should be set as {@link InputListener} on the consuming {@link GlShaderProgram}
|
||||
* and as {@link OutputListener} on the producing {@link GlShaderProgram}.
|
||||
*/
|
||||
/* package */ final class ChainingGlTextureProcessorListener
|
||||
implements GlTextureProcessor.InputListener, GlTextureProcessor.OutputListener {
|
||||
/* package */ final class ChainingGlShaderProgramListener
|
||||
implements GlShaderProgram.InputListener, GlShaderProgram.OutputListener {
|
||||
|
||||
private final GlTextureProcessor producingGlTextureProcessor;
|
||||
private final GlTextureProcessor consumingGlTextureProcessor;
|
||||
private final GlShaderProgram producingGlShaderProgram;
|
||||
private final GlShaderProgram consumingGlShaderProgram;
|
||||
private final FrameProcessingTaskExecutor frameProcessingTaskExecutor;
|
||||
|
||||
@GuardedBy("this")
|
||||
private final Queue<Pair<TextureInfo, Long>> availableFrames;
|
||||
|
||||
@GuardedBy("this")
|
||||
private int consumingGlTextureProcessorInputCapacity;
|
||||
private int consumingGlShaderProgramInputCapacity;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param producingGlTextureProcessor The {@link GlTextureProcessor} for which this listener will
|
||||
* be set as {@link OutputListener}.
|
||||
* @param consumingGlTextureProcessor The {@link GlTextureProcessor} for which this listener will
|
||||
* be set as {@link InputListener}.
|
||||
* @param producingGlShaderProgram The {@link GlShaderProgram} for which this listener will be set
|
||||
* as {@link OutputListener}.
|
||||
* @param consumingGlShaderProgram The {@link GlShaderProgram} for which this listener will be set
|
||||
* as {@link InputListener}.
|
||||
* @param frameProcessingTaskExecutor The {@link FrameProcessingTaskExecutor} that is used for
|
||||
* OpenGL calls. All calls to the producing/consuming {@link GlTextureProcessor} will be
|
||||
* executed by the {@link FrameProcessingTaskExecutor}. The caller is responsible for
|
||||
* releasing the {@link FrameProcessingTaskExecutor}.
|
||||
* OpenGL calls. All calls to the producing/consuming {@link GlShaderProgram} will be executed
|
||||
* by the {@link FrameProcessingTaskExecutor}. The caller is responsible for releasing the
|
||||
* {@link FrameProcessingTaskExecutor}.
|
||||
*/
|
||||
public ChainingGlTextureProcessorListener(
|
||||
GlTextureProcessor producingGlTextureProcessor,
|
||||
GlTextureProcessor consumingGlTextureProcessor,
|
||||
public ChainingGlShaderProgramListener(
|
||||
GlShaderProgram producingGlShaderProgram,
|
||||
GlShaderProgram consumingGlShaderProgram,
|
||||
FrameProcessingTaskExecutor frameProcessingTaskExecutor) {
|
||||
this.producingGlTextureProcessor = producingGlTextureProcessor;
|
||||
this.consumingGlTextureProcessor = consumingGlTextureProcessor;
|
||||
this.producingGlShaderProgram = producingGlShaderProgram;
|
||||
this.consumingGlShaderProgram = consumingGlShaderProgram;
|
||||
this.frameProcessingTaskExecutor = frameProcessingTaskExecutor;
|
||||
availableFrames = new ArrayDeque<>();
|
||||
}
|
||||
@ -69,18 +69,17 @@ import java.util.Queue;
|
||||
public synchronized void onReadyToAcceptInputFrame() {
|
||||
@Nullable Pair<TextureInfo, Long> pendingFrame = availableFrames.poll();
|
||||
if (pendingFrame == null) {
|
||||
consumingGlTextureProcessorInputCapacity++;
|
||||
consumingGlShaderProgramInputCapacity++;
|
||||
return;
|
||||
}
|
||||
|
||||
long presentationTimeUs = pendingFrame.second;
|
||||
if (presentationTimeUs == C.TIME_END_OF_SOURCE) {
|
||||
frameProcessingTaskExecutor.submit(
|
||||
consumingGlTextureProcessor::signalEndOfCurrentInputStream);
|
||||
frameProcessingTaskExecutor.submit(consumingGlShaderProgram::signalEndOfCurrentInputStream);
|
||||
} else {
|
||||
frameProcessingTaskExecutor.submit(
|
||||
() ->
|
||||
consumingGlTextureProcessor.queueInputFrame(
|
||||
consumingGlShaderProgram.queueInputFrame(
|
||||
/* inputTexture= */ pendingFrame.first, presentationTimeUs));
|
||||
}
|
||||
}
|
||||
@ -88,25 +87,25 @@ import java.util.Queue;
|
||||
@Override
|
||||
public void onInputFrameProcessed(TextureInfo inputTexture) {
|
||||
frameProcessingTaskExecutor.submit(
|
||||
() -> producingGlTextureProcessor.releaseOutputFrame(inputTexture));
|
||||
() -> producingGlShaderProgram.releaseOutputFrame(inputTexture));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onFlush() {
|
||||
consumingGlTextureProcessorInputCapacity = 0;
|
||||
consumingGlShaderProgramInputCapacity = 0;
|
||||
availableFrames.clear();
|
||||
frameProcessingTaskExecutor.submit(producingGlTextureProcessor::flush);
|
||||
frameProcessingTaskExecutor.submit(producingGlShaderProgram::flush);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onOutputFrameAvailable(
|
||||
TextureInfo outputTexture, long presentationTimeUs) {
|
||||
if (consumingGlTextureProcessorInputCapacity > 0) {
|
||||
if (consumingGlShaderProgramInputCapacity > 0) {
|
||||
frameProcessingTaskExecutor.submit(
|
||||
() ->
|
||||
consumingGlTextureProcessor.queueInputFrame(
|
||||
consumingGlShaderProgram.queueInputFrame(
|
||||
/* inputTexture= */ outputTexture, presentationTimeUs));
|
||||
consumingGlTextureProcessorInputCapacity--;
|
||||
consumingGlShaderProgramInputCapacity--;
|
||||
} else {
|
||||
availableFrames.add(new Pair<>(outputTexture, presentationTimeUs));
|
||||
}
|
||||
@ -117,8 +116,7 @@ import java.util.Queue;
|
||||
if (!availableFrames.isEmpty()) {
|
||||
availableFrames.add(new Pair<>(TextureInfo.UNSET, C.TIME_END_OF_SOURCE));
|
||||
} else {
|
||||
frameProcessingTaskExecutor.submit(
|
||||
consumingGlTextureProcessor::signalEndOfCurrentInputStream);
|
||||
frameProcessingTaskExecutor.submit(consumingGlShaderProgram::signalEndOfCurrentInputStream);
|
||||
}
|
||||
}
|
||||
}
|
@ -44,8 +44,8 @@ public interface ColorLut extends GlEffect {
|
||||
/** This method must be executed on the same thread as other GL commands. */
|
||||
@Override
|
||||
@WorkerThread
|
||||
default SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
||||
default SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
|
||||
throws FrameProcessingException {
|
||||
return new ColorLutProcessor(context, /* colorLut= */ this, useHdr);
|
||||
return new ColorLutShaderProgram(context, /* colorLut= */ this, useHdr);
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import androidx.media3.common.util.Size;
|
||||
import java.io.IOException;
|
||||
|
||||
/** 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 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.
|
||||
* @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 {
|
||||
super(useHdr);
|
||||
// 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;
|
||||
|
||||
try {
|
@ -41,8 +41,8 @@ public class Contrast implements GlEffect {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
||||
public SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
|
||||
throws FrameProcessingException {
|
||||
return new ContrastProcessor(context, this, useHdr);
|
||||
return new ContrastShaderProgram(context, this, useHdr);
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import androidx.media3.common.util.Size;
|
||||
import java.io.IOException;
|
||||
|
||||
/** 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 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.
|
||||
* @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 {
|
||||
super(useHdr);
|
||||
// Use 1.0001f to avoid division by zero issues.
|
@ -16,12 +16,12 @@
|
||||
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
|
||||
* 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
|
@ -25,26 +25,26 @@ import androidx.media3.common.FrameInfo;
|
||||
import androidx.media3.common.FrameProcessingException;
|
||||
import androidx.media3.common.FrameProcessor;
|
||||
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.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
private final FrameProcessingTaskExecutor frameProcessingTaskExecutor;
|
||||
private final ExternalTextureProcessor externalTextureProcessor;
|
||||
private final ExternalShaderProgram externalShaderProgram;
|
||||
private final int externalTexId;
|
||||
private final SurfaceTexture surfaceTexture;
|
||||
private final float[] textureTransformMatrix;
|
||||
private final Queue<FrameInfo> pendingFrames;
|
||||
|
||||
// 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.
|
||||
// Read and written only on GL thread.
|
||||
private int numberOfFramesToDropOnBecomingAvailable;
|
||||
@ -66,16 +66,16 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
/**
|
||||
* 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}.
|
||||
* @param frameProcessingTaskExecutor The {@link FrameProcessingTaskExecutor}.
|
||||
* @throws FrameProcessingException If a problem occurs while creating the external texture.
|
||||
*/
|
||||
public ExternalTextureManager(
|
||||
ExternalTextureProcessor externalTextureProcessor,
|
||||
ExternalShaderProgram externalShaderProgram,
|
||||
FrameProcessingTaskExecutor frameProcessingTaskExecutor)
|
||||
throws FrameProcessingException {
|
||||
this.externalTextureProcessor = externalTextureProcessor;
|
||||
this.externalShaderProgram = externalShaderProgram;
|
||||
this.frameProcessingTaskExecutor = frameProcessingTaskExecutor;
|
||||
try {
|
||||
externalTexId = GlUtil.createExternalTexture();
|
||||
@ -85,7 +85,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
surfaceTexture = new SurfaceTexture(externalTexId);
|
||||
textureTransformMatrix = new float[16];
|
||||
pendingFrames = new ConcurrentLinkedQueue<>();
|
||||
externalTextureProcessorInputCapacity = new AtomicInteger();
|
||||
externalShaderProgramInputCapacity = new AtomicInteger();
|
||||
|
||||
previousStreamOffsetUs = C.TIME_UNSET;
|
||||
}
|
||||
@ -101,7 +101,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
maybeExecuteAfterFlushTask();
|
||||
} else {
|
||||
availableFrameCount++;
|
||||
maybeQueueFrameToExternalTextureProcessor();
|
||||
maybeQueueFrameToExternalShaderProgram();
|
||||
}
|
||||
}));
|
||||
return surfaceTexture;
|
||||
@ -111,8 +111,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
public void onReadyToAcceptInputFrame() {
|
||||
frameProcessingTaskExecutor.submit(
|
||||
() -> {
|
||||
externalTextureProcessorInputCapacity.incrementAndGet();
|
||||
maybeQueueFrameToExternalTextureProcessor();
|
||||
externalShaderProgramInputCapacity.incrementAndGet();
|
||||
maybeQueueFrameToExternalShaderProgram();
|
||||
});
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
frameProcessingTaskExecutor.submit(
|
||||
() -> {
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
@ -166,7 +166,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
() -> {
|
||||
inputStreamEnded = true;
|
||||
if (pendingFrames.isEmpty() && currentFrame == null) {
|
||||
externalTextureProcessor.signalEndOfCurrentInputStream();
|
||||
externalShaderProgram.signalEndOfCurrentInputStream();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -183,7 +183,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
availableFrameCount--;
|
||||
surfaceTexture.updateTexImage();
|
||||
}
|
||||
externalTextureProcessorInputCapacity.set(0);
|
||||
externalShaderProgramInputCapacity.set(0);
|
||||
currentFrame = null;
|
||||
pendingFrames.clear();
|
||||
maybeExecuteAfterFlushTask();
|
||||
@ -197,8 +197,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void maybeQueueFrameToExternalTextureProcessor() {
|
||||
if (externalTextureProcessorInputCapacity.get() == 0
|
||||
private void maybeQueueFrameToExternalShaderProgram() {
|
||||
if (externalShaderProgramInputCapacity.get() == 0
|
||||
|| availableFrameCount == 0
|
||||
|| currentFrame != null) {
|
||||
return;
|
||||
@ -209,28 +209,28 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
this.currentFrame = pendingFrames.peek();
|
||||
|
||||
FrameInfo currentFrame = checkStateNotNull(this.currentFrame);
|
||||
externalTextureProcessorInputCapacity.decrementAndGet();
|
||||
externalShaderProgramInputCapacity.decrementAndGet();
|
||||
surfaceTexture.getTransformMatrix(textureTransformMatrix);
|
||||
externalTextureProcessor.setTextureTransformMatrix(textureTransformMatrix);
|
||||
externalShaderProgram.setTextureTransformMatrix(textureTransformMatrix);
|
||||
long frameTimeNs = surfaceTexture.getTimestamp();
|
||||
long offsetToAddUs = currentFrame.offsetToAddUs;
|
||||
long streamOffsetUs = currentFrame.streamOffsetUs;
|
||||
if (streamOffsetUs != previousStreamOffsetUs) {
|
||||
if (previousStreamOffsetUs != C.TIME_UNSET) {
|
||||
externalTextureProcessor.signalEndOfCurrentInputStream();
|
||||
externalShaderProgram.signalEndOfCurrentInputStream();
|
||||
}
|
||||
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;
|
||||
externalTextureProcessor.queueInputFrame(
|
||||
externalShaderProgram.queueInputFrame(
|
||||
new TextureInfo(
|
||||
externalTexId, /* fboId= */ C.INDEX_UNSET, currentFrame.width, currentFrame.height),
|
||||
presentationTimeUs);
|
||||
checkStateNotNull(pendingFrames.remove());
|
||||
|
||||
if (inputStreamEnded && pendingFrames.isEmpty()) {
|
||||
externalTextureProcessor.signalEndOfCurrentInputStream();
|
||||
externalShaderProgram.signalEndOfCurrentInputStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,19 +51,19 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
/**
|
||||
* Wrapper around a {@link GlTextureProcessor} that writes to the provided output surface and
|
||||
* optional debug surface view.
|
||||
* Wrapper around a {@link GlShaderProgram} that writes to the provided output surface and optional
|
||||
* 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
|
||||
* 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
|
||||
* GlTextureProcessor} instances used by {@link FrameProcessor}.
|
||||
* <p>This wrapper is used for the final {@link GlShaderProgram} instance in the chain of {@link
|
||||
* 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 ImmutableList<GlMatrixTransformation> matrixTransformations;
|
||||
@ -83,7 +83,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
private int inputWidth;
|
||||
private int inputHeight;
|
||||
@Nullable private MatrixTextureProcessor matrixTextureProcessor;
|
||||
@Nullable private MatrixShaderProgram matrixShaderProgram;
|
||||
@Nullable private SurfaceViewWrapper debugSurfaceViewWrapper;
|
||||
private InputListener inputListener;
|
||||
private @MonotonicNonNull Size outputSizeBeforeSurfaceTransformation;
|
||||
@ -99,7 +99,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@Nullable
|
||||
private EGLSurface outputEglSurface;
|
||||
|
||||
public FinalMatrixTextureProcessorWrapper(
|
||||
public FinalMatrixShaderProgramWrapper(
|
||||
Context context,
|
||||
EGLDisplay eglDisplay,
|
||||
EGLContext eglContext,
|
||||
@ -167,7 +167,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
|
||||
@ -195,8 +195,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
public void flush() {
|
||||
// Drops all frames that aren't released yet.
|
||||
availableFrames.clear();
|
||||
if (matrixTextureProcessor != null) {
|
||||
matrixTextureProcessor.flush();
|
||||
if (matrixShaderProgram != null) {
|
||||
matrixShaderProgram.flush();
|
||||
}
|
||||
inputListener.onFlush();
|
||||
inputListener.onReadyToAcceptInputFrame();
|
||||
@ -205,8 +205,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@Override
|
||||
@WorkerThread
|
||||
public synchronized void release() throws FrameProcessingException {
|
||||
if (matrixTextureProcessor != null) {
|
||||
matrixTextureProcessor.release();
|
||||
if (matrixShaderProgram != null) {
|
||||
matrixShaderProgram.release();
|
||||
}
|
||||
try {
|
||||
GlUtil.destroyEglSurface(eglDisplay, outputEglSurface);
|
||||
@ -224,8 +224,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
/* destPost= */ 0,
|
||||
/* length= */ textureTransformMatrix.length);
|
||||
|
||||
if (matrixTextureProcessor != null) {
|
||||
matrixTextureProcessor.setTextureTransformMatrix(textureTransformMatrix);
|
||||
if (matrixShaderProgram != null) {
|
||||
matrixShaderProgram.setTextureTransformMatrix(textureTransformMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,7 +295,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
EGLSurface outputEglSurface = this.outputEglSurface;
|
||||
SurfaceInfo outputSurfaceInfo = this.outputSurfaceInfo;
|
||||
MatrixTextureProcessor matrixTextureProcessor = this.matrixTextureProcessor;
|
||||
MatrixShaderProgram matrixShaderProgram = this.matrixShaderProgram;
|
||||
|
||||
GlUtil.focusEglSurface(
|
||||
eglDisplay,
|
||||
@ -304,7 +304,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
outputSurfaceInfo.width,
|
||||
outputSurfaceInfo.height);
|
||||
GlUtil.clearOutputFrame();
|
||||
matrixTextureProcessor.drawFrame(inputTexture.texId, presentationTimeUs);
|
||||
matrixShaderProgram.drawFrame(inputTexture.texId, presentationTimeUs);
|
||||
|
||||
EGLExt.eglPresentationTimeANDROID(
|
||||
eglDisplay,
|
||||
@ -316,7 +316,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
}
|
||||
|
||||
@EnsuresNonNullIf(
|
||||
expression = {"outputSurfaceInfo", "outputEglSurface", "matrixTextureProcessor"},
|
||||
expression = {"outputSurfaceInfo", "outputEglSurface", "matrixShaderProgram"},
|
||||
result = true)
|
||||
private synchronized boolean ensureConfigured(int inputWidth, int inputHeight)
|
||||
throws FrameProcessingException, GlUtil.GlException {
|
||||
@ -340,9 +340,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
}
|
||||
|
||||
if (outputSurfaceInfo == null) {
|
||||
if (matrixTextureProcessor != null) {
|
||||
matrixTextureProcessor.release();
|
||||
matrixTextureProcessor = null;
|
||||
if (matrixShaderProgram != null) {
|
||||
matrixShaderProgram.release();
|
||||
matrixShaderProgram = null;
|
||||
}
|
||||
GlUtil.destroyEglSurface(eglDisplay, outputEglSurface);
|
||||
outputEglSurface = null;
|
||||
@ -372,13 +372,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
this.debugSurfaceView = debugSurfaceView;
|
||||
}
|
||||
|
||||
if (matrixTextureProcessor != null && outputSizeOrRotationChanged) {
|
||||
matrixTextureProcessor.release();
|
||||
matrixTextureProcessor = null;
|
||||
if (matrixShaderProgram != null && outputSizeOrRotationChanged) {
|
||||
matrixShaderProgram.release();
|
||||
matrixShaderProgram = null;
|
||||
outputSizeOrRotationChanged = false;
|
||||
}
|
||||
if (matrixTextureProcessor == null) {
|
||||
matrixTextureProcessor = createMatrixTextureProcessorForOutputSurface(outputSurfaceInfo);
|
||||
if (matrixShaderProgram == null) {
|
||||
matrixShaderProgram = createMatrixShaderProgramForOutputSurface(outputSurfaceInfo);
|
||||
}
|
||||
|
||||
this.outputSurfaceInfo = outputSurfaceInfo;
|
||||
@ -386,7 +386,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
return true;
|
||||
}
|
||||
|
||||
private MatrixTextureProcessor createMatrixTextureProcessorForOutputSurface(
|
||||
private MatrixShaderProgram createMatrixShaderProgramForOutputSurface(
|
||||
SurfaceInfo outputSurfaceInfo) throws FrameProcessingException {
|
||||
ImmutableList.Builder<GlMatrixTransformation> matrixTransformationListBuilder =
|
||||
new ImmutableList.Builder<GlMatrixTransformation>().addAll(matrixTransformations);
|
||||
@ -400,46 +400,46 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
Presentation.createForWidthAndHeight(
|
||||
outputSurfaceInfo.width, outputSurfaceInfo.height, Presentation.LAYOUT_SCALE_TO_FIT));
|
||||
|
||||
MatrixTextureProcessor matrixTextureProcessor;
|
||||
MatrixShaderProgram matrixShaderProgram;
|
||||
ImmutableList<GlMatrixTransformation> expandedMatrixTransformations =
|
||||
matrixTransformationListBuilder.build();
|
||||
if (sampleFromExternalTexture) {
|
||||
matrixTextureProcessor =
|
||||
MatrixTextureProcessor.createWithExternalSampler(
|
||||
matrixShaderProgram =
|
||||
MatrixShaderProgram.createWithExternalSampler(
|
||||
context,
|
||||
expandedMatrixTransformations,
|
||||
rgbMatrices,
|
||||
/* inputColorInfo= */ inputColorInfo,
|
||||
/* outputColorInfo= */ outputColorInfo);
|
||||
} else {
|
||||
matrixTextureProcessor =
|
||||
MatrixTextureProcessor.createApplyingOetf(
|
||||
matrixShaderProgram =
|
||||
MatrixShaderProgram.createApplyingOetf(
|
||||
context, expandedMatrixTransformations, rgbMatrices, outputColorInfo);
|
||||
}
|
||||
|
||||
matrixTextureProcessor.setTextureTransformMatrix(textureTransformMatrix);
|
||||
Size outputSize = matrixTextureProcessor.configure(inputWidth, inputHeight);
|
||||
matrixShaderProgram.setTextureTransformMatrix(textureTransformMatrix);
|
||||
Size outputSize = matrixShaderProgram.configure(inputWidth, inputHeight);
|
||||
checkState(outputSize.getWidth() == outputSurfaceInfo.width);
|
||||
checkState(outputSize.getHeight() == outputSurfaceInfo.height);
|
||||
return matrixTextureProcessor;
|
||||
return matrixShaderProgram;
|
||||
}
|
||||
|
||||
private void maybeRenderFrameToDebugSurface(TextureInfo inputTexture, long presentationTimeUs) {
|
||||
if (debugSurfaceViewWrapper == null || this.matrixTextureProcessor == null) {
|
||||
if (debugSurfaceViewWrapper == null || this.matrixShaderProgram == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MatrixTextureProcessor matrixTextureProcessor = this.matrixTextureProcessor;
|
||||
MatrixShaderProgram matrixShaderProgram = this.matrixShaderProgram;
|
||||
try {
|
||||
debugSurfaceViewWrapper.maybeRenderToSurfaceView(
|
||||
() -> {
|
||||
GlUtil.clearOutputFrame();
|
||||
@C.ColorTransfer
|
||||
int configuredColorTransfer = matrixTextureProcessor.getOutputColorTransfer();
|
||||
matrixTextureProcessor.setOutputColorTransfer(
|
||||
int configuredColorTransfer = matrixShaderProgram.getOutputColorTransfer();
|
||||
matrixShaderProgram.setOutputColorTransfer(
|
||||
checkNotNull(debugSurfaceViewWrapper).outputColorTransfer);
|
||||
matrixTextureProcessor.drawFrame(inputTexture.texId, presentationTimeUs);
|
||||
matrixTextureProcessor.setOutputColorTransfer(configuredColorTransfer);
|
||||
matrixShaderProgram.drawFrame(inputTexture.texId, presentationTimeUs);
|
||||
matrixShaderProgram.setOutputColorTransfer(configuredColorTransfer);
|
||||
});
|
||||
} catch (FrameProcessingException | GlUtil.GlException e) {
|
||||
Log.d(TAG, "Error rendering to debug preview", e);
|
@ -50,8 +50,8 @@ public class FrameCache implements GlEffect {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
||||
public GlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
|
||||
throws FrameProcessingException {
|
||||
return new FrameCacheTextureProcessor(context, capacity, useHdr);
|
||||
return new FrameCacheShaderProgram(context, capacity, useHdr);
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ import java.util.concurrent.Executor;
|
||||
*
|
||||
* <p>Implements {@link FrameCache}.
|
||||
*/
|
||||
/* package */ class FrameCacheTextureProcessor implements GlTextureProcessor {
|
||||
/* package */ class FrameCacheShaderProgram implements GlShaderProgram {
|
||||
private static final String VERTEX_SHADER_TRANSFORMATION_ES2_PATH =
|
||||
"shaders/vertex_shader_transformation_es2.glsl";
|
||||
private static final String FRAGMENT_SHADER_TRANSFORMATION_ES2_PATH =
|
||||
@ -53,7 +53,7 @@ import java.util.concurrent.Executor;
|
||||
private Executor errorListenerExecutor;
|
||||
|
||||
/** Creates a new instance. */
|
||||
public FrameCacheTextureProcessor(Context context, int capacity, boolean useHdr)
|
||||
public FrameCacheShaderProgram(Context context, int capacity, boolean useHdr)
|
||||
throws FrameProcessingException {
|
||||
freeOutputTextures = new ArrayDeque<>();
|
||||
inUseOutputTextures = new ArrayDeque<>();
|
@ -21,24 +21,23 @@ import androidx.media3.common.FrameProcessingException;
|
||||
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
|
||||
* #toGlTextureProcessor(Context, boolean) converted} to a {@link GlTextureProcessor} which applies
|
||||
* the effect.
|
||||
* #toGlShaderProgram(Context, boolean) converted} to a {@link GlShaderProgram} which applies the
|
||||
* effect.
|
||||
*/
|
||||
@UnstableApi
|
||||
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 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.
|
||||
* @throws FrameProcessingException If an error occurs while creating the {@link
|
||||
* GlTextureProcessor}.
|
||||
* @throws FrameProcessingException If an error occurs while creating the {@link GlShaderProgram}.
|
||||
*/
|
||||
GlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
||||
GlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
|
||||
throws FrameProcessingException;
|
||||
}
|
||||
|
@ -152,8 +152,8 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
|
||||
|
||||
/**
|
||||
* Creates the OpenGL context, surfaces, textures, and frame buffers, initializes {@link
|
||||
* GlTextureProcessor} instances corresponding to the {@link GlEffect} instances, and returns a
|
||||
* new {@code GlEffectsFrameProcessor}.
|
||||
* GlShaderProgram} instances corresponding to the {@link GlEffect} instances, and returns a new
|
||||
* {@code GlEffectsFrameProcessor}.
|
||||
*
|
||||
* <p>All {@link Effect} instances must be {@link GlEffect} instances.
|
||||
*
|
||||
@ -199,8 +199,8 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
ImmutableList<GlTextureProcessor> textureProcessors =
|
||||
getGlTextureProcessorsForGlEffects(
|
||||
ImmutableList<GlShaderProgram> shaderPrograms =
|
||||
getGlShaderProgramsForGlEffects(
|
||||
context,
|
||||
effects,
|
||||
eglDisplay,
|
||||
@ -213,29 +213,29 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
|
||||
listener);
|
||||
FrameProcessingTaskExecutor frameProcessingTaskExecutor =
|
||||
new FrameProcessingTaskExecutor(singleThreadExecutorService, listener);
|
||||
chainTextureProcessorsWithListeners(
|
||||
textureProcessors, frameProcessingTaskExecutor, listener, executor);
|
||||
chainShaderProgramsWithListeners(
|
||||
shaderPrograms, frameProcessingTaskExecutor, listener, executor);
|
||||
|
||||
return new GlEffectsFrameProcessor(
|
||||
eglDisplay,
|
||||
eglContext,
|
||||
frameProcessingTaskExecutor,
|
||||
textureProcessors,
|
||||
shaderPrograms,
|
||||
releaseFramesAutomatically);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines consecutive {@link GlMatrixTransformation} and {@link RgbMatrix} instances into a
|
||||
* single {@link MatrixTextureProcessor} and converts all other {@link GlEffect} instances to
|
||||
* separate {@link GlTextureProcessor} instances.
|
||||
* single {@link MatrixShaderProgram} and converts all other {@link GlEffect} instances to
|
||||
* separate {@link GlShaderProgram} 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.
|
||||
* The first is an {@link ExternalTextureProcessor} and the last is a {@link
|
||||
* FinalMatrixTextureProcessorWrapper}.
|
||||
* @return A non-empty list of {@link GlShaderProgram} instances to apply in the given order. The
|
||||
* first is an {@link ExternalShaderProgram} and the last is a {@link
|
||||
* FinalMatrixShaderProgramWrapper}.
|
||||
*/
|
||||
private static ImmutableList<GlTextureProcessor> getGlTextureProcessorsForGlEffects(
|
||||
private static ImmutableList<GlShaderProgram> getGlShaderProgramsForGlEffects(
|
||||
Context context,
|
||||
List<Effect> effects,
|
||||
EGLDisplay eglDisplay,
|
||||
@ -247,8 +247,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
|
||||
Executor executor,
|
||||
Listener listener)
|
||||
throws FrameProcessingException {
|
||||
ImmutableList.Builder<GlTextureProcessor> textureProcessorListBuilder =
|
||||
new ImmutableList.Builder<>();
|
||||
ImmutableList.Builder<GlShaderProgram> shaderProgramListBuilder = new ImmutableList.Builder<>();
|
||||
ImmutableList.Builder<GlMatrixTransformation> matrixTransformationListBuilder =
|
||||
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();
|
||||
boolean isOutputTransferHdr = ColorInfo.isTransferHdr(outputColorInfo);
|
||||
if (!matrixTransformations.isEmpty() || !rgbMatrices.isEmpty() || sampleFromExternalTexture) {
|
||||
MatrixTextureProcessor matrixTextureProcessor;
|
||||
MatrixShaderProgram matrixShaderProgram;
|
||||
if (sampleFromExternalTexture) {
|
||||
matrixTextureProcessor =
|
||||
MatrixTextureProcessor.createWithExternalSampler(
|
||||
matrixShaderProgram =
|
||||
MatrixShaderProgram.createWithExternalSampler(
|
||||
context,
|
||||
matrixTransformations,
|
||||
rgbMatrices,
|
||||
/* inputColorInfo= */ inputColorInfo,
|
||||
/* outputColorInfo= */ linearColorInfo);
|
||||
} else {
|
||||
matrixTextureProcessor =
|
||||
MatrixTextureProcessor.create(
|
||||
matrixShaderProgram =
|
||||
MatrixShaderProgram.create(
|
||||
context, matrixTransformations, rgbMatrices, isOutputTransferHdr);
|
||||
}
|
||||
textureProcessorListBuilder.add(matrixTextureProcessor);
|
||||
shaderProgramListBuilder.add(matrixShaderProgram);
|
||||
matrixTransformationListBuilder = new ImmutableList.Builder<>();
|
||||
rgbMatrixListBuilder = new ImmutableList.Builder<>();
|
||||
sampleFromExternalTexture = false;
|
||||
}
|
||||
textureProcessorListBuilder.add(glEffect.toGlTextureProcessor(context, isOutputTransferHdr));
|
||||
shaderProgramListBuilder.add(glEffect.toGlShaderProgram(context, isOutputTransferHdr));
|
||||
}
|
||||
|
||||
textureProcessorListBuilder.add(
|
||||
new FinalMatrixTextureProcessorWrapper(
|
||||
shaderProgramListBuilder.add(
|
||||
new FinalMatrixShaderProgramWrapper(
|
||||
context,
|
||||
eglDisplay,
|
||||
eglContext,
|
||||
@ -313,30 +312,28 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
|
||||
releaseFramesAutomatically,
|
||||
executor,
|
||||
listener));
|
||||
return textureProcessorListBuilder.build();
|
||||
return shaderProgramListBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Chains the given {@link GlTextureProcessor} instances using {@link
|
||||
* ChainingGlTextureProcessorListener} instances.
|
||||
* Chains the given {@link GlShaderProgram} instances using {@link
|
||||
* ChainingGlShaderProgramListener} instances.
|
||||
*/
|
||||
private static void chainTextureProcessorsWithListeners(
|
||||
ImmutableList<GlTextureProcessor> textureProcessors,
|
||||
private static void chainShaderProgramsWithListeners(
|
||||
ImmutableList<GlShaderProgram> shaderPrograms,
|
||||
FrameProcessingTaskExecutor frameProcessingTaskExecutor,
|
||||
Listener frameProcessorListener,
|
||||
Executor frameProcessorListenerExecutor) {
|
||||
for (int i = 0; i < textureProcessors.size() - 1; i++) {
|
||||
GlTextureProcessor producingGlTextureProcessor = textureProcessors.get(i);
|
||||
GlTextureProcessor consumingGlTextureProcessor = textureProcessors.get(i + 1);
|
||||
ChainingGlTextureProcessorListener chainingGlTextureProcessorListener =
|
||||
new ChainingGlTextureProcessorListener(
|
||||
producingGlTextureProcessor,
|
||||
consumingGlTextureProcessor,
|
||||
frameProcessingTaskExecutor);
|
||||
producingGlTextureProcessor.setOutputListener(chainingGlTextureProcessorListener);
|
||||
producingGlTextureProcessor.setErrorListener(
|
||||
for (int i = 0; i < shaderPrograms.size() - 1; i++) {
|
||||
GlShaderProgram producingGlShaderProgram = shaderPrograms.get(i);
|
||||
GlShaderProgram consumingGlShaderProgram = shaderPrograms.get(i + 1);
|
||||
ChainingGlShaderProgramListener chainingGlShaderProgramListener =
|
||||
new ChainingGlShaderProgramListener(
|
||||
producingGlShaderProgram, consumingGlShaderProgram, frameProcessingTaskExecutor);
|
||||
producingGlShaderProgram.setOutputListener(chainingGlShaderProgramListener);
|
||||
producingGlShaderProgram.setErrorListener(
|
||||
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 Surface inputSurface;
|
||||
private final boolean releaseFramesAutomatically;
|
||||
private final FinalMatrixTextureProcessorWrapper finalTextureProcessorWrapper;
|
||||
private final ImmutableList<GlTextureProcessor> allTextureProcessors;
|
||||
private final FinalMatrixShaderProgramWrapper finalShaderProgramWrapper;
|
||||
private final ImmutableList<GlShaderProgram> allShaderPrograms;
|
||||
|
||||
/**
|
||||
* 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,
|
||||
EGLContext eglContext,
|
||||
FrameProcessingTaskExecutor frameProcessingTaskExecutor,
|
||||
ImmutableList<GlTextureProcessor> textureProcessors,
|
||||
ImmutableList<GlShaderProgram> shaderPrograms,
|
||||
boolean releaseFramesAutomatically)
|
||||
throws FrameProcessingException {
|
||||
|
||||
@ -374,17 +371,17 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
|
||||
this.frameProcessingTaskExecutor = frameProcessingTaskExecutor;
|
||||
this.releaseFramesAutomatically = releaseFramesAutomatically;
|
||||
|
||||
checkState(!textureProcessors.isEmpty());
|
||||
checkState(textureProcessors.get(0) instanceof ExternalTextureProcessor);
|
||||
checkState(getLast(textureProcessors) instanceof FinalMatrixTextureProcessorWrapper);
|
||||
ExternalTextureProcessor inputExternalTextureProcessor =
|
||||
(ExternalTextureProcessor) textureProcessors.get(0);
|
||||
checkState(!shaderPrograms.isEmpty());
|
||||
checkState(shaderPrograms.get(0) instanceof ExternalShaderProgram);
|
||||
checkState(getLast(shaderPrograms) instanceof FinalMatrixShaderProgramWrapper);
|
||||
ExternalShaderProgram inputExternalShaderProgram =
|
||||
(ExternalShaderProgram) shaderPrograms.get(0);
|
||||
inputExternalTextureManager =
|
||||
new ExternalTextureManager(inputExternalTextureProcessor, frameProcessingTaskExecutor);
|
||||
inputExternalTextureProcessor.setInputListener(inputExternalTextureManager);
|
||||
new ExternalTextureManager(inputExternalShaderProgram, frameProcessingTaskExecutor);
|
||||
inputExternalShaderProgram.setInputListener(inputExternalTextureManager);
|
||||
inputSurface = new Surface(inputExternalTextureManager.getSurfaceTexture());
|
||||
finalTextureProcessorWrapper = (FinalMatrixTextureProcessorWrapper) getLast(textureProcessors);
|
||||
allTextureProcessors = textureProcessors;
|
||||
finalShaderProgramWrapper = (FinalMatrixShaderProgramWrapper) getLast(shaderPrograms);
|
||||
allShaderPrograms = shaderPrograms;
|
||||
previousStreamOffsetUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@ -423,7 +420,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
|
||||
nextInputFrameInfo = adjustForPixelWidthHeightRatio(inputFrameInfo);
|
||||
|
||||
if (nextInputFrameInfo.streamOffsetUs != previousStreamOffsetUs) {
|
||||
finalTextureProcessorWrapper.appendStream(nextInputFrameInfo.streamOffsetUs);
|
||||
finalShaderProgramWrapper.appendStream(nextInputFrameInfo.streamOffsetUs);
|
||||
previousStreamOffsetUs = nextInputFrameInfo.streamOffsetUs;
|
||||
}
|
||||
}
|
||||
@ -444,7 +441,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
|
||||
|
||||
@Override
|
||||
public void setOutputSurfaceInfo(@Nullable SurfaceInfo outputSurfaceInfo) {
|
||||
finalTextureProcessorWrapper.setOutputSurfaceInfo(outputSurfaceInfo);
|
||||
finalShaderProgramWrapper.setOutputSurfaceInfo(outputSurfaceInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -453,7 +450,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
|
||||
!releaseFramesAutomatically,
|
||||
"Calling this method is not allowed when releaseFramesAutomatically is enabled");
|
||||
frameProcessingTaskExecutor.submitWithHighPriority(
|
||||
() -> finalTextureProcessorWrapper.releaseOutputFrame(releaseTimeNs));
|
||||
() -> finalShaderProgramWrapper.releaseOutputFrame(releaseTimeNs));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -469,7 +466,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
|
||||
frameProcessingTaskExecutor.flush();
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
inputExternalTextureManager.setOnFlushCompleteListener(latch::countDown);
|
||||
frameProcessingTaskExecutor.submit(finalTextureProcessorWrapper::flush);
|
||||
frameProcessingTaskExecutor.submit(finalShaderProgramWrapper::flush);
|
||||
latch.await();
|
||||
inputExternalTextureManager.setOnFlushCompleteListener(null);
|
||||
} catch (InterruptedException e) {
|
||||
@ -481,8 +478,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
|
||||
public void release() {
|
||||
try {
|
||||
frameProcessingTaskExecutor.release(
|
||||
/* releaseTask= */ this::releaseTextureProcessorsAndDestroyGlContext,
|
||||
RELEASE_WAIT_TIME_MS);
|
||||
/* releaseTask= */ this::releaseShaderProgramsAndDestroyGlContext, RELEASE_WAIT_TIME_MS);
|
||||
} catch (InterruptedException unexpected) {
|
||||
Thread.currentThread().interrupt();
|
||||
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}.
|
||||
*/
|
||||
@WorkerThread
|
||||
private void releaseTextureProcessorsAndDestroyGlContext()
|
||||
private void releaseShaderProgramsAndDestroyGlContext()
|
||||
throws GlUtil.GlException, FrameProcessingException {
|
||||
for (int i = 0; i < allTextureProcessors.size(); i++) {
|
||||
allTextureProcessors.get(i).release();
|
||||
for (int i = 0; i < allShaderPrograms.size(); i++) {
|
||||
allShaderPrograms.get(i).release();
|
||||
}
|
||||
GlUtil.destroyEglContext(eglDisplay, eglContext);
|
||||
}
|
||||
|
@ -53,9 +53,9 @@ public interface GlMatrixTransformation extends GlEffect {
|
||||
float[] getGlMatrixArray(long presentationTimeUs);
|
||||
|
||||
@Override
|
||||
default SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
||||
default SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
|
||||
throws FrameProcessingException {
|
||||
return MatrixTextureProcessor.create(
|
||||
return MatrixShaderProgram.create(
|
||||
context,
|
||||
/* matrixTransformations= */ ImmutableList.of(this),
|
||||
/* rgbMatrices= */ ImmutableList.of(),
|
||||
|
@ -22,29 +22,29 @@ import java.util.concurrent.Executor;
|
||||
/**
|
||||
* 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
|
||||
* {@linkplain InputListener#onInputFrameProcessed(TextureInfo) listener} once the texture's
|
||||
* contents have been processed.
|
||||
*
|
||||
* <p>The {@code GlTextureProcessor} produces output frames asynchronously and notifies its owner
|
||||
* when they are available via its {@linkplain OutputListener#onOutputFrameAvailable(TextureInfo,
|
||||
* long) listener}. The {@code GlTextureProcessor} instance's owner must surrender the texture back
|
||||
* to the {@code GlTextureProcessor} via {@link #releaseOutputFrame(TextureInfo)} when it has
|
||||
* finished processing it.
|
||||
* <p>The {@code GlShaderProgram} produces output frames asynchronously and notifies its owner when
|
||||
* they are available via its {@linkplain OutputListener#onOutputFrameAvailable(TextureInfo, long)
|
||||
* listener}. The {@code GlShaderProgram} instance's owner must surrender the texture back to the
|
||||
* {@code GlShaderProgram} via {@link #releaseOutputFrame(TextureInfo)} when it has finished
|
||||
* processing it.
|
||||
*
|
||||
* <p>{@code GlTextureProcessor} implementations can choose to produce output frames before
|
||||
* receiving input frames or process several input frames before producing an output frame. However,
|
||||
* {@code GlTextureProcessor} implementations cannot assume that they will receive more than one
|
||||
* input frame at a time, so they must process each input frame they accept even if they cannot
|
||||
* produce output yet.
|
||||
* <p>{@code GlShaderProgram} implementations can choose to produce output frames before receiving
|
||||
* input frames or process several input frames before producing an output frame. However, {@code
|
||||
* GlShaderProgram} implementations cannot assume that they will receive more than one input frame
|
||||
* at a time, so they must process each input frame they accept even if they cannot produce output
|
||||
* yet.
|
||||
*
|
||||
* <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
|
||||
* configure it to share data with the context of thread the interface methods are called on.
|
||||
*/
|
||||
@UnstableApi
|
||||
public interface GlTextureProcessor {
|
||||
public interface GlShaderProgram {
|
||||
|
||||
/**
|
||||
* Listener for input-related frame processing events.
|
||||
@ -53,7 +53,7 @@ public interface GlTextureProcessor {
|
||||
*/
|
||||
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
|
||||
* called once.
|
||||
@ -61,9 +61,9 @@ public interface GlTextureProcessor {
|
||||
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.
|
||||
*
|
||||
* @param inputTexture The {@link TextureInfo} that was used to {@linkplain
|
||||
@ -72,9 +72,9 @@ public interface GlTextureProcessor {
|
||||
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.
|
||||
*/
|
||||
default void onFlush() {}
|
||||
@ -87,12 +87,12 @@ public interface GlTextureProcessor {
|
||||
*/
|
||||
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
|
||||
* #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
|
||||
* frames before this output frame is released.
|
||||
* as there is no guarantee that the {@link GlShaderProgram} will produce further output frames
|
||||
* before this output frame is released.
|
||||
*
|
||||
* @param outputTexture A {@link TextureInfo} describing the texture containing the output
|
||||
* frame.
|
||||
@ -101,8 +101,8 @@ public interface GlTextureProcessor {
|
||||
default void onOutputFrameAvailable(TextureInfo outputTexture, long presentationTimeUs) {}
|
||||
|
||||
/**
|
||||
* Called when the {@link GlTextureProcessor} will not produce further output frames belonging
|
||||
* to the current output stream.
|
||||
* Called when the {@link GlShaderProgram} will not produce further output frames belonging to
|
||||
* the current output stream.
|
||||
*/
|
||||
default void onCurrentOutputStreamEnded() {}
|
||||
}
|
||||
@ -117,7 +117,7 @@ public interface GlTextureProcessor {
|
||||
* 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
|
||||
* the {@link GlTextureProcessor} should be released.
|
||||
* the {@link GlShaderProgram} should be released.
|
||||
*/
|
||||
void onFrameProcessingError(FrameProcessingException e);
|
||||
}
|
||||
@ -150,11 +150,11 @@ public interface GlTextureProcessor {
|
||||
/**
|
||||
* 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
|
||||
* 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}.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Notifies the texture processor that the frame on the given output texture is no longer used and
|
||||
* can be overwritten.
|
||||
* Notifies the {@code GlShaderProgram} that the frame on the given output texture is no longer
|
||||
* used and can be overwritten.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* <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();
|
||||
|
||||
/**
|
||||
* Flushes the {@code GlTextureProcessor}.
|
||||
* Flushes the {@code GlShaderProgram}.
|
||||
*
|
||||
* <p>The texture processor should reclaim the ownership of its allocated textures, {@linkplain
|
||||
* InputListener#onFlush notify} its {@link InputListener} about the flush event, and {@linkplain
|
||||
* InputListener#onReadyToAcceptInputFrame report its availability} if necessary.
|
||||
* <p>The {@code GlShaderProgram} should reclaim the ownership of its allocated textures,
|
||||
* {@linkplain InputListener#onFlush notify} its {@link InputListener} about the flush event, and
|
||||
* {@linkplain InputListener#onReadyToAcceptInputFrame report its availability} if necessary.
|
||||
*/
|
||||
void flush();
|
||||
|
@ -113,8 +113,8 @@ public class HslAdjustment implements GlEffect {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
||||
public SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
|
||||
throws FrameProcessingException {
|
||||
return new HslProcessor(context, /* hslAdjustment= */ this, useHdr);
|
||||
return new HslShaderProgram(context, /* hslAdjustment= */ this, useHdr);
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import androidx.media3.common.util.Size;
|
||||
import java.io.IOException;
|
||||
|
||||
/** 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 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.
|
||||
* @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 {
|
||||
super(useHdr);
|
||||
// TODO(b/241241680): Check if HDR <-> HSL works the same or not.
|
@ -52,8 +52,8 @@ import java.util.List;
|
||||
*/
|
||||
@UnstableApi
|
||||
@SuppressWarnings("FunctionalInterfaceClash") // b/228192298
|
||||
/* package */ final class MatrixTextureProcessor extends SingleFrameGlTextureProcessor
|
||||
implements ExternalTextureProcessor {
|
||||
/* package */ final class MatrixShaderProgram extends SingleFrameGlShaderProgram
|
||||
implements ExternalShaderProgram {
|
||||
|
||||
private static final String VERTEX_SHADER_TRANSFORMATION_PATH =
|
||||
"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
|
||||
* operation fails or is unsupported.
|
||||
*/
|
||||
public static MatrixTextureProcessor create(
|
||||
public static MatrixShaderProgram create(
|
||||
Context context,
|
||||
List<GlMatrixTransformation> matrixTransformations,
|
||||
List<RgbMatrix> rgbMatrices,
|
||||
@ -155,7 +155,7 @@ import java.util.List;
|
||||
context, VERTEX_SHADER_TRANSFORMATION_PATH, FRAGMENT_SHADER_TRANSFORMATION_PATH);
|
||||
|
||||
// No transfer functions needed, because input and output are both optical colors.
|
||||
return new MatrixTextureProcessor(
|
||||
return new MatrixShaderProgram(
|
||||
glProgram,
|
||||
ImmutableList.copyOf(matrixTransformations),
|
||||
ImmutableList.copyOf(rgbMatrices),
|
||||
@ -171,7 +171,7 @@ import java.util.List;
|
||||
* external texture.
|
||||
*
|
||||
* <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
|
||||
* ColorInfo#colorTransfer outputColorInfo OETF}, if needed, to convert back to an electrical
|
||||
* color output.
|
||||
@ -188,7 +188,7 @@ import java.util.List;
|
||||
* @throws FrameProcessingException If a problem occurs while reading shader files or an OpenGL
|
||||
* operation fails or is unsupported.
|
||||
*/
|
||||
public static MatrixTextureProcessor createWithExternalSampler(
|
||||
public static MatrixShaderProgram createWithExternalSampler(
|
||||
Context context,
|
||||
List<GlMatrixTransformation> matrixTransformations,
|
||||
List<RgbMatrix> rgbMatrices,
|
||||
@ -242,7 +242,7 @@ import java.util.List;
|
||||
glProgram.setIntUniform("uOutputColorTransfer", outputColorTransfer);
|
||||
}
|
||||
|
||||
return new MatrixTextureProcessor(
|
||||
return new MatrixShaderProgram(
|
||||
glProgram,
|
||||
ImmutableList.copyOf(matrixTransformations),
|
||||
ImmutableList.copyOf(rgbMatrices),
|
||||
@ -254,7 +254,7 @@ import java.util.List;
|
||||
* Creates a new instance.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* <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
|
||||
* operation fails or is unsupported.
|
||||
*/
|
||||
public static MatrixTextureProcessor createApplyingOetf(
|
||||
public static MatrixShaderProgram createApplyingOetf(
|
||||
Context context,
|
||||
List<GlMatrixTransformation> matrixTransformations,
|
||||
List<RgbMatrix> rgbMatrices,
|
||||
@ -297,7 +297,7 @@ import java.util.List;
|
||||
glProgram.setIntUniform("uOutputColorTransfer", outputColorTransfer);
|
||||
}
|
||||
|
||||
return new MatrixTextureProcessor(
|
||||
return new MatrixShaderProgram(
|
||||
glProgram,
|
||||
ImmutableList.copyOf(matrixTransformations),
|
||||
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
|
||||
* EXT_YUV_target} OpenGL extension.
|
||||
*/
|
||||
private MatrixTextureProcessor(
|
||||
private MatrixShaderProgram(
|
||||
GlProgram glProgram,
|
||||
ImmutableList<GlMatrixTransformation> matrixTransformations,
|
||||
ImmutableList<RgbMatrix> rgbMatrices,
|
||||
@ -403,7 +403,7 @@ import java.util.List;
|
||||
/**
|
||||
* 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}.
|
||||
*/
|
||||
public void setOutputColorTransfer(@C.ColorTransfer int colorTransfer) {
|
@ -39,8 +39,8 @@ public final class OverlayEffect implements GlEffect {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
||||
public SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
|
||||
throws FrameProcessingException {
|
||||
return new OverlayTextureProcessor(context, useHdr, overlays);
|
||||
return new OverlayShaderProgram(context, useHdr, overlays);
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ import androidx.media3.common.util.Util;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/** 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;
|
||||
|
||||
@ -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.
|
||||
* @throws FrameProcessingException If a problem occurs while reading shader files.
|
||||
*/
|
||||
public OverlayTextureProcessor(
|
||||
public OverlayShaderProgram(
|
||||
Context context, boolean useHdr, ImmutableList<TextureOverlay> overlays)
|
||||
throws FrameProcessingException {
|
||||
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.
|
||||
// We use one for every overlay and one for the video.
|
||||
checkArgument(
|
||||
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;
|
||||
aspectRatioMatrix = GlUtil.create4x4IdentityMatrix();
|
||||
overlayMatrix = GlUtil.create4x4IdentityMatrix();
|
@ -91,9 +91,9 @@ public class RgbFilter implements RgbMatrix {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
||||
public SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
|
||||
throws FrameProcessingException {
|
||||
checkForConsistentHdrSetting(useHdr);
|
||||
return RgbMatrix.super.toGlTextureProcessor(context, useHdr);
|
||||
return RgbMatrix.super.toGlShaderProgram(context, useHdr);
|
||||
}
|
||||
}
|
||||
|
@ -34,15 +34,15 @@ public interface RgbMatrix extends GlEffect {
|
||||
* @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
|
||||
* 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.
|
||||
*/
|
||||
float[] getMatrix(long presentationTimeUs, boolean useHdr);
|
||||
|
||||
@Override
|
||||
default SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
||||
default SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
|
||||
throws FrameProcessingException {
|
||||
return MatrixTextureProcessor.create(
|
||||
return MatrixShaderProgram.create(
|
||||
context,
|
||||
/* matrixTransformations= */ ImmutableList.of(),
|
||||
/* rgbMatrices= */ ImmutableList.of(this),
|
||||
|
@ -128,13 +128,13 @@ public class SingleColorLut implements ColorLut {
|
||||
Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
|
||||
/** Must be called after {@link #toGlTextureProcessor(Context, boolean)}. */
|
||||
/** Must be called after {@link #toGlShaderProgram(Context, boolean)}. */
|
||||
@Override
|
||||
public int getLutTextureId(long presentationTimeUs) {
|
||||
checkState(
|
||||
lutTextureId != Format.NO_VALUE,
|
||||
"The LUT has not been stored as a texture in OpenGL yet. You must to call"
|
||||
+ " #toGlTextureProcessor() first.");
|
||||
+ " #toGlShaderProgram() first.");
|
||||
return lutTextureId;
|
||||
}
|
||||
|
||||
@ -149,7 +149,7 @@ public class SingleColorLut implements ColorLut {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
||||
public SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
|
||||
throws FrameProcessingException {
|
||||
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);
|
||||
}
|
||||
|
||||
return new ColorLutProcessor(context, /* colorLut= */ this, useHdr);
|
||||
return new ColorLutShaderProgram(context, /* colorLut= */ this, useHdr);
|
||||
}
|
||||
|
||||
private static int storeLutAsTexture(Bitmap bitmap) throws GlUtil.GlException {
|
||||
|
@ -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
|
||||
* into an output frame, with changes to pixels specific to the implementation.
|
||||
*
|
||||
* <p>{@code SingleFrameGlTextureProcessor} implementations must produce exactly one output frame
|
||||
* per input frame with the same presentation timestamp. For more flexibility, implement {@link
|
||||
* GlTextureProcessor} directly.
|
||||
* <p>{@code SingleFrameGlShaderProgram} implementations must produce exactly one output frame per
|
||||
* input frame with the same presentation timestamp. For more flexibility, implement {@link
|
||||
* GlShaderProgram} directly.
|
||||
*
|
||||
* <p>All methods in this class must be called on the thread that owns the OpenGL context.
|
||||
*/
|
||||
@UnstableApi
|
||||
public abstract class SingleFrameGlTextureProcessor implements GlTextureProcessor {
|
||||
public abstract class SingleFrameGlShaderProgram implements GlShaderProgram {
|
||||
|
||||
private final boolean useHdr;
|
||||
|
||||
@ -52,12 +52,12 @@ public abstract class SingleFrameGlTextureProcessor implements GlTextureProcesso
|
||||
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
|
||||
* 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;
|
||||
inputListener = new InputListener() {};
|
||||
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
|
||||
* and before drawing subsequent frames with different input dimensions.
|
||||
@ -81,9 +81,9 @@ public abstract class SingleFrameGlTextureProcessor implements GlTextureProcesso
|
||||
/**
|
||||
* Draws one frame.
|
||||
*
|
||||
* <p>This method may only be called after the texture processor has been {@link #configure(int,
|
||||
* int) configured}. The caller is responsible for focussing the correct render target before
|
||||
* calling this method.
|
||||
* <p>This method may only be called after the shader program has been {@link #configure(int, int)
|
||||
* configured}. The caller is responsible for focussing the correct render target before calling
|
||||
* this method.
|
||||
*
|
||||
* <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.
|
||||
@ -118,7 +118,7 @@ public abstract class SingleFrameGlTextureProcessor implements GlTextureProcesso
|
||||
public final void queueInputFrame(TextureInfo inputTexture, long presentationTimeUs) {
|
||||
checkState(
|
||||
!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.");
|
||||
|
||||
try {
|
@ -25,9 +25,9 @@ import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/** Tests for {@link ChainingGlTextureProcessorListener}. */
|
||||
/** Tests for {@link ChainingGlShaderProgramListener}. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class ChainingGlTextureProcessorListenerTest {
|
||||
public final class ChainingGlShaderProgramListenerTest {
|
||||
private static final long EXECUTOR_WAIT_TIME_MS = 100;
|
||||
|
||||
private final FrameProcessor.Listener mockFrameProcessorListener =
|
||||
@ -35,13 +35,11 @@ public final class ChainingGlTextureProcessorListenerTest {
|
||||
private final FrameProcessingTaskExecutor frameProcessingTaskExecutor =
|
||||
new FrameProcessingTaskExecutor(
|
||||
Util.newSingleThreadExecutor("Test"), mockFrameProcessorListener);
|
||||
private final GlTextureProcessor mockProducingGlTextureProcessor = mock(GlTextureProcessor.class);
|
||||
private final GlTextureProcessor mockConsumingGlTextureProcessor = mock(GlTextureProcessor.class);
|
||||
private final ChainingGlTextureProcessorListener chainingGlTextureProcessorListener =
|
||||
new ChainingGlTextureProcessorListener(
|
||||
mockProducingGlTextureProcessor,
|
||||
mockConsumingGlTextureProcessor,
|
||||
frameProcessingTaskExecutor);
|
||||
private final GlShaderProgram mockProducingGlShaderProgram = mock(GlShaderProgram.class);
|
||||
private final GlShaderProgram mockConsumingGlShaderProgram = mock(GlShaderProgram.class);
|
||||
private final ChainingGlShaderProgramListener chainingGlShaderProgramListener =
|
||||
new ChainingGlShaderProgramListener(
|
||||
mockProducingGlShaderProgram, mockConsumingGlShaderProgram, frameProcessingTaskExecutor);
|
||||
|
||||
@After
|
||||
public void release() throws InterruptedException {
|
||||
@ -49,47 +47,47 @@ public final class ChainingGlTextureProcessorListenerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onInputFrameProcessed_surrendersFrameToPreviousGlTextureProcessor()
|
||||
public void onInputFrameProcessed_surrendersFrameToPreviousGlShaderProgram()
|
||||
throws InterruptedException {
|
||||
TextureInfo texture =
|
||||
new TextureInfo(/* texId= */ 1, /* fboId= */ 1, /* width= */ 100, /* height= */ 100);
|
||||
|
||||
chainingGlTextureProcessorListener.onInputFrameProcessed(texture);
|
||||
chainingGlShaderProgramListener.onInputFrameProcessed(texture);
|
||||
Thread.sleep(EXECUTOR_WAIT_TIME_MS);
|
||||
|
||||
verify(mockProducingGlTextureProcessor).releaseOutputFrame(texture);
|
||||
verify(mockProducingGlShaderProgram).releaseOutputFrame(texture);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onOutputFrameAvailable_afterAcceptsInputFrame_passesFrameToNextGlTextureProcessor()
|
||||
public void onOutputFrameAvailable_afterAcceptsInputFrame_passesFrameToNextGlShaderProgram()
|
||||
throws InterruptedException {
|
||||
TextureInfo texture =
|
||||
new TextureInfo(/* texId= */ 1, /* fboId= */ 1, /* width= */ 100, /* height= */ 100);
|
||||
long presentationTimeUs = 123;
|
||||
|
||||
chainingGlTextureProcessorListener.onReadyToAcceptInputFrame();
|
||||
chainingGlTextureProcessorListener.onOutputFrameAvailable(texture, presentationTimeUs);
|
||||
chainingGlShaderProgramListener.onReadyToAcceptInputFrame();
|
||||
chainingGlShaderProgramListener.onOutputFrameAvailable(texture, presentationTimeUs);
|
||||
Thread.sleep(EXECUTOR_WAIT_TIME_MS);
|
||||
|
||||
verify(mockConsumingGlTextureProcessor).queueInputFrame(texture, presentationTimeUs);
|
||||
verify(mockConsumingGlShaderProgram).queueInputFrame(texture, presentationTimeUs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onOutputFrameAvailable_beforeAcceptsInputFrame_passesFrameToNextGlTextureProcessor()
|
||||
public void onOutputFrameAvailable_beforeAcceptsInputFrame_passesFrameToNextGlShaderProgram()
|
||||
throws InterruptedException {
|
||||
TextureInfo texture =
|
||||
new TextureInfo(/* texId= */ 1, /* fboId= */ 1, /* width= */ 100, /* height= */ 100);
|
||||
long presentationTimeUs = 123;
|
||||
|
||||
chainingGlTextureProcessorListener.onOutputFrameAvailable(texture, presentationTimeUs);
|
||||
chainingGlTextureProcessorListener.onReadyToAcceptInputFrame();
|
||||
chainingGlShaderProgramListener.onOutputFrameAvailable(texture, presentationTimeUs);
|
||||
chainingGlShaderProgramListener.onReadyToAcceptInputFrame();
|
||||
Thread.sleep(EXECUTOR_WAIT_TIME_MS);
|
||||
|
||||
verify(mockConsumingGlTextureProcessor).queueInputFrame(texture, presentationTimeUs);
|
||||
verify(mockConsumingGlShaderProgram).queueInputFrame(texture, presentationTimeUs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onOutputFrameAvailable_twoFrames_passesFirstBeforeSecondToNextGlTextureProcessor()
|
||||
public void onOutputFrameAvailable_twoFrames_passesFirstBeforeSecondToNextGlShaderProgram()
|
||||
throws InterruptedException {
|
||||
TextureInfo firstTexture =
|
||||
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);
|
||||
long secondPresentationTimeUs = 567;
|
||||
|
||||
chainingGlTextureProcessorListener.onOutputFrameAvailable(
|
||||
firstTexture, firstPresentationTimeUs);
|
||||
chainingGlTextureProcessorListener.onOutputFrameAvailable(
|
||||
secondTexture, secondPresentationTimeUs);
|
||||
chainingGlTextureProcessorListener.onReadyToAcceptInputFrame();
|
||||
chainingGlTextureProcessorListener.onReadyToAcceptInputFrame();
|
||||
chainingGlShaderProgramListener.onOutputFrameAvailable(firstTexture, firstPresentationTimeUs);
|
||||
chainingGlShaderProgramListener.onOutputFrameAvailable(secondTexture, secondPresentationTimeUs);
|
||||
chainingGlShaderProgramListener.onReadyToAcceptInputFrame();
|
||||
chainingGlShaderProgramListener.onReadyToAcceptInputFrame();
|
||||
Thread.sleep(EXECUTOR_WAIT_TIME_MS);
|
||||
|
||||
verify(mockConsumingGlTextureProcessor).queueInputFrame(firstTexture, firstPresentationTimeUs);
|
||||
verify(mockConsumingGlTextureProcessor)
|
||||
.queueInputFrame(secondTexture, secondPresentationTimeUs);
|
||||
verify(mockConsumingGlShaderProgram).queueInputFrame(firstTexture, firstPresentationTimeUs);
|
||||
verify(mockConsumingGlShaderProgram).queueInputFrame(secondTexture, secondPresentationTimeUs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onOutputStreamEnded_signalsInputStreamEndedToNextGlTextureProcessor()
|
||||
public void onOutputStreamEnded_signalsInputStreamEndedToNextGlShaderProgram()
|
||||
throws InterruptedException {
|
||||
chainingGlTextureProcessorListener.onCurrentOutputStreamEnded();
|
||||
chainingGlShaderProgramListener.onCurrentOutputStreamEnded();
|
||||
Thread.sleep(EXECUTOR_WAIT_TIME_MS);
|
||||
|
||||
verify(mockConsumingGlTextureProcessor).signalEndOfCurrentInputStream();
|
||||
verify(mockConsumingGlShaderProgram).signalEndOfCurrentInputStream();
|
||||
}
|
||||
}
|
@ -25,8 +25,8 @@ import org.junit.runner.RunWith;
|
||||
/**
|
||||
* Unit tests for {@link ScaleToFitTransformation}.
|
||||
*
|
||||
* <p>See {@code MatrixTextureProcessorPixelTest} for pixel tests testing {@link
|
||||
* MatrixTextureProcessor} given a transformation matrix.
|
||||
* <p>See {@code MatrixShaderProgramPixelTest} for pixel tests testing {@link MatrixShaderProgram}
|
||||
* given a transformation matrix.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class ScaleToFitTransformationTest {
|
||||
|
Loading…
x
Reference in New Issue
Block a user