FrameProcessor: Use factories instead of a builder for Presentation.
PiperOrigin-RevId: 456064021
This commit is contained in:
parent
931562c243
commit
f5d8800d51
@ -204,10 +204,10 @@ public final class FrameProcessorChainPixelTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processData_withPresentation_setResolution_producesExpectedOutput() throws Exception {
|
||||
String testId = "processData_withPresentation_setResolution";
|
||||
setUpAndPrepareFirstFrame(
|
||||
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO, new Presentation.Builder().setResolution(480).build());
|
||||
public void processData_withPresentation_createForHeight_producesExpectedOutput()
|
||||
throws Exception {
|
||||
String testId = "processData_withPresentation_createForHeight";
|
||||
setUpAndPrepareFirstFrame(DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO, Presentation.createForHeight(480));
|
||||
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(REQUEST_OUTPUT_HEIGHT_PNG_ASSET_PATH);
|
||||
|
||||
Bitmap actualBitmap = processFirstFrameAndEnd();
|
||||
@ -222,14 +222,13 @@ public final class FrameProcessorChainPixelTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processData_withCropAndPresentation_producesExpectedOutput() throws Exception {
|
||||
String testId = "processData_withCropAndPresentation";
|
||||
public void processData_withCropThenPresentation_producesExpectedOutput() throws Exception {
|
||||
String testId = "processData_withCropThenPresentation";
|
||||
setUpAndPrepareFirstFrame(
|
||||
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO,
|
||||
new Crop(/* left= */ -.5f, /* right= */ .5f, /* bottom= */ -.5f, /* top= */ .5f),
|
||||
new Presentation.Builder()
|
||||
.setAspectRatio(/* aspectRatio= */ .5f, Presentation.LAYOUT_SCALE_TO_FIT)
|
||||
.build());
|
||||
Presentation.createForAspectRatio(
|
||||
/* aspectRatio= */ .5f, Presentation.LAYOUT_SCALE_TO_FIT));
|
||||
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(CROP_THEN_ASPECT_RATIO_PNG_ASSET_PATH);
|
||||
|
||||
Bitmap actualBitmap = processFirstFrameAndEnd();
|
||||
|
@ -26,6 +26,7 @@ import android.opengl.EGLContext;
|
||||
import android.opengl.EGLDisplay;
|
||||
import android.opengl.EGLSurface;
|
||||
import android.util.Size;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.util.GlUtil;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import java.io.IOException;
|
||||
@ -95,7 +96,8 @@ public final class PresentationPixelTest {
|
||||
@Test
|
||||
public void drawFrame_noEdits_producesExpectedOutput() throws Exception {
|
||||
String testId = "drawFrame_noEdits";
|
||||
presentationTextureProcessor = new Presentation.Builder().build().toGlTextureProcessor(context);
|
||||
presentationTextureProcessor =
|
||||
Presentation.createForHeight(C.LENGTH_UNSET).toGlTextureProcessor(context);
|
||||
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||
@ -119,9 +121,7 @@ public final class PresentationPixelTest {
|
||||
throws Exception {
|
||||
String testId = "drawFrame_changeAspectRatio_scaleToFit_narrow";
|
||||
presentationTextureProcessor =
|
||||
new Presentation.Builder()
|
||||
.setAspectRatio(1f, Presentation.LAYOUT_SCALE_TO_FIT)
|
||||
.build()
|
||||
Presentation.createForAspectRatio(/* aspectRatio= */ 1f, Presentation.LAYOUT_SCALE_TO_FIT)
|
||||
.toGlTextureProcessor(context);
|
||||
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
@ -147,9 +147,7 @@ public final class PresentationPixelTest {
|
||||
throws Exception {
|
||||
String testId = "drawFrame_changeAspectRatio_scaleToFit_wide";
|
||||
presentationTextureProcessor =
|
||||
new Presentation.Builder()
|
||||
.setAspectRatio(2f, Presentation.LAYOUT_SCALE_TO_FIT)
|
||||
.build()
|
||||
Presentation.createForAspectRatio(/* aspectRatio= */ 2f, Presentation.LAYOUT_SCALE_TO_FIT)
|
||||
.toGlTextureProcessor(context);
|
||||
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
@ -175,9 +173,8 @@ public final class PresentationPixelTest {
|
||||
throws Exception {
|
||||
String testId = "drawFrame_changeAspectRatio_scaleToFitWithCrop_narrow";
|
||||
presentationTextureProcessor =
|
||||
new Presentation.Builder()
|
||||
.setAspectRatio(1f, Presentation.LAYOUT_SCALE_TO_FIT_WITH_CROP)
|
||||
.build()
|
||||
Presentation.createForAspectRatio(
|
||||
/* aspectRatio= */ 1f, Presentation.LAYOUT_SCALE_TO_FIT_WITH_CROP)
|
||||
.toGlTextureProcessor(context);
|
||||
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
@ -203,9 +200,8 @@ public final class PresentationPixelTest {
|
||||
throws Exception {
|
||||
String testId = "drawFrame_changeAspectRatio_scaleToFitWithCrop_wide";
|
||||
presentationTextureProcessor =
|
||||
new Presentation.Builder()
|
||||
.setAspectRatio(2f, Presentation.LAYOUT_SCALE_TO_FIT_WITH_CROP)
|
||||
.build()
|
||||
Presentation.createForAspectRatio(
|
||||
/* aspectRatio= */ 2f, Presentation.LAYOUT_SCALE_TO_FIT_WITH_CROP)
|
||||
.toGlTextureProcessor(context);
|
||||
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
@ -231,9 +227,7 @@ public final class PresentationPixelTest {
|
||||
throws Exception {
|
||||
String testId = "drawFrame_changeAspectRatio_stretchToFit_narrow";
|
||||
presentationTextureProcessor =
|
||||
new Presentation.Builder()
|
||||
.setAspectRatio(1f, Presentation.LAYOUT_STRETCH_TO_FIT)
|
||||
.build()
|
||||
Presentation.createForAspectRatio(/* aspectRatio= */ 1f, Presentation.LAYOUT_STRETCH_TO_FIT)
|
||||
.toGlTextureProcessor(context);
|
||||
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
@ -259,9 +253,7 @@ public final class PresentationPixelTest {
|
||||
throws Exception {
|
||||
String testId = "drawFrame_changeAspectRatio_stretchToFit_wide";
|
||||
presentationTextureProcessor =
|
||||
new Presentation.Builder()
|
||||
.setAspectRatio(2f, Presentation.LAYOUT_STRETCH_TO_FIT)
|
||||
.build()
|
||||
Presentation.createForAspectRatio(/* aspectRatio= */ 2f, Presentation.LAYOUT_STRETCH_TO_FIT)
|
||||
.toGlTextureProcessor(context);
|
||||
Size outputSize = presentationTextureProcessor.configure(inputWidth, inputHeight);
|
||||
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||
|
@ -259,12 +259,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
if (outputSurfaceInfo.width != outputSize.getWidth()
|
||||
|| outputSurfaceInfo.height != outputSize.getHeight()) {
|
||||
matrixTransformationListBuilder.add(
|
||||
new Presentation.Builder()
|
||||
.setAspectRatio(
|
||||
outputSurfaceInfo.width / (float) outputSurfaceInfo.height,
|
||||
Presentation.LAYOUT_SCALE_TO_FIT)
|
||||
.setResolution(outputSurfaceInfo.height)
|
||||
.build());
|
||||
Presentation.createForWidthAndHeight(
|
||||
outputSurfaceInfo.width, outputSurfaceInfo.height, Presentation.LAYOUT_SCALE_TO_FIT));
|
||||
}
|
||||
|
||||
// Convert final list of matrix transformations (including additional transformations for the
|
||||
|
@ -36,8 +36,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
* the input pixels onto the output frame geometry (for example, by stretching the input frame to
|
||||
* match the specified output frame, or fitting the input frame using letterboxing).
|
||||
*
|
||||
* <p>Aspect ratio is applied before setting resolution.
|
||||
*
|
||||
* <p>The background color of the output frame will be black, with alpha = 0 if applicable.
|
||||
*/
|
||||
@UnstableApi
|
||||
@ -49,8 +47,7 @@ public final class Presentation implements MatrixTransformation {
|
||||
* <p>One of {@link #LAYOUT_SCALE_TO_FIT}, {@link #LAYOUT_SCALE_TO_FIT_WITH_CROP}, or {@link
|
||||
* #LAYOUT_STRETCH_TO_FIT}.
|
||||
*
|
||||
* <p>May scale either width or height, leaving the other output dimension equal to its input,
|
||||
* unless {@link Builder#setResolution(int)} rescales width and height.
|
||||
* <p>May scale either width or height, leaving the other output dimension equal to its input.
|
||||
*/
|
||||
@Documented
|
||||
@Retention(SOURCE)
|
||||
@ -100,81 +97,82 @@ public final class Presentation implements MatrixTransformation {
|
||||
*/
|
||||
public static final int LAYOUT_STRETCH_TO_FIT = 2;
|
||||
|
||||
/** A builder for {@link Presentation} instances. */
|
||||
public static final class Builder {
|
||||
private static final float ASPECT_RATIO_UNSET = -1f;
|
||||
|
||||
// Optional fields.
|
||||
private int outputHeight;
|
||||
private float aspectRatio;
|
||||
private @Layout int layout;
|
||||
|
||||
/** Creates a builder with default values. */
|
||||
public Builder() {
|
||||
outputHeight = C.LENGTH_UNSET;
|
||||
aspectRatio = C.LENGTH_UNSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the output resolution using the output height.
|
||||
*
|
||||
* <p>The default value, {@link C#LENGTH_UNSET}, corresponds to using the same height as the
|
||||
* input. Output width of the displayed frame will scale to preserve the frame's aspect ratio
|
||||
* after other transformations.
|
||||
*
|
||||
* <p>For example, a 1920x1440 frame can be scaled to 640x480 by calling {@code
|
||||
* setResolution(480)}.
|
||||
*
|
||||
* @param height The output height of the displayed frame, in pixels.
|
||||
* @return This builder.
|
||||
*/
|
||||
public Builder setResolution(int height) {
|
||||
this.outputHeight = height;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aspect ratio (width/height ratio) for the output frame.
|
||||
*
|
||||
* <p>Resizes a frame's width or height to conform to an {@code aspectRatio}, given a {@link
|
||||
* Layout}. {@code aspectRatio} defaults to {@link C#LENGTH_UNSET}, which corresponds to the
|
||||
* same aspect ratio as the input frame. {@code layout} defaults to {@link #LAYOUT_SCALE_TO_FIT}
|
||||
*
|
||||
* <p>Width and height values set may be rescaled by {@link #setResolution(int)}, which is
|
||||
* applied after aspect ratio changes.
|
||||
*
|
||||
* @param aspectRatio The aspect ratio (width/height ratio) of the output frame. Must be
|
||||
* positive.
|
||||
* @return This builder.
|
||||
*/
|
||||
public Builder setAspectRatio(float aspectRatio, @Layout int layout) {
|
||||
checkArgument(aspectRatio > 0, "aspect ratio " + aspectRatio + " must be positive");
|
||||
checkArgument(
|
||||
layout == LAYOUT_SCALE_TO_FIT
|
||||
|| layout == LAYOUT_SCALE_TO_FIT_WITH_CROP
|
||||
|| layout == LAYOUT_STRETCH_TO_FIT,
|
||||
"invalid layout " + layout);
|
||||
this.aspectRatio = aspectRatio;
|
||||
this.layout = layout;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Presentation build() {
|
||||
return new Presentation(outputHeight, aspectRatio, layout);
|
||||
}
|
||||
private static void checkLayout(@Layout int layout) {
|
||||
checkArgument(
|
||||
layout == LAYOUT_SCALE_TO_FIT
|
||||
|| layout == LAYOUT_SCALE_TO_FIT_WITH_CROP
|
||||
|| layout == LAYOUT_STRETCH_TO_FIT,
|
||||
"invalid layout " + layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Presentation} instance.
|
||||
*
|
||||
* <p>The output frame will have the given aspect ratio (width/height ratio). Width or height will
|
||||
* be resized to conform to this {@code aspectRatio}, given a {@link Layout}.
|
||||
*
|
||||
* @param aspectRatio The aspect ratio (width/height ratio) of the output frame. Must be positive.
|
||||
* @param layout The layout of the output frame.
|
||||
*/
|
||||
public static Presentation createForAspectRatio(float aspectRatio, @Layout int layout) {
|
||||
checkArgument(
|
||||
aspectRatio == C.LENGTH_UNSET || aspectRatio > 0,
|
||||
"aspect ratio " + aspectRatio + " must be positive or unset");
|
||||
checkLayout(layout);
|
||||
return new Presentation(
|
||||
/* width= */ C.LENGTH_UNSET, /* height= */ C.LENGTH_UNSET, aspectRatio, layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Presentation} instance.
|
||||
*
|
||||
* <p>The output frame will have the given height. Width will scale to preserve the input aspect
|
||||
* ratio.
|
||||
*
|
||||
* @param height The height of the output frame, in pixels.
|
||||
*/
|
||||
public static Presentation createForHeight(int height) {
|
||||
return new Presentation(
|
||||
/* width= */ C.LENGTH_UNSET, height, ASPECT_RATIO_UNSET, LAYOUT_SCALE_TO_FIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Presentation} instance.
|
||||
*
|
||||
* <p>The output frame will have the given width and height, given a {@link Layout}.
|
||||
*
|
||||
* <p>Width and height must be positive integers representing the output frame's width and height.
|
||||
*
|
||||
* @param width The width of the output frame, in pixels.
|
||||
* @param height The height of the output frame, in pixels.
|
||||
* @param layout The layout of the output frame.
|
||||
*/
|
||||
public static Presentation createForWidthAndHeight(int width, int height, @Layout int layout) {
|
||||
checkArgument(width > 0, "width " + width + " must be positive");
|
||||
checkArgument(height > 0, "height " + height + " must be positive");
|
||||
checkLayout(layout);
|
||||
return new Presentation(width, height, ASPECT_RATIO_UNSET, layout);
|
||||
}
|
||||
|
||||
private final int requestedWidthPixels;
|
||||
private final int requestedHeightPixels;
|
||||
private final float requestedAspectRatio;
|
||||
private float requestedAspectRatio;
|
||||
private final @Layout int layout;
|
||||
|
||||
private float outputWidth;
|
||||
private float outputHeight;
|
||||
private @MonotonicNonNull Matrix transformationMatrix;
|
||||
|
||||
/** Creates a new instance. */
|
||||
private Presentation(int requestedHeightPixels, float requestedAspectRatio, @Layout int layout) {
|
||||
this.requestedHeightPixels = requestedHeightPixels;
|
||||
this.requestedAspectRatio = requestedAspectRatio;
|
||||
private Presentation(int width, int height, float aspectRatio, @Layout int layout) {
|
||||
checkArgument(
|
||||
(aspectRatio == C.LENGTH_UNSET) || (width == C.LENGTH_UNSET),
|
||||
"width and aspect ratio should not both be set");
|
||||
|
||||
this.requestedWidthPixels = width;
|
||||
this.requestedHeightPixels = height;
|
||||
this.requestedAspectRatio = aspectRatio;
|
||||
this.layout = layout;
|
||||
|
||||
outputWidth = C.LENGTH_UNSET;
|
||||
@ -191,13 +189,21 @@ public final class Presentation implements MatrixTransformation {
|
||||
outputWidth = inputWidth;
|
||||
outputHeight = inputHeight;
|
||||
|
||||
if ((requestedWidthPixels != C.LENGTH_UNSET) && (requestedHeightPixels != C.LENGTH_UNSET)) {
|
||||
requestedAspectRatio = (float) requestedWidthPixels / requestedHeightPixels;
|
||||
}
|
||||
|
||||
if (requestedAspectRatio != C.LENGTH_UNSET) {
|
||||
applyAspectRatio();
|
||||
}
|
||||
|
||||
// Scale width and height to desired requestedHeightPixels, preserving aspect ratio.
|
||||
if (requestedHeightPixels != C.LENGTH_UNSET && requestedHeightPixels != outputHeight) {
|
||||
outputWidth = requestedHeightPixels * outputWidth / outputHeight;
|
||||
// Scale output width and height to requested values.
|
||||
if (requestedHeightPixels != C.LENGTH_UNSET) {
|
||||
if (requestedWidthPixels != C.LENGTH_UNSET) {
|
||||
outputWidth = requestedWidthPixels;
|
||||
} else {
|
||||
outputWidth = requestedHeightPixels * outputWidth / outputHeight;
|
||||
}
|
||||
outputHeight = requestedHeightPixels;
|
||||
}
|
||||
return new Size(Math.round(outputWidth), Math.round(outputHeight));
|
||||
|
@ -88,8 +88,7 @@ import org.checkerframework.dataflow.qual.Pure;
|
||||
.build());
|
||||
}
|
||||
if (transformationRequest.outputHeight != C.LENGTH_UNSET) {
|
||||
effectsListBuilder.add(
|
||||
new Presentation.Builder().setResolution(transformationRequest.outputHeight).build());
|
||||
effectsListBuilder.add(Presentation.createForHeight(transformationRequest.outputHeight));
|
||||
}
|
||||
|
||||
AtomicReference<TransformationException> encoderInitializationException =
|
||||
|
@ -18,6 +18,7 @@ package androidx.media3.transformer;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.util.Size;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -33,7 +34,7 @@ public final class PresentationTest {
|
||||
public void configure_noEdits_leavesFramesUnchanged() {
|
||||
int inputWidth = 200;
|
||||
int inputHeight = 150;
|
||||
Presentation presentation = new Presentation.Builder().build();
|
||||
Presentation presentation = Presentation.createForHeight(C.LENGTH_UNSET);
|
||||
|
||||
Size outputSize = presentation.configure(inputWidth, inputHeight);
|
||||
|
||||
@ -42,11 +43,11 @@ public final class PresentationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configure_setResolution_changesDimensions() {
|
||||
public void configure_createForHeight_changesDimensions() {
|
||||
int inputWidth = 200;
|
||||
int inputHeight = 150;
|
||||
int requestedHeight = 300;
|
||||
Presentation presentation = new Presentation.Builder().setResolution(requestedHeight).build();
|
||||
Presentation presentation = Presentation.createForHeight(requestedHeight);
|
||||
|
||||
Size outputSize = presentation.configure(inputWidth, inputHeight);
|
||||
|
||||
@ -55,14 +56,12 @@ public final class PresentationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configure_setAspectRatio_changesDimensions() {
|
||||
public void configure_createForAspectRatio_changesDimensions() {
|
||||
int inputWidth = 300;
|
||||
int inputHeight = 200;
|
||||
float aspectRatio = 2f;
|
||||
Presentation presentation =
|
||||
new Presentation.Builder()
|
||||
.setAspectRatio(aspectRatio, Presentation.LAYOUT_SCALE_TO_FIT)
|
||||
.build();
|
||||
Presentation.createForAspectRatio(aspectRatio, Presentation.LAYOUT_SCALE_TO_FIT);
|
||||
|
||||
Size outputSize = presentation.configure(inputWidth, inputHeight);
|
||||
|
||||
@ -71,20 +70,18 @@ public final class PresentationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configure_setAspectRatioAndResolution_changesDimensions() {
|
||||
public void configure_createForWidthAndHeight_changesDimensions() {
|
||||
int inputWidth = 300;
|
||||
int inputHeight = 200;
|
||||
float aspectRatio = 2f;
|
||||
int requestedHeight = 100;
|
||||
int requestedWidth = 100;
|
||||
int requestedHeight = 300;
|
||||
Presentation presentation =
|
||||
new Presentation.Builder()
|
||||
.setAspectRatio(aspectRatio, Presentation.LAYOUT_SCALE_TO_FIT)
|
||||
.setResolution(requestedHeight)
|
||||
.build();
|
||||
Presentation.createForWidthAndHeight(
|
||||
requestedWidth, requestedHeight, Presentation.LAYOUT_SCALE_TO_FIT);
|
||||
|
||||
Size outputSize = presentation.configure(inputWidth, inputHeight);
|
||||
|
||||
assertThat(outputSize.getWidth()).isEqualTo(Math.round(aspectRatio * requestedHeight));
|
||||
assertThat(outputSize.getWidth()).isEqualTo(requestedWidth);
|
||||
assertThat(outputSize.getHeight()).isEqualTo(requestedHeight);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user