listeners;
private DebugViewProvider debugViewProvider;
private Looper looper;
@@ -119,6 +122,7 @@ public final class Transformer {
debugViewProvider = DebugViewProvider.NONE;
containerMimeType = MimeTypes.VIDEO_MP4;
transformationRequest = new TransformationRequest.Builder().build();
+ frameProcessors = ImmutableList.of();
}
/**
@@ -135,7 +139,8 @@ public final class Transformer {
encoderFactory = Codec.EncoderFactory.DEFAULT;
debugViewProvider = DebugViewProvider.NONE;
containerMimeType = MimeTypes.VIDEO_MP4;
- this.transformationRequest = new TransformationRequest.Builder().build();
+ transformationRequest = new TransformationRequest.Builder().build();
+ frameProcessors = ImmutableList.of();
}
/** Creates a builder with the values of the provided {@link Transformer}. */
@@ -147,6 +152,7 @@ public final class Transformer {
this.removeVideo = transformer.removeVideo;
this.containerMimeType = transformer.containerMimeType;
this.transformationRequest = transformer.transformationRequest;
+ this.frameProcessors = transformer.frameProcessors;
this.listeners = transformer.listeners;
this.looper = transformer.looper;
this.encoderFactory = transformer.encoderFactory;
@@ -178,6 +184,24 @@ public final class Transformer {
return this;
}
+ /**
+ * Sets the {@linkplain GlFrameProcessor frame processors} to apply to each frame.
+ *
+ * The {@linkplain GlFrameProcessor frame processors} are applied before any {@linkplain
+ * TransformationRequest.Builder#setScale(float, float) scale}, {@linkplain
+ * TransformationRequest.Builder#setRotationDegrees(float) rotation}, or {@linkplain
+ * TransformationRequest.Builder#setResolution(int) resolution} changes specified in the {@link
+ * #setTransformationRequest(TransformationRequest) TransformationRequest} but after {@linkplain
+ * TransformationRequest.Builder#setFlattenForSlowMotion(boolean) slow-motion flattening}.
+ *
+ * @param frameProcessors The {@linkplain GlFrameProcessor frame processors}.
+ * @return This builder.
+ */
+ public Builder setFrameProcessors(List frameProcessors) {
+ this.frameProcessors = ImmutableList.copyOf(frameProcessors);
+ return this;
+ }
+
/**
* Sets the {@link MediaSource.Factory} to be used to retrieve the inputs to transform.
*
@@ -406,6 +430,7 @@ public final class Transformer {
removeVideo,
containerMimeType,
transformationRequest,
+ frameProcessors,
listeners,
looper,
clock,
@@ -527,6 +552,7 @@ public final class Transformer {
private final boolean removeVideo;
private final String containerMimeType;
private final TransformationRequest transformationRequest;
+ private final ImmutableList frameProcessors;
private final Looper looper;
private final Clock clock;
private final Codec.EncoderFactory encoderFactory;
@@ -547,6 +573,7 @@ public final class Transformer {
boolean removeVideo,
String containerMimeType,
TransformationRequest transformationRequest,
+ ImmutableList frameProcessors,
ListenerSet listeners,
Looper looper,
Clock clock,
@@ -561,6 +588,7 @@ public final class Transformer {
this.removeVideo = removeVideo;
this.containerMimeType = containerMimeType;
this.transformationRequest = transformationRequest;
+ this.frameProcessors = frameProcessors;
this.listeners = listeners;
this.looper = looper;
this.clock = clock;
@@ -701,6 +729,7 @@ public final class Transformer {
removeAudio,
removeVideo,
transformationRequest,
+ frameProcessors,
encoderFactory,
decoderFactory,
new FallbackListener(mediaItem, listeners, transformationRequest),
@@ -812,6 +841,7 @@ public final class Transformer {
private final boolean removeAudio;
private final boolean removeVideo;
private final TransformationRequest transformationRequest;
+ private final ImmutableList frameProcessors;
private final Codec.EncoderFactory encoderFactory;
private final Codec.DecoderFactory decoderFactory;
private final FallbackListener fallbackListener;
@@ -823,6 +853,7 @@ public final class Transformer {
boolean removeAudio,
boolean removeVideo,
TransformationRequest transformationRequest,
+ ImmutableList frameProcessors,
Codec.EncoderFactory encoderFactory,
Codec.DecoderFactory decoderFactory,
FallbackListener fallbackListener,
@@ -832,6 +863,7 @@ public final class Transformer {
this.removeAudio = removeAudio;
this.removeVideo = removeVideo;
this.transformationRequest = transformationRequest;
+ this.frameProcessors = frameProcessors;
this.encoderFactory = encoderFactory;
this.decoderFactory = decoderFactory;
this.fallbackListener = fallbackListener;
@@ -867,6 +899,7 @@ public final class Transformer {
muxerWrapper,
mediaClock,
transformationRequest,
+ frameProcessors,
encoderFactory,
decoderFactory,
fallbackListener,
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerVideoRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerVideoRenderer.java
index 4e79f35148..c0c8adcbfa 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerVideoRenderer.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerVideoRenderer.java
@@ -25,6 +25,7 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
+import com.google.common.collect.ImmutableList;
import java.nio.ByteBuffer;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@@ -34,6 +35,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private static final String TAG = "TVideoRenderer";
private final Context context;
+ private final ImmutableList frameProcessors;
private final Codec.EncoderFactory encoderFactory;
private final Codec.DecoderFactory decoderFactory;
private final Transformer.DebugViewProvider debugViewProvider;
@@ -46,12 +48,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
MuxerWrapper muxerWrapper,
TransformerMediaClock mediaClock,
TransformationRequest transformationRequest,
+ ImmutableList frameProcessors,
Codec.EncoderFactory encoderFactory,
Codec.DecoderFactory decoderFactory,
FallbackListener fallbackListener,
Transformer.DebugViewProvider debugViewProvider) {
super(C.TRACK_TYPE_VIDEO, muxerWrapper, mediaClock, transformationRequest, fallbackListener);
this.context = context;
+ this.frameProcessors = frameProcessors;
this.encoderFactory = encoderFactory;
this.decoderFactory = decoderFactory;
this.debugViewProvider = debugViewProvider;
@@ -86,6 +90,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
context,
inputFormat,
transformationRequest,
+ frameProcessors,
decoderFactory,
encoderFactory,
muxerWrapper.getSupportedSampleMimeTypes(getTrackType()),
@@ -126,6 +131,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
&& transformationRequest.outputHeight != inputFormat.height) {
return false;
}
+ if (!frameProcessors.isEmpty()) {
+ return false;
+ }
return true;
}
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoTranscodingSamplePipeline.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoTranscodingSamplePipeline.java
index e314a0a1c1..0d61832395 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoTranscodingSamplePipeline.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoTranscodingSamplePipeline.java
@@ -52,6 +52,7 @@ import org.checkerframework.dataflow.qual.Pure;
Context context,
Format inputFormat,
TransformationRequest transformationRequest,
+ ImmutableList frameProcessors,
Codec.DecoderFactory decoderFactory,
Codec.EncoderFactory encoderFactory,
List allowedOutputMimeTypes,
@@ -69,7 +70,6 @@ import org.checkerframework.dataflow.qual.Pure;
int decodedHeight =
(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.
ScaleToFitFrameProcessor scaleToFitFrameProcessor =
new ScaleToFitFrameProcessor.Builder(context)
@@ -86,7 +86,11 @@ import org.checkerframework.dataflow.qual.Pure;
inputFormat.pixelWidthHeightRatio,
/* inputWidth= */ decodedWidth,
/* inputHeight= */ decodedHeight,
- ImmutableList.of(scaleToFitFrameProcessor, presentationFrameProcessor),
+ new ImmutableList.Builder()
+ .addAll(frameProcessors)
+ .add(scaleToFitFrameProcessor)
+ .add(presentationFrameProcessor)
+ .build(),
transformationRequest.enableHdrEditing);
Size requestedEncoderSize = frameProcessorChain.getOutputSize();
outputRotationDegrees = presentationFrameProcessor.getOutputRotationDegrees();