Skip to content

Commit f5d8800

Browse files
dway123icbaker
authored andcommitted
FrameProcessor: Use factories instead of a builder for Presentation.
PiperOrigin-RevId: 456064021
1 parent 931562c commit f5d8800

File tree

6 files changed

+109
-120
lines changed

6 files changed

+109
-120
lines changed

libraries/transformer/src/androidTest/java/androidx/media3/transformer/FrameProcessorChainPixelTest.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -204,10 +204,10 @@ public void processData_withScaleToFitAndMatrixTransformation_producesExpectedOu
204204
}
205205

206206
@Test
207-
public void processData_withPresentation_setResolution_producesExpectedOutput() throws Exception {
208-
String testId = "processData_withPresentation_setResolution";
209-
setUpAndPrepareFirstFrame(
210-
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO, new Presentation.Builder().setResolution(480).build());
207+
public void processData_withPresentation_createForHeight_producesExpectedOutput()
208+
throws Exception {
209+
String testId = "processData_withPresentation_createForHeight";
210+
setUpAndPrepareFirstFrame(DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO, Presentation.createForHeight(480));
211211
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(REQUEST_OUTPUT_HEIGHT_PNG_ASSET_PATH);
212212

213213
Bitmap actualBitmap = processFirstFrameAndEnd();
@@ -222,14 +222,13 @@ public void processData_withPresentation_setResolution_producesExpectedOutput()
222222
}
223223

224224
@Test
225-
public void processData_withCropAndPresentation_producesExpectedOutput() throws Exception {
226-
String testId = "processData_withCropAndPresentation";
225+
public void processData_withCropThenPresentation_producesExpectedOutput() throws Exception {
226+
String testId = "processData_withCropThenPresentation";
227227
setUpAndPrepareFirstFrame(
228228
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO,
229229
new Crop(/* left= */ -.5f, /* right= */ .5f, /* bottom= */ -.5f, /* top= */ .5f),
230-
new Presentation.Builder()
231-
.setAspectRatio(/* aspectRatio= */ .5f, Presentation.LAYOUT_SCALE_TO_FIT)
232-
.build());
230+
Presentation.createForAspectRatio(
231+
/* aspectRatio= */ .5f, Presentation.LAYOUT_SCALE_TO_FIT));
233232
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(CROP_THEN_ASPECT_RATIO_PNG_ASSET_PATH);
234233

235234
Bitmap actualBitmap = processFirstFrameAndEnd();

libraries/transformer/src/androidTest/java/androidx/media3/transformer/PresentationPixelTest.java

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import android.opengl.EGLDisplay;
2727
import android.opengl.EGLSurface;
2828
import android.util.Size;
29+
import androidx.media3.common.C;
2930
import androidx.media3.common.util.GlUtil;
3031
import androidx.test.ext.junit.runners.AndroidJUnit4;
3132
import java.io.IOException;
@@ -95,7 +96,8 @@ public void release() throws GlUtil.GlException, FrameProcessingException {
9596
@Test
9697
public void drawFrame_noEdits_producesExpectedOutput() throws Exception {
9798
String testId = "drawFrame_noEdits";
98-
presentationTextureProcessor = new Presentation.Builder().build().toGlTextureProcessor(context);
99+
presentationTextureProcessor =
100+
Presentation.createForHeight(C.LENGTH_UNSET).toGlTextureProcessor(context);
99101
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
100102
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
101103
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ORIGINAL_PNG_ASSET_PATH);
@@ -119,9 +121,7 @@ public void drawFrame_changeAspectRatio_scaleToFit_narrow_producesExpectedOutput
119121
throws Exception {
120122
String testId = "drawFrame_changeAspectRatio_scaleToFit_narrow";
121123
presentationTextureProcessor =
122-
new Presentation.Builder()
123-
.setAspectRatio(1f, Presentation.LAYOUT_SCALE_TO_FIT)
124-
.build()
124+
Presentation.createForAspectRatio(/* aspectRatio= */ 1f, Presentation.LAYOUT_SCALE_TO_FIT)
125125
.toGlTextureProcessor(context);
126126
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
127127
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
@@ -147,9 +147,7 @@ public void drawFrame_changeAspectRatio_scaleToFit_wide_producesExpectedOutput()
147147
throws Exception {
148148
String testId = "drawFrame_changeAspectRatio_scaleToFit_wide";
149149
presentationTextureProcessor =
150-
new Presentation.Builder()
151-
.setAspectRatio(2f, Presentation.LAYOUT_SCALE_TO_FIT)
152-
.build()
150+
Presentation.createForAspectRatio(/* aspectRatio= */ 2f, Presentation.LAYOUT_SCALE_TO_FIT)
153151
.toGlTextureProcessor(context);
154152
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
155153
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
@@ -175,9 +173,8 @@ public void drawFrame_changeAspectRatio_scaleToFitWithCrop_narrow_producesExpect
175173
throws Exception {
176174
String testId = "drawFrame_changeAspectRatio_scaleToFitWithCrop_narrow";
177175
presentationTextureProcessor =
178-
new Presentation.Builder()
179-
.setAspectRatio(1f, Presentation.LAYOUT_SCALE_TO_FIT_WITH_CROP)
180-
.build()
176+
Presentation.createForAspectRatio(
177+
/* aspectRatio= */ 1f, Presentation.LAYOUT_SCALE_TO_FIT_WITH_CROP)
181178
.toGlTextureProcessor(context);
182179
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
183180
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
@@ -203,9 +200,8 @@ public void drawFrame_changeAspectRatio_scaleToFitWithCrop_wide_producesExpected
203200
throws Exception {
204201
String testId = "drawFrame_changeAspectRatio_scaleToFitWithCrop_wide";
205202
presentationTextureProcessor =
206-
new Presentation.Builder()
207-
.setAspectRatio(2f, Presentation.LAYOUT_SCALE_TO_FIT_WITH_CROP)
208-
.build()
203+
Presentation.createForAspectRatio(
204+
/* aspectRatio= */ 2f, Presentation.LAYOUT_SCALE_TO_FIT_WITH_CROP)
209205
.toGlTextureProcessor(context);
210206
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
211207
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
@@ -231,9 +227,7 @@ public void drawFrame_changeAspectRatio_stretchToFit_narrow_producesExpectedOutp
231227
throws Exception {
232228
String testId = "drawFrame_changeAspectRatio_stretchToFit_narrow";
233229
presentationTextureProcessor =
234-
new Presentation.Builder()
235-
.setAspectRatio(1f, Presentation.LAYOUT_STRETCH_TO_FIT)
236-
.build()
230+
Presentation.createForAspectRatio(/* aspectRatio= */ 1f, Presentation.LAYOUT_STRETCH_TO_FIT)
237231
.toGlTextureProcessor(context);
238232
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
239233
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
@@ -259,9 +253,7 @@ public void drawFrame_changeAspectRatio_stretchToFit_wide_producesExpectedOutput
259253
throws Exception {
260254
String testId = "drawFrame_changeAspectRatio_stretchToFit_wide";
261255
presentationTextureProcessor =
262-
new Presentation.Builder()
263-
.setAspectRatio(2f, Presentation.LAYOUT_STRETCH_TO_FIT)
264-
.build()
256+
Presentation.createForAspectRatio(/* aspectRatio= */ 2f, Presentation.LAYOUT_STRETCH_TO_FIT)
265257
.toGlTextureProcessor(context);
266258
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
267259
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());

libraries/transformer/src/main/java/androidx/media3/transformer/FrameProcessorChain.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -259,12 +259,8 @@ private static FrameProcessorChain createOpenGlObjectsAndFrameProcessorChain(
259259
if (outputSurfaceInfo.width != outputSize.getWidth()
260260
|| outputSurfaceInfo.height != outputSize.getHeight()) {
261261
matrixTransformationListBuilder.add(
262-
new Presentation.Builder()
263-
.setAspectRatio(
264-
outputSurfaceInfo.width / (float) outputSurfaceInfo.height,
265-
Presentation.LAYOUT_SCALE_TO_FIT)
266-
.setResolution(outputSurfaceInfo.height)
267-
.build());
262+
Presentation.createForWidthAndHeight(
263+
outputSurfaceInfo.width, outputSurfaceInfo.height, Presentation.LAYOUT_SCALE_TO_FIT));
268264
}
269265

270266
// Convert final list of matrix transformations (including additional transformations for the

libraries/transformer/src/main/java/androidx/media3/transformer/Presentation.java

Lines changed: 75 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@
3636
* the input pixels onto the output frame geometry (for example, by stretching the input frame to
3737
* match the specified output frame, or fitting the input frame using letterboxing).
3838
*
39-
* <p>Aspect ratio is applied before setting resolution.
40-
*
4139
* <p>The background color of the output frame will be black, with alpha = 0 if applicable.
4240
*/
4341
@UnstableApi
@@ -49,8 +47,7 @@ public final class Presentation implements MatrixTransformation {
4947
* <p>One of {@link #LAYOUT_SCALE_TO_FIT}, {@link #LAYOUT_SCALE_TO_FIT_WITH_CROP}, or {@link
5048
* #LAYOUT_STRETCH_TO_FIT}.
5149
*
52-
* <p>May scale either width or height, leaving the other output dimension equal to its input,
53-
* unless {@link Builder#setResolution(int)} rescales width and height.
50+
* <p>May scale either width or height, leaving the other output dimension equal to its input.
5451
*/
5552
@Documented
5653
@Retention(SOURCE)
@@ -100,81 +97,82 @@ public final class Presentation implements MatrixTransformation {
10097
*/
10198
public static final int LAYOUT_STRETCH_TO_FIT = 2;
10299

103-
/** A builder for {@link Presentation} instances. */
104-
public static final class Builder {
105-
106-
// Optional fields.
107-
private int outputHeight;
108-
private float aspectRatio;
109-
private @Layout int layout;
100+
private static final float ASPECT_RATIO_UNSET = -1f;
110101

111-
/** Creates a builder with default values. */
112-
public Builder() {
113-
outputHeight = C.LENGTH_UNSET;
114-
aspectRatio = C.LENGTH_UNSET;
115-
}
102+
private static void checkLayout(@Layout int layout) {
103+
checkArgument(
104+
layout == LAYOUT_SCALE_TO_FIT
105+
|| layout == LAYOUT_SCALE_TO_FIT_WITH_CROP
106+
|| layout == LAYOUT_STRETCH_TO_FIT,
107+
"invalid layout " + layout);
108+
}
116109

117-
/**
118-
* Sets the output resolution using the output height.
119-
*
120-
* <p>The default value, {@link C#LENGTH_UNSET}, corresponds to using the same height as the
121-
* input. Output width of the displayed frame will scale to preserve the frame's aspect ratio
122-
* after other transformations.
123-
*
124-
* <p>For example, a 1920x1440 frame can be scaled to 640x480 by calling {@code
125-
* setResolution(480)}.
126-
*
127-
* @param height The output height of the displayed frame, in pixels.
128-
* @return This builder.
129-
*/
130-
public Builder setResolution(int height) {
131-
this.outputHeight = height;
132-
return this;
133-
}
110+
/**
111+
* Creates a new {@link Presentation} instance.
112+
*
113+
* <p>The output frame will have the given aspect ratio (width/height ratio). Width or height will
114+
* be resized to conform to this {@code aspectRatio}, given a {@link Layout}.
115+
*
116+
* @param aspectRatio The aspect ratio (width/height ratio) of the output frame. Must be positive.
117+
* @param layout The layout of the output frame.
118+
*/
119+
public static Presentation createForAspectRatio(float aspectRatio, @Layout int layout) {
120+
checkArgument(
121+
aspectRatio == C.LENGTH_UNSET || aspectRatio > 0,
122+
"aspect ratio " + aspectRatio + " must be positive or unset");
123+
checkLayout(layout);
124+
return new Presentation(
125+
/* width= */ C.LENGTH_UNSET, /* height= */ C.LENGTH_UNSET, aspectRatio, layout);
126+
}
134127

135-
/**
136-
* Sets the aspect ratio (width/height ratio) for the output frame.
137-
*
138-
* <p>Resizes a frame's width or height to conform to an {@code aspectRatio}, given a {@link
139-
* Layout}. {@code aspectRatio} defaults to {@link C#LENGTH_UNSET}, which corresponds to the
140-
* same aspect ratio as the input frame. {@code layout} defaults to {@link #LAYOUT_SCALE_TO_FIT}
141-
*
142-
* <p>Width and height values set may be rescaled by {@link #setResolution(int)}, which is
143-
* applied after aspect ratio changes.
144-
*
145-
* @param aspectRatio The aspect ratio (width/height ratio) of the output frame. Must be
146-
* positive.
147-
* @return This builder.
148-
*/
149-
public Builder setAspectRatio(float aspectRatio, @Layout int layout) {
150-
checkArgument(aspectRatio > 0, "aspect ratio " + aspectRatio + " must be positive");
151-
checkArgument(
152-
layout == LAYOUT_SCALE_TO_FIT
153-
|| layout == LAYOUT_SCALE_TO_FIT_WITH_CROP
154-
|| layout == LAYOUT_STRETCH_TO_FIT,
155-
"invalid layout " + layout);
156-
this.aspectRatio = aspectRatio;
157-
this.layout = layout;
158-
return this;
159-
}
128+
/**
129+
* Creates a new {@link Presentation} instance.
130+
*
131+
* <p>The output frame will have the given height. Width will scale to preserve the input aspect
132+
* ratio.
133+
*
134+
* @param height The height of the output frame, in pixels.
135+
*/
136+
public static Presentation createForHeight(int height) {
137+
return new Presentation(
138+
/* width= */ C.LENGTH_UNSET, height, ASPECT_RATIO_UNSET, LAYOUT_SCALE_TO_FIT);
139+
}
160140

161-
public Presentation build() {
162-
return new Presentation(outputHeight, aspectRatio, layout);
163-
}
141+
/**
142+
* Creates a new {@link Presentation} instance.
143+
*
144+
* <p>The output frame will have the given width and height, given a {@link Layout}.
145+
*
146+
* <p>Width and height must be positive integers representing the output frame's width and height.
147+
*
148+
* @param width The width of the output frame, in pixels.
149+
* @param height The height of the output frame, in pixels.
150+
* @param layout The layout of the output frame.
151+
*/
152+
public static Presentation createForWidthAndHeight(int width, int height, @Layout int layout) {
153+
checkArgument(width > 0, "width " + width + " must be positive");
154+
checkArgument(height > 0, "height " + height + " must be positive");
155+
checkLayout(layout);
156+
return new Presentation(width, height, ASPECT_RATIO_UNSET, layout);
164157
}
165158

159+
private final int requestedWidthPixels;
166160
private final int requestedHeightPixels;
167-
private final float requestedAspectRatio;
161+
private float requestedAspectRatio;
168162
private final @Layout int layout;
169163

170164
private float outputWidth;
171165
private float outputHeight;
172166
private @MonotonicNonNull Matrix transformationMatrix;
173167

174-
/** Creates a new instance. */
175-
private Presentation(int requestedHeightPixels, float requestedAspectRatio, @Layout int layout) {
176-
this.requestedHeightPixels = requestedHeightPixels;
177-
this.requestedAspectRatio = requestedAspectRatio;
168+
private Presentation(int width, int height, float aspectRatio, @Layout int layout) {
169+
checkArgument(
170+
(aspectRatio == C.LENGTH_UNSET) || (width == C.LENGTH_UNSET),
171+
"width and aspect ratio should not both be set");
172+
173+
this.requestedWidthPixels = width;
174+
this.requestedHeightPixels = height;
175+
this.requestedAspectRatio = aspectRatio;
178176
this.layout = layout;
179177

180178
outputWidth = C.LENGTH_UNSET;
@@ -191,13 +189,21 @@ public Size configure(int inputWidth, int inputHeight) {
191189
outputWidth = inputWidth;
192190
outputHeight = inputHeight;
193191

192+
if ((requestedWidthPixels != C.LENGTH_UNSET) && (requestedHeightPixels != C.LENGTH_UNSET)) {
193+
requestedAspectRatio = (float) requestedWidthPixels / requestedHeightPixels;
194+
}
195+
194196
if (requestedAspectRatio != C.LENGTH_UNSET) {
195197
applyAspectRatio();
196198
}
197199

198-
// Scale width and height to desired requestedHeightPixels, preserving aspect ratio.
199-
if (requestedHeightPixels != C.LENGTH_UNSET && requestedHeightPixels != outputHeight) {
200-
outputWidth = requestedHeightPixels * outputWidth / outputHeight;
200+
// Scale output width and height to requested values.
201+
if (requestedHeightPixels != C.LENGTH_UNSET) {
202+
if (requestedWidthPixels != C.LENGTH_UNSET) {
203+
outputWidth = requestedWidthPixels;
204+
} else {
205+
outputWidth = requestedHeightPixels * outputWidth / outputHeight;
206+
}
201207
outputHeight = requestedHeightPixels;
202208
}
203209
return new Size(Math.round(outputWidth), Math.round(outputHeight));

libraries/transformer/src/main/java/androidx/media3/transformer/VideoTranscodingSamplePipeline.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,7 @@ public VideoTranscodingSamplePipeline(
8888
.build());
8989
}
9090
if (transformationRequest.outputHeight != C.LENGTH_UNSET) {
91-
effectsListBuilder.add(
92-
new Presentation.Builder().setResolution(transformationRequest.outputHeight).build());
91+
effectsListBuilder.add(Presentation.createForHeight(transformationRequest.outputHeight));
9392
}
9493

9594
AtomicReference<TransformationException> encoderInitializationException =

0 commit comments

Comments
 (0)