Commit 37559dea by hschlueter Committed by Ian Baker

Configure the frame sizes in FrameProcessorChain instead of caller.

Configuring the frame sizes between frame processors is now the
FrameProcessorChain's rather than the caller's responsibility.
The caller can getOutputSize() and override it for encoder fallback
in configure().

PiperOrigin-RevId: 437048436
parent 20daaa20
...@@ -41,9 +41,7 @@ import android.util.Size; ...@@ -41,9 +41,7 @@ import android.util.Size;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.collect.Iterables;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.List;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
...@@ -247,24 +245,26 @@ public final class FrameProcessorChainPixelTest { ...@@ -247,24 +245,26 @@ public final class FrameProcessorChainPixelTest {
int inputWidth = checkNotNull(mediaFormat).getInteger(MediaFormat.KEY_WIDTH); int inputWidth = checkNotNull(mediaFormat).getInteger(MediaFormat.KEY_WIDTH);
int inputHeight = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT); int inputHeight = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
List<GlFrameProcessor> frameProcessorsList = asList(frameProcessors);
List<Size> sizes =
FrameProcessorChain.configureSizes(inputWidth, inputHeight, frameProcessorsList);
assertThat(sizes).isNotEmpty();
int outputWidth = Iterables.getLast(sizes).getWidth();
int outputHeight = Iterables.getLast(sizes).getHeight();
outputImageReader =
ImageReader.newInstance(
outputWidth, outputHeight, PixelFormat.RGBA_8888, /* maxImages= */ 1);
frameProcessorChain = frameProcessorChain =
new FrameProcessorChain( new FrameProcessorChain(
context, context,
PIXEL_WIDTH_HEIGHT_RATIO, PIXEL_WIDTH_HEIGHT_RATIO,
frameProcessorsList, inputWidth,
sizes, inputHeight,
asList(frameProcessors),
/* enableExperimentalHdrEditing= */ false); /* enableExperimentalHdrEditing= */ false);
Size outputSize = frameProcessorChain.getOutputSize();
outputImageReader =
ImageReader.newInstance(
outputSize.getWidth(),
outputSize.getHeight(),
PixelFormat.RGBA_8888,
/* maxImages= */ 1);
frameProcessorChain.configure( frameProcessorChain.configure(
outputImageReader.getSurface(), outputWidth, outputHeight, /* debugSurfaceView= */ null); outputImageReader.getSurface(),
outputSize.getWidth(),
outputSize.getHeight(),
/* debugSurfaceView= */ null);
frameProcessorChain.registerInputFrame(); frameProcessorChain.registerInputFrame();
// Queue the first video frame from the extractor. // Queue the first video frame from the extractor.
......
...@@ -29,7 +29,6 @@ import androidx.media3.common.Format; ...@@ -29,7 +29,6 @@ import androidx.media3.common.Format;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.decoder.DecoderInputBuffer; import androidx.media3.decoder.DecoderInputBuffer;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import java.util.List; import java.util.List;
import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.Pure;
...@@ -70,6 +69,7 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -70,6 +69,7 @@ import org.checkerframework.dataflow.qual.Pure;
int decodedHeight = int decodedHeight =
(inputFormat.rotationDegrees % 180 == 0) ? inputFormat.height : inputFormat.width; (inputFormat.rotationDegrees % 180 == 0) ? inputFormat.height : inputFormat.width;
// TODO(b/214975934): Allow a list of frame processors to be passed into the sample pipeline.
// 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(context)
...@@ -80,13 +80,15 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -80,13 +80,15 @@ import org.checkerframework.dataflow.qual.Pure;
new PresentationFrameProcessor.Builder(context) new PresentationFrameProcessor.Builder(context)
.setResolution(transformationRequest.outputHeight) .setResolution(transformationRequest.outputHeight)
.build(); .build();
// TODO(b/214975934): Allow a list of frame processors to be passed into the sample pipeline. frameProcessorChain =
ImmutableList<GlFrameProcessor> frameProcessors = new FrameProcessorChain(
ImmutableList.of(scaleToFitFrameProcessor, presentationFrameProcessor); context,
List<Size> frameProcessorSizes = inputFormat.pixelWidthHeightRatio,
FrameProcessorChain.configureSizes(decodedWidth, decodedHeight, frameProcessors); /* inputWidth= */ decodedWidth,
Size requestedEncoderSize = Iterables.getLast(frameProcessorSizes); /* inputHeight= */ decodedHeight,
// TODO(b/213190310): Move output rotation configuration to PresentationFrameProcessor. ImmutableList.of(scaleToFitFrameProcessor, presentationFrameProcessor),
transformationRequest.enableHdrEditing);
Size requestedEncoderSize = frameProcessorChain.getOutputSize();
outputRotationDegrees = presentationFrameProcessor.getOutputRotationDegrees(); outputRotationDegrees = presentationFrameProcessor.getOutputRotationDegrees();
Format requestedEncoderFormat = Format requestedEncoderFormat =
...@@ -110,13 +112,6 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -110,13 +112,6 @@ import org.checkerframework.dataflow.qual.Pure;
requestedEncoderFormat, requestedEncoderFormat,
encoderSupportedFormat)); encoderSupportedFormat));
frameProcessorChain =
new FrameProcessorChain(
context,
inputFormat.pixelWidthHeightRatio,
frameProcessors,
frameProcessorSizes,
transformationRequest.enableHdrEditing);
frameProcessorChain.configure( frameProcessorChain.configure(
/* outputSurface= */ encoder.getInputSurface(), /* outputSurface= */ encoder.getInputSurface(),
/* outputWidth= */ encoderSupportedFormat.width, /* outputWidth= */ encoderSupportedFormat.width,
......
...@@ -35,6 +35,7 @@ import org.junit.runner.RunWith; ...@@ -35,6 +35,7 @@ import org.junit.runner.RunWith;
*/ */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public final class FrameProcessorChainTest { public final class FrameProcessorChainTest {
@Test @Test
public void construct_withSupportedPixelWidthHeightRatio_completesSuccessfully() public void construct_withSupportedPixelWidthHeightRatio_completesSuccessfully()
throws TransformationException { throws TransformationException {
...@@ -43,8 +44,9 @@ public final class FrameProcessorChainTest { ...@@ -43,8 +44,9 @@ public final class FrameProcessorChainTest {
new FrameProcessorChain( new FrameProcessorChain(
context, context,
/* pixelWidthHeightRatio= */ 1, /* pixelWidthHeightRatio= */ 1,
/* inputWidth= */ 200,
/* inputHeight= */ 100,
/* frameProcessors= */ ImmutableList.of(), /* frameProcessors= */ ImmutableList.of(),
/* sizes= */ ImmutableList.of(new Size(200, 100)),
/* enableExperimentalHdrEditing= */ false); /* enableExperimentalHdrEditing= */ false);
} }
...@@ -59,8 +61,9 @@ public final class FrameProcessorChainTest { ...@@ -59,8 +61,9 @@ public final class FrameProcessorChainTest {
new FrameProcessorChain( new FrameProcessorChain(
context, context,
/* pixelWidthHeightRatio= */ 2, /* pixelWidthHeightRatio= */ 2,
/* inputWidth= */ 200,
/* inputHeight= */ 100,
/* frameProcessors= */ ImmutableList.of(), /* frameProcessors= */ ImmutableList.of(),
/* sizes= */ ImmutableList.of(new Size(200, 100)),
/* enableExperimentalHdrEditing= */ false)); /* enableExperimentalHdrEditing= */ false));
assertThat(exception).hasCauseThat().isInstanceOf(UnsupportedOperationException.class); assertThat(exception).hasCauseThat().isInstanceOf(UnsupportedOperationException.class);
...@@ -68,46 +71,63 @@ public final class FrameProcessorChainTest { ...@@ -68,46 +71,63 @@ public final class FrameProcessorChainTest {
} }
@Test @Test
public void configureOutputDimensions_withEmptyList_returnsInputSize() { public void getOutputSize_withoutFrameProcessors_returnsInputSize()
throws TransformationException {
Size inputSize = new Size(200, 100); Size inputSize = new Size(200, 100);
FrameProcessorChain frameProcessorChain =
createFrameProcessorChainWithFakeFrameProcessors(
inputSize, /* frameProcessorOutputSizes= */ ImmutableList.of());
List<Size> sizes = Size outputSize = frameProcessorChain.getOutputSize();
FrameProcessorChain.configureSizes(
inputSize.getWidth(), inputSize.getHeight(), /* frameProcessors= */ ImmutableList.of());
assertThat(sizes).containsExactly(inputSize); assertThat(outputSize).isEqualTo(inputSize);
} }
@Test @Test
public void configureOutputDimensions_withOneFrameProcessor_returnsItsInputAndOutputDimensions() { public void getOutputSize_withOneFrameProcessor_returnsItsOutputSize()
throws TransformationException {
Size inputSize = new Size(200, 100); Size inputSize = new Size(200, 100);
Size outputSize = new Size(300, 250); Size frameProcessorOutputSize = new Size(300, 250);
GlFrameProcessor frameProcessor = new FakeFrameProcessor(outputSize); FrameProcessorChain frameProcessorChain =
createFrameProcessorChainWithFakeFrameProcessors(
inputSize, /* frameProcessorOutputSizes= */ ImmutableList.of(frameProcessorOutputSize));
List<Size> sizes = Size frameProcessorChainOutputSize = frameProcessorChain.getOutputSize();
FrameProcessorChain.configureSizes(
inputSize.getWidth(), inputSize.getHeight(), ImmutableList.of(frameProcessor));
assertThat(sizes).containsExactly(inputSize, outputSize).inOrder(); assertThat(frameProcessorChainOutputSize).isEqualTo(frameProcessorOutputSize);
} }
@Test @Test
public void configureOutputDimensions_withThreeFrameProcessors_propagatesOutputDimensions() { public void getOutputSize_withThreeFrameProcessors_returnsLastOutputSize()
throws TransformationException {
Size inputSize = new Size(200, 100); Size inputSize = new Size(200, 100);
Size outputSize1 = new Size(300, 250); Size outputSize1 = new Size(300, 250);
Size outputSize2 = new Size(400, 244); Size outputSize2 = new Size(400, 244);
Size outputSize3 = new Size(150, 160); Size outputSize3 = new Size(150, 160);
GlFrameProcessor frameProcessor1 = new FakeFrameProcessor(outputSize1); FrameProcessorChain frameProcessorChain =
GlFrameProcessor frameProcessor2 = new FakeFrameProcessor(outputSize2); createFrameProcessorChainWithFakeFrameProcessors(
GlFrameProcessor frameProcessor3 = new FakeFrameProcessor(outputSize3); inputSize,
/* frameProcessorOutputSizes= */ ImmutableList.of(
outputSize1, outputSize2, outputSize3));
List<Size> sizes = Size frameProcessorChainOutputSize = frameProcessorChain.getOutputSize();
FrameProcessorChain.configureSizes(
inputSize.getWidth(),
inputSize.getHeight(),
ImmutableList.of(frameProcessor1, frameProcessor2, frameProcessor3));
assertThat(sizes).containsExactly(inputSize, outputSize1, outputSize2, outputSize3).inOrder(); assertThat(frameProcessorChainOutputSize).isEqualTo(outputSize3);
}
private static FrameProcessorChain createFrameProcessorChainWithFakeFrameProcessors(
Size inputSize, List<Size> frameProcessorOutputSizes) throws TransformationException {
ImmutableList.Builder<GlFrameProcessor> frameProcessors = new ImmutableList.Builder<>();
for (Size element : frameProcessorOutputSizes) {
frameProcessors.add(new FakeFrameProcessor(element));
}
return new FrameProcessorChain(
getApplicationContext(),
/* pixelWidthHeightRatio= */ 1,
inputSize.getWidth(),
inputSize.getHeight(),
frameProcessors.build(),
/* enableExperimentalHdrEditing= */ false);
} }
private static class FakeFrameProcessor implements GlFrameProcessor { private static class FakeFrameProcessor implements GlFrameProcessor {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment