mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add custom MediaSource.Factory
attribute to CompositionPlayer
Introduced a `mediaSourceFactory` attribute to CompositionPlayer. This allows for the use of a custom MediaSource.Factory when creating media sources, providing more flexibility and control over media source creation. Previously, the default `MediaSource.Factory` was used in all cases. PiperOrigin-RevId: 700391911
This commit is contained in:
parent
96c35966d8
commit
d5d5771cd2
@ -54,7 +54,9 @@ import androidx.media3.exoplayer.RendererCapabilities;
|
|||||||
import androidx.media3.exoplayer.image.BitmapFactoryImageDecoder;
|
import androidx.media3.exoplayer.image.BitmapFactoryImageDecoder;
|
||||||
import androidx.media3.exoplayer.image.ImageDecoder;
|
import androidx.media3.exoplayer.image.ImageDecoder;
|
||||||
import androidx.media3.exoplayer.image.ImageDecoderException;
|
import androidx.media3.exoplayer.image.ImageDecoderException;
|
||||||
|
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
|
||||||
import androidx.media3.exoplayer.source.ExternalLoader;
|
import androidx.media3.exoplayer.source.ExternalLoader;
|
||||||
|
import androidx.media3.exoplayer.source.MediaSource;
|
||||||
import androidx.media3.test.utils.TestSpeedProvider;
|
import androidx.media3.test.utils.TestSpeedProvider;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||||
@ -264,12 +266,15 @@ public class CompositionPlayerTest {
|
|||||||
PlayerTestListener listener = new PlayerTestListener(TEST_TIMEOUT_MS);
|
PlayerTestListener listener = new PlayerTestListener(TEST_TIMEOUT_MS);
|
||||||
ExternalLoader externalImageLoader =
|
ExternalLoader externalImageLoader =
|
||||||
loadRequest -> immediateFuture(Util.getUtf8Bytes(loadRequest.uri.toString()));
|
loadRequest -> immediateFuture(Util.getUtf8Bytes(loadRequest.uri.toString()));
|
||||||
|
MediaSource.Factory mediaSourceFactory =
|
||||||
|
new DefaultMediaSourceFactory(applicationContext)
|
||||||
|
.setExternalImageLoader(externalImageLoader);
|
||||||
|
|
||||||
instrumentation.runOnMainSync(
|
instrumentation.runOnMainSync(
|
||||||
() -> {
|
() -> {
|
||||||
compositionPlayer =
|
compositionPlayer =
|
||||||
new CompositionPlayer.Builder(applicationContext)
|
new CompositionPlayer.Builder(applicationContext)
|
||||||
.setExternalImageLoader(externalImageLoader)
|
.setMediaSourceFactory(mediaSourceFactory)
|
||||||
.setImageDecoderFactory(new TestImageDecoderFactory())
|
.setImageDecoderFactory(new TestImageDecoderFactory())
|
||||||
.build();
|
.build();
|
||||||
// Set a surface on the player even though there is no UI on this test. We need a surface
|
// Set a surface on the player even though there is no UI on this test. We need a surface
|
||||||
|
@ -37,7 +37,6 @@ import androidx.annotation.VisibleForTesting;
|
|||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.Effect;
|
import androidx.media3.common.Effect;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
import androidx.media3.common.MimeTypes;
|
|
||||||
import androidx.media3.common.PlaybackException;
|
import androidx.media3.common.PlaybackException;
|
||||||
import androidx.media3.common.Player;
|
import androidx.media3.common.Player;
|
||||||
import androidx.media3.common.PreviewingVideoGraph;
|
import androidx.media3.common.PreviewingVideoGraph;
|
||||||
@ -63,7 +62,6 @@ import androidx.media3.exoplayer.image.ImageDecoder;
|
|||||||
import androidx.media3.exoplayer.source.ClippingMediaSource;
|
import androidx.media3.exoplayer.source.ClippingMediaSource;
|
||||||
import androidx.media3.exoplayer.source.ConcatenatingMediaSource2;
|
import androidx.media3.exoplayer.source.ConcatenatingMediaSource2;
|
||||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
|
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
|
||||||
import androidx.media3.exoplayer.source.ExternalLoader;
|
|
||||||
import androidx.media3.exoplayer.source.FilteringMediaSource;
|
import androidx.media3.exoplayer.source.FilteringMediaSource;
|
||||||
import androidx.media3.exoplayer.source.ForwardingTimeline;
|
import androidx.media3.exoplayer.source.ForwardingTimeline;
|
||||||
import androidx.media3.exoplayer.source.MediaPeriod;
|
import androidx.media3.exoplayer.source.MediaPeriod;
|
||||||
@ -118,7 +116,7 @@ public final class CompositionPlayer extends SimpleBasePlayer
|
|||||||
|
|
||||||
private @MonotonicNonNull Looper looper;
|
private @MonotonicNonNull Looper looper;
|
||||||
private @MonotonicNonNull AudioSink audioSink;
|
private @MonotonicNonNull AudioSink audioSink;
|
||||||
private @MonotonicNonNull ExternalLoader externalImageLoader;
|
private MediaSource.Factory mediaSourceFactory;
|
||||||
private ImageDecoder.Factory imageDecoderFactory;
|
private ImageDecoder.Factory imageDecoderFactory;
|
||||||
private Clock clock;
|
private Clock clock;
|
||||||
private PreviewingVideoGraph.@MonotonicNonNull Factory previewingVideoGraphFactory;
|
private PreviewingVideoGraph.@MonotonicNonNull Factory previewingVideoGraphFactory;
|
||||||
@ -131,6 +129,7 @@ public final class CompositionPlayer extends SimpleBasePlayer
|
|||||||
*/
|
*/
|
||||||
public Builder(Context context) {
|
public Builder(Context context) {
|
||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
|
mediaSourceFactory = new DefaultMediaSourceFactory(context);
|
||||||
imageDecoderFactory = ImageDecoder.Factory.DEFAULT;
|
imageDecoderFactory = ImageDecoder.Factory.DEFAULT;
|
||||||
clock = Clock.DEFAULT;
|
clock = Clock.DEFAULT;
|
||||||
}
|
}
|
||||||
@ -165,20 +164,19 @@ public final class CompositionPlayer extends SimpleBasePlayer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@link ExternalLoader} for loading image media items with MIME type set to {@link
|
* Sets the {@link MediaSource.Factory} that *creates* the {@link MediaSource} for {@link
|
||||||
* MimeTypes#APPLICATION_EXTERNALLY_LOADED_IMAGE}. When setting an external loader, also set an
|
* EditedMediaItem#mediaItem MediaItems} in a {@link Composition}.
|
||||||
* {@link ImageDecoder.Factory} with {@link #setImageDecoderFactory(ImageDecoder.Factory)}.
|
|
||||||
*
|
*
|
||||||
* <p>By default, the player will not be able to load images with media type of {@link
|
* <p>To use an external image loader, one could create a {@link DefaultMediaSourceFactory},
|
||||||
* androidx.media3.common.MimeTypes#APPLICATION_EXTERNALLY_LOADED_IMAGE}.
|
* {@linkplain DefaultMediaSourceFactory#setExternalImageLoader set the external image loader},
|
||||||
|
* and pass in the {@link DefaultMediaSourceFactory} here.
|
||||||
*
|
*
|
||||||
* @param externalImageLoader The {@link ExternalLoader}.
|
* @param mediaSourceFactory The {@link MediaSource.Factory}
|
||||||
* @return This builder, for convenience.
|
* @return This builder, for convenience.
|
||||||
* @see DefaultMediaSourceFactory#setExternalImageLoader(ExternalLoader)
|
|
||||||
*/
|
*/
|
||||||
@CanIgnoreReturnValue
|
@CanIgnoreReturnValue
|
||||||
public Builder setExternalImageLoader(ExternalLoader externalImageLoader) {
|
public Builder setMediaSourceFactory(MediaSource.Factory mediaSourceFactory) {
|
||||||
this.externalImageLoader = externalImageLoader;
|
this.mediaSourceFactory = mediaSourceFactory;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,7 +285,7 @@ public final class CompositionPlayer extends SimpleBasePlayer
|
|||||||
private final HandlerWrapper applicationHandler;
|
private final HandlerWrapper applicationHandler;
|
||||||
private final List<ExoPlayer> players;
|
private final List<ExoPlayer> players;
|
||||||
private final AudioSink finalAudioSink;
|
private final AudioSink finalAudioSink;
|
||||||
@Nullable private final ExternalLoader externalImageLoader;
|
private final MediaSource.Factory mediaSourceFactory;
|
||||||
private final ImageDecoder.Factory imageDecoderFactory;
|
private final ImageDecoder.Factory imageDecoderFactory;
|
||||||
private final PreviewingVideoGraph.Factory previewingVideoGraphFactory;
|
private final PreviewingVideoGraph.Factory previewingVideoGraphFactory;
|
||||||
private final HandlerWrapper compositionInternalListenerHandler;
|
private final HandlerWrapper compositionInternalListenerHandler;
|
||||||
@ -316,7 +314,7 @@ public final class CompositionPlayer extends SimpleBasePlayer
|
|||||||
clock = builder.clock;
|
clock = builder.clock;
|
||||||
applicationHandler = clock.createHandler(builder.looper, /* callback= */ null);
|
applicationHandler = clock.createHandler(builder.looper, /* callback= */ null);
|
||||||
finalAudioSink = checkNotNull(builder.audioSink);
|
finalAudioSink = checkNotNull(builder.audioSink);
|
||||||
externalImageLoader = builder.externalImageLoader;
|
mediaSourceFactory = builder.mediaSourceFactory;
|
||||||
imageDecoderFactory = builder.imageDecoderFactory;
|
imageDecoderFactory = builder.imageDecoderFactory;
|
||||||
previewingVideoGraphFactory = checkNotNull(builder.previewingVideoGraphFactory);
|
previewingVideoGraphFactory = checkNotNull(builder.previewingVideoGraphFactory);
|
||||||
compositionInternalListenerHandler = clock.createHandler(builder.looper, /* callback= */ null);
|
compositionInternalListenerHandler = clock.createHandler(builder.looper, /* callback= */ null);
|
||||||
@ -750,10 +748,6 @@ public final class CompositionPlayer extends SimpleBasePlayer
|
|||||||
|
|
||||||
private void setPrimaryPlayerSequence(ExoPlayer player, EditedMediaItemSequence sequence) {
|
private void setPrimaryPlayerSequence(ExoPlayer player, EditedMediaItemSequence sequence) {
|
||||||
ConcatenatingMediaSource2.Builder mediaSourceBuilder = new ConcatenatingMediaSource2.Builder();
|
ConcatenatingMediaSource2.Builder mediaSourceBuilder = new ConcatenatingMediaSource2.Builder();
|
||||||
DefaultMediaSourceFactory defaultMediaSourceFactory = new DefaultMediaSourceFactory(context);
|
|
||||||
if (externalImageLoader != null) {
|
|
||||||
defaultMediaSourceFactory.setExternalImageLoader(externalImageLoader);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < sequence.editedMediaItems.size(); i++) {
|
for (int i = 0; i < sequence.editedMediaItems.size(); i++) {
|
||||||
EditedMediaItem editedMediaItem = sequence.editedMediaItems.get(i);
|
EditedMediaItem editedMediaItem = sequence.editedMediaItems.get(i);
|
||||||
@ -767,8 +761,7 @@ public final class CompositionPlayer extends SimpleBasePlayer
|
|||||||
editedMediaItem.mediaItem.clippingConfiguration.endPositionUs);
|
editedMediaItem.mediaItem.clippingConfiguration.endPositionUs);
|
||||||
|
|
||||||
// The MediaSource that loads the MediaItem
|
// The MediaSource that loads the MediaItem
|
||||||
MediaSource mainMediaSource =
|
MediaSource mainMediaSource = mediaSourceFactory.createMediaSource(editedMediaItem.mediaItem);
|
||||||
defaultMediaSourceFactory.createMediaSource(editedMediaItem.mediaItem);
|
|
||||||
if (editedMediaItem.removeAudio) {
|
if (editedMediaItem.removeAudio) {
|
||||||
mainMediaSource =
|
mainMediaSource =
|
||||||
new FilteringMediaSource(
|
new FilteringMediaSource(
|
||||||
@ -791,7 +784,6 @@ public final class CompositionPlayer extends SimpleBasePlayer
|
|||||||
// TODO: b/331392198 - Repeat only looping sequences, after sequences can be of arbitrary
|
// TODO: b/331392198 - Repeat only looping sequences, after sequences can be of arbitrary
|
||||||
// length.
|
// length.
|
||||||
ConcatenatingMediaSource2.Builder mediaSourceBuilder = new ConcatenatingMediaSource2.Builder();
|
ConcatenatingMediaSource2.Builder mediaSourceBuilder = new ConcatenatingMediaSource2.Builder();
|
||||||
DefaultMediaSourceFactory defaultMediaSourceFactory = new DefaultMediaSourceFactory(context);
|
|
||||||
|
|
||||||
long accumulatedDurationUs = 0;
|
long accumulatedDurationUs = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@ -801,7 +793,7 @@ public final class CompositionPlayer extends SimpleBasePlayer
|
|||||||
MediaItem mediaItem = editedMediaItem.mediaItem;
|
MediaItem mediaItem = editedMediaItem.mediaItem;
|
||||||
if (accumulatedDurationUs + itemPresentationDurationUs <= primarySequenceDurationUs) {
|
if (accumulatedDurationUs + itemPresentationDurationUs <= primarySequenceDurationUs) {
|
||||||
mediaSourceBuilder.add(
|
mediaSourceBuilder.add(
|
||||||
defaultMediaSourceFactory.createMediaSource(mediaItem),
|
mediaSourceFactory.createMediaSource(mediaItem),
|
||||||
/* initialPlaceholderDurationMs= */ usToMs(itemPresentationDurationUs));
|
/* initialPlaceholderDurationMs= */ usToMs(itemPresentationDurationUs));
|
||||||
accumulatedDurationUs += itemPresentationDurationUs;
|
accumulatedDurationUs += itemPresentationDurationUs;
|
||||||
} else {
|
} else {
|
||||||
@ -809,7 +801,7 @@ public final class CompositionPlayer extends SimpleBasePlayer
|
|||||||
// TODO: b/289989542 - Handle already clipped, or speed adjusted media.
|
// TODO: b/289989542 - Handle already clipped, or speed adjusted media.
|
||||||
mediaSourceBuilder.add(
|
mediaSourceBuilder.add(
|
||||||
new ClippingMediaSource(
|
new ClippingMediaSource(
|
||||||
defaultMediaSourceFactory.createMediaSource(mediaItem),
|
mediaSourceFactory.createMediaSource(mediaItem),
|
||||||
mediaItem.clippingConfiguration.startPositionUs,
|
mediaItem.clippingConfiguration.startPositionUs,
|
||||||
mediaItem.clippingConfiguration.startPositionUs + remainingDurationUs),
|
mediaItem.clippingConfiguration.startPositionUs + remainingDurationUs),
|
||||||
/* initialPlaceholderDurationMs= */ usToMs(remainingDurationUs));
|
/* initialPlaceholderDurationMs= */ usToMs(remainingDurationUs));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user