Make startTransformation methods take an EditedMediaItem

Usages of the deprecated methods in Transformer.Builder will be removed
in a follow-up CL.

PiperOrigin-RevId: 502889423
This commit is contained in:
kimvde 2023-01-18 16:53:05 +00:00 committed by christosts
parent d4db33a535
commit aa72b45cdf
2 changed files with 62 additions and 65 deletions

View File

@ -40,9 +40,7 @@ import androidx.media3.common.util.HandlerWrapper;
import androidx.media3.common.util.ListenerSet; import androidx.media3.common.util.ListenerSet;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.effect.GlEffect;
import androidx.media3.effect.GlEffectsFrameProcessor; import androidx.media3.effect.GlEffectsFrameProcessor;
import androidx.media3.effect.GlMatrixTransformation;
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory; import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.MediaSource;
import androidx.media3.extractor.DefaultExtractorsFactory; import androidx.media3.extractor.DefaultExtractorsFactory;
@ -153,34 +151,24 @@ public final class Transformer {
} }
/** /**
* Sets the {@link AudioProcessor} instances to apply to audio buffers. * @deprecated Set the {@linkplain AudioProcessor audio processors} in an {@link
* * EditedMediaItem}, and pass it to {@link #startTransformation(EditedMediaItem, String)} or
* <p>The {@link AudioProcessor} instances are applied in the order of the list, and buffers * {@link #startTransformation(EditedMediaItem, ParcelFileDescriptor)} instead.
* will only be modified by that {@link AudioProcessor} if it {@link AudioProcessor#isActive()}
* based on the current configuration.
*/ */
@CanIgnoreReturnValue @CanIgnoreReturnValue
@Deprecated
public Builder setAudioProcessors(List<AudioProcessor> audioProcessors) { public Builder setAudioProcessors(List<AudioProcessor> audioProcessors) {
this.audioProcessors = ImmutableList.copyOf(audioProcessors); this.audioProcessors = ImmutableList.copyOf(audioProcessors);
return this; return this;
} }
/** /**
* Sets the {@link Effect} instances to apply to each video frame. * @deprecated Set the {@linkplain Effect video effects} in an {@link EditedMediaItem}, and pass
* * it to {@link #startTransformation(EditedMediaItem, String)} or {@link
* <p>The {@link Effect} instances are applied before any {@linkplain * #startTransformation(EditedMediaItem, ParcelFileDescriptor)} instead.
* TransformationRequest.Builder#setResolution(int) resolution} change specified in the {@link
* #setTransformationRequest(TransformationRequest) TransformationRequest} but after {@linkplain
* TransformationRequest.Builder#setFlattenForSlowMotion(boolean) slow-motion flattening}.
*
* <p>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.
*/ */
@CanIgnoreReturnValue @CanIgnoreReturnValue
@Deprecated
public Builder setVideoEffects(List<Effect> effects) { public Builder setVideoEffects(List<Effect> effects) {
this.videoEffects = ImmutableList.copyOf(effects); this.videoEffects = ImmutableList.copyOf(effects);
return this; return this;
@ -301,20 +289,12 @@ public final class Transformer {
} }
/** /**
* Sets the {@link FrameProcessor.Factory} for the {@link FrameProcessor} to use when applying * @deprecated Set the {@link FrameProcessor.Factory} in an {@link EditedMediaItem}, and pass it
* {@linkplain Effect effects} to the video frames. * to {@link #startTransformation(EditedMediaItem, String)} or {@link
* * #startTransformation(EditedMediaItem, ParcelFileDescriptor)} instead.
* <p>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)}.
*
* <p>The default is {@link GlEffectsFrameProcessor.Factory}.
*
* @param frameProcessorFactory The {@link FrameProcessor.Factory} to use.
* @return This builder.
*/ */
@CanIgnoreReturnValue @CanIgnoreReturnValue
@Deprecated
public Builder setFrameProcessorFactory(FrameProcessor.Factory frameProcessorFactory) { public Builder setFrameProcessorFactory(FrameProcessor.Factory frameProcessorFactory) {
this.frameProcessorFactory = frameProcessorFactory; this.frameProcessorFactory = frameProcessorFactory;
return this; return this;
@ -412,11 +392,13 @@ public final class Transformer {
* <li>Duration will match duration of the input media. * <li>Duration will match duration of the input media.
* <li>Sample mime type will match {@link TransformationRequest#audioMimeType}, or {@link * <li>Sample mime type will match {@link TransformationRequest#audioMimeType}, or {@link
* MimeTypes#AUDIO_AAC} if {@code null}. * MimeTypes#AUDIO_AAC} if {@code null}.
* <li>Sample rate will be {@code 44100} hz. This can be modified by passing a {@link * <li>Sample rate will be {@code 44100} hz. This can be modified by creating a {@link
* SonicAudioProcessor} to {@link #setAudioProcessors(List)}, using {@link * SonicAudioProcessor}, setting its {@linkplain
* SonicAudioProcessor#setOutputSampleRateHz(int)}. * SonicAudioProcessor#setOutputSampleRateHz(int) sample rate}, and passing it to the
* {@link EditedMediaItem} used to start the transformation.
* <li>Channel count will be {@code 2}. This can be modified by implementing a custom {@link * <li>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.
* </ul> * </ul>
* *
* @param generateSilentAudio Whether to generate silent audio for the output file if there is * @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 * ignored. For adaptive bitrate, if no custom {@link AssetLoader.Factory} is specified, the
* highest bitrate video and audio streams are selected. * 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. * @param path The path to the output file.
* @throws IllegalArgumentException If the path is invalid. * @throws IllegalArgumentException If the path is invalid.
* @throws IllegalArgumentException If the {@link MediaItem} is not supported. * @throws IllegalArgumentException If the {@link MediaItem} is not supported.
* @throws IllegalStateException If this method is called from the wrong thread. * @throws IllegalStateException If this method is called from the wrong thread.
* @throws IllegalStateException If a transformation is already in progress. * @throws IllegalStateException If a transformation is already in progress.
*/ */
public void startTransformation(MediaItem mediaItem, String path) { public void startTransformation(EditedMediaItem editedMediaItem, String path) {
startTransformationInternal(mediaItem, path, /* parcelFileDescriptor= */ null); 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 * ignored. For adaptive bitrate, if no custom {@link AssetLoader.Factory} is specified, the
* highest bitrate video and audio streams are selected. * 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. * @param parcelFileDescriptor A readable and writable {@link ParcelFileDescriptor} of the output.
* The file referenced by this ParcelFileDescriptor should not be used before the * 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 * 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. * @throws IllegalStateException If a transformation is already in progress.
*/ */
@RequiresApi(26) @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) { 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( private void startTransformationInternal(
MediaItem mediaItem, EditedMediaItem editedMediaItem,
@Nullable String path, @Nullable String path,
@Nullable ParcelFileDescriptor parcelFileDescriptor) { @Nullable ParcelFileDescriptor parcelFileDescriptor) {
MediaItem mediaItem = editedMediaItem.mediaItem;
if (!mediaItem.clippingConfiguration.equals(MediaItem.ClippingConfiguration.UNSET) if (!mediaItem.clippingConfiguration.equals(MediaItem.ClippingConfiguration.UNSET)
&& transformationRequest.flattenForSlowMotion) { && transformationRequest.flattenForSlowMotion) {
// TODO(b/233986762): Support clipping with SEF flattening. // TODO(b/233986762): Support clipping with SEF flattening.
@ -752,17 +761,14 @@ public final class Transformer {
transformerInternal = transformerInternal =
new TransformerInternal( new TransformerInternal(
context, context,
mediaItem, editedMediaItem,
path, path,
parcelFileDescriptor, parcelFileDescriptor,
transformationRequest, transformationRequest,
audioProcessors,
videoEffects,
removeAudio, removeAudio,
removeVideo, removeVideo,
generateSilentAudio, generateSilentAudio,
assetLoaderFactory, assetLoaderFactory,
frameProcessorFactory,
encoderFactory, encoderFactory,
muxerFactory, muxerFactory,
transformerInternalListener, transformerInternalListener,

View File

@ -35,11 +35,9 @@ import androidx.media3.common.C;
import androidx.media3.common.DebugViewProvider; import androidx.media3.common.DebugViewProvider;
import androidx.media3.common.Effect; import androidx.media3.common.Effect;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.FrameProcessor;
import androidx.media3.common.MediaItem; import androidx.media3.common.MediaItem;
import androidx.media3.common.Metadata; import androidx.media3.common.Metadata;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.audio.AudioProcessor;
import androidx.media3.common.util.Clock; import androidx.media3.common.util.Clock;
import androidx.media3.common.util.ConditionVariable; import androidx.media3.common.util.ConditionVariable;
import androidx.media3.common.util.HandlerWrapper; 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.Presentation;
import androidx.media3.effect.ScaleToFitTransformation; import androidx.media3.effect.ScaleToFitTransformation;
import androidx.media3.extractor.metadata.mp4.SlowMotionData; import androidx.media3.extractor.metadata.mp4.SlowMotionData;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -94,9 +91,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final Context context; private final Context context;
private final TransformationRequest transformationRequest; private final TransformationRequest transformationRequest;
private final ImmutableList<AudioProcessor> audioProcessors;
private final ImmutableList<Effect> videoEffects;
private final FrameProcessor.Factory frameProcessorFactory;
private final CapturingEncoderFactory encoderFactory; private final CapturingEncoderFactory encoderFactory;
private final Listener listener; private final Listener listener;
private final HandlerWrapper applicationHandler; private final HandlerWrapper applicationHandler;
@ -105,6 +99,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final HandlerThread internalHandlerThread; private final HandlerThread internalHandlerThread;
private final HandlerWrapper internalHandler; private final HandlerWrapper internalHandler;
private final AssetLoader assetLoader; private final AssetLoader assetLoader;
private final Effects effects;
private final List<SamplePipeline> samplePipelines; private final List<SamplePipeline> samplePipelines;
private final MuxerWrapper muxerWrapper; private final MuxerWrapper muxerWrapper;
private final ConditionVariable transformerConditionVariable; private final ConditionVariable transformerConditionVariable;
@ -119,17 +114,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public TransformerInternal( public TransformerInternal(
Context context, Context context,
MediaItem mediaItem, EditedMediaItem editedMediaItem,
@Nullable String outputPath, @Nullable String outputPath,
@Nullable ParcelFileDescriptor outputParcelFileDescriptor, @Nullable ParcelFileDescriptor outputParcelFileDescriptor,
TransformationRequest transformationRequest, TransformationRequest transformationRequest,
ImmutableList<AudioProcessor> audioProcessors,
ImmutableList<Effect> videoEffects,
boolean removeAudio, boolean removeAudio,
boolean removeVideo, boolean removeVideo,
boolean generateSilentAudio, boolean generateSilentAudio,
AssetLoader.Factory assetLoaderFactory, AssetLoader.Factory assetLoaderFactory,
FrameProcessor.Factory frameProcessorFactory,
Codec.EncoderFactory encoderFactory, Codec.EncoderFactory encoderFactory,
Muxer.Factory muxerFactory, Muxer.Factory muxerFactory,
Listener listener, Listener listener,
@ -139,10 +131,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
Clock clock) { Clock clock) {
this.context = context; this.context = context;
this.transformationRequest = transformationRequest; this.transformationRequest = transformationRequest;
this.audioProcessors = audioProcessors;
this.videoEffects = videoEffects;
this.generateSilentAudio = generateSilentAudio; this.generateSilentAudio = generateSilentAudio;
this.frameProcessorFactory = frameProcessorFactory;
this.encoderFactory = new CapturingEncoderFactory(encoderFactory); this.encoderFactory = new CapturingEncoderFactory(encoderFactory);
this.listener = listener; this.listener = listener;
this.applicationHandler = applicationHandler; this.applicationHandler = applicationHandler;
@ -151,6 +140,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
internalHandlerThread = new HandlerThread("Transformer:Internal"); internalHandlerThread = new HandlerThread("Transformer:Internal");
internalHandlerThread.start(); internalHandlerThread.start();
Looper internalLooper = internalHandlerThread.getLooper(); Looper internalLooper = internalHandlerThread.getLooper();
MediaItem mediaItem = editedMediaItem.mediaItem;
ComponentListener componentListener = new ComponentListener(mediaItem, fallbackListener); ComponentListener componentListener = new ComponentListener(mediaItem, fallbackListener);
assetLoader = assetLoader =
assetLoaderFactory assetLoaderFactory
@ -158,6 +148,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
.setRemoveVideo(removeVideo) .setRemoveVideo(removeVideo)
.setFlattenVideoForSlowMotion(transformationRequest.flattenForSlowMotion) .setFlattenVideoForSlowMotion(transformationRequest.flattenForSlowMotion)
.createAssetLoader(mediaItem, internalLooper, componentListener); .createAssetLoader(mediaItem, internalLooper, componentListener);
effects = editedMediaItem.effects;
samplePipelines = new ArrayList<>(); samplePipelines = new ArrayList<>();
muxerWrapper = muxerWrapper =
new MuxerWrapper(outputPath, outputParcelFileDescriptor, muxerFactory, componentListener); new MuxerWrapper(outputPath, outputParcelFileDescriptor, muxerFactory, componentListener);
@ -490,7 +481,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
streamStartPositionUs, streamStartPositionUs,
streamOffsetUs, streamOffsetUs,
transformationRequest, transformationRequest,
audioProcessors, effects.audioProcessors,
generateSilentAudio ? durationUs : C.TIME_UNSET, generateSilentAudio ? durationUs : C.TIME_UNSET,
encoderFactory, encoderFactory,
muxerWrapper, muxerWrapper,
@ -502,8 +493,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
streamStartPositionUs, streamStartPositionUs,
streamOffsetUs, streamOffsetUs,
transformationRequest, transformationRequest,
videoEffects, effects.videoEffects,
frameProcessorFactory, effects.frameProcessorFactory,
encoderFactory, encoderFactory,
muxerWrapper, muxerWrapper,
/* errorConsumer= */ this::onTransformationError, /* errorConsumer= */ this::onTransformationError,
@ -534,7 +525,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
if (transformationRequest.flattenForSlowMotion && isSlowMotion(inputFormat)) { if (transformationRequest.flattenForSlowMotion && isSlowMotion(inputFormat)) {
return true; return true;
} }
if (!audioProcessors.isEmpty()) { if (!effects.audioProcessors.isEmpty()) {
return true; return true;
} }
if (generateSilentAudio) { if (generateSilentAudio) {
@ -582,8 +573,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
// TODO(b/265927935): consider generalizing this logic. // TODO(b/265927935): consider generalizing this logic.
for (int i = 0; i < videoEffects.size(); i++) { for (int i = 0; i < effects.videoEffects.size(); i++) {
Effect videoEffect = videoEffects.get(i); Effect videoEffect = effects.videoEffects.get(i);
if (videoEffect instanceof Presentation) { if (videoEffect instanceof Presentation) {
Presentation presentation = (Presentation) videoEffect; Presentation presentation = (Presentation) videoEffect;
// The decoder rotates encoded frames for display by inputFormat.rotationDegrees. // The decoder rotates encoded frames for display by inputFormat.rotationDegrees.