diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AssetLoader.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AssetLoader.java index 85a3a2c911..b14ca8c7c9 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AssetLoader.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AssetLoader.java @@ -16,7 +16,13 @@ package com.google.android.exoplayer2.transformer; +import android.content.Context; +import android.os.Looper; import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.MediaItem; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.util.Clock; +import com.google.errorprone.annotations.CanIgnoreReturnValue; /** * Provides media data to a {@linkplain Transformer}. @@ -28,6 +34,82 @@ import com.google.android.exoplayer2.Format; */ public interface AssetLoader { + /** A factory for {@link AssetLoader} instances. */ + interface Factory { + + /** Sets the 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). + * + *

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 + * TransformationRequest.Builder#setFlattenForSlowMotion(boolean)}. + */ + @CanIgnoreReturnValue + Factory setFlattenVideoForSlowMotion(boolean flattenVideoForSlowMotion); + + /** Sets the {@link MediaSource.Factory} to be used to retrieve the samples. */ + @CanIgnoreReturnValue + Factory setMediaSourceFactory(MediaSource.Factory mediaSourceFactory); + + /** Sets the {@link Codec.DecoderFactory} to be used to decode the samples (if necessary). */ + @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}. + */ + AssetLoader createAssetLoader(); + } + /** * A listener of asset loader events. * diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultAssetLoaderFactory.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultAssetLoaderFactory.java new file mode 100644 index 0000000000..f0f0287796 --- /dev/null +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultAssetLoaderFactory.java @@ -0,0 +1,127 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.exoplayer2.transformer; + +import static com.google.android.exoplayer2.util.Assertions.checkStateNotNull; + +import android.content.Context; +import android.os.Looper; +import androidx.annotation.Nullable; +import com.google.android.exoplayer2.MediaItem; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.util.Clock; +import com.google.errorprone.annotations.CanIgnoreReturnValue; + +/** The default {@link AssetLoader.Factory} implementation. */ +public final class DefaultAssetLoaderFactory implements AssetLoader.Factory { + + @Nullable private Context context; + @Nullable private MediaItem mediaItem; + 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; + + @Override + @CanIgnoreReturnValue + public AssetLoader.Factory setContext(Context context) { + this.context = context; + return this; + } + + @Override + @CanIgnoreReturnValue + public AssetLoader.Factory setMediaItem(MediaItem mediaItem) { + this.mediaItem = mediaItem; + return this; + } + + @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 + @CanIgnoreReturnValue + public AssetLoader.Factory setMediaSourceFactory(MediaSource.Factory mediaSourceFactory) { + this.mediaSourceFactory = mediaSourceFactory; + return this; + } + + @Override + @CanIgnoreReturnValue + public AssetLoader.Factory setDecoderFactory(Codec.DecoderFactory decoderFactory) { + this.decoderFactory = decoderFactory; + return this; + } + + @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() { + return new ExoPlayerAssetLoader( + checkStateNotNull(context), + checkStateNotNull(mediaItem), + removeAudio, + removeVideo, + flattenVideoForSlowMotion, + checkStateNotNull(mediaSourceFactory), + checkStateNotNull(decoderFactory), + checkStateNotNull(looper), + checkStateNotNull(listener), + checkStateNotNull(clock)); + } +} diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java index a84c23c29b..99ba44e82a 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java @@ -90,6 +90,7 @@ public final class Transformer { private boolean forceSilentAudio; private ListenerSet listeners; private MediaSource.@MonotonicNonNull Factory mediaSourceFactory; + private AssetLoader.Factory assetLoaderFactory; private Codec.DecoderFactory decoderFactory; private Codec.EncoderFactory encoderFactory; private FrameProcessor.Factory frameProcessorFactory; @@ -108,6 +109,7 @@ 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(); @@ -129,6 +131,7 @@ public final class Transformer { this.forceSilentAudio = transformer.forceSilentAudio; this.listeners = transformer.listeners; this.mediaSourceFactory = transformer.mediaSourceFactory; + this.assetLoaderFactory = transformer.assetLoaderFactory; this.decoderFactory = transformer.decoderFactory; this.encoderFactory = transformer.encoderFactory; this.frameProcessorFactory = transformer.frameProcessorFactory; @@ -304,6 +307,20 @@ public final class Transformer { return this; } + /** + * Sets the {@link AssetLoader.Factory} to be used to retrieve the samples to transform. + * + *

The default value is a {@link DefaultAssetLoaderFactory}. + * + * @param assetLoaderFactory An {@link AssetLoader.Factory}. + * @return This builder. + */ + @CanIgnoreReturnValue + public Builder setAssetLoaderFactory(AssetLoader.Factory assetLoaderFactory) { + this.assetLoaderFactory = assetLoaderFactory; + return this; + } + /** * Sets the {@link Codec.DecoderFactory} that will be used by the transformer. * @@ -476,6 +493,7 @@ public final class Transformer { forceSilentAudio, listeners, mediaSourceFactory, + assetLoaderFactory, decoderFactory, encoderFactory, frameProcessorFactory, @@ -589,6 +607,7 @@ public final class Transformer { private final boolean forceSilentAudio; private final ListenerSet listeners; private final MediaSource.Factory mediaSourceFactory; + private final AssetLoader.Factory assetLoaderFactory; private final FrameProcessor.Factory frameProcessorFactory; private final Muxer.Factory muxerFactory; private final Looper looper; @@ -607,6 +626,7 @@ public final class Transformer { boolean forceSilentAudio, ListenerSet listeners, MediaSource.Factory mediaSourceFactory, + AssetLoader.Factory assetLoaderFactory, Codec.DecoderFactory decoderFactory, Codec.EncoderFactory encoderFactory, FrameProcessor.Factory frameProcessorFactory, @@ -628,6 +648,7 @@ public final class Transformer { this.forceSilentAudio = forceSilentAudio; this.listeners = listeners; this.mediaSourceFactory = mediaSourceFactory; + this.assetLoaderFactory = assetLoaderFactory; this.decoderFactory = decoderFactory; this.encoderFactory = encoderFactory; this.frameProcessorFactory = frameProcessorFactory; @@ -770,6 +791,7 @@ public final class Transformer { removeVideo, forceSilentAudio, mediaSourceFactory, + assetLoaderFactory, decoderFactory, encoderFactory, frameProcessorFactory, diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerInternal.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerInternal.java index 6d95c75c30..14998ef75c 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerInternal.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerInternal.java @@ -128,6 +128,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; boolean removeVideo, boolean forceSilentAudio, MediaSource.Factory mediaSourceFactory, + AssetLoader.Factory assetLoaderFactory, Codec.DecoderFactory decoderFactory, Codec.EncoderFactory encoderFactory, FrameProcessor.Factory frameProcessorFactory, @@ -152,17 +153,18 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; Looper internalLooper = internalHandlerThread.getLooper(); ComponentListener componentListener = new ComponentListener(mediaItem, fallbackListener); assetLoader = - new ExoPlayerAssetLoader( - context, - mediaItem, - removeAudio, - removeVideo, - transformationRequest.flattenForSlowMotion, - mediaSourceFactory, - decoderFactory, - internalLooper, - componentListener, - clock); + assetLoaderFactory + .setContext(context) + .setMediaItem(mediaItem) + .setRemoveAudio(removeAudio) + .setRemoveVideo(removeVideo) + .setFlattenVideoForSlowMotion(transformationRequest.flattenForSlowMotion) + .setMediaSourceFactory(mediaSourceFactory) + .setDecoderFactory(decoderFactory) + .setLooper(internalLooper) + .setListener(componentListener) + .setClock(clock) + .createAssetLoader(); samplePipelines = new ArrayList<>(); silentSamplePipelineIndex = C.INDEX_UNSET; dequeueBufferConditionVariable = new ConditionVariable();