Remove setters from AssetLoader.Factory

It's unusual to have setters on a Factory.

PiperOrigin-RevId: 501212264
This commit is contained in:
kimvde 2023-01-11 09:30:18 +00:00 committed by Rohit Singh
parent 375299bf36
commit 9880926dd5
7 changed files with 67 additions and 183 deletions

View file

@ -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.
*
* <p>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);
}
/**

View file

@ -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);
}
}

View file

@ -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.
*
* <p>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);
}
}

View file

@ -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<Transformer.Listener> 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.
*
* <p>The default value is a {@link DefaultAssetLoaderFactory}.
* <p>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,

View file

@ -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();

View file

@ -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 {

View file

@ -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<SampleConsumer> sampleConsumerRef;
@Nullable private AssetLoader.Listener listener;
public Factory(
@SupportedOutputTypes int supportedOutputTypes,
@Nullable AtomicReference<SampleConsumer> 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);
}
}