Add context param to GlFrameProcessor initialize().

PiperOrigin-RevId: 442826391
This commit is contained in:
hschlueter 2022-04-19 17:04:21 +01:00 committed by Ian Baker
parent afa551ab8f
commit 5248bbb882
18 changed files with 132 additions and 183 deletions

View File

@ -15,7 +15,6 @@
*/ */
package androidx.media3.demo.transformer; package androidx.media3.demo.transformer;
import android.content.Context;
import android.graphics.Matrix; import android.graphics.Matrix;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
@ -32,27 +31,26 @@ import androidx.media3.transformer.GlFrameProcessor;
* #ZOOM_DURATION_SECONDS} seconds, such that the rectangle filled with the input frame increases * #ZOOM_DURATION_SECONDS} seconds, such that the rectangle filled with the input frame increases
* linearly in size from a single point to filling the full output frame. * linearly in size from a single point to filling the full output frame.
*/ */
public static GlFrameProcessor createZoomInTransitionFrameProcessor(Context context) { public static GlFrameProcessor createZoomInTransitionFrameProcessor() {
return new AdvancedFrameProcessor( return new AdvancedFrameProcessor(
context,
/* matrixProvider= */ AdvancedFrameProcessorFactory::calculateZoomInTransitionMatrix); /* matrixProvider= */ AdvancedFrameProcessorFactory::calculateZoomInTransitionMatrix);
} }
/** /**
* Returns a {@link GlFrameProcessor} that crops frames to a rectangle that moves on an ellipse. * Returns a {@link GlFrameProcessor} that crops frames to a rectangle that moves on an ellipse.
*/ */
public static GlFrameProcessor createDizzyCropFrameProcessor(Context context) { public static GlFrameProcessor createDizzyCropFrameProcessor() {
return new AdvancedFrameProcessor( return new AdvancedFrameProcessor(
context, /* matrixProvider= */ AdvancedFrameProcessorFactory::calculateDizzyCropMatrix); /* matrixProvider= */ AdvancedFrameProcessorFactory::calculateDizzyCropMatrix);
} }
/** /**
* Returns a {@link GlFrameProcessor} that rotates a frame in 3D around the y-axis and applies * Returns a {@link GlFrameProcessor} that rotates a frame in 3D around the y-axis and applies
* perspective projection to 2D. * perspective projection to 2D.
*/ */
public static GlFrameProcessor createSpin3dFrameProcessor(Context context) { public static GlFrameProcessor createSpin3dFrameProcessor() {
return new AdvancedFrameProcessor( return new AdvancedFrameProcessor(
context, /* matrixProvider= */ AdvancedFrameProcessorFactory::calculate3dSpinMatrix); /* matrixProvider= */ AdvancedFrameProcessorFactory::calculate3dSpinMatrix);
} }
private static final float ZOOM_DURATION_SECONDS = 2f; private static final float ZOOM_DURATION_SECONDS = 2f;

View File

@ -53,20 +53,18 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private static final int BITMAP_WIDTH_HEIGHT = 512; private static final int BITMAP_WIDTH_HEIGHT = 512;
private final Context context;
private final Paint paint; private final Paint paint;
private final Bitmap overlayBitmap; private final Bitmap overlayBitmap;
private final Bitmap logoBitmap;
private final Canvas overlayCanvas; private final Canvas overlayCanvas;
private float bitmapScaleX; private float bitmapScaleX;
private float bitmapScaleY; private float bitmapScaleY;
private int bitmapTexId; private int bitmapTexId;
private @MonotonicNonNull Size outputSize; private @MonotonicNonNull Size outputSize;
private @MonotonicNonNull Bitmap logoBitmap;
private @MonotonicNonNull GlProgram glProgram; private @MonotonicNonNull GlProgram glProgram;
public BitmapOverlayFrameProcessor(Context context) { public BitmapOverlayFrameProcessor() {
this.context = context;
paint = new Paint(); paint = new Paint();
paint.setTextSize(64); paint.setTextSize(64);
paint.setAntiAlias(true); paint.setAntiAlias(true);
@ -75,18 +73,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
overlayBitmap = overlayBitmap =
Bitmap.createBitmap(BITMAP_WIDTH_HEIGHT, BITMAP_WIDTH_HEIGHT, Bitmap.Config.ARGB_8888); Bitmap.createBitmap(BITMAP_WIDTH_HEIGHT, BITMAP_WIDTH_HEIGHT, Bitmap.Config.ARGB_8888);
overlayCanvas = new Canvas(overlayBitmap); overlayCanvas = new Canvas(overlayBitmap);
try {
logoBitmap =
((BitmapDrawable)
context.getPackageManager().getApplicationIcon(context.getPackageName()))
.getBitmap();
} catch (PackageManager.NameNotFoundException e) {
throw new IllegalStateException(e);
}
} }
@Override @Override
public void initialize(int inputTexId, int inputWidth, int inputHeight) throws IOException { public void initialize(Context context, int inputTexId, int inputWidth, int inputHeight)
throws IOException {
if (inputWidth > inputHeight) { if (inputWidth > inputHeight) {
bitmapScaleX = inputWidth / (float) inputHeight; bitmapScaleX = inputWidth / (float) inputHeight;
bitmapScaleY = 1f; bitmapScaleY = 1f;
@ -96,6 +87,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
outputSize = new Size(inputWidth, inputHeight); outputSize = new Size(inputWidth, inputHeight);
try {
logoBitmap =
((BitmapDrawable)
context.getPackageManager().getApplicationIcon(context.getPackageName()))
.getBitmap();
} catch (PackageManager.NameNotFoundException e) {
throw new IllegalStateException(e);
}
bitmapTexId = GlUtil.createTexture(BITMAP_WIDTH_HEIGHT, BITMAP_WIDTH_HEIGHT); bitmapTexId = GlUtil.createTexture(BITMAP_WIDTH_HEIGHT, BITMAP_WIDTH_HEIGHT);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, /* level= */ 0, overlayBitmap, /* border= */ 0); GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, /* level= */ 0, overlayBitmap, /* border= */ 0);
@ -125,7 +124,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
String text = String text =
String.format(Locale.US, "%.02f", presentationTimeUs / (float) C.MICROS_PER_SECOND); String.format(Locale.US, "%.02f", presentationTimeUs / (float) C.MICROS_PER_SECOND);
overlayBitmap.eraseColor(Color.TRANSPARENT); overlayBitmap.eraseColor(Color.TRANSPARENT);
overlayCanvas.drawBitmap(logoBitmap, /* left= */ 3, /* top= */ 378, paint); overlayCanvas.drawBitmap(checkStateNotNull(logoBitmap), /* left= */ 3, /* top= */ 378, paint);
overlayCanvas.drawText(text, /* x= */ 160, /* y= */ 466, paint); overlayCanvas.drawText(text, /* x= */ 160, /* y= */ 466, paint);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, bitmapTexId); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, bitmapTexId);
GLUtils.texSubImage2D( GLUtils.texSubImage2D(

View File

@ -40,7 +40,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private static final String FRAGMENT_SHADER_PATH = "fragment_shader_vignette_es2.glsl"; private static final String FRAGMENT_SHADER_PATH = "fragment_shader_vignette_es2.glsl";
private static final float DIMMING_PERIOD_US = 5_600_000f; private static final float DIMMING_PERIOD_US = 5_600_000f;
private final Context context;
private float centerX; private float centerX;
private float centerY; private float centerY;
private float minInnerRadius; private float minInnerRadius;
@ -69,15 +68,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* @param outerRadius The radius after which all pixels are black. * @param outerRadius The radius after which all pixels are black.
*/ */
public PeriodicVignetteFrameProcessor( public PeriodicVignetteFrameProcessor(
Context context, float centerX, float centerY, float minInnerRadius, float maxInnerRadius, float outerRadius) {
float centerX,
float centerY,
float minInnerRadius,
float maxInnerRadius,
float outerRadius) {
checkArgument(minInnerRadius <= maxInnerRadius); checkArgument(minInnerRadius <= maxInnerRadius);
checkArgument(maxInnerRadius <= outerRadius); checkArgument(maxInnerRadius <= outerRadius);
this.context = context;
this.centerX = centerX; this.centerX = centerX;
this.centerY = centerY; this.centerY = centerY;
this.minInnerRadius = minInnerRadius; this.minInnerRadius = minInnerRadius;
@ -86,7 +79,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
@Override @Override
public void initialize(int inputTexId, int inputWidth, int inputHeight) throws IOException { public void initialize(Context context, int inputTexId, int inputWidth, int inputHeight)
throws IOException {
outputSize = new Size(inputWidth, inputHeight); outputSize = new Size(inputWidth, inputHeight);
glProgram = new GlProgram(context, VERTEX_SHADER_PATH, FRAGMENT_SHADER_PATH); glProgram = new GlProgram(context, VERTEX_SHADER_PATH, FRAGMENT_SHADER_PATH);
glProgram.setSamplerTexIdUniform("uTexSampler", inputTexId, /* texUnitIndex= */ 0); glProgram.setSamplerTexIdUniform("uTexSampler", inputTexId, /* texUnitIndex= */ 0);

View File

@ -246,13 +246,11 @@ public final class TransformerActivity extends AppCompatActivity {
bundle.getBooleanArray(ConfigurationActivity.DEMO_FRAME_PROCESSORS_SELECTIONS); bundle.getBooleanArray(ConfigurationActivity.DEMO_FRAME_PROCESSORS_SELECTIONS);
if (selectedFrameProcessors != null) { if (selectedFrameProcessors != null) {
if (selectedFrameProcessors[0]) { if (selectedFrameProcessors[0]) {
frameProcessors.add( frameProcessors.add(AdvancedFrameProcessorFactory.createDizzyCropFrameProcessor());
AdvancedFrameProcessorFactory.createDizzyCropFrameProcessor(/* context= */ this));
} }
if (selectedFrameProcessors[1]) { if (selectedFrameProcessors[1]) {
frameProcessors.add( frameProcessors.add(
new PeriodicVignetteFrameProcessor( new PeriodicVignetteFrameProcessor(
/* context= */ this,
bundle.getFloat(ConfigurationActivity.PERIODIC_VIGNETTE_CENTER_X), bundle.getFloat(ConfigurationActivity.PERIODIC_VIGNETTE_CENTER_X),
bundle.getFloat(ConfigurationActivity.PERIODIC_VIGNETTE_CENTER_Y), bundle.getFloat(ConfigurationActivity.PERIODIC_VIGNETTE_CENTER_Y),
/* minInnerRadius= */ bundle.getFloat( /* minInnerRadius= */ bundle.getFloat(
@ -262,16 +260,13 @@ public final class TransformerActivity extends AppCompatActivity {
bundle.getFloat(ConfigurationActivity.PERIODIC_VIGNETTE_OUTER_RADIUS))); bundle.getFloat(ConfigurationActivity.PERIODIC_VIGNETTE_OUTER_RADIUS)));
} }
if (selectedFrameProcessors[2]) { if (selectedFrameProcessors[2]) {
frameProcessors.add( frameProcessors.add(AdvancedFrameProcessorFactory.createSpin3dFrameProcessor());
AdvancedFrameProcessorFactory.createSpin3dFrameProcessor(/* context= */ this));
} }
if (selectedFrameProcessors[3]) { if (selectedFrameProcessors[3]) {
frameProcessors.add(new BitmapOverlayFrameProcessor(/* context= */ this)); frameProcessors.add(new BitmapOverlayFrameProcessor());
} }
if (selectedFrameProcessors[4]) { if (selectedFrameProcessors[4]) {
frameProcessors.add( frameProcessors.add(AdvancedFrameProcessorFactory.createZoomInTransitionFrameProcessor());
AdvancedFrameProcessorFactory.createZoomInTransitionFrameProcessor(
/* context= */ this));
} }
transformerBuilder.setFrameProcessors(frameProcessors.build()); transformerBuilder.setFrameProcessors(frameProcessors.build());
} }

View File

@ -93,8 +93,8 @@ public final class AdvancedFrameProcessorPixelTest {
public void drawFrame_noEdits_producesExpectedOutput() throws Exception { public void drawFrame_noEdits_producesExpectedOutput() throws Exception {
String testId = "drawFrame_noEdits"; String testId = "drawFrame_noEdits";
Matrix identityMatrix = new Matrix(); Matrix identityMatrix = new Matrix();
advancedFrameProcessor = new AdvancedFrameProcessor(getApplicationContext(), identityMatrix); advancedFrameProcessor = new AdvancedFrameProcessor(identityMatrix);
advancedFrameProcessor.initialize(inputTexId, width, height); advancedFrameProcessor.initialize(getApplicationContext(), inputTexId, width, height);
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ORIGINAL_PNG_ASSET_PATH);
advancedFrameProcessor.drawFrame(/* presentationTimeUs= */ 0); advancedFrameProcessor.drawFrame(/* presentationTimeUs= */ 0);
@ -115,9 +115,8 @@ public final class AdvancedFrameProcessorPixelTest {
String testId = "drawFrame_translateRight"; String testId = "drawFrame_translateRight";
Matrix translateRightMatrix = new Matrix(); Matrix translateRightMatrix = new Matrix();
translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0); translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0);
advancedFrameProcessor = advancedFrameProcessor = new AdvancedFrameProcessor(translateRightMatrix);
new AdvancedFrameProcessor(getApplicationContext(), translateRightMatrix); advancedFrameProcessor.initialize(getApplicationContext(), inputTexId, width, height);
advancedFrameProcessor.initialize(inputTexId, width, height);
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(TRANSLATE_RIGHT_PNG_ASSET_PATH); Bitmap expectedBitmap = BitmapTestUtil.readBitmap(TRANSLATE_RIGHT_PNG_ASSET_PATH);
advancedFrameProcessor.drawFrame(/* presentationTimeUs= */ 0); advancedFrameProcessor.drawFrame(/* presentationTimeUs= */ 0);
@ -138,8 +137,8 @@ public final class AdvancedFrameProcessorPixelTest {
String testId = "drawFrame_scaleNarrow"; String testId = "drawFrame_scaleNarrow";
Matrix scaleNarrowMatrix = new Matrix(); Matrix scaleNarrowMatrix = new Matrix();
scaleNarrowMatrix.postScale(.5f, 1.2f); scaleNarrowMatrix.postScale(.5f, 1.2f);
advancedFrameProcessor = new AdvancedFrameProcessor(getApplicationContext(), scaleNarrowMatrix); advancedFrameProcessor = new AdvancedFrameProcessor(scaleNarrowMatrix);
advancedFrameProcessor.initialize(inputTexId, width, height); advancedFrameProcessor.initialize(getApplicationContext(), inputTexId, width, height);
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(SCALE_NARROW_PNG_ASSET_PATH); Bitmap expectedBitmap = BitmapTestUtil.readBitmap(SCALE_NARROW_PNG_ASSET_PATH);
advancedFrameProcessor.drawFrame(/* presentationTimeUs= */ 0); advancedFrameProcessor.drawFrame(/* presentationTimeUs= */ 0);
@ -160,8 +159,8 @@ public final class AdvancedFrameProcessorPixelTest {
String testId = "drawFrame_rotate90"; String testId = "drawFrame_rotate90";
Matrix rotate90Matrix = new Matrix(); Matrix rotate90Matrix = new Matrix();
rotate90Matrix.postRotate(/* degrees= */ 90); rotate90Matrix.postRotate(/* degrees= */ 90);
advancedFrameProcessor = new AdvancedFrameProcessor(getApplicationContext(), rotate90Matrix); advancedFrameProcessor = new AdvancedFrameProcessor(rotate90Matrix);
advancedFrameProcessor.initialize(inputTexId, width, height); advancedFrameProcessor.initialize(getApplicationContext(), inputTexId, width, height);
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ROTATE_90_PNG_ASSET_PATH); Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ROTATE_90_PNG_ASSET_PATH);
advancedFrameProcessor.drawFrame(/* presentationTimeUs= */ 0); advancedFrameProcessor.drawFrame(/* presentationTimeUs= */ 0);

View File

@ -110,8 +110,7 @@ public final class FrameProcessorChainPixelTest {
String testId = "processData_withAdvancedFrameProcessor_translateRight"; String testId = "processData_withAdvancedFrameProcessor_translateRight";
Matrix translateRightMatrix = new Matrix(); Matrix translateRightMatrix = new Matrix();
translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0); translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0);
GlFrameProcessor glFrameProcessor = GlFrameProcessor glFrameProcessor = new AdvancedFrameProcessor(translateRightMatrix);
new AdvancedFrameProcessor(getApplicationContext(), translateRightMatrix);
setUpAndPrepareFirstFrame(glFrameProcessor); setUpAndPrepareFirstFrame(glFrameProcessor);
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(TRANSLATE_RIGHT_PNG_ASSET_PATH); Bitmap expectedBitmap = BitmapTestUtil.readBitmap(TRANSLATE_RIGHT_PNG_ASSET_PATH);
@ -133,11 +132,9 @@ public final class FrameProcessorChainPixelTest {
Matrix translateRightMatrix = new Matrix(); Matrix translateRightMatrix = new Matrix();
translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0); translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0);
GlFrameProcessor translateRightFrameProcessor = GlFrameProcessor translateRightFrameProcessor =
new AdvancedFrameProcessor(getApplicationContext(), translateRightMatrix); new AdvancedFrameProcessor(translateRightMatrix);
GlFrameProcessor rotate45FrameProcessor = GlFrameProcessor rotate45FrameProcessor =
new ScaleToFitFrameProcessor.Builder(getApplicationContext()) new ScaleToFitFrameProcessor.Builder().setRotationDegrees(45).build();
.setRotationDegrees(45)
.build();
setUpAndPrepareFirstFrame(translateRightFrameProcessor, rotate45FrameProcessor); setUpAndPrepareFirstFrame(translateRightFrameProcessor, rotate45FrameProcessor);
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(TRANSLATE_THEN_ROTATE_PNG_ASSET_PATH); Bitmap expectedBitmap = BitmapTestUtil.readBitmap(TRANSLATE_THEN_ROTATE_PNG_ASSET_PATH);
@ -157,13 +154,11 @@ public final class FrameProcessorChainPixelTest {
throws Exception { throws Exception {
String testId = "processData_withScaleToFitAndAdvancedFrameProcessors"; String testId = "processData_withScaleToFitAndAdvancedFrameProcessors";
GlFrameProcessor rotate45FrameProcessor = GlFrameProcessor rotate45FrameProcessor =
new ScaleToFitFrameProcessor.Builder(getApplicationContext()) new ScaleToFitFrameProcessor.Builder().setRotationDegrees(45).build();
.setRotationDegrees(45)
.build();
Matrix translateRightMatrix = new Matrix(); Matrix translateRightMatrix = new Matrix();
translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0); translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0);
GlFrameProcessor translateRightFrameProcessor = GlFrameProcessor translateRightFrameProcessor =
new AdvancedFrameProcessor(getApplicationContext(), translateRightMatrix); new AdvancedFrameProcessor(translateRightMatrix);
setUpAndPrepareFirstFrame(rotate45FrameProcessor, translateRightFrameProcessor); setUpAndPrepareFirstFrame(rotate45FrameProcessor, translateRightFrameProcessor);
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ROTATE_THEN_TRANSLATE_PNG_ASSET_PATH); Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ROTATE_THEN_TRANSLATE_PNG_ASSET_PATH);
@ -183,7 +178,7 @@ public final class FrameProcessorChainPixelTest {
throws Exception { throws Exception {
String testId = "processData_withPresentationFrameProcessor_setResolution"; String testId = "processData_withPresentationFrameProcessor_setResolution";
GlFrameProcessor glFrameProcessor = GlFrameProcessor glFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()).setResolution(480).build(); new PresentationFrameProcessor.Builder().setResolution(480).build();
setUpAndPrepareFirstFrame(glFrameProcessor); setUpAndPrepareFirstFrame(glFrameProcessor);
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(REQUEST_OUTPUT_HEIGHT_PNG_ASSET_PATH); Bitmap expectedBitmap = BitmapTestUtil.readBitmap(REQUEST_OUTPUT_HEIGHT_PNG_ASSET_PATH);
@ -203,9 +198,7 @@ public final class FrameProcessorChainPixelTest {
throws Exception { throws Exception {
String testId = "processData_withScaleToFitFrameProcessor_rotate45"; String testId = "processData_withScaleToFitFrameProcessor_rotate45";
GlFrameProcessor glFrameProcessor = GlFrameProcessor glFrameProcessor =
new ScaleToFitFrameProcessor.Builder(getApplicationContext()) new ScaleToFitFrameProcessor.Builder().setRotationDegrees(45).build();
.setRotationDegrees(45)
.build();
setUpAndPrepareFirstFrame(glFrameProcessor); setUpAndPrepareFirstFrame(glFrameProcessor);
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ROTATE45_SCALE_TO_FIT_PNG_ASSET_PATH); Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ROTATE45_SCALE_TO_FIT_PNG_ASSET_PATH);

View File

@ -138,7 +138,7 @@ public final class FrameProcessorChainTest {
} }
@Override @Override
public void initialize(int inputTexId, int inputWidth, int inputHeight) {} public void initialize(Context context, int inputTexId, int inputWidth, int inputHeight) {}
@Override @Override
public Size getOutputSize() { public Size getOutputSize() {

View File

@ -101,9 +101,9 @@ public final class PresentationFrameProcessorPixelTest {
@Test @Test
public void drawFrame_noEdits_producesExpectedOutput() throws Exception { public void drawFrame_noEdits_producesExpectedOutput() throws Exception {
String testId = "drawFrame_noEdits"; String testId = "drawFrame_noEdits";
presentationFrameProcessor = presentationFrameProcessor = new PresentationFrameProcessor.Builder().build();
new PresentationFrameProcessor.Builder(getApplicationContext()).build(); presentationFrameProcessor.initialize(
presentationFrameProcessor.initialize(inputTexId, inputWidth, inputHeight); getApplicationContext(), inputTexId, inputWidth, inputHeight);
Size outputSize = presentationFrameProcessor.getOutputSize(); Size outputSize = presentationFrameProcessor.getOutputSize();
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ORIGINAL_PNG_ASSET_PATH); Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ORIGINAL_PNG_ASSET_PATH);
@ -126,10 +126,11 @@ public final class PresentationFrameProcessorPixelTest {
public void drawFrame_cropSmaller_producesExpectedOutput() throws Exception { public void drawFrame_cropSmaller_producesExpectedOutput() throws Exception {
String testId = "drawFrame_cropSmaller"; String testId = "drawFrame_cropSmaller";
GlFrameProcessor presentationFrameProcessor = GlFrameProcessor presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder()
.setCrop(/* left= */ -.9f, /* right= */ .1f, /* bottom= */ -1f, /* top= */ .5f) .setCrop(/* left= */ -.9f, /* right= */ .1f, /* bottom= */ -1f, /* top= */ .5f)
.build(); .build();
presentationFrameProcessor.initialize(inputTexId, inputWidth, inputHeight); presentationFrameProcessor.initialize(
getApplicationContext(), inputTexId, inputWidth, inputHeight);
Size outputSize = presentationFrameProcessor.getOutputSize(); Size outputSize = presentationFrameProcessor.getOutputSize();
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(CROP_SMALLER_PNG_ASSET_PATH); Bitmap expectedBitmap = BitmapTestUtil.readBitmap(CROP_SMALLER_PNG_ASSET_PATH);
@ -152,10 +153,11 @@ public final class PresentationFrameProcessorPixelTest {
public void drawFrame_cropLarger_producesExpectedOutput() throws Exception { public void drawFrame_cropLarger_producesExpectedOutput() throws Exception {
String testId = "drawFrame_cropSmaller"; String testId = "drawFrame_cropSmaller";
GlFrameProcessor presentationFrameProcessor = GlFrameProcessor presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder()
.setCrop(/* left= */ -2f, /* right= */ 2f, /* bottom= */ -1f, /* top= */ 2f) .setCrop(/* left= */ -2f, /* right= */ 2f, /* bottom= */ -1f, /* top= */ 2f)
.build(); .build();
presentationFrameProcessor.initialize(inputTexId, inputWidth, inputHeight); presentationFrameProcessor.initialize(
getApplicationContext(), inputTexId, inputWidth, inputHeight);
Size outputSize = presentationFrameProcessor.getOutputSize(); Size outputSize = presentationFrameProcessor.getOutputSize();
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(CROP_LARGER_PNG_ASSET_PATH); Bitmap expectedBitmap = BitmapTestUtil.readBitmap(CROP_LARGER_PNG_ASSET_PATH);
@ -179,10 +181,11 @@ public final class PresentationFrameProcessorPixelTest {
throws Exception { throws Exception {
String testId = "drawFrame_changeAspectRatio_scaleToFit_narrow"; String testId = "drawFrame_changeAspectRatio_scaleToFit_narrow";
presentationFrameProcessor = presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder()
.setAspectRatio(1f, PresentationFrameProcessor.SCALE_TO_FIT) .setAspectRatio(1f, PresentationFrameProcessor.SCALE_TO_FIT)
.build(); .build();
presentationFrameProcessor.initialize(inputTexId, inputWidth, inputHeight); presentationFrameProcessor.initialize(
getApplicationContext(), inputTexId, inputWidth, inputHeight);
Size outputSize = presentationFrameProcessor.getOutputSize(); Size outputSize = presentationFrameProcessor.getOutputSize();
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = Bitmap expectedBitmap =
@ -207,10 +210,11 @@ public final class PresentationFrameProcessorPixelTest {
throws Exception { throws Exception {
String testId = "drawFrame_changeAspectRatio_scaleToFit_wide"; String testId = "drawFrame_changeAspectRatio_scaleToFit_wide";
presentationFrameProcessor = presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder()
.setAspectRatio(2f, PresentationFrameProcessor.SCALE_TO_FIT) .setAspectRatio(2f, PresentationFrameProcessor.SCALE_TO_FIT)
.build(); .build();
presentationFrameProcessor.initialize(inputTexId, inputWidth, inputHeight); presentationFrameProcessor.initialize(
getApplicationContext(), inputTexId, inputWidth, inputHeight);
Size outputSize = presentationFrameProcessor.getOutputSize(); Size outputSize = presentationFrameProcessor.getOutputSize();
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = Bitmap expectedBitmap =
@ -235,10 +239,11 @@ public final class PresentationFrameProcessorPixelTest {
throws Exception { throws Exception {
String testId = "drawFrame_changeAspectRatio_scaleToFitWithCrop_narrow"; String testId = "drawFrame_changeAspectRatio_scaleToFitWithCrop_narrow";
presentationFrameProcessor = presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder()
.setAspectRatio(1f, PresentationFrameProcessor.SCALE_TO_FIT_WITH_CROP) .setAspectRatio(1f, PresentationFrameProcessor.SCALE_TO_FIT_WITH_CROP)
.build(); .build();
presentationFrameProcessor.initialize(inputTexId, inputWidth, inputHeight); presentationFrameProcessor.initialize(
getApplicationContext(), inputTexId, inputWidth, inputHeight);
Size outputSize = presentationFrameProcessor.getOutputSize(); Size outputSize = presentationFrameProcessor.getOutputSize();
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = Bitmap expectedBitmap =
@ -263,10 +268,11 @@ public final class PresentationFrameProcessorPixelTest {
throws Exception { throws Exception {
String testId = "drawFrame_changeAspectRatio_scaleToFitWithCrop_wide"; String testId = "drawFrame_changeAspectRatio_scaleToFitWithCrop_wide";
presentationFrameProcessor = presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder()
.setAspectRatio(2f, PresentationFrameProcessor.SCALE_TO_FIT_WITH_CROP) .setAspectRatio(2f, PresentationFrameProcessor.SCALE_TO_FIT_WITH_CROP)
.build(); .build();
presentationFrameProcessor.initialize(inputTexId, inputWidth, inputHeight); presentationFrameProcessor.initialize(
getApplicationContext(), inputTexId, inputWidth, inputHeight);
Size outputSize = presentationFrameProcessor.getOutputSize(); Size outputSize = presentationFrameProcessor.getOutputSize();
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = Bitmap expectedBitmap =
@ -291,10 +297,11 @@ public final class PresentationFrameProcessorPixelTest {
throws Exception { throws Exception {
String testId = "drawFrame_changeAspectRatio_stretchToFit_narrow"; String testId = "drawFrame_changeAspectRatio_stretchToFit_narrow";
presentationFrameProcessor = presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder()
.setAspectRatio(1f, PresentationFrameProcessor.STRETCH_TO_FIT) .setAspectRatio(1f, PresentationFrameProcessor.STRETCH_TO_FIT)
.build(); .build();
presentationFrameProcessor.initialize(inputTexId, inputWidth, inputHeight); presentationFrameProcessor.initialize(
getApplicationContext(), inputTexId, inputWidth, inputHeight);
Size outputSize = presentationFrameProcessor.getOutputSize(); Size outputSize = presentationFrameProcessor.getOutputSize();
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = Bitmap expectedBitmap =
@ -319,10 +326,11 @@ public final class PresentationFrameProcessorPixelTest {
throws Exception { throws Exception {
String testId = "drawFrame_changeAspectRatio_stretchToFit_wide"; String testId = "drawFrame_changeAspectRatio_stretchToFit_wide";
presentationFrameProcessor = presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder()
.setAspectRatio(2f, PresentationFrameProcessor.STRETCH_TO_FIT) .setAspectRatio(2f, PresentationFrameProcessor.STRETCH_TO_FIT)
.build(); .build();
presentationFrameProcessor.initialize(inputTexId, inputWidth, inputHeight); presentationFrameProcessor.initialize(
getApplicationContext(), inputTexId, inputWidth, inputHeight);
Size outputSize = presentationFrameProcessor.getOutputSize(); Size outputSize = presentationFrameProcessor.getOutputSize();
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight()); setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
Bitmap expectedBitmap = Bitmap expectedBitmap =

View File

@ -111,7 +111,6 @@ public final class AdvancedFrameProcessor implements GlFrameProcessor {
return matrix4x4Array; return matrix4x4Array;
} }
private final Context context;
private final GlMatrixProvider matrixProvider; private final GlMatrixProvider matrixProvider;
private @MonotonicNonNull Size size; private @MonotonicNonNull Size size;
@ -120,37 +119,33 @@ public final class AdvancedFrameProcessor implements GlFrameProcessor {
/** /**
* Creates a new instance. * Creates a new instance.
* *
* @param context The {@link Context}.
* @param transformationMatrix The transformation {@link android.graphics.Matrix} to apply to each * @param transformationMatrix The transformation {@link android.graphics.Matrix} to apply to each
* frame. Operations are done on normalized device coordinates (-1 to 1 on x and y), and no * frame. Operations are done on normalized device coordinates (-1 to 1 on x and y), and no
* automatic adjustments are applied on the transformation matrix. * automatic adjustments are applied on the transformation matrix.
*/ */
public AdvancedFrameProcessor(Context context, android.graphics.Matrix transformationMatrix) { public AdvancedFrameProcessor(android.graphics.Matrix transformationMatrix) {
this(context, getGlMatrixArray(transformationMatrix)); this(getGlMatrixArray(transformationMatrix));
} }
/** /**
* Creates a new instance. * Creates a new instance.
* *
* @param context The {@link Context}.
* @param matrixProvider A {@link MatrixProvider} that provides the transformation matrix to apply * @param matrixProvider A {@link MatrixProvider} that provides the transformation matrix to apply
* to each frame. * to each frame.
*/ */
public AdvancedFrameProcessor(Context context, MatrixProvider matrixProvider) { public AdvancedFrameProcessor(MatrixProvider matrixProvider) {
this.context = context;
this.matrixProvider = matrixProvider; this.matrixProvider = matrixProvider;
} }
/** /**
* Creates a new instance. * Creates a new instance.
* *
* @param context The {@link Context}.
* @param transformationMatrix The 4x4 transformation {@link android.opengl.Matrix} to apply to * @param transformationMatrix The 4x4 transformation {@link android.opengl.Matrix} to apply to
* each frame. Operations are done on normalized device coordinates (-1 to 1 on x and y), and * each frame. Operations are done on normalized device coordinates (-1 to 1 on x and y), and
* no automatic adjustments are applied on the transformation matrix. * no automatic adjustments are applied on the transformation matrix.
*/ */
public AdvancedFrameProcessor(Context context, float[] transformationMatrix) { public AdvancedFrameProcessor(float[] transformationMatrix) {
this(context, /* matrixProvider= */ (long presentationTimeUs) -> transformationMatrix.clone()); this(/* matrixProvider= */ (long presentationTimeUs) -> transformationMatrix.clone());
checkArgument( checkArgument(
transformationMatrix.length == 16, "A 4x4 transformation matrix must have 16 elements."); transformationMatrix.length == 16, "A 4x4 transformation matrix must have 16 elements.");
} }
@ -158,17 +153,16 @@ public final class AdvancedFrameProcessor implements GlFrameProcessor {
/** /**
* Creates a new instance. * Creates a new instance.
* *
* @param context The {@link Context}.
* @param matrixProvider A {@link GlMatrixProvider} that updates the transformation matrix for * @param matrixProvider A {@link GlMatrixProvider} that updates the transformation matrix for
* each frame. * each frame.
*/ */
public AdvancedFrameProcessor(Context context, GlMatrixProvider matrixProvider) { public AdvancedFrameProcessor(GlMatrixProvider matrixProvider) {
this.context = context;
this.matrixProvider = matrixProvider; this.matrixProvider = matrixProvider;
} }
@Override @Override
public void initialize(int inputTexId, int inputWidth, int inputHeight) throws IOException { public void initialize(Context context, int inputTexId, int inputWidth, int inputHeight)
throws IOException {
checkArgument(inputWidth > 0, "inputWidth must be positive"); checkArgument(inputWidth > 0, "inputWidth must be positive");
checkArgument(inputHeight > 0, "inputHeight must be positive"); checkArgument(inputHeight > 0, "inputHeight must be positive");

View File

@ -49,19 +49,18 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
1.683f, -0.652f, 0.0f, 1.683f, -0.652f, 0.0f,
}; };
private final Context context;
private final boolean enableExperimentalHdrEditing; private final boolean enableExperimentalHdrEditing;
private @MonotonicNonNull Size size; private @MonotonicNonNull Size size;
private @MonotonicNonNull GlProgram glProgram; private @MonotonicNonNull GlProgram glProgram;
public ExternalCopyFrameProcessor(Context context, boolean enableExperimentalHdrEditing) { public ExternalCopyFrameProcessor(boolean enableExperimentalHdrEditing) {
this.context = context;
this.enableExperimentalHdrEditing = enableExperimentalHdrEditing; this.enableExperimentalHdrEditing = enableExperimentalHdrEditing;
} }
@Override @Override
public void initialize(int inputTexId, int inputWidth, int inputHeight) throws IOException { public void initialize(Context context, int inputTexId, int inputWidth, int inputHeight)
throws IOException {
checkArgument(inputWidth > 0, "inputWidth must be positive"); checkArgument(inputWidth > 0, "inputWidth must be positive");
checkArgument(inputHeight > 0, "inputHeight must be positive"); checkArgument(inputHeight > 0, "inputHeight must be positive");

View File

@ -104,13 +104,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
ExecutorService singleThreadExecutorService = Util.newSingleThreadExecutor(THREAD_NAME); ExecutorService singleThreadExecutorService = Util.newSingleThreadExecutor(THREAD_NAME);
ExternalCopyFrameProcessor externalCopyFrameProcessor = ExternalCopyFrameProcessor externalCopyFrameProcessor =
new ExternalCopyFrameProcessor(context, enableExperimentalHdrEditing); new ExternalCopyFrameProcessor(enableExperimentalHdrEditing);
try { try {
return singleThreadExecutorService return singleThreadExecutorService
.submit( .submit(
() -> () ->
createOpenGlObjectsAndFrameProcessorChain( createOpenGlObjectsAndFrameProcessorChain(
context,
inputWidth, inputWidth,
inputHeight, inputHeight,
frameProcessors, frameProcessors,
@ -136,6 +137,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
*/ */
@WorkerThread @WorkerThread
private static FrameProcessorChain createOpenGlObjectsAndFrameProcessorChain( private static FrameProcessorChain createOpenGlObjectsAndFrameProcessorChain(
Context context,
int inputWidth, int inputWidth,
int inputHeight, int inputHeight,
List<GlFrameProcessor> frameProcessors, List<GlFrameProcessor> frameProcessors,
@ -162,14 +164,16 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
} }
int inputExternalTexId = GlUtil.createExternalTexture(); int inputExternalTexId = GlUtil.createExternalTexture();
externalCopyFrameProcessor.initialize(inputExternalTexId, inputWidth, inputHeight); externalCopyFrameProcessor.initialize(context, inputExternalTexId, inputWidth, inputHeight);
int[] framebuffers = new int[frameProcessors.size()]; int[] framebuffers = new int[frameProcessors.size()];
Size inputSize = externalCopyFrameProcessor.getOutputSize(); Size inputSize = externalCopyFrameProcessor.getOutputSize();
for (int i = 0; i < frameProcessors.size(); i++) { for (int i = 0; i < frameProcessors.size(); i++) {
int inputTexId = GlUtil.createTexture(inputSize.getWidth(), inputSize.getHeight()); int inputTexId = GlUtil.createTexture(inputSize.getWidth(), inputSize.getHeight());
framebuffers[i] = GlUtil.createFboForTexture(inputTexId); framebuffers[i] = GlUtil.createFboForTexture(inputTexId);
frameProcessors.get(i).initialize(inputTexId, inputSize.getWidth(), inputSize.getHeight()); frameProcessors
.get(i)
.initialize(context, inputTexId, inputSize.getWidth(), inputSize.getHeight());
inputSize = frameProcessors.get(i).getOutputSize(); inputSize = frameProcessors.get(i).getOutputSize();
} }
return new FrameProcessorChain( return new FrameProcessorChain(

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.transformer; package androidx.media3.transformer;
import android.content.Context;
import android.util.Size; import android.util.Size;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import java.io.IOException; import java.io.IOException;
@ -26,7 +27,7 @@ import java.io.IOException;
* *
* <ol> * <ol>
* <li>The constructor, for implementation-specific arguments. * <li>The constructor, for implementation-specific arguments.
* <li>{@link #initialize(int,int,int)}, to set up graphics initialization. * <li>{@link #initialize(Context, int, int, int)}, to set up graphics initialization.
* <li>{@link #drawFrame(long)}, to process one frame. * <li>{@link #drawFrame(long)}, to process one frame.
* <li>{@link #release()}, upon conclusion of processing. * <li>{@link #release()}, upon conclusion of processing.
* </ol> * </ol>
@ -40,17 +41,19 @@ public interface GlFrameProcessor {
* *
* <p>This method may only be called if there is a current OpenGL context. * <p>This method may only be called if there is a current OpenGL context.
* *
* @param context The {@link Context}.
* @param inputTexId Identifier of a 2D OpenGL texture. * @param inputTexId Identifier of a 2D OpenGL texture.
* @param inputWidth The input width, in pixels. * @param inputWidth The input width, in pixels.
* @param inputHeight The input height, in pixels. * @param inputHeight The input height, in pixels.
*/ */
void initialize(int inputTexId, int inputWidth, int inputHeight) throws IOException; void initialize(Context context, int inputTexId, int inputWidth, int inputHeight)
throws IOException;
/** /**
* Returns the output {@link Size} of frames processed through {@link #drawFrame(long)}. * Returns the output {@link Size} of frames processed through {@link #drawFrame(long)}.
* *
* <p>This method may only be called after the frame processor has been {@link * <p>This method may only be called after the frame processor has been {@link
* #initialize(int,int,int) initialized}. * #initialize(Context, int, int, int) initialized}.
*/ */
Size getOutputSize(); Size getOutputSize();
@ -58,8 +61,8 @@ public interface GlFrameProcessor {
* Draws one frame. * Draws one frame.
* *
* <p>This method may only be called after the frame processor has been {@link * <p>This method may only be called after the frame processor has been {@link
* #initialize(int,int,int) initialized}. The caller is responsible for focussing the correct * #initialize(Context, int, int, int) initialized}. The caller is responsible for focussing the
* render target before calling this method. * correct render target before calling this method.
* *
* <p>A minimal implementation should tell OpenGL to use its shader program, bind the shader * <p>A minimal implementation should tell OpenGL to use its shader program, bind the shader
* program's vertex attributes and uniforms, and issue a drawing command. * program's vertex attributes and uniforms, and issue a drawing command.

View File

@ -71,9 +71,6 @@ public final class PresentationFrameProcessor implements GlFrameProcessor {
/** A builder for {@link PresentationFrameProcessor} instances. */ /** A builder for {@link PresentationFrameProcessor} instances. */
public static final class Builder { public static final class Builder {
// Mandatory field.
private final Context context;
// Optional fields. // Optional fields.
private int heightPixels; private int heightPixels;
private float cropLeft; private float cropLeft;
@ -83,13 +80,8 @@ public final class PresentationFrameProcessor implements GlFrameProcessor {
private float aspectRatio; private float aspectRatio;
private @PresentationStrategy int presentationStrategy; private @PresentationStrategy int presentationStrategy;
/** /** Creates a builder with default values. */
* Creates a builder with default values. public Builder() {
*
* @param context The {@link Context}.
*/
public Builder(Context context) {
this.context = context;
heightPixels = C.LENGTH_UNSET; heightPixels = C.LENGTH_UNSET;
cropLeft = -1f; cropLeft = -1f;
cropRight = 1f; cropRight = 1f;
@ -182,7 +174,6 @@ public final class PresentationFrameProcessor implements GlFrameProcessor {
public PresentationFrameProcessor build() { public PresentationFrameProcessor build() {
return new PresentationFrameProcessor( return new PresentationFrameProcessor(
context,
heightPixels, heightPixels,
cropLeft, cropLeft,
cropRight, cropRight,
@ -197,7 +188,6 @@ public final class PresentationFrameProcessor implements GlFrameProcessor {
GlUtil.glAssertionsEnabled = true; GlUtil.glAssertionsEnabled = true;
} }
private final Context context;
private final int requestedHeightPixels; private final int requestedHeightPixels;
private final float cropLeft; private final float cropLeft;
private final float cropRight; private final float cropRight;
@ -214,7 +204,6 @@ public final class PresentationFrameProcessor implements GlFrameProcessor {
/** Creates a new instance. */ /** Creates a new instance. */
private PresentationFrameProcessor( private PresentationFrameProcessor(
Context context,
int requestedHeightPixels, int requestedHeightPixels,
float cropLeft, float cropLeft,
float cropRight, float cropRight,
@ -222,7 +211,6 @@ public final class PresentationFrameProcessor implements GlFrameProcessor {
float cropTop, float cropTop,
float requestedAspectRatio, float requestedAspectRatio,
@PresentationStrategy int presentationStrategy) { @PresentationStrategy int presentationStrategy) {
this.context = context;
this.requestedHeightPixels = requestedHeightPixels; this.requestedHeightPixels = requestedHeightPixels;
this.cropLeft = cropLeft; this.cropLeft = cropLeft;
this.cropRight = cropRight; this.cropRight = cropRight;
@ -238,10 +226,11 @@ public final class PresentationFrameProcessor implements GlFrameProcessor {
} }
@Override @Override
public void initialize(int inputTexId, int inputWidth, int inputHeight) throws IOException { public void initialize(Context context, int inputTexId, int inputWidth, int inputHeight)
throws IOException {
configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight); configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight);
advancedFrameProcessor = new AdvancedFrameProcessor(context, transformationMatrix); advancedFrameProcessor = new AdvancedFrameProcessor(transformationMatrix);
advancedFrameProcessor.initialize(inputTexId, inputWidth, inputHeight); advancedFrameProcessor.initialize(context, inputTexId, inputWidth, inputHeight);
} }
@Override @Override
@ -257,7 +246,8 @@ public final class PresentationFrameProcessor implements GlFrameProcessor {
* *
* <p>Return values may be {@code 0} or {@code 90} degrees. * <p>Return values may be {@code 0} or {@code 90} degrees.
* *
* <p>The frame processor must be {@linkplain #initialize(int,int,int) initialized}. * <p>The frame processor must be {@linkplain GlFrameProcessor#initialize(Context, int, int, int)
* initialized}.
*/ */
public int getOutputRotationDegrees() { public int getOutputRotationDegrees() {
checkState( checkState(

View File

@ -40,22 +40,14 @@ public final class ScaleToFitFrameProcessor implements GlFrameProcessor {
/** A builder for {@link ScaleToFitFrameProcessor} instances. */ /** A builder for {@link ScaleToFitFrameProcessor} instances. */
public static final class Builder { public static final class Builder {
// Mandatory field.
private final Context context;
// Optional fields. // Optional fields.
private float scaleX; private float scaleX;
private float scaleY; private float scaleY;
private float rotationDegrees; private float rotationDegrees;
/** /** Creates a builder with default values. */
* Creates a builder with default values. public Builder() {
*
* @param context The {@link Context}.
*/
public Builder(Context context) {
this.context = context;
scaleX = 1; scaleX = 1;
scaleY = 1; scaleY = 1;
rotationDegrees = 0; rotationDegrees = 0;
@ -90,7 +82,7 @@ public final class ScaleToFitFrameProcessor implements GlFrameProcessor {
} }
public ScaleToFitFrameProcessor build() { public ScaleToFitFrameProcessor build() {
return new ScaleToFitFrameProcessor(context, scaleX, scaleY, rotationDegrees); return new ScaleToFitFrameProcessor(scaleX, scaleY, rotationDegrees);
} }
} }
@ -98,7 +90,6 @@ public final class ScaleToFitFrameProcessor implements GlFrameProcessor {
GlUtil.glAssertionsEnabled = true; GlUtil.glAssertionsEnabled = true;
} }
private final Context context;
private final Matrix transformationMatrix; private final Matrix transformationMatrix;
private @MonotonicNonNull AdvancedFrameProcessor advancedFrameProcessor; private @MonotonicNonNull AdvancedFrameProcessor advancedFrameProcessor;
@ -108,25 +99,22 @@ public final class ScaleToFitFrameProcessor implements GlFrameProcessor {
/** /**
* Creates a new instance. * Creates a new instance.
* *
* @param context The {@link Context}.
* @param scaleX The multiplier by which the frame will scale horizontally, along the x-axis. * @param scaleX The multiplier by which the frame will scale horizontally, along the x-axis.
* @param scaleY The multiplier by which the frame will scale vertically, along the y-axis. * @param scaleY The multiplier by which the frame will scale vertically, along the y-axis.
* @param rotationDegrees How much to rotate the frame counterclockwise, in degrees. * @param rotationDegrees How much to rotate the frame counterclockwise, in degrees.
*/ */
private ScaleToFitFrameProcessor( private ScaleToFitFrameProcessor(float scaleX, float scaleY, float rotationDegrees) {
Context context, float scaleX, float scaleY, float rotationDegrees) {
this.context = context;
this.transformationMatrix = new Matrix(); this.transformationMatrix = new Matrix();
this.transformationMatrix.postScale(scaleX, scaleY); this.transformationMatrix.postScale(scaleX, scaleY);
this.transformationMatrix.postRotate(rotationDegrees); this.transformationMatrix.postRotate(rotationDegrees);
} }
@Override @Override
public void initialize(int inputTexId, int inputWidth, int inputHeight) throws IOException { public void initialize(Context context, int inputTexId, int inputWidth, int inputHeight)
throws IOException {
configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight); configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight);
advancedFrameProcessor = new AdvancedFrameProcessor(context, adjustedTransformationMatrix); advancedFrameProcessor = new AdvancedFrameProcessor(adjustedTransformationMatrix);
advancedFrameProcessor.initialize(inputTexId, inputWidth, inputHeight); advancedFrameProcessor.initialize(context, inputTexId, inputWidth, inputHeight);
} }
@Override @Override

View File

@ -72,12 +72,12 @@ import org.checkerframework.dataflow.qual.Pure;
// TODO(b/213190310): Don't create a ScaleToFitFrameProcessor if scale and rotation are unset. // TODO(b/213190310): Don't create a ScaleToFitFrameProcessor if scale and rotation are unset.
ScaleToFitFrameProcessor scaleToFitFrameProcessor = ScaleToFitFrameProcessor scaleToFitFrameProcessor =
new ScaleToFitFrameProcessor.Builder(context) new ScaleToFitFrameProcessor.Builder()
.setScale(transformationRequest.scaleX, transformationRequest.scaleY) .setScale(transformationRequest.scaleX, transformationRequest.scaleY)
.setRotationDegrees(transformationRequest.rotationDegrees) .setRotationDegrees(transformationRequest.rotationDegrees)
.build(); .build();
PresentationFrameProcessor presentationFrameProcessor = PresentationFrameProcessor presentationFrameProcessor =
new PresentationFrameProcessor.Builder(context) new PresentationFrameProcessor.Builder()
.setResolution(transformationRequest.outputHeight) .setResolution(transformationRequest.outputHeight)
.build(); .build();
frameProcessorChain = frameProcessorChain =

View File

@ -15,7 +15,6 @@
*/ */
package androidx.media3.transformer; package androidx.media3.transformer;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertThrows;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
@ -35,11 +34,11 @@ public final class AdvancedFrameProcessorTest {
public void construct_withInvalidMatrixSize_throwsException() { public void construct_withInvalidMatrixSize_throwsException() {
assertThrows( assertThrows(
IllegalArgumentException.class, IllegalArgumentException.class,
() -> new AdvancedFrameProcessor(getApplicationContext(), new float[4])); () -> new AdvancedFrameProcessor(/* transformationMatrix= */ new float[4]));
} }
@Test @Test
public void construct_withValidMatrixSize_completesSuccessfully() { public void construct_withValidMatrixSize_completesSuccessfully() {
new AdvancedFrameProcessor(getApplicationContext(), new float[16]); new AdvancedFrameProcessor(/* transformationMatrix= */ new float[16]);
} }
} }

View File

@ -15,7 +15,6 @@
*/ */
package androidx.media3.transformer; package androidx.media3.transformer;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertThrows;
@ -38,7 +37,7 @@ public final class PresentationFrameProcessorTest {
int inputWidth = 200; int inputWidth = 200;
int inputHeight = 150; int inputHeight = 150;
PresentationFrameProcessor presentationFrameProcessor = PresentationFrameProcessor presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()).build(); new PresentationFrameProcessor.Builder().build();
presentationFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight); presentationFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight);
Size outputSize = presentationFrameProcessor.getOutputSize(); Size outputSize = presentationFrameProcessor.getOutputSize();
@ -53,7 +52,7 @@ public final class PresentationFrameProcessorTest {
int inputWidth = 150; int inputWidth = 150;
int inputHeight = 150; int inputHeight = 150;
PresentationFrameProcessor presentationFrameProcessor = PresentationFrameProcessor presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()).build(); new PresentationFrameProcessor.Builder().build();
presentationFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight); presentationFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight);
Size outputSize = presentationFrameProcessor.getOutputSize(); Size outputSize = presentationFrameProcessor.getOutputSize();
@ -68,7 +67,7 @@ public final class PresentationFrameProcessorTest {
int inputWidth = 150; int inputWidth = 150;
int inputHeight = 200; int inputHeight = 200;
PresentationFrameProcessor presentationFrameProcessor = PresentationFrameProcessor presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()).build(); new PresentationFrameProcessor.Builder().build();
presentationFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight); presentationFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight);
Size outputSize = presentationFrameProcessor.getOutputSize(); Size outputSize = presentationFrameProcessor.getOutputSize();
@ -84,9 +83,7 @@ public final class PresentationFrameProcessorTest {
int inputHeight = 150; int inputHeight = 150;
int requestedHeight = 300; int requestedHeight = 300;
PresentationFrameProcessor presentationFrameProcessor = PresentationFrameProcessor presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder().setResolution(requestedHeight).build();
.setResolution(requestedHeight)
.build();
presentationFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight); presentationFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight);
Size outputSize = presentationFrameProcessor.getOutputSize(); Size outputSize = presentationFrameProcessor.getOutputSize();
@ -105,9 +102,7 @@ public final class PresentationFrameProcessorTest {
float bottom = .5f; float bottom = .5f;
float top = 1f; float top = 1f;
PresentationFrameProcessor presentationFrameProcessor = PresentationFrameProcessor presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder().setCrop(left, right, bottom, top).build();
.setCrop(left, right, bottom, top)
.build();
presentationFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight); presentationFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight);
Size outputSize = presentationFrameProcessor.getOutputSize(); Size outputSize = presentationFrameProcessor.getOutputSize();
@ -129,7 +124,7 @@ public final class PresentationFrameProcessorTest {
float top = 1f; float top = 1f;
int requestedHeight = 100; int requestedHeight = 100;
PresentationFrameProcessor presentationFrameProcessor = PresentationFrameProcessor presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder()
.setCrop(left, right, bottom, top) .setCrop(left, right, bottom, top)
.setResolution(requestedHeight) .setResolution(requestedHeight)
.build(); .build();
@ -156,7 +151,7 @@ public final class PresentationFrameProcessorTest {
float top = 1f; float top = 1f;
int requestedHeight = 100; int requestedHeight = 100;
PresentationFrameProcessor presentationFrameProcessor = PresentationFrameProcessor presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder()
.setResolution(requestedHeight) .setResolution(requestedHeight)
.setCrop(left, right, bottom, top) .setCrop(left, right, bottom, top)
.build(); .build();
@ -179,7 +174,7 @@ public final class PresentationFrameProcessorTest {
int inputHeight = 200; int inputHeight = 200;
float aspectRatio = 2f; float aspectRatio = 2f;
PresentationFrameProcessor presentationFrameProcessor = PresentationFrameProcessor presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder()
.setAspectRatio(aspectRatio, PresentationFrameProcessor.SCALE_TO_FIT) .setAspectRatio(aspectRatio, PresentationFrameProcessor.SCALE_TO_FIT)
.build(); .build();
@ -198,7 +193,7 @@ public final class PresentationFrameProcessorTest {
float aspectRatio = 2f; float aspectRatio = 2f;
int requestedHeight = 100; int requestedHeight = 100;
PresentationFrameProcessor presentationFrameProcessor = PresentationFrameProcessor presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder()
.setAspectRatio(aspectRatio, PresentationFrameProcessor.SCALE_TO_FIT) .setAspectRatio(aspectRatio, PresentationFrameProcessor.SCALE_TO_FIT)
.setResolution(requestedHeight) .setResolution(requestedHeight)
.build(); .build();
@ -214,7 +209,7 @@ public final class PresentationFrameProcessorTest {
@Test @Test
public void getOutputSize_setAspectRatioAndCrop_throwsIllegalStateException() { public void getOutputSize_setAspectRatioAndCrop_throwsIllegalStateException() {
PresentationFrameProcessor.Builder presentationFrameProcessor = PresentationFrameProcessor.Builder presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder()
.setAspectRatio(/* aspectRatio= */ 2f, PresentationFrameProcessor.SCALE_TO_FIT); .setAspectRatio(/* aspectRatio= */ 2f, PresentationFrameProcessor.SCALE_TO_FIT);
assertThrows( assertThrows(
@ -227,7 +222,7 @@ public final class PresentationFrameProcessorTest {
@Test @Test
public void getOutputSize_setCropAndAspectRatio_throwsIllegalStateException() { public void getOutputSize_setCropAndAspectRatio_throwsIllegalStateException() {
PresentationFrameProcessor.Builder presentationFrameProcessor = PresentationFrameProcessor.Builder presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()) new PresentationFrameProcessor.Builder()
.setCrop(/* left= */ -.5f, /* right= */ .5f, /* bottom= */ .5f, /* top= */ 1f); .setCrop(/* left= */ -.5f, /* right= */ .5f, /* bottom= */ .5f, /* top= */ 1f);
assertThrows( assertThrows(
@ -240,7 +235,7 @@ public final class PresentationFrameProcessorTest {
@Test @Test
public void getOutputRotationDegreesBeforeConfigure_throwsIllegalStateException() { public void getOutputRotationDegreesBeforeConfigure_throwsIllegalStateException() {
PresentationFrameProcessor presentationFrameProcessor = PresentationFrameProcessor presentationFrameProcessor =
new PresentationFrameProcessor.Builder(getApplicationContext()).build(); new PresentationFrameProcessor.Builder().build();
// configureOutputSize not called before getOutputRotationDegrees. // configureOutputSize not called before getOutputRotationDegrees.
assertThrows(IllegalStateException.class, presentationFrameProcessor::getOutputRotationDegrees); assertThrows(IllegalStateException.class, presentationFrameProcessor::getOutputRotationDegrees);

View File

@ -15,7 +15,6 @@
*/ */
package androidx.media3.transformer; package androidx.media3.transformer;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.util.Size; import android.util.Size;
@ -37,7 +36,7 @@ public final class ScaleToFitFrameProcessorTest {
int inputWidth = 200; int inputWidth = 200;
int inputHeight = 150; int inputHeight = 150;
ScaleToFitFrameProcessor scaleToFitFrameProcessor = ScaleToFitFrameProcessor scaleToFitFrameProcessor =
new ScaleToFitFrameProcessor.Builder(getApplicationContext()).build(); new ScaleToFitFrameProcessor.Builder().build();
scaleToFitFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight); scaleToFitFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight);
Size outputSize = scaleToFitFrameProcessor.getOutputSize(); Size outputSize = scaleToFitFrameProcessor.getOutputSize();
@ -51,7 +50,7 @@ public final class ScaleToFitFrameProcessorTest {
int inputWidth = 200; int inputWidth = 200;
int inputHeight = 150; int inputHeight = 150;
ScaleToFitFrameProcessor scaleToFitFrameProcessor = ScaleToFitFrameProcessor scaleToFitFrameProcessor =
new ScaleToFitFrameProcessor.Builder(getApplicationContext()) new ScaleToFitFrameProcessor.Builder()
.setScale(/* scaleX= */ .5f, /* scaleY= */ 1f) .setScale(/* scaleX= */ .5f, /* scaleY= */ 1f)
.build(); .build();
@ -67,9 +66,7 @@ public final class ScaleToFitFrameProcessorTest {
int inputWidth = 200; int inputWidth = 200;
int inputHeight = 150; int inputHeight = 150;
ScaleToFitFrameProcessor scaleToFitFrameProcessor = ScaleToFitFrameProcessor scaleToFitFrameProcessor =
new ScaleToFitFrameProcessor.Builder(getApplicationContext()) new ScaleToFitFrameProcessor.Builder().setScale(/* scaleX= */ 2f, /* scaleY= */ 1f).build();
.setScale(/* scaleX= */ 2f, /* scaleY= */ 1f)
.build();
scaleToFitFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight); scaleToFitFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight);
Size outputSize = scaleToFitFrameProcessor.getOutputSize(); Size outputSize = scaleToFitFrameProcessor.getOutputSize();
@ -83,9 +80,7 @@ public final class ScaleToFitFrameProcessorTest {
int inputWidth = 200; int inputWidth = 200;
int inputHeight = 150; int inputHeight = 150;
ScaleToFitFrameProcessor scaleToFitFrameProcessor = ScaleToFitFrameProcessor scaleToFitFrameProcessor =
new ScaleToFitFrameProcessor.Builder(getApplicationContext()) new ScaleToFitFrameProcessor.Builder().setScale(/* scaleX= */ 1f, /* scaleY= */ 2f).build();
.setScale(/* scaleX= */ 1f, /* scaleY= */ 2f)
.build();
scaleToFitFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight); scaleToFitFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight);
Size outputSize = scaleToFitFrameProcessor.getOutputSize(); Size outputSize = scaleToFitFrameProcessor.getOutputSize();
@ -99,9 +94,7 @@ public final class ScaleToFitFrameProcessorTest {
int inputWidth = 200; int inputWidth = 200;
int inputHeight = 150; int inputHeight = 150;
ScaleToFitFrameProcessor scaleToFitFrameProcessor = ScaleToFitFrameProcessor scaleToFitFrameProcessor =
new ScaleToFitFrameProcessor.Builder(getApplicationContext()) new ScaleToFitFrameProcessor.Builder().setRotationDegrees(90).build();
.setRotationDegrees(90)
.build();
scaleToFitFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight); scaleToFitFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight);
Size outputSize = scaleToFitFrameProcessor.getOutputSize(); Size outputSize = scaleToFitFrameProcessor.getOutputSize();
@ -115,9 +108,7 @@ public final class ScaleToFitFrameProcessorTest {
int inputWidth = 200; int inputWidth = 200;
int inputHeight = 150; int inputHeight = 150;
ScaleToFitFrameProcessor scaleToFitFrameProcessor = ScaleToFitFrameProcessor scaleToFitFrameProcessor =
new ScaleToFitFrameProcessor.Builder(getApplicationContext()) new ScaleToFitFrameProcessor.Builder().setRotationDegrees(45).build();
.setRotationDegrees(45)
.build();
long expectedOutputWidthHeight = 247; long expectedOutputWidthHeight = 247;
scaleToFitFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight); scaleToFitFrameProcessor.configureOutputSizeAndTransformationMatrix(inputWidth, inputHeight);