From f5e31989abbaa6437647e98c110a3bf8553f4086 Mon Sep 17 00:00:00 2001 From: kimvde Date: Mon, 30 Jan 2023 14:09:39 +0000 Subject: [PATCH] Pass an EditedMediaItem to AssetLoader.Factory PiperOrigin-RevId: 505671326 --- .../media3/transformer/AssetLoader.java | 57 +++++------------- .../transformer/CompositeAssetLoader.java | 22 +++---- .../DefaultAssetLoaderFactory.java | 25 +------- .../transformer/ExoPlayerAssetLoader.java | 60 ++++--------------- .../transformer/TransformerInternal.java | 6 +- .../transformer/ExoPlayerAssetLoaderTest.java | 8 +-- .../transformer/TransformerEndToEndTest.java | 18 +----- 7 files changed, 46 insertions(+), 150 deletions(-) diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/AssetLoader.java b/libraries/transformer/src/main/java/androidx/media3/transformer/AssetLoader.java index 8ee4b990e4..26d247d90b 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/AssetLoader.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/AssetLoader.java @@ -22,10 +22,8 @@ import android.os.Looper; import androidx.annotation.IntDef; import androidx.annotation.IntRange; import androidx.media3.common.Format; -import androidx.media3.common.MediaItem; import androidx.media3.common.util.UnstableApi; import com.google.common.collect.ImmutableMap; -import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -38,61 +36,34 @@ import java.lang.annotation.Target; * *

Only audio and video samples are supported. Both audio and video tracks can be provided by a * single asset loader, but outputting multiple tracks of the same type is not supported. + * + *

An asset loader is responsible for {@linkplain EditedMediaItem.Builder#setRemoveAudio(boolean) + * removing audio} or {@linkplain EditedMediaItem.Builder#setRemoveVideo(boolean) video} if + * requested. + * + *

If {@linkplain EditedMediaItem.Builder#setFlattenForSlowMotion(boolean) slow motion + * flattening} is requested, the asset loader should flatten the video track for media containing + * slow motion markers. This is usually done prior to decoding. The audio samples are flattened + * after they are output by the {@link AssetLoader}, because this is done on decoded samples. */ @UnstableApi public interface AssetLoader { - /** - * A factory for {@link AssetLoader} instances. - * - *

The setters in this interface will be called with the values used to build and start the - * {@link Transformer}. - */ + /** A factory for {@link AssetLoader} instances. */ interface Factory { /** - * Sets whether to remove the audio samples from the output (if any). + * Creates an {@link AssetLoader} instance. * - *

The audio and video cannot both be removed because the output would not contain any - * samples. - */ - @CanIgnoreReturnValue - Factory setRemoveAudio(boolean removeAudio); - - /** - * Sets whether to remove the video samples from the output (if any). - * - *

The audio and video cannot both be removed because the output would not contain any - * samples. - */ - @CanIgnoreReturnValue - Factory setRemoveVideo(boolean removeVideo); - - /** - * Sets whether the video samples should be flattened prior to decoding for media containing - * slow motion markers. - * - *

The audio samples are flattened after they are output by the {@link AssetLoader}, because - * this is done on decoded samples. - * - *

For more information on slow motion flattening, see {@link - * EditedMediaItem.Builder#setFlattenForSlowMotion(boolean)}. - */ - @CanIgnoreReturnValue - Factory setFlattenVideoForSlowMotion(boolean flattenVideoForSlowMotion); - - /** - * Creates an {@link AssetLoader} instance. All the setters in this factory must be called - * before creating the {@link AssetLoader}. - * - * @param mediaItem The {@link MediaItem} to load. + * @param editedMediaItem The {@link EditedMediaItem} to load. * @param looper The {@link Looper} that's used to access the {@link AssetLoader} after it's * been created. * @param listener The {@link Listener} on which the {@link AssetLoader} should notify of * events. * @return An {@link AssetLoader}. */ - AssetLoader createAssetLoader(MediaItem mediaItem, Looper looper, Listener listener); + AssetLoader createAssetLoader( + EditedMediaItem editedMediaItem, Looper looper, Listener listener); } /** diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/CompositeAssetLoader.java b/libraries/transformer/src/main/java/androidx/media3/transformer/CompositeAssetLoader.java index 9650506a52..bcd7acc13b 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/CompositeAssetLoader.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/CompositeAssetLoader.java @@ -26,7 +26,6 @@ import androidx.annotation.Nullable; import androidx.media3.common.C; import androidx.media3.common.ColorInfo; import androidx.media3.common.Format; -import androidx.media3.common.MediaItem; import androidx.media3.common.MimeTypes; import androidx.media3.common.util.Clock; import androidx.media3.common.util.HandlerWrapper; @@ -44,7 +43,7 @@ import java.util.concurrent.atomic.AtomicLong; */ /* package */ final class CompositeAssetLoader implements AssetLoader, AssetLoader.Listener { - private final List mediaItems; + private final List editedMediaItems; private final AtomicInteger currentMediaItemIndex; private final AssetLoader.Factory assetLoaderFactory; private final HandlerWrapper handler; @@ -58,12 +57,12 @@ import java.util.concurrent.atomic.AtomicLong; private volatile long currentDurationUs; public CompositeAssetLoader( - List mediaItems, + List editedMediaItems, AssetLoader.Factory assetLoaderFactory, Looper looper, Listener listener, Clock clock) { - this.mediaItems = mediaItems; + this.editedMediaItems = editedMediaItems; this.assetLoaderFactory = assetLoaderFactory; compositeAssetLoaderListener = listener; currentMediaItemIndex = new AtomicInteger(); @@ -75,7 +74,7 @@ import java.util.concurrent.atomic.AtomicLong; // constructor. @SuppressWarnings("nullness:argument.type.incompatible") AssetLoader currentAssetLoader = - assetLoaderFactory.createAssetLoader(mediaItems.get(0), looper, /* listener= */ this); + assetLoaderFactory.createAssetLoader(editedMediaItems.get(0), looper, /* listener= */ this); this.currentAssetLoader = currentAssetLoader; } @@ -87,7 +86,7 @@ import java.util.concurrent.atomic.AtomicLong; @Override public @Transformer.ProgressState int getProgress(ProgressHolder progressHolder) { int progressState = currentAssetLoader.getProgress(progressHolder); - int mediaItemCount = mediaItems.size(); + int mediaItemCount = editedMediaItems.size(); if (mediaItemCount == 1 || progressState == PROGRESS_STATE_NOT_STARTED) { return progressState; } @@ -116,7 +115,7 @@ import java.util.concurrent.atomic.AtomicLong; @Override public void onDurationUs(long durationUs) { currentDurationUs = durationUs; - if (mediaItems.size() == 1) { + if (editedMediaItems.size() == 1) { compositeAssetLoaderListener.onDurationUs(durationUs); } else if (currentMediaItemIndex.get() == 0) { // TODO(b/252537210): support silent audio track for sequence of AssetLoaders (silent audio @@ -194,7 +193,7 @@ import java.util.concurrent.atomic.AtomicLong; DecoderInputBuffer inputBuffer = checkStateNotNull(sampleConsumer.getInputBuffer()); if (inputBuffer.isEndOfStream()) { nonEndedTracks.decrementAndGet(); - if (currentMediaItemIndex.get() < mediaItems.size() - 1) { + if (currentMediaItemIndex.get() < editedMediaItems.size() - 1) { if (nonEndedTracks.get() == 0) { switchAssetLoader(); } @@ -233,7 +232,7 @@ import java.util.concurrent.atomic.AtomicLong; @Override public void signalEndOfVideoInput() { nonEndedTracks.decrementAndGet(); - if (currentMediaItemIndex.get() < mediaItems.size() - 1) { + if (currentMediaItemIndex.get() < editedMediaItems.size() - 1) { if (nonEndedTracks.get() == 0) { switchAssetLoader(); sampleConsumer.setVideoOffsetToAddUs(totalDurationUs.get()); @@ -248,10 +247,11 @@ import java.util.concurrent.atomic.AtomicLong; handler.post( () -> { currentAssetLoader.release(); - MediaItem mediaItem = mediaItems.get(currentMediaItemIndex.incrementAndGet()); + EditedMediaItem editedMediaItem = + editedMediaItems.get(currentMediaItemIndex.incrementAndGet()); currentAssetLoader = assetLoaderFactory.createAssetLoader( - mediaItem, + editedMediaItem, checkNotNull(Looper.myLooper()), /* listener= */ CompositeAssetLoader.this); currentAssetLoader.start(); diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultAssetLoaderFactory.java b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultAssetLoaderFactory.java index ce7cf92613..1db4e794ad 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultAssetLoaderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultAssetLoaderFactory.java @@ -18,11 +18,9 @@ package androidx.media3.transformer; import android.content.Context; import android.os.Looper; -import androidx.media3.common.MediaItem; import androidx.media3.common.util.Clock; import androidx.media3.common.util.UnstableApi; import androidx.media3.exoplayer.source.MediaSource; -import com.google.errorprone.annotations.CanIgnoreReturnValue; /** The default {@link AssetLoader.Factory} implementation. */ @UnstableApi @@ -64,28 +62,9 @@ public final class DefaultAssetLoaderFactory implements AssetLoader.Factory { new ExoPlayerAssetLoader.Factory(context, decoderFactory, clock, mediaSourceFactory); } - @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setRemoveAudio(boolean removeAudio) { - return assetLoaderFactory.setRemoveAudio(removeAudio); - } - - @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setRemoveVideo(boolean removeVideo) { - return assetLoaderFactory.setRemoveVideo(removeVideo); - } - - @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setFlattenVideoForSlowMotion(boolean flattenVideoForSlowMotion) { - assetLoaderFactory.setFlattenVideoForSlowMotion(flattenVideoForSlowMotion); - return this; - } - @Override public AssetLoader createAssetLoader( - MediaItem mediaItem, Looper looper, AssetLoader.Listener listener) { - return assetLoaderFactory.createAssetLoader(mediaItem, looper, listener); + EditedMediaItem editedMediaItem, Looper looper, AssetLoader.Listener listener) { + return assetLoaderFactory.createAssetLoader(editedMediaItem, looper, listener); } } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoader.java b/libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoader.java index 91990daf44..c63971ea6a 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoader.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoader.java @@ -34,7 +34,6 @@ import android.os.Handler; import android.os.Looper; import androidx.annotation.Nullable; import androidx.media3.common.C; -import androidx.media3.common.MediaItem; import androidx.media3.common.PlaybackException; import androidx.media3.common.Player; import androidx.media3.common.Timeline; @@ -55,7 +54,6 @@ import androidx.media3.exoplayer.video.VideoRendererEventListener; import androidx.media3.extractor.DefaultExtractorsFactory; import androidx.media3.extractor.mp4.Mp4Extractor; import com.google.common.collect.ImmutableMap; -import com.google.errorprone.annotations.CanIgnoreReturnValue; /** An {@link AssetLoader} implementation that uses an {@link ExoPlayer} to load samples. */ @UnstableApi @@ -69,10 +67,6 @@ public final class ExoPlayerAssetLoader implements AssetLoader { private final Clock clock; @Nullable private final MediaSource.Factory mediaSourceFactory; - private boolean removeAudio; - private boolean removeVideo; - private boolean flattenVideoForSlowMotion; - /** * Creates an instance using a {@link DefaultMediaSourceFactory}. * @@ -112,51 +106,22 @@ public final class ExoPlayerAssetLoader implements AssetLoader { } @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setRemoveAudio(boolean removeAudio) { - this.removeAudio = removeAudio; - return this; - } - - @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setRemoveVideo(boolean removeVideo) { - this.removeVideo = removeVideo; - return this; - } - - @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setFlattenVideoForSlowMotion(boolean flattenVideoForSlowMotion) { - this.flattenVideoForSlowMotion = flattenVideoForSlowMotion; - return this; - } - - @Override - public AssetLoader createAssetLoader(MediaItem mediaItem, Looper looper, Listener listener) { + public AssetLoader createAssetLoader( + EditedMediaItem editedMediaItem, Looper looper, Listener listener) { MediaSource.Factory mediaSourceFactory = this.mediaSourceFactory; if (mediaSourceFactory == null) { DefaultExtractorsFactory defaultExtractorsFactory = new DefaultExtractorsFactory(); - if (flattenVideoForSlowMotion) { + if (editedMediaItem.flattenForSlowMotion) { defaultExtractorsFactory.setMp4ExtractorFlags(Mp4Extractor.FLAG_READ_SEF_DATA); } mediaSourceFactory = new DefaultMediaSourceFactory(context, defaultExtractorsFactory); } return new ExoPlayerAssetLoader( - context, - mediaItem, - removeAudio, - removeVideo, - flattenVideoForSlowMotion, - mediaSourceFactory, - decoderFactory, - looper, - listener, - clock); + context, editedMediaItem, mediaSourceFactory, decoderFactory, looper, listener, clock); } } - private final MediaItem mediaItem; + private final EditedMediaItem editedMediaItem; private final CapturingDecoderFactory decoderFactory; private final ExoPlayer player; @@ -164,16 +129,13 @@ public final class ExoPlayerAssetLoader implements AssetLoader { private ExoPlayerAssetLoader( Context context, - MediaItem mediaItem, - boolean removeAudio, - boolean removeVideo, - boolean flattenForSlowMotion, + EditedMediaItem editedMediaItem, MediaSource.Factory mediaSourceFactory, Codec.DecoderFactory decoderFactory, Looper looper, Listener listener, Clock clock) { - this.mediaItem = mediaItem; + this.editedMediaItem = editedMediaItem; this.decoderFactory = new CapturingDecoderFactory(decoderFactory); DefaultTrackSelector trackSelector = new DefaultTrackSelector(context); @@ -195,7 +157,11 @@ public final class ExoPlayerAssetLoader implements AssetLoader { new ExoPlayer.Builder( context, new RenderersFactoryImpl( - removeAudio, removeVideo, flattenForSlowMotion, this.decoderFactory, listener)) + editedMediaItem.removeAudio, + editedMediaItem.removeVideo, + editedMediaItem.flattenForSlowMotion, + this.decoderFactory, + listener)) .setMediaSourceFactory(mediaSourceFactory) .setTrackSelector(trackSelector) .setLoadControl(loadControl) @@ -214,7 +180,7 @@ public final class ExoPlayerAssetLoader implements AssetLoader { @Override public void start() { - player.setMediaItem(mediaItem); + player.setMediaItem(editedMediaItem.mediaItem); player.prepare(); progressState = PROGRESS_STATE_WAITING_FOR_AVAILABILITY; } 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 202d99b8e5..83bbb8bb9b 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java @@ -136,11 +136,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; Looper internalLooper = internalHandlerThread.getLooper(); ComponentListener componentListener = new ComponentListener(editedMediaItem, fallbackListener); assetLoader = - assetLoaderFactory - .setRemoveAudio(editedMediaItem.removeAudio) - .setRemoveVideo(editedMediaItem.removeVideo) - .setFlattenVideoForSlowMotion(editedMediaItem.flattenForSlowMotion) - .createAssetLoader(editedMediaItem.mediaItem, internalLooper, componentListener); + assetLoaderFactory.createAssetLoader(editedMediaItem, internalLooper, componentListener); samplePipelines = new ArrayList<>(); muxerWrapper = new MuxerWrapper(outputPath, muxerFactory, componentListener); transformerConditionVariable = new ConditionVariable(); diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/ExoPlayerAssetLoaderTest.java b/libraries/transformer/src/test/java/androidx/media3/transformer/ExoPlayerAssetLoaderTest.java index 78ea52c03d..6e721ecf0e 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/ExoPlayerAssetLoaderTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/ExoPlayerAssetLoaderTest.java @@ -117,12 +117,10 @@ public class ExoPlayerAssetLoaderTest { Looper looper, AssetLoader.Listener listener, Clock clock) { Context context = ApplicationProvider.getApplicationContext(); Codec.DecoderFactory decoderFactory = new DefaultDecoderFactory(context); - MediaItem mediaItem = MediaItem.fromUri("asset:///media/mp4/sample.mp4"); + EditedMediaItem editedMediaItem = + new EditedMediaItem.Builder(MediaItem.fromUri("asset:///media/mp4/sample.mp4")).build(); return new ExoPlayerAssetLoader.Factory(context, decoderFactory, clock) - .setRemoveAudio(false) - .setRemoveVideo(false) - .setFlattenVideoForSlowMotion(false) - .createAssetLoader(mediaItem, looper, listener); + .createAssetLoader(editedMediaItem, looper, listener); } private static final class FakeSampleConsumer implements SampleConsumer { diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java index c1b111a7d3..0cc72a0f21 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java @@ -1229,22 +1229,8 @@ public final class TransformerEndToEndTest { } @Override - public AssetLoader.Factory setRemoveAudio(boolean removeAudio) { - return this; - } - - @Override - public AssetLoader.Factory setRemoveVideo(boolean removeVideo) { - return this; - } - - @Override - public AssetLoader.Factory setFlattenVideoForSlowMotion(boolean flattenVideoForSlowMotion) { - return this; - } - - @Override - public AssetLoader createAssetLoader(MediaItem mediaItem, Looper looper, Listener listener) { + public AssetLoader createAssetLoader( + EditedMediaItem editedMediaItem, Looper looper, Listener listener) { return new FakeAssetLoader(listener, supportedOutputTypes, sampleConsumerRef); } }