diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java
index 25ec93ef22..c2a605661d 100644
--- a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java
+++ b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java
@@ -40,9 +40,7 @@ import androidx.media3.common.util.HandlerWrapper;
import androidx.media3.common.util.ListenerSet;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
-import androidx.media3.effect.GlEffect;
import androidx.media3.effect.GlEffectsFrameProcessor;
-import androidx.media3.effect.GlMatrixTransformation;
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
import androidx.media3.exoplayer.source.MediaSource;
import androidx.media3.extractor.DefaultExtractorsFactory;
@@ -153,34 +151,24 @@ public final class Transformer {
}
/**
- * Sets the {@link AudioProcessor} instances to apply to audio buffers.
- *
- *
The {@link AudioProcessor} instances are applied in the order of the list, and buffers
- * will only be modified by that {@link AudioProcessor} if it {@link AudioProcessor#isActive()}
- * based on the current configuration.
+ * @deprecated Set the {@linkplain AudioProcessor audio processors} in an {@link
+ * EditedMediaItem}, and pass it to {@link #startTransformation(EditedMediaItem, String)} or
+ * {@link #startTransformation(EditedMediaItem, ParcelFileDescriptor)} instead.
*/
@CanIgnoreReturnValue
+ @Deprecated
public Builder setAudioProcessors(List audioProcessors) {
this.audioProcessors = ImmutableList.copyOf(audioProcessors);
return this;
}
/**
- * Sets the {@link Effect} instances to apply to each video frame.
- *
- * The {@link Effect} instances are applied before any {@linkplain
- * TransformationRequest.Builder#setResolution(int) resolution} change specified in the {@link
- * #setTransformationRequest(TransformationRequest) TransformationRequest} but after {@linkplain
- * TransformationRequest.Builder#setFlattenForSlowMotion(boolean) slow-motion flattening}.
- *
- *
The default {@link FrameProcessor} only supports {@link GlEffect} instances. To use other
- * effects, call {@link #setFrameProcessorFactory(FrameProcessor.Factory)} with a custom {@link
- * FrameProcessor.Factory}.
- *
- * @param effects The {@link Effect} instances to apply to each video frame.
- * @return This builder.
+ * @deprecated Set the {@linkplain Effect video effects} in an {@link EditedMediaItem}, and pass
+ * it to {@link #startTransformation(EditedMediaItem, String)} or {@link
+ * #startTransformation(EditedMediaItem, ParcelFileDescriptor)} instead.
*/
@CanIgnoreReturnValue
+ @Deprecated
public Builder setVideoEffects(List effects) {
this.videoEffects = ImmutableList.copyOf(effects);
return this;
@@ -301,20 +289,12 @@ public final class Transformer {
}
/**
- * Sets the {@link FrameProcessor.Factory} for the {@link FrameProcessor} to use when applying
- * {@linkplain Effect effects} to the video frames.
- *
- * This factory will be used to create the {@link FrameProcessor} used for applying the
- * {@link Effect} instances passed to {@link #setVideoEffects(List)} and any additional {@link
- * GlMatrixTransformation} instances derived from the {@link TransformationRequest} set using
- * {@link #setTransformationRequest(TransformationRequest)}.
- *
- *
The default is {@link GlEffectsFrameProcessor.Factory}.
- *
- * @param frameProcessorFactory The {@link FrameProcessor.Factory} to use.
- * @return This builder.
+ * @deprecated Set the {@link FrameProcessor.Factory} in an {@link EditedMediaItem}, and pass it
+ * to {@link #startTransformation(EditedMediaItem, String)} or {@link
+ * #startTransformation(EditedMediaItem, ParcelFileDescriptor)} instead.
*/
@CanIgnoreReturnValue
+ @Deprecated
public Builder setFrameProcessorFactory(FrameProcessor.Factory frameProcessorFactory) {
this.frameProcessorFactory = frameProcessorFactory;
return this;
@@ -412,11 +392,13 @@ public final class Transformer {
*
Duration will match duration of the input media.
* Sample mime type will match {@link TransformationRequest#audioMimeType}, or {@link
* MimeTypes#AUDIO_AAC} if {@code null}.
- * Sample rate will be {@code 44100} hz. This can be modified by passing a {@link
- * SonicAudioProcessor} to {@link #setAudioProcessors(List)}, using {@link
- * SonicAudioProcessor#setOutputSampleRateHz(int)}.
+ * Sample rate will be {@code 44100} hz. This can be modified by creating a {@link
+ * SonicAudioProcessor}, setting its {@linkplain
+ * SonicAudioProcessor#setOutputSampleRateHz(int) sample rate}, and passing it to the
+ * {@link EditedMediaItem} used to start the transformation.
* Channel count will be {@code 2}. This can be modified by implementing a custom {@link
- * AudioProcessor} and passing it to {@link #setAudioProcessors(List)}.
+ * AudioProcessor} and passing it to the {@link EditedMediaItem} used to start the
+ * transformation.
*
*
* @param generateSilentAudio Whether to generate silent audio for the output file if there is
@@ -690,15 +672,16 @@ public final class Transformer {
* ignored. For adaptive bitrate, if no custom {@link AssetLoader.Factory} is specified, the
* highest bitrate video and audio streams are selected.
*
- * @param mediaItem The {@link MediaItem} to transform.
+ * @param editedMediaItem The {@link MediaItem} to transform, with the transformations to apply to
+ * it.
* @param path The path to the output file.
* @throws IllegalArgumentException If the path is invalid.
* @throws IllegalArgumentException If the {@link MediaItem} is not supported.
* @throws IllegalStateException If this method is called from the wrong thread.
* @throws IllegalStateException If a transformation is already in progress.
*/
- public void startTransformation(MediaItem mediaItem, String path) {
- startTransformationInternal(mediaItem, path, /* parcelFileDescriptor= */ null);
+ public void startTransformation(EditedMediaItem editedMediaItem, String path) {
+ startTransformationInternal(editedMediaItem, path, /* parcelFileDescriptor= */ null);
}
/**
@@ -715,7 +698,8 @@ public final class Transformer {
* ignored. For adaptive bitrate, if no custom {@link AssetLoader.Factory} is specified, the
* highest bitrate video and audio streams are selected.
*
- * @param mediaItem The {@link MediaItem} to transform.
+ * @param editedMediaItem The {@link MediaItem} to transform, with the transformations to apply to
+ * it.
* @param parcelFileDescriptor A readable and writable {@link ParcelFileDescriptor} of the output.
* The file referenced by this ParcelFileDescriptor should not be used before the
* transformation is completed. It is the responsibility of the caller to close the
@@ -726,14 +710,39 @@ public final class Transformer {
* @throws IllegalStateException If a transformation is already in progress.
*/
@RequiresApi(26)
+ public void startTransformation(
+ EditedMediaItem editedMediaItem, ParcelFileDescriptor parcelFileDescriptor) {
+ startTransformationInternal(editedMediaItem, /* path= */ null, parcelFileDescriptor);
+ }
+
+ /**
+ * @deprecated Use {@link #startTransformation(EditedMediaItem, String)} instead.
+ */
+ @Deprecated
+ public void startTransformation(MediaItem mediaItem, String path) {
+ EditedMediaItem editedMediaItem =
+ new EditedMediaItem(
+ mediaItem, new Effects(audioProcessors, videoEffects, frameProcessorFactory));
+ startTransformationInternal(editedMediaItem, path, /* parcelFileDescriptor= */ null);
+ }
+
+ /**
+ * @deprecated Use {@link #startTransformation(EditedMediaItem, ParcelFileDescriptor)} instead.
+ */
+ @Deprecated
+ @RequiresApi(26)
public void startTransformation(MediaItem mediaItem, ParcelFileDescriptor parcelFileDescriptor) {
- startTransformationInternal(mediaItem, /* path= */ null, parcelFileDescriptor);
+ EditedMediaItem editedMediaItem =
+ new EditedMediaItem(
+ mediaItem, new Effects(audioProcessors, videoEffects, frameProcessorFactory));
+ startTransformationInternal(editedMediaItem, /* path= */ null, parcelFileDescriptor);
}
private void startTransformationInternal(
- MediaItem mediaItem,
+ EditedMediaItem editedMediaItem,
@Nullable String path,
@Nullable ParcelFileDescriptor parcelFileDescriptor) {
+ MediaItem mediaItem = editedMediaItem.mediaItem;
if (!mediaItem.clippingConfiguration.equals(MediaItem.ClippingConfiguration.UNSET)
&& transformationRequest.flattenForSlowMotion) {
// TODO(b/233986762): Support clipping with SEF flattening.
@@ -752,17 +761,14 @@ public final class Transformer {
transformerInternal =
new TransformerInternal(
context,
- mediaItem,
+ editedMediaItem,
path,
parcelFileDescriptor,
transformationRequest,
- audioProcessors,
- videoEffects,
removeAudio,
removeVideo,
generateSilentAudio,
assetLoaderFactory,
- frameProcessorFactory,
encoderFactory,
muxerFactory,
transformerInternalListener,
diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java
index 215317d711..029682adaa 100644
--- a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java
+++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java
@@ -35,11 +35,9 @@ import androidx.media3.common.C;
import androidx.media3.common.DebugViewProvider;
import androidx.media3.common.Effect;
import androidx.media3.common.Format;
-import androidx.media3.common.FrameProcessor;
import androidx.media3.common.MediaItem;
import androidx.media3.common.Metadata;
import androidx.media3.common.MimeTypes;
-import androidx.media3.common.audio.AudioProcessor;
import androidx.media3.common.util.Clock;
import androidx.media3.common.util.ConditionVariable;
import androidx.media3.common.util.HandlerWrapper;
@@ -47,7 +45,6 @@ import androidx.media3.common.util.Size;
import androidx.media3.effect.Presentation;
import androidx.media3.effect.ScaleToFitTransformation;
import androidx.media3.extractor.metadata.mp4.SlowMotionData;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
@@ -94,9 +91,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final Context context;
private final TransformationRequest transformationRequest;
- private final ImmutableList audioProcessors;
- private final ImmutableList videoEffects;
- private final FrameProcessor.Factory frameProcessorFactory;
private final CapturingEncoderFactory encoderFactory;
private final Listener listener;
private final HandlerWrapper applicationHandler;
@@ -105,6 +99,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final HandlerThread internalHandlerThread;
private final HandlerWrapper internalHandler;
private final AssetLoader assetLoader;
+ private final Effects effects;
private final List samplePipelines;
private final MuxerWrapper muxerWrapper;
private final ConditionVariable transformerConditionVariable;
@@ -119,17 +114,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public TransformerInternal(
Context context,
- MediaItem mediaItem,
+ EditedMediaItem editedMediaItem,
@Nullable String outputPath,
@Nullable ParcelFileDescriptor outputParcelFileDescriptor,
TransformationRequest transformationRequest,
- ImmutableList audioProcessors,
- ImmutableList videoEffects,
boolean removeAudio,
boolean removeVideo,
boolean generateSilentAudio,
AssetLoader.Factory assetLoaderFactory,
- FrameProcessor.Factory frameProcessorFactory,
Codec.EncoderFactory encoderFactory,
Muxer.Factory muxerFactory,
Listener listener,
@@ -139,10 +131,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
Clock clock) {
this.context = context;
this.transformationRequest = transformationRequest;
- this.audioProcessors = audioProcessors;
- this.videoEffects = videoEffects;
this.generateSilentAudio = generateSilentAudio;
- this.frameProcessorFactory = frameProcessorFactory;
this.encoderFactory = new CapturingEncoderFactory(encoderFactory);
this.listener = listener;
this.applicationHandler = applicationHandler;
@@ -151,6 +140,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
internalHandlerThread = new HandlerThread("Transformer:Internal");
internalHandlerThread.start();
Looper internalLooper = internalHandlerThread.getLooper();
+ MediaItem mediaItem = editedMediaItem.mediaItem;
ComponentListener componentListener = new ComponentListener(mediaItem, fallbackListener);
assetLoader =
assetLoaderFactory
@@ -158,6 +148,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
.setRemoveVideo(removeVideo)
.setFlattenVideoForSlowMotion(transformationRequest.flattenForSlowMotion)
.createAssetLoader(mediaItem, internalLooper, componentListener);
+ effects = editedMediaItem.effects;
samplePipelines = new ArrayList<>();
muxerWrapper =
new MuxerWrapper(outputPath, outputParcelFileDescriptor, muxerFactory, componentListener);
@@ -490,7 +481,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
streamStartPositionUs,
streamOffsetUs,
transformationRequest,
- audioProcessors,
+ effects.audioProcessors,
generateSilentAudio ? durationUs : C.TIME_UNSET,
encoderFactory,
muxerWrapper,
@@ -502,8 +493,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
streamStartPositionUs,
streamOffsetUs,
transformationRequest,
- videoEffects,
- frameProcessorFactory,
+ effects.videoEffects,
+ effects.frameProcessorFactory,
encoderFactory,
muxerWrapper,
/* errorConsumer= */ this::onTransformationError,
@@ -534,7 +525,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
if (transformationRequest.flattenForSlowMotion && isSlowMotion(inputFormat)) {
return true;
}
- if (!audioProcessors.isEmpty()) {
+ if (!effects.audioProcessors.isEmpty()) {
return true;
}
if (generateSilentAudio) {
@@ -582,8 +573,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
// TODO(b/265927935): consider generalizing this logic.
- for (int i = 0; i < videoEffects.size(); i++) {
- Effect videoEffect = videoEffects.get(i);
+ for (int i = 0; i < effects.videoEffects.size(); i++) {
+ Effect videoEffect = effects.videoEffects.get(i);
if (videoEffect instanceof Presentation) {
Presentation presentation = (Presentation) videoEffect;
// The decoder rotates encoded frames for display by inputFormat.rotationDegrees.