Add AssetLoader.Factory

This is so that apps can customise AssetLoader

PiperOrigin-RevId: 494998497
This commit is contained in:
kimvde 2022-12-13 13:58:05 +00:00 committed by Ian Baker
parent beee4732fb
commit 5759eda37e
4 changed files with 246 additions and 11 deletions

View file

@ -16,8 +16,14 @@
package androidx.media3.transformer;
import android.content.Context;
import android.os.Looper;
import androidx.media3.common.Format;
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;
/**
* Provides media data to a {@linkplain Transformer}.
@ -30,6 +36,82 @@ import androidx.media3.common.util.UnstableApi;
@UnstableApi
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).
*
* <p>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).
*
* <p>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.
*
* <p>The audio samples are flattened after they are output by the {@link AssetLoader}, because
* this is done on decoded samples.
*
* <p>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.
*
* <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}.
*/
AssetLoader createAssetLoader();
}
/**
* A listener of asset loader events.
*

View file

@ -0,0 +1,129 @@
/*
* 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 androidx.media3.transformer;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
import android.content.Context;
import android.os.Looper;
import androidx.annotation.Nullable;
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
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));
}
}

View file

@ -92,6 +92,7 @@ public final class Transformer {
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;
private FrameProcessor.Factory frameProcessorFactory;
@ -110,6 +111,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();
@ -131,6 +133,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;
@ -306,6 +309,20 @@ public final class Transformer {
return this;
}
/**
* Sets the {@link AssetLoader.Factory} to be used to retrieve the samples to transform.
*
* <p>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.
*
@ -478,6 +495,7 @@ public final class Transformer {
forceSilentAudio,
listeners,
mediaSourceFactory,
assetLoaderFactory,
decoderFactory,
encoderFactory,
frameProcessorFactory,
@ -591,6 +609,7 @@ public final class Transformer {
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;
private final Looper looper;
@ -609,6 +628,7 @@ public final class Transformer {
boolean forceSilentAudio,
ListenerSet<Listener> listeners,
MediaSource.Factory mediaSourceFactory,
AssetLoader.Factory assetLoaderFactory,
Codec.DecoderFactory decoderFactory,
Codec.EncoderFactory encoderFactory,
FrameProcessor.Factory frameProcessorFactory,
@ -630,6 +650,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;
@ -772,6 +793,7 @@ public final class Transformer {
removeVideo,
forceSilentAudio,
mediaSourceFactory,
assetLoaderFactory,
decoderFactory,
encoderFactory,
frameProcessorFactory,

View file

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