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
This commit is contained in:
parent
20daaa20ef
commit
37559deacf
@ -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 {
|
|||||||
|
|
||||||
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.
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.transformer;
|
package androidx.media3.transformer;
|
||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkArgument;
|
|
||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
import static androidx.media3.common.util.Assertions.checkState;
|
import static androidx.media3.common.util.Assertions.checkState;
|
||||||
import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
||||||
@ -29,6 +28,7 @@ import android.opengl.EGLDisplay;
|
|||||||
import android.opengl.EGLExt;
|
import android.opengl.EGLExt;
|
||||||
import android.opengl.EGLSurface;
|
import android.opengl.EGLSurface;
|
||||||
import android.opengl.GLES20;
|
import android.opengl.GLES20;
|
||||||
|
import android.util.Pair;
|
||||||
import android.util.Size;
|
import android.util.Size;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.SurfaceView;
|
import android.view.SurfaceView;
|
||||||
@ -36,8 +36,8 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.util.GlUtil;
|
import androidx.media3.common.util.GlUtil;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
@ -56,8 +56,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
* processed on a background thread as it becomes available. All input frames should be {@link
|
* processed on a background thread as it becomes available. All input frames should be {@link
|
||||||
* #registerInputFrame() registered} before they are rendered to the input surface. {@link
|
* #registerInputFrame() registered} before they are rendered to the input surface. {@link
|
||||||
* #hasPendingFrames()} can be used to check whether there are frames that have not been fully
|
* #hasPendingFrames()} can be used to check whether there are frames that have not been fully
|
||||||
* processed yet. The {@code FrameProcessorChain} writes output to the surface passed to {@link
|
* processed yet. Output is written to its {@link #configure(Surface, int, int, SurfaceView) output
|
||||||
* #configure(Surface, int, int, SurfaceView)}.
|
* surface}.
|
||||||
*/
|
*/
|
||||||
/* package */ final class FrameProcessorChain {
|
/* package */ final class FrameProcessorChain {
|
||||||
|
|
||||||
@ -65,32 +65,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
GlUtil.glAssertionsEnabled = true;
|
GlUtil.glAssertionsEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures the output {@link Size sizes} of a list of {@link GlFrameProcessor
|
|
||||||
* GlFrameProcessors}.
|
|
||||||
*
|
|
||||||
* @param inputWidth The width of frames passed to the first {@link GlFrameProcessor}.
|
|
||||||
* @param inputHeight The height of frames passed to the first {@link GlFrameProcessor}.
|
|
||||||
* @param frameProcessors The {@link GlFrameProcessor GlFrameProcessors}.
|
|
||||||
* @return A mutable {@link List} containing the input {@link Size} as well as the output {@link
|
|
||||||
* Size} of each {@link GlFrameProcessor}.
|
|
||||||
*/
|
|
||||||
// TODO(b/218488308): Return an immutable list once VideoTranscodingSamplePipeline no longer needs
|
|
||||||
// to modify this list for encoder fallback.
|
|
||||||
public static List<Size> configureSizes(
|
|
||||||
int inputWidth, int inputHeight, List<GlFrameProcessor> frameProcessors) {
|
|
||||||
|
|
||||||
List<Size> sizes = new ArrayList<>(frameProcessors.size() + 1);
|
|
||||||
sizes.add(new Size(inputWidth, inputHeight));
|
|
||||||
for (int i = 0; i < frameProcessors.size(); i++) {
|
|
||||||
sizes.add(
|
|
||||||
frameProcessors
|
|
||||||
.get(i)
|
|
||||||
.configureOutputSize(getLast(sizes).getWidth(), getLast(sizes).getHeight()));
|
|
||||||
}
|
|
||||||
return sizes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String THREAD_NAME = "Transformer:FrameProcessorChain";
|
private static final String THREAD_NAME = "Transformer:FrameProcessorChain";
|
||||||
|
|
||||||
private final boolean enableExperimentalHdrEditing;
|
private final boolean enableExperimentalHdrEditing;
|
||||||
@ -129,12 +103,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
* <p>The {@link ExternalCopyFrameProcessor} writes to the first framebuffer.
|
* <p>The {@link ExternalCopyFrameProcessor} writes to the first framebuffer.
|
||||||
*/
|
*/
|
||||||
private final int[] framebuffers;
|
private final int[] framebuffers;
|
||||||
/**
|
/** The input {@link Size} of each of the {@code frameProcessors}. */
|
||||||
* The input {@link Size}, i.e., the output {@link Size} of the {@link
|
private final ImmutableList<Size> inputSizes;
|
||||||
* ExternalCopyFrameProcessor}), as well as the output {@link Size} of each of the {@code
|
|
||||||
* frameProcessors}.
|
|
||||||
*/
|
|
||||||
private final List<Size> sizes;
|
|
||||||
|
|
||||||
private int outputWidth;
|
private int outputWidth;
|
||||||
private int outputHeight;
|
private int outputHeight;
|
||||||
@ -157,23 +127,20 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
*
|
*
|
||||||
* @param context A {@link Context}.
|
* @param context A {@link Context}.
|
||||||
* @param pixelWidthHeightRatio The ratio of width over height, for each pixel.
|
* @param pixelWidthHeightRatio The ratio of width over height, for each pixel.
|
||||||
|
* @param inputWidth The input frame width, in pixels.
|
||||||
|
* @param inputHeight The input frame height, in pixels.
|
||||||
* @param frameProcessors The {@link GlFrameProcessor GlFrameProcessors} to apply to each frame.
|
* @param frameProcessors The {@link GlFrameProcessor GlFrameProcessors} to apply to each frame.
|
||||||
* Their output sizes must be {@link GlFrameProcessor#configureOutputSize(int, int)}
|
|
||||||
* configured}.
|
|
||||||
* @param sizes The input {@link Size} as well as the output {@link Size} of each {@link
|
|
||||||
* GlFrameProcessor}.
|
|
||||||
* @param enableExperimentalHdrEditing Whether to attempt to process the input as an HDR signal.
|
* @param enableExperimentalHdrEditing Whether to attempt to process the input as an HDR signal.
|
||||||
* @throws TransformationException If the {@code pixelWidthHeightRatio} isn't 1.
|
* @throws TransformationException If the {@code pixelWidthHeightRatio} isn't 1.
|
||||||
*/
|
*/
|
||||||
public FrameProcessorChain(
|
public FrameProcessorChain(
|
||||||
Context context,
|
Context context,
|
||||||
float pixelWidthHeightRatio,
|
float pixelWidthHeightRatio,
|
||||||
|
int inputWidth,
|
||||||
|
int inputHeight,
|
||||||
List<GlFrameProcessor> frameProcessors,
|
List<GlFrameProcessor> frameProcessors,
|
||||||
List<Size> sizes,
|
|
||||||
boolean enableExperimentalHdrEditing)
|
boolean enableExperimentalHdrEditing)
|
||||||
throws TransformationException {
|
throws TransformationException {
|
||||||
checkArgument(frameProcessors.size() + 1 == sizes.size());
|
|
||||||
|
|
||||||
if (pixelWidthHeightRatio != 1.0f) {
|
if (pixelWidthHeightRatio != 1.0f) {
|
||||||
// TODO(b/211782176): Consider implementing support for non-square pixels.
|
// TODO(b/211782176): Consider implementing support for non-square pixels.
|
||||||
throw TransformationException.createForFrameProcessorChain(
|
throw TransformationException.createForFrameProcessorChain(
|
||||||
@ -186,7 +153,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
|
|
||||||
this.enableExperimentalHdrEditing = enableExperimentalHdrEditing;
|
this.enableExperimentalHdrEditing = enableExperimentalHdrEditing;
|
||||||
this.frameProcessors = frameProcessors;
|
this.frameProcessors = frameProcessors;
|
||||||
this.sizes = sizes;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
eglDisplay = GlUtil.createEglDisplay();
|
eglDisplay = GlUtil.createEglDisplay();
|
||||||
@ -205,12 +171,20 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
externalCopyFrameProcessor =
|
externalCopyFrameProcessor =
|
||||||
new ExternalCopyFrameProcessor(context, enableExperimentalHdrEditing);
|
new ExternalCopyFrameProcessor(context, enableExperimentalHdrEditing);
|
||||||
framebuffers = new int[frameProcessors.size()];
|
framebuffers = new int[frameProcessors.size()];
|
||||||
outputWidth = getLast(sizes).getWidth();
|
Pair<ImmutableList<Size>, Size> sizes =
|
||||||
outputHeight = getLast(sizes).getHeight();
|
configureFrameProcessorSizes(inputWidth, inputHeight, frameProcessors);
|
||||||
|
inputSizes = sizes.first;
|
||||||
|
outputWidth = sizes.second.getWidth();
|
||||||
|
outputHeight = sizes.second.getHeight();
|
||||||
debugPreviewWidth = C.LENGTH_UNSET;
|
debugPreviewWidth = C.LENGTH_UNSET;
|
||||||
debugPreviewHeight = C.LENGTH_UNSET;
|
debugPreviewHeight = C.LENGTH_UNSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the output {@link Size}. */
|
||||||
|
public Size getOutputSize() {
|
||||||
|
return new Size(outputWidth, outputHeight);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the {@code FrameProcessorChain} to process frames to the specified output targets.
|
* Configures the {@code FrameProcessorChain} to process frames to the specified output targets.
|
||||||
*
|
*
|
||||||
@ -399,12 +373,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
GlUtil.focusEglSurface(eglDisplay, eglContext, eglSurface, outputWidth, outputHeight);
|
GlUtil.focusEglSurface(eglDisplay, eglContext, eglSurface, outputWidth, outputHeight);
|
||||||
|
|
||||||
inputExternalTexId = GlUtil.createExternalTexture();
|
inputExternalTexId = GlUtil.createExternalTexture();
|
||||||
externalCopyFrameProcessor.configureOutputSize(
|
Size inputSize = inputSizes.get(0);
|
||||||
/* inputWidth= */ sizes.get(0).getWidth(), /* inputHeight= */ sizes.get(0).getHeight());
|
externalCopyFrameProcessor.configureOutputSize(inputSize.getWidth(), inputSize.getHeight());
|
||||||
externalCopyFrameProcessor.initialize(inputExternalTexId);
|
externalCopyFrameProcessor.initialize(inputExternalTexId);
|
||||||
|
|
||||||
for (int i = 0; i < frameProcessors.size(); i++) {
|
for (int i = 0; i < frameProcessors.size(); i++) {
|
||||||
int inputTexId = GlUtil.createTexture(sizes.get(i).getWidth(), sizes.get(i).getHeight());
|
inputSize = inputSizes.get(i);
|
||||||
|
int inputTexId = GlUtil.createTexture(inputSize.getWidth(), inputSize.getHeight());
|
||||||
framebuffers[i] = GlUtil.createFboForTexture(inputTexId);
|
framebuffers[i] = GlUtil.createFboForTexture(inputTexId);
|
||||||
frameProcessors.get(i).initialize(inputTexId);
|
frameProcessors.get(i).initialize(inputTexId);
|
||||||
}
|
}
|
||||||
@ -423,16 +398,18 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
private void processFrame() {
|
private void processFrame() {
|
||||||
checkState(Thread.currentThread().equals(glThread));
|
checkState(Thread.currentThread().equals(glThread));
|
||||||
|
|
||||||
|
Size outputSize = inputSizes.get(0);
|
||||||
if (frameProcessors.isEmpty()) {
|
if (frameProcessors.isEmpty()) {
|
||||||
GlUtil.focusEglSurface(eglDisplay, eglContext, eglSurface, outputWidth, outputHeight);
|
GlUtil.focusEglSurface(
|
||||||
|
eglDisplay, eglContext, eglSurface, outputSize.getWidth(), outputSize.getHeight());
|
||||||
} else {
|
} else {
|
||||||
GlUtil.focusFramebuffer(
|
GlUtil.focusFramebuffer(
|
||||||
eglDisplay,
|
eglDisplay,
|
||||||
eglContext,
|
eglContext,
|
||||||
eglSurface,
|
eglSurface,
|
||||||
framebuffers[0],
|
framebuffers[0],
|
||||||
sizes.get(0).getWidth(),
|
outputSize.getWidth(),
|
||||||
sizes.get(0).getHeight());
|
outputSize.getHeight());
|
||||||
}
|
}
|
||||||
inputSurfaceTexture.updateTexImage();
|
inputSurfaceTexture.updateTexImage();
|
||||||
inputSurfaceTexture.getTransformMatrix(textureTransformMatrix);
|
inputSurfaceTexture.getTransformMatrix(textureTransformMatrix);
|
||||||
@ -441,13 +418,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
externalCopyFrameProcessor.updateProgramAndDraw(presentationTimeNs);
|
externalCopyFrameProcessor.updateProgramAndDraw(presentationTimeNs);
|
||||||
|
|
||||||
for (int i = 0; i < frameProcessors.size() - 1; i++) {
|
for (int i = 0; i < frameProcessors.size() - 1; i++) {
|
||||||
|
outputSize = inputSizes.get(i + 1);
|
||||||
GlUtil.focusFramebuffer(
|
GlUtil.focusFramebuffer(
|
||||||
eglDisplay,
|
eglDisplay,
|
||||||
eglContext,
|
eglContext,
|
||||||
eglSurface,
|
eglSurface,
|
||||||
framebuffers[i + 1],
|
framebuffers[i + 1],
|
||||||
sizes.get(i + 1).getWidth(),
|
outputSize.getWidth(),
|
||||||
sizes.get(i + 1).getHeight());
|
outputSize.getHeight());
|
||||||
frameProcessors.get(i).updateProgramAndDraw(presentationTimeNs);
|
frameProcessors.get(i).updateProgramAndDraw(presentationTimeNs);
|
||||||
}
|
}
|
||||||
if (!frameProcessors.isEmpty()) {
|
if (!frameProcessors.isEmpty()) {
|
||||||
@ -470,4 +448,30 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
|
|
||||||
checkState(pendingFrameCount.getAndDecrement() > 0);
|
checkState(pendingFrameCount.getAndDecrement() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the input and output {@link Size sizes} of a list of {@link GlFrameProcessor
|
||||||
|
* GlFrameProcessors}.
|
||||||
|
*
|
||||||
|
* @param inputWidth The width of frames passed to the first {@link GlFrameProcessor}, in pixels.
|
||||||
|
* @param inputHeight The height of frames passed to the first {@link GlFrameProcessor}, in
|
||||||
|
* pixels.
|
||||||
|
* @param frameProcessors The {@link GlFrameProcessor GlFrameProcessors}.
|
||||||
|
* @return The input {@link Size} of each {@link GlFrameProcessor} and the output {@link Size} of
|
||||||
|
* the final {@link GlFrameProcessor}.
|
||||||
|
*/
|
||||||
|
private static Pair<ImmutableList<Size>, Size> configureFrameProcessorSizes(
|
||||||
|
int inputWidth, int inputHeight, List<GlFrameProcessor> frameProcessors) {
|
||||||
|
Size size = new Size(inputWidth, inputHeight);
|
||||||
|
if (frameProcessors.isEmpty()) {
|
||||||
|
return Pair.create(ImmutableList.of(size), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImmutableList.Builder<Size> inputSizes = new ImmutableList.Builder<>();
|
||||||
|
for (int i = 0; i < frameProcessors.size(); i++) {
|
||||||
|
inputSizes.add(size);
|
||||||
|
size = frameProcessors.get(i).configureOutputSize(size.getWidth(), size.getHeight());
|
||||||
|
}
|
||||||
|
return Pair.create(inputSizes.build(), size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|||||||
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;
|
|||||||
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;
|
|||||||
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;
|
|||||||
*/
|
*/
|
||||||
@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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user