Move setMediaSourceFactory to ExoPlayerAssetLoader

The MediaSourceFactory won't be used by the other AssetLoaders

In order to do that, ExoPlayerAssetLoader has been made public, and the
DefaultAssetLoaderFactory has become a wrapper around
ExoPlayerAssetLoader.

PiperOrigin-RevId: 496386853
This commit is contained in:
kimvde 2022-12-19 14:43:30 +00:00 committed by Tianyi Feng
parent ce766d7622
commit cd70a5cef5
7 changed files with 159 additions and 100 deletions

View File

@ -20,7 +20,6 @@ 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;
@ -34,10 +33,15 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
*/
public interface AssetLoader {
/** A factory for {@link AssetLoader} instances. */
/**
* A factory for {@link AssetLoader} instances.
*
* <p>The setters in this interface will be called with the values used to build and start the
* {@link Transformer}.
*/
interface Factory {
/** Sets the context. */
/** Sets the {@link Context}. */
@CanIgnoreReturnValue
Factory setContext(Context context);
@ -76,10 +80,6 @@ public interface AssetLoader {
@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);
@ -111,7 +111,7 @@ public interface AssetLoader {
}
/**
* A listener of asset loader events.
* A listener of {@link AssetLoader} events.
*
* <p>This listener is typically used in the following way:
*

View File

@ -16,112 +16,79 @@
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;
private final AssetLoader.Factory assetLoaderFactory;
/** Creates an instance. */
public DefaultAssetLoaderFactory() {
assetLoaderFactory = new ExoPlayerAssetLoader.Factory();
}
@Override
@CanIgnoreReturnValue
public AssetLoader.Factory setContext(Context context) {
this.context = context;
return this;
return assetLoaderFactory.setContext(context);
}
@Override
@CanIgnoreReturnValue
public AssetLoader.Factory setMediaItem(MediaItem mediaItem) {
this.mediaItem = mediaItem;
return this;
return assetLoaderFactory.setMediaItem(mediaItem);
}
@Override
@CanIgnoreReturnValue
public AssetLoader.Factory setRemoveAudio(boolean removeAudio) {
this.removeAudio = removeAudio;
return this;
return assetLoaderFactory.setRemoveAudio(removeAudio);
}
@Override
@CanIgnoreReturnValue
public AssetLoader.Factory setRemoveVideo(boolean removeVideo) {
this.removeVideo = removeVideo;
return this;
return assetLoaderFactory.setRemoveVideo(removeVideo);
}
@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;
assetLoaderFactory.setFlattenVideoForSlowMotion(flattenVideoForSlowMotion);
return this;
}
@Override
@CanIgnoreReturnValue
public AssetLoader.Factory setDecoderFactory(Codec.DecoderFactory decoderFactory) {
this.decoderFactory = decoderFactory;
return this;
return assetLoaderFactory.setDecoderFactory(decoderFactory);
}
@Override
@CanIgnoreReturnValue
public AssetLoader.Factory setLooper(Looper looper) {
this.looper = looper;
return this;
return assetLoaderFactory.setLooper(looper);
}
@Override
@CanIgnoreReturnValue
public AssetLoader.Factory setListener(AssetLoader.Listener listener) {
this.listener = listener;
return this;
return assetLoaderFactory.setListener(listener);
}
@Override
@CanIgnoreReturnValue
public AssetLoader.Factory setClock(Clock clock) {
this.clock = clock;
return this;
return assetLoaderFactory.setClock(clock);
}
@Override
public AssetLoader createAssetLoader() {
return new ExoPlayerAssetLoader(
checkStateNotNull(context),
checkStateNotNull(mediaItem),
removeAudio,
removeVideo,
flattenVideoForSlowMotion,
checkStateNotNull(mediaSourceFactory),
checkStateNotNull(decoderFactory),
checkStateNotNull(looper),
checkStateNotNull(listener),
checkStateNotNull(clock));
return assetLoaderFactory.createAssetLoader();
}
}

View File

@ -24,11 +24,13 @@ import static com.google.android.exoplayer2.transformer.Transformer.PROGRESS_STA
import static com.google.android.exoplayer2.transformer.Transformer.PROGRESS_STATE_NO_TRANSFORMATION;
import static com.google.android.exoplayer2.transformer.Transformer.PROGRESS_STATE_UNAVAILABLE;
import static com.google.android.exoplayer2.transformer.Transformer.PROGRESS_STATE_WAITING_FOR_AVAILABILITY;
import static com.google.android.exoplayer2.util.Assertions.checkStateNotNull;
import static java.lang.Math.min;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.ExoPlayer;
@ -40,21 +42,146 @@ import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor;
import com.google.android.exoplayer2.metadata.MetadataOutput;
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.text.TextOutput;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.video.VideoRendererEventListener;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
/* package */ final class ExoPlayerAssetLoader implements AssetLoader {
/** An {@link AssetLoader} implementation that uses an {@link ExoPlayer} to load samples. */
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 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)}.
*/
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) {
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 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() {
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);
}
return new ExoPlayerAssetLoader(
context,
checkStateNotNull(mediaItem),
removeAudio,
removeVideo,
flattenVideoForSlowMotion,
mediaSourceFactory,
checkStateNotNull(decoderFactory),
checkStateNotNull(looper),
checkStateNotNull(listener),
checkStateNotNull(clock));
}
}
private final MediaItem mediaItem;
private final ExoPlayer player;
private @Transformer.ProgressState int progressState;
public ExoPlayerAssetLoader(
private ExoPlayerAssetLoader(
Context context,
MediaItem mediaItem,
boolean removeAudio,

View File

@ -140,10 +140,10 @@ public final class TransformationRequest {
* <li>The recording frame rate of the video is 120 or 240 fps.
* </ul>
*
* <p>If specifying a {@link MediaSource.Factory} using {@link
* Transformer.Builder#setMediaSourceFactory(MediaSource.Factory)}, make sure that {@link
* Mp4Extractor#FLAG_READ_SEF_DATA} is set on the {@link Mp4Extractor} used. Otherwise, the slow
* motion metadata will be ignored and the input won't be flattened.
* <p>If using an {@link ExoPlayerAssetLoader.Factory} with a provided {@link
* MediaSource.Factory}, make sure that {@link Mp4Extractor#FLAG_READ_SEF_DATA} is set on the
* {@link Mp4Extractor} used. Otherwise, the slow motion metadata will be ignored and the input
* won't be flattened.
*
* <p>Using slow motion flattening together with {@link
* com.google.android.exoplayer2.MediaItem.ClippingConfiguration} is not supported yet.

View File

@ -34,9 +34,6 @@ import com.google.android.exoplayer2.audio.SonicAudioProcessor;
import com.google.android.exoplayer2.effect.GlEffect;
import com.google.android.exoplayer2.effect.GlEffectsFrameProcessor;
import com.google.android.exoplayer2.effect.GlMatrixTransformation;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor;
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.DebugViewProvider;
@ -53,7 +50,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/**
* A transformer to transform media inputs.
@ -89,7 +85,6 @@ public final class Transformer {
private boolean removeVideo;
private boolean forceSilentAudio;
private ListenerSet<Transformer.Listener> listeners;
private MediaSource.@MonotonicNonNull Factory mediaSourceFactory;
private AssetLoader.Factory assetLoaderFactory;
private Codec.DecoderFactory decoderFactory;
private Codec.EncoderFactory encoderFactory;
@ -130,7 +125,6 @@ public final class Transformer {
this.removeVideo = transformer.removeVideo;
this.forceSilentAudio = transformer.forceSilentAudio;
this.listeners = transformer.listeners;
this.mediaSourceFactory = transformer.mediaSourceFactory;
this.assetLoaderFactory = transformer.assetLoaderFactory;
this.decoderFactory = transformer.decoderFactory;
this.encoderFactory = transformer.encoderFactory;
@ -292,21 +286,6 @@ public final class Transformer {
return this;
}
/**
* Sets the {@link MediaSource.Factory} to be used to retrieve the inputs to transform.
*
* <p>The default value is a {@link DefaultMediaSourceFactory} built with the context provided
* in {@linkplain #Builder(Context) the constructor}.
*
* @param mediaSourceFactory A {@link MediaSource.Factory}.
* @return This builder.
*/
@CanIgnoreReturnValue
public Builder setMediaSourceFactory(MediaSource.Factory mediaSourceFactory) {
this.mediaSourceFactory = mediaSourceFactory;
return this;
}
/**
* Sets the {@link AssetLoader.Factory} to be used to retrieve the samples to transform.
*
@ -476,13 +455,6 @@ public final class Transformer {
if (transformationRequest.videoMimeType != null) {
checkSampleMimeType(transformationRequest.videoMimeType);
}
if (mediaSourceFactory == null) {
DefaultExtractorsFactory defaultExtractorsFactory = new DefaultExtractorsFactory();
if (transformationRequest.flattenForSlowMotion) {
defaultExtractorsFactory.setMp4ExtractorFlags(Mp4Extractor.FLAG_READ_SEF_DATA);
}
mediaSourceFactory = new DefaultMediaSourceFactory(context, defaultExtractorsFactory);
}
return new Transformer(
context,
transformationRequest,
@ -492,7 +464,6 @@ public final class Transformer {
removeVideo,
forceSilentAudio,
listeners,
mediaSourceFactory,
assetLoaderFactory,
decoderFactory,
encoderFactory,
@ -618,7 +589,6 @@ public final class Transformer {
private final boolean removeVideo;
private final boolean forceSilentAudio;
private final ListenerSet<Transformer.Listener> listeners;
private final MediaSource.Factory mediaSourceFactory;
private final AssetLoader.Factory assetLoaderFactory;
private final FrameProcessor.Factory frameProcessorFactory;
private final Muxer.Factory muxerFactory;
@ -637,7 +607,6 @@ public final class Transformer {
boolean removeVideo,
boolean forceSilentAudio,
ListenerSet<Listener> listeners,
MediaSource.Factory mediaSourceFactory,
AssetLoader.Factory assetLoaderFactory,
Codec.DecoderFactory decoderFactory,
Codec.EncoderFactory encoderFactory,
@ -659,7 +628,6 @@ public final class Transformer {
this.removeVideo = removeVideo;
this.forceSilentAudio = forceSilentAudio;
this.listeners = listeners;
this.mediaSourceFactory = mediaSourceFactory;
this.assetLoaderFactory = assetLoaderFactory;
this.decoderFactory = decoderFactory;
this.encoderFactory = encoderFactory;
@ -802,7 +770,6 @@ public final class Transformer {
removeAudio,
removeVideo,
forceSilentAudio,
mediaSourceFactory,
assetLoaderFactory,
decoderFactory,
encoderFactory,

View File

@ -35,7 +35,6 @@ import com.google.android.exoplayer2.audio.AudioProcessor;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.mp4.SlowMotionData;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.ConditionVariable;
import com.google.android.exoplayer2.util.DebugViewProvider;
@ -126,7 +125,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
boolean removeAudio,
boolean removeVideo,
boolean forceSilentAudio,
MediaSource.Factory mediaSourceFactory,
AssetLoader.Factory assetLoaderFactory,
Codec.DecoderFactory decoderFactory,
Codec.EncoderFactory encoderFactory,
@ -158,7 +156,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
.setRemoveAudio(removeAudio)
.setRemoveVideo(removeVideo)
.setFlattenVideoForSlowMotion(transformationRequest.flattenForSlowMotion)
.setMediaSourceFactory(mediaSourceFactory)
.setDecoderFactory(this.decoderFactory)
.setLooper(internalLooper)
.setListener(componentListener)

View File

@ -533,10 +533,11 @@ public final class TransformerEndToEndTest {
MediaSource.Factory mediaSourceFactory =
new DefaultMediaSourceFactory(
context, new SlowExtractorsFactory(/* delayBetweenReadsMs= */ 10));
AssetLoader.Factory assetLoaderFactory = new ExoPlayerAssetLoader.Factory(mediaSourceFactory);
Muxer.Factory muxerFactory = new TestMuxerFactory(/* maxDelayBetweenSamplesMs= */ 1);
Transformer transformer =
createTransformerBuilder(/* enableFallback= */ false)
.setMediaSourceFactory(mediaSourceFactory)
.setAssetLoaderFactory(assetLoaderFactory)
.setMuxerFactory(muxerFactory)
.build();
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);