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 82b55cf371..3890a5f29c 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/AssetLoader.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/AssetLoader.java @@ -18,13 +18,11 @@ package androidx.media3.transformer; import static java.lang.annotation.ElementType.TYPE_USE; -import android.content.Context; 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.Clock; import androidx.media3.common.util.UnstableApi; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.lang.annotation.Documented; @@ -51,14 +49,6 @@ public interface AssetLoader { */ interface Factory { - /** Sets the {@link Context}. */ - @CanIgnoreReturnValue - Factory setContext(Context context); - - /** Sets the {@link MediaItem} to load. */ - @CanIgnoreReturnValue - Factory setMediaItem(MediaItem mediaItem); - /** * Sets whether to remove the audio samples from the output (if any). * @@ -94,30 +84,18 @@ public interface AssetLoader { @CanIgnoreReturnValue Factory setDecoderFactory(Codec.DecoderFactory decoderFactory); - /** - * Sets the {@link Looper} that's used to access the {@link AssetLoader} after it's been - * created. - */ - @CanIgnoreReturnValue - Factory setLooper(Looper looper); - - /** Sets the {@link Listener} on which the {@link AssetLoader} should notify of events. */ - @CanIgnoreReturnValue - Factory setListener(AssetLoader.Listener listener); - - /** - * The {@link Clock} to use. - * - *

Should always be {@link Clock#DEFAULT} except for testing. - */ - @CanIgnoreReturnValue - Factory setClock(Clock clock); - /** * 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 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(); + AssetLoader createAssetLoader(MediaItem mediaItem, Looper looper, Listener listener); } /** 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 8a19b01639..117a9ead04 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultAssetLoaderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultAssetLoaderFactory.java @@ -21,6 +21,7 @@ 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. */ @@ -29,21 +30,18 @@ public final class DefaultAssetLoaderFactory implements AssetLoader.Factory { private final AssetLoader.Factory assetLoaderFactory; - /** Creates an instance. */ - public DefaultAssetLoaderFactory() { - assetLoaderFactory = new ExoPlayerAssetLoader.Factory(); - } - - @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setContext(Context context) { - return assetLoaderFactory.setContext(context); - } - - @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setMediaItem(MediaItem mediaItem) { - return assetLoaderFactory.setMediaItem(mediaItem); + /** + * Creates an instance. + * + * @param context The {@link Context}. + * @param mediaSourceFactory The {@link MediaSource.Factory} to use to retrieve the samples to + * transform when an {@link ExoPlayerAssetLoader} is used. + * @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for + * testing. + */ + public DefaultAssetLoaderFactory( + Context context, MediaSource.Factory mediaSourceFactory, Clock clock) { + assetLoaderFactory = new ExoPlayerAssetLoader.Factory(context, mediaSourceFactory, clock); } @Override @@ -72,25 +70,8 @@ public final class DefaultAssetLoaderFactory implements AssetLoader.Factory { } @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setLooper(Looper looper) { - return assetLoaderFactory.setLooper(looper); - } - - @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setListener(AssetLoader.Listener listener) { - return assetLoaderFactory.setListener(listener); - } - - @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setClock(Clock clock) { - return assetLoaderFactory.setClock(clock); - } - - @Override - public AssetLoader createAssetLoader() { - return assetLoaderFactory.createAssetLoader(); + public AssetLoader createAssetLoader( + MediaItem mediaItem, Looper looper, AssetLoader.Listener listener) { + return assetLoaderFactory.createAssetLoader(mediaItem, 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 bbf5f5a80a..e6f903f864 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoader.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoader.java @@ -48,13 +48,10 @@ import androidx.media3.exoplayer.Renderer; import androidx.media3.exoplayer.RenderersFactory; import androidx.media3.exoplayer.audio.AudioRendererEventListener; import androidx.media3.exoplayer.metadata.MetadataOutput; -import androidx.media3.exoplayer.source.DefaultMediaSourceFactory; import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.text.TextOutput; import androidx.media3.exoplayer.trackselection.DefaultTrackSelector; import androidx.media3.exoplayer.video.VideoRendererEventListener; -import androidx.media3.extractor.DefaultExtractorsFactory; -import androidx.media3.extractor.mp4.Mp4Extractor; import com.google.errorprone.annotations.CanIgnoreReturnValue; /** An {@link AssetLoader} implementation that uses an {@link ExoPlayer} to load samples. */ @@ -64,48 +61,28 @@ public final class ExoPlayerAssetLoader implements AssetLoader { /** An {@link AssetLoader.Factory} for {@link ExoPlayerAssetLoader} instances. */ public static final class Factory implements AssetLoader.Factory { - @Nullable private Context context; - @Nullable private MediaItem mediaItem; + private final Context context; + private final MediaSource.Factory mediaSourceFactory; + private final Clock clock; + private boolean removeAudio; private boolean removeVideo; private boolean flattenVideoForSlowMotion; - @Nullable private MediaSource.Factory mediaSourceFactory; @Nullable private Codec.DecoderFactory decoderFactory; - @Nullable private Looper looper; - @Nullable private AssetLoader.Listener listener; - @Nullable private Clock clock; /** * Creates an instance. * - *

The {@link ExoPlayerAssetLoader} instances produced use a {@link - * DefaultMediaSourceFactory} built with the context provided in {@linkplain - * #setContext(Context)}. + * @param context The {@link Context}. + * @param mediaSourceFactory The {@link MediaSource.Factory} to use to retrieve the samples to + * transform. + * @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for + * testing. */ - public Factory() {} - - /** - * Creates an instance. - * - * @param mediaSourceFactory The {@link MediaSource.Factory} to be used to retrieve the samples - * to transform. - */ - public Factory(MediaSource.Factory mediaSourceFactory) { - this.mediaSourceFactory = mediaSourceFactory; - } - - @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setContext(Context context) { + public Factory(Context context, MediaSource.Factory mediaSourceFactory, Clock clock) { this.context = context; - return this; - } - - @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setMediaItem(MediaItem mediaItem) { - this.mediaItem = mediaItem; - return this; + this.mediaSourceFactory = mediaSourceFactory; + this.clock = clock; } @Override @@ -137,47 +114,18 @@ public final class ExoPlayerAssetLoader implements AssetLoader { } @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setLooper(Looper looper) { - this.looper = looper; - return this; - } - - @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setListener(AssetLoader.Listener listener) { - this.listener = listener; - return this; - } - - @Override - @CanIgnoreReturnValue - public AssetLoader.Factory setClock(Clock clock) { - this.clock = clock; - return this; - } - - @Override - public AssetLoader createAssetLoader() { - Context context = checkStateNotNull(this.context); - if (mediaSourceFactory == null) { - DefaultExtractorsFactory defaultExtractorsFactory = new DefaultExtractorsFactory(); - if (flattenVideoForSlowMotion) { - defaultExtractorsFactory.setMp4ExtractorFlags(Mp4Extractor.FLAG_READ_SEF_DATA); - } - mediaSourceFactory = new DefaultMediaSourceFactory(context, defaultExtractorsFactory); - } + public AssetLoader createAssetLoader(MediaItem mediaItem, Looper looper, Listener listener) { return new ExoPlayerAssetLoader( context, - checkStateNotNull(mediaItem), + mediaItem, removeAudio, removeVideo, flattenVideoForSlowMotion, mediaSourceFactory, checkStateNotNull(decoderFactory), - checkStateNotNull(looper), - checkStateNotNull(listener), - checkStateNotNull(clock)); + looper, + listener, + clock); } } 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 dc5ce658b3..c4aca97801 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java @@ -43,6 +43,10 @@ import androidx.media3.effect.GlEffect; import androidx.media3.effect.GlEffectsFrameProcessor; import androidx.media3.effect.GlMatrixTransformation; import androidx.media3.exoplayer.audio.SonicAudioProcessor; +import androidx.media3.exoplayer.source.DefaultMediaSourceFactory; +import androidx.media3.exoplayer.source.MediaSource; +import androidx.media3.extractor.DefaultExtractorsFactory; +import androidx.media3.extractor.mp4.Mp4Extractor; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.lang.annotation.Documented; @@ -86,7 +90,7 @@ public final class Transformer { private boolean removeVideo; private boolean forceSilentAudio; private ListenerSet listeners; - private AssetLoader.Factory assetLoaderFactory; + @Nullable private AssetLoader.Factory assetLoaderFactory; private Codec.DecoderFactory decoderFactory; private Codec.EncoderFactory encoderFactory; private FrameProcessor.Factory frameProcessorFactory; @@ -105,7 +109,6 @@ public final class Transformer { transformationRequest = new TransformationRequest.Builder().build(); audioProcessors = ImmutableList.of(); videoEffects = ImmutableList.of(); - assetLoaderFactory = new DefaultAssetLoaderFactory(); decoderFactory = new DefaultDecoderFactory(this.context); encoderFactory = new DefaultEncoderFactory.Builder(this.context).build(); frameProcessorFactory = new GlEffectsFrameProcessor.Factory(); @@ -290,7 +293,8 @@ public final class Transformer { /** * Sets the {@link AssetLoader.Factory} to be used to retrieve the samples to transform. * - *

The default value is a {@link DefaultAssetLoaderFactory}. + *

The default value is a {@link DefaultAssetLoaderFactory} built with a {@link + * DefaultMediaSourceFactory}. * * @param assetLoaderFactory An {@link AssetLoader.Factory}. * @return This builder. @@ -456,6 +460,15 @@ public final class Transformer { if (transformationRequest.videoMimeType != null) { checkSampleMimeType(transformationRequest.videoMimeType); } + if (assetLoaderFactory == null) { + DefaultExtractorsFactory defaultExtractorsFactory = new DefaultExtractorsFactory(); + if (transformationRequest.flattenForSlowMotion) { + defaultExtractorsFactory.setMp4ExtractorFlags(Mp4Extractor.FLAG_READ_SEF_DATA); + } + MediaSource.Factory mediaSourceFactory = + new DefaultMediaSourceFactory(context, defaultExtractorsFactory); + assetLoaderFactory = new DefaultAssetLoaderFactory(context, mediaSourceFactory, clock); + } return new Transformer( context, transformationRequest, 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 bdd86b7eec..d3aeccb102 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java @@ -161,16 +161,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ComponentListener componentListener = new ComponentListener(mediaItem, fallbackListener); assetLoader = assetLoaderFactory - .setContext(context) - .setMediaItem(mediaItem) .setRemoveAudio(removeAudio) .setRemoveVideo(removeVideo) .setFlattenVideoForSlowMotion(transformationRequest.flattenForSlowMotion) .setDecoderFactory(this.decoderFactory) - .setLooper(internalLooper) - .setListener(componentListener) - .setClock(clock) - .createAssetLoader(); + .createAssetLoader(mediaItem, internalLooper, componentListener); samplePipelines = new ArrayList<>(); silentSamplePipelineIndex = C.INDEX_UNSET; dequeueBufferConditionVariable = 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 4e5d9cabfc..092e986e09 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/ExoPlayerAssetLoaderTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/ExoPlayerAssetLoaderTest.java @@ -27,6 +27,8 @@ import androidx.media3.common.Format; import androidx.media3.common.MediaItem; import androidx.media3.common.util.Clock; import androidx.media3.decoder.DecoderInputBuffer; +import androidx.media3.exoplayer.source.DefaultMediaSourceFactory; +import androidx.media3.exoplayer.source.MediaSource; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import java.time.Duration; @@ -116,18 +118,14 @@ public class ExoPlayerAssetLoaderTest { private static AssetLoader getAssetLoader( Looper looper, AssetLoader.Listener listener, Clock clock) { Context context = ApplicationProvider.getApplicationContext(); + MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(context); MediaItem mediaItem = MediaItem.fromUri("asset:///media/mp4/sample.mp4"); - return new ExoPlayerAssetLoader.Factory() - .setContext(context) - .setMediaItem(mediaItem) + return new ExoPlayerAssetLoader.Factory(context, mediaSourceFactory, clock) .setRemoveAudio(false) .setRemoveVideo(false) .setFlattenVideoForSlowMotion(false) .setDecoderFactory(new DefaultDecoderFactory(context)) - .setLooper(looper) - .setListener(listener) - .setClock(clock) - .createAssetLoader(); + .createAssetLoader(mediaItem, 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 69a1cc27ff..e4801dd86c 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java @@ -16,7 +16,6 @@ package androidx.media3.transformer; -import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.test.utils.robolectric.RobolectricUtil.runLooperUntil; import static androidx.media3.transformer.AssetLoader.SUPPORTED_OUTPUT_TYPE_DECODED; import static androidx.media3.transformer.AssetLoader.SUPPORTED_OUTPUT_TYPE_ENCODED; @@ -47,7 +46,6 @@ import androidx.media3.common.C; 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.Util; import androidx.media3.exoplayer.audio.SonicAudioProcessor; import androidx.media3.exoplayer.source.DefaultMediaSourceFactory; @@ -529,7 +527,8 @@ public final class TransformerEndToEndTest { MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory( context, new SlowExtractorsFactory(/* delayBetweenReadsMs= */ 10)); - AssetLoader.Factory assetLoaderFactory = new ExoPlayerAssetLoader.Factory(mediaSourceFactory); + AssetLoader.Factory assetLoaderFactory = + new ExoPlayerAssetLoader.Factory(context, mediaSourceFactory, clock); Muxer.Factory muxerFactory = new TestMuxerFactory(/* maxDelayBetweenSamplesMs= */ 1); Transformer transformer = createTransformerBuilder(/* enableFallback= */ false) @@ -1079,8 +1078,6 @@ public final class TransformerEndToEndTest { private final @SupportedOutputTypes int supportedOutputTypes; @Nullable private final AtomicReference sampleConsumerRef; - @Nullable private AssetLoader.Listener listener; - public Factory( @SupportedOutputTypes int supportedOutputTypes, @Nullable AtomicReference sampleConsumerRef) { @@ -1088,16 +1085,6 @@ public final class TransformerEndToEndTest { this.sampleConsumerRef = sampleConsumerRef; } - @Override - public AssetLoader.Factory setContext(Context context) { - return this; - } - - @Override - public AssetLoader.Factory setMediaItem(MediaItem mediaItem) { - return this; - } - @Override public AssetLoader.Factory setRemoveAudio(boolean removeAudio) { return this; @@ -1119,24 +1106,8 @@ public final class TransformerEndToEndTest { } @Override - public AssetLoader.Factory setLooper(Looper looper) { - return this; - } - - @Override - public AssetLoader.Factory setListener(Listener listener) { - this.listener = listener; - return this; - } - - @Override - public AssetLoader.Factory setClock(Clock clock) { - return this; - } - - @Override - public AssetLoader createAssetLoader() { - return new FakeAssetLoader(checkNotNull(listener), supportedOutputTypes, sampleConsumerRef); + public AssetLoader createAssetLoader(MediaItem mediaItem, Looper looper, Listener listener) { + return new FakeAssetLoader(listener, supportedOutputTypes, sampleConsumerRef); } }