add media item based playlist methods

After this change users of ExoPlayerImpl and SimpleExoPlayer can use the media item base playlist API which converts the media item to a media source.

It adds the media item based methods to the ExoPlayer instead of the Player interface. This avoids a big change in the CastPlayer which requires migrating the cast extension to the MediaItem of the core module (follow up CLs).

PiperOrigin-RevId: 300575567
This commit is contained in:
bachinger 2020-03-12 17:29:47 +00:00 committed by Oliver Woodman
parent 1e387601a6
commit 2028fdd756
5 changed files with 332 additions and 13 deletions

View file

@ -24,8 +24,10 @@ import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer;
import com.google.android.exoplayer2.metadata.MetadataRenderer;
import com.google.android.exoplayer2.source.ClippingMediaSource;
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
import com.google.android.exoplayer2.source.LoopingMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSourceFactory;
import com.google.android.exoplayer2.source.MergingMediaSource;
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.source.ShuffleOrder;
@ -138,6 +140,7 @@ public interface ExoPlayer extends Player {
private Clock clock;
private TrackSelector trackSelector;
private MediaSourceFactory mediaSourceFactory;
private LoadControl loadControl;
private BandwidthMeter bandwidthMeter;
private Looper looper;
@ -154,6 +157,7 @@ public interface ExoPlayer extends Player {
*
* <ul>
* <li>{@link TrackSelector}: {@link DefaultTrackSelector}
* <li>{@link MediaSourceFactory}: {@link DefaultMediaSourceFactory}
* <li>{@link LoadControl}: {@link DefaultLoadControl}
* <li>{@link BandwidthMeter}: {@link DefaultBandwidthMeter#getSingletonInstance(Context)}
* <li>{@link Looper}: The {@link Looper} associated with the current thread, or the {@link
@ -171,6 +175,7 @@ public interface ExoPlayer extends Player {
this(
renderers,
new DefaultTrackSelector(context),
DefaultMediaSourceFactory.newInstance(context),
new DefaultLoadControl(),
DefaultBandwidthMeter.getSingletonInstance(context),
Util.getLooper(),
@ -188,6 +193,7 @@ public interface ExoPlayer extends Player {
*
* @param renderers The {@link Renderer Renderers} to be used by the player.
* @param trackSelector A {@link TrackSelector}.
* @param mediaSourceFactory A {@link MediaSourceFactory}.
* @param loadControl A {@link LoadControl}.
* @param bandwidthMeter A {@link BandwidthMeter}.
* @param looper A {@link Looper} that must be used for all calls to the player.
@ -198,6 +204,7 @@ public interface ExoPlayer extends Player {
public Builder(
Renderer[] renderers,
TrackSelector trackSelector,
MediaSourceFactory mediaSourceFactory,
LoadControl loadControl,
BandwidthMeter bandwidthMeter,
Looper looper,
@ -207,6 +214,7 @@ public interface ExoPlayer extends Player {
Assertions.checkArgument(renderers.length > 0);
this.renderers = renderers;
this.trackSelector = trackSelector;
this.mediaSourceFactory = mediaSourceFactory;
this.loadControl = loadControl;
this.bandwidthMeter = bandwidthMeter;
this.looper = looper;
@ -243,6 +251,19 @@ public interface ExoPlayer extends Player {
return this;
}
/**
* Sets the {@link MediaSourceFactory} that will be used by the player.
*
* @param mediaSourceFactory A {@link MediaSourceFactory}.
* @return This builder.
* @throws IllegalStateException If {@link #build()} has already been called.
*/
public Builder setMediaSourceFactory(MediaSourceFactory mediaSourceFactory) {
Assertions.checkState(!buildCalled);
this.mediaSourceFactory = mediaSourceFactory;
return this;
}
/**
* Sets the {@link LoadControl} that will be used by the player.
*
@ -331,7 +352,7 @@ public interface ExoPlayer extends Player {
/**
* Builds an {@link ExoPlayer} instance.
*
* @throws IllegalStateException If {@link #build()} has already been called.
* @throws IllegalStateException If {@code build} has already been called.
*/
public ExoPlayer build() {
Assertions.checkState(!buildCalled);
@ -340,6 +361,7 @@ public interface ExoPlayer extends Player {
new ExoPlayerImpl(
renderers,
trackSelector,
mediaSourceFactory,
loadControl,
bandwidthMeter,
analyticsCollector,
@ -362,9 +384,6 @@ public interface ExoPlayer extends Player {
@Deprecated
void retry();
/** Prepares the player. */
void prepare();
/** @deprecated Use {@link #setMediaSource(MediaSource)} and {@link #prepare()} instead. */
@Deprecated
void prepare(MediaSource mediaSource);
@ -375,6 +394,9 @@ public interface ExoPlayer extends Player {
@Deprecated
void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState);
/** Prepares the player. */
void prepare();
/**
* Clears the playlist, adds the specified {@link MediaSource MediaSources} and resets the
* position to the default position.
@ -462,6 +484,93 @@ public interface ExoPlayer extends Player {
*/
void addMediaSources(int index, List<MediaSource> mediaSources);
/**
* Clears the playlist, adds the specified {@link MediaItem MediaItems} and resets the position to
* the default position.
*
* @param mediaItems The new {@link MediaItem MediaItems}.
*/
void setMediaItems(List<MediaItem> mediaItems);
/**
* Clears the playlist and adds the specified {@link MediaItem MediaItems}.
*
* @param mediaItems The new {@link MediaItem MediaItems}.
* @param resetPosition Whether the playback position should be reset to the default position in
* the first {@link Timeline.Window}. If false, playback will start from the position defined
* by {@link #getCurrentWindowIndex()} and {@link #getCurrentPosition()}.
*/
void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition);
/**
* Clears the playlist and adds the specified {@link MediaItem MediaItems}.
*
* @param mediaItems The new {@link MediaItem MediaItems}.
* @param startWindowIndex The window index to start playback from. If {@link C#INDEX_UNSET} is
* passed, the current position is not reset.
* @param startPositionMs The position in milliseconds to start playback from. If {@link
* C#TIME_UNSET} is passed, the default position of the given window is used. In any case, if
* {@code startWindowIndex} is set to {@link C#INDEX_UNSET}, this parameter is ignored and the
* position is not reset at all.
*/
void setMediaItems(List<MediaItem> mediaItems, int startWindowIndex, long startPositionMs);
/**
* Clears the playlist, adds the specified {@link MediaItem} and resets the position to the
* default position.
*
* @param mediaItem The new {@link MediaItem}.
*/
void setMediaItem(MediaItem mediaItem);
/**
* Clears the playlist and adds the specified {@link MediaItem}.
*
* @param mediaItem The new {@link MediaItem}.
* @param startPositionMs The position in milliseconds to start playback from.
*/
void setMediaItem(MediaItem mediaItem, long startPositionMs);
/**
* Clears the playlist and adds the specified {@link MediaItem}.
*
* @param mediaItem The new {@link MediaItem}.
* @param resetPosition Whether the playback position should be reset to the default position. If
* false, playback will start from the position defined by {@link #getCurrentWindowIndex()}
* and {@link #getCurrentPosition()}.
*/
void setMediaItem(MediaItem mediaItem, boolean resetPosition);
/**
* Adds a media item to the end of the playlist.
*
* @param mediaItem The {@link MediaItem} to add.
*/
void addMediaItem(MediaItem mediaItem);
/**
* Adds a media item at the given index of the playlist.
*
* @param index The index at which to add the item.
* @param mediaItem The {@link MediaItem} to add.
*/
void addMediaItem(int index, MediaItem mediaItem);
/**
* Adds a list of media items to the end of the playlist.
*
* @param mediaItems The {@link MediaItem MediaItems} to add.
*/
void addMediaItems(List<MediaItem> mediaItems);
/**
* Adds a list of media items at the given index of the playlist.
*
* @param index The index at which to add the media items.
* @param mediaItems The {@link MediaItem MediaItems} to add.
*/
void addMediaItems(int index, List<MediaItem> mediaItems);
/**
* Moves the media item at the current index to the new index.
*

View file

@ -18,6 +18,7 @@ package com.google.android.exoplayer2;
import android.content.Context;
import android.os.Looper;
import com.google.android.exoplayer2.analytics.AnalyticsCollector;
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
@ -197,6 +198,7 @@ public final class ExoPlayerFactory {
context,
renderersFactory,
trackSelector,
DefaultMediaSourceFactory.newInstance(context),
loadControl,
bandwidthMeter,
analyticsCollector,
@ -251,6 +253,7 @@ public final class ExoPlayerFactory {
return new ExoPlayerImpl(
renderers,
trackSelector,
DefaultMediaSourceFactory.newInstance(context),
loadControl,
bandwidthMeter,
/* analyticsCollector= */ null,

View file

@ -25,6 +25,7 @@ import com.google.android.exoplayer2.PlayerMessage.Target;
import com.google.android.exoplayer2.analytics.AnalyticsCollector;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.MediaSourceFactory;
import com.google.android.exoplayer2.source.ShuffleOrder;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.TrackSelection;
@ -69,6 +70,7 @@ import java.util.concurrent.TimeoutException;
private final ArrayDeque<Runnable> pendingListenerNotifications;
private final List<Playlist.MediaSourceHolder> mediaSourceHolders;
private final boolean useLazyPreparation;
private final MediaSourceFactory mediaSourceFactory;
@RepeatMode private int repeatMode;
private boolean shuffleModeEnabled;
@ -95,15 +97,16 @@ import java.util.concurrent.TimeoutException;
/**
* Constructs an instance. Must be called from a thread that has an associated {@link Looper}.
*
* @param renderers The {@link Renderer}s that will be used by the instance.
* @param trackSelector The {@link TrackSelector} that will be used by the instance.
* @param loadControl The {@link LoadControl} that will be used by the instance.
* @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance.
* @param analyticsCollector The {@link AnalyticsCollector} that will be used by the instance.
* @param renderers The {@link Renderer}s.
* @param trackSelector The {@link TrackSelector}.
* @param mediaSourceFactory The {@link MediaSourceFactory}.
* @param loadControl The {@link LoadControl}.
* @param bandwidthMeter The {@link BandwidthMeter}.
* @param analyticsCollector The {@link AnalyticsCollector}.
* @param useLazyPreparation Whether playlist items are prepared lazily. If false, all manifest
* loads and other initial preparation steps happen immediately. If true, these initial
* preparations are triggered only when the player starts buffering the media.
* @param clock The {@link Clock} that will be used by the instance.
* @param clock The {@link Clock}.
* @param looper The {@link Looper} which must be used for all calls to the player and which is
* used to call listeners on.
*/
@ -111,6 +114,7 @@ import java.util.concurrent.TimeoutException;
public ExoPlayerImpl(
Renderer[] renderers,
TrackSelector trackSelector,
MediaSourceFactory mediaSourceFactory,
LoadControl loadControl,
BandwidthMeter bandwidthMeter,
@Nullable AnalyticsCollector analyticsCollector,
@ -122,6 +126,7 @@ import java.util.concurrent.TimeoutException;
Assertions.checkState(renderers.length > 0);
this.renderers = Assertions.checkNotNull(renderers);
this.trackSelector = Assertions.checkNotNull(trackSelector);
this.mediaSourceFactory = mediaSourceFactory;
this.useLazyPreparation = useLazyPreparation;
repeatMode = Player.REPEAT_MODE_OFF;
listeners = new CopyOnWriteArrayList<>();
@ -306,6 +311,37 @@ import java.util.concurrent.TimeoutException;
prepare();
}
@Override
public void setMediaItem(MediaItem mediaItem) {
setMediaItems(Collections.singletonList(mediaItem));
}
@Override
public void setMediaItem(MediaItem mediaItem, long startPositionMs) {
setMediaItems(Collections.singletonList(mediaItem), /* startWindowIndex= */ 0, startPositionMs);
}
@Override
public void setMediaItem(MediaItem mediaItem, boolean resetPosition) {
setMediaItems(Collections.singletonList(mediaItem), resetPosition);
}
@Override
public void setMediaItems(List<MediaItem> mediaItems) {
setMediaItems(mediaItems, /* resetPosition= */ true);
}
@Override
public void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition) {
setMediaSources(createMediaSources(mediaItems), resetPosition);
}
@Override
public void setMediaItems(
List<MediaItem> mediaItems, int startWindowIndex, long startPositionMs) {
setMediaSources(createMediaSources(mediaItems), startWindowIndex, startPositionMs);
}
@Override
public void setMediaSource(MediaSource mediaSource) {
setMediaSources(Collections.singletonList(mediaSource));
@ -329,7 +365,7 @@ import java.util.concurrent.TimeoutException;
@Override
public void setMediaSources(List<MediaSource> mediaSources, boolean resetPosition) {
setMediaItemsInternal(
setMediaSourcesInternal(
mediaSources,
/* startWindowIndex= */ C.INDEX_UNSET,
/* startPositionMs= */ C.TIME_UNSET,
@ -339,10 +375,30 @@ import java.util.concurrent.TimeoutException;
@Override
public void setMediaSources(
List<MediaSource> mediaSources, int startWindowIndex, long startPositionMs) {
setMediaItemsInternal(
setMediaSourcesInternal(
mediaSources, startWindowIndex, startPositionMs, /* resetToDefaultPosition= */ false);
}
@Override
public void addMediaItem(int index, MediaItem mediaItem) {
addMediaItems(index, Collections.singletonList(mediaItem));
}
@Override
public void addMediaItem(MediaItem mediaItem) {
addMediaItems(Collections.singletonList(mediaItem));
}
@Override
public void addMediaItems(List<MediaItem> mediaItems) {
addMediaItems(/* index= */ mediaSourceHolders.size(), mediaItems);
}
@Override
public void addMediaItems(int index, List<MediaItem> mediaItems) {
addMediaSources(index, createMediaSources(mediaItems));
}
@Override
public void addMediaSource(MediaSource mediaSource) {
addMediaSources(Collections.singletonList(mediaSource));
@ -816,6 +872,14 @@ import java.util.concurrent.TimeoutException;
}
}
private List<MediaSource> createMediaSources(List<MediaItem> mediaItems) {
List<MediaSource> mediaSources = new ArrayList<>();
for (int i = 0; i < mediaItems.size(); i++) {
mediaSources.add(mediaSourceFactory.createMediaSource(mediaItems.get(i)));
}
return mediaSources;
}
@SuppressWarnings("deprecation")
private void handlePlaybackSpeed(float playbackSpeed, boolean operationAck) {
if (operationAck) {
@ -923,7 +987,7 @@ import java.util.concurrent.TimeoutException;
}
@SuppressWarnings("deprecation")
private void setMediaItemsInternal(
private void setMediaSourcesInternal(
List<MediaSource> mediaItems,
int startWindowIndex,
long startPositionMs,

View file

@ -38,7 +38,9 @@ import com.google.android.exoplayer2.audio.AuxEffectInfo;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.metadata.Metadata;
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.source.MediaSourceFactory;
import com.google.android.exoplayer2.source.ShuffleOrder;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.text.Cue;
@ -89,6 +91,7 @@ public class SimpleExoPlayer extends BasePlayer
private Clock clock;
private TrackSelector trackSelector;
private MediaSourceFactory mediaSourceFactory;
private LoadControl loadControl;
private BandwidthMeter bandwidthMeter;
private AnalyticsCollector analyticsCollector;
@ -108,6 +111,7 @@ public class SimpleExoPlayer extends BasePlayer
* <ul>
* <li>{@link RenderersFactory}: {@link DefaultRenderersFactory}
* <li>{@link TrackSelector}: {@link DefaultTrackSelector}
* <li>{@link MediaSourceFactory}: {@link DefaultMediaSourceFactory}
* <li>{@link LoadControl}: {@link DefaultLoadControl}
* <li>{@link BandwidthMeter}: {@link DefaultBandwidthMeter#getSingletonInstance(Context)}
* <li>{@link Looper}: The {@link Looper} associated with the current thread, or the {@link
@ -138,6 +142,7 @@ public class SimpleExoPlayer extends BasePlayer
context,
renderersFactory,
new DefaultTrackSelector(context),
DefaultMediaSourceFactory.newInstance(context),
new DefaultLoadControl(),
DefaultBandwidthMeter.getSingletonInstance(context),
Util.getLooper(),
@ -157,6 +162,7 @@ public class SimpleExoPlayer extends BasePlayer
* @param renderersFactory A factory for creating {@link Renderer Renderers} to be used by the
* player.
* @param trackSelector A {@link TrackSelector}.
* @param mediaSourceFactory A {@link MediaSourceFactory}.
* @param loadControl A {@link LoadControl}.
* @param bandwidthMeter A {@link BandwidthMeter}.
* @param looper A {@link Looper} that must be used for all calls to the player.
@ -170,6 +176,7 @@ public class SimpleExoPlayer extends BasePlayer
Context context,
RenderersFactory renderersFactory,
TrackSelector trackSelector,
MediaSourceFactory mediaSourceFactory,
LoadControl loadControl,
BandwidthMeter bandwidthMeter,
Looper looper,
@ -179,6 +186,7 @@ public class SimpleExoPlayer extends BasePlayer
this.context = context;
this.renderersFactory = renderersFactory;
this.trackSelector = trackSelector;
this.mediaSourceFactory = mediaSourceFactory;
this.loadControl = loadControl;
this.bandwidthMeter = bandwidthMeter;
this.looper = looper;
@ -200,6 +208,19 @@ public class SimpleExoPlayer extends BasePlayer
return this;
}
/**
* Sets the {@link MediaSourceFactory} that will be used by the player.
*
* @param mediaSourceFactory A {@link MediaSourceFactory}.
* @return This builder.
* @throws IllegalStateException If {@link #build()} has already been called.
*/
public Builder setMediaSourceFactory(MediaSourceFactory mediaSourceFactory) {
Assertions.checkState(!buildCalled);
this.mediaSourceFactory = mediaSourceFactory;
return this;
}
/**
* Sets the {@link LoadControl} that will be used by the player.
*
@ -350,6 +371,7 @@ public class SimpleExoPlayer extends BasePlayer
builder.context,
builder.renderersFactory,
builder.trackSelector,
builder.mediaSourceFactory,
builder.loadControl,
builder.bandwidthMeter,
builder.analyticsCollector,
@ -378,6 +400,7 @@ public class SimpleExoPlayer extends BasePlayer
Context context,
RenderersFactory renderersFactory,
TrackSelector trackSelector,
MediaSourceFactory mediaSourceFactory,
LoadControl loadControl,
BandwidthMeter bandwidthMeter,
AnalyticsCollector analyticsCollector,
@ -414,6 +437,7 @@ public class SimpleExoPlayer extends BasePlayer
new ExoPlayerImpl(
renderers,
trackSelector,
mediaSourceFactory,
loadControl,
bandwidthMeter,
analyticsCollector,
@ -1231,6 +1255,49 @@ public class SimpleExoPlayer extends BasePlayer
prepare();
}
@Override
public void setMediaItems(List<MediaItem> mediaItems) {
verifyApplicationThread();
analyticsCollector.resetForNewPlaylist();
player.setMediaItems(mediaItems);
}
@Override
public void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition) {
verifyApplicationThread();
analyticsCollector.resetForNewPlaylist();
player.setMediaItems(mediaItems, resetPosition);
}
@Override
public void setMediaItems(
List<MediaItem> mediaItems, int startWindowIndex, long startPositionMs) {
verifyApplicationThread();
analyticsCollector.resetForNewPlaylist();
player.setMediaItems(mediaItems, startWindowIndex, startPositionMs);
}
@Override
public void setMediaItem(MediaItem mediaItem) {
verifyApplicationThread();
analyticsCollector.resetForNewPlaylist();
player.setMediaItem(mediaItem);
}
@Override
public void setMediaItem(MediaItem mediaItem, boolean resetPosition) {
verifyApplicationThread();
analyticsCollector.resetForNewPlaylist();
player.setMediaItem(mediaItem, resetPosition);
}
@Override
public void setMediaItem(MediaItem mediaItem, long startPositionMs) {
verifyApplicationThread();
analyticsCollector.resetForNewPlaylist();
player.setMediaItem(mediaItem, startPositionMs);
}
@Override
public void setMediaSources(List<MediaSource> mediaSources) {
verifyApplicationThread();
@ -1274,6 +1341,30 @@ public class SimpleExoPlayer extends BasePlayer
player.setMediaSource(mediaSource, startPositionMs);
}
@Override
public void addMediaItems(List<MediaItem> mediaItems) {
verifyApplicationThread();
player.addMediaItems(mediaItems);
}
@Override
public void addMediaItems(int index, List<MediaItem> mediaItems) {
verifyApplicationThread();
player.addMediaItems(index, mediaItems);
}
@Override
public void addMediaItem(MediaItem mediaItem) {
verifyApplicationThread();
player.addMediaItem(mediaItem);
}
@Override
public void addMediaItem(int index, MediaItem mediaItem) {
verifyApplicationThread();
player.addMediaItem(index, mediaItem);
}
@Override
public void addMediaSource(MediaSource mediaSource) {
verifyApplicationThread();

View file

@ -20,6 +20,7 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.BasePlayer;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.PlayerMessage;
@ -135,6 +136,37 @@ public abstract class StubExoPlayer extends BasePlayer implements ExoPlayer {
throw new UnsupportedOperationException();
}
@Override
public void setMediaItem(MediaItem mediaItem) {
throw new UnsupportedOperationException();
}
@Override
public void setMediaItem(MediaItem mediaItem, long startPositionMs) {
throw new UnsupportedOperationException();
}
@Override
public void setMediaItem(MediaItem mediaItem, boolean resetPosition) {
throw new UnsupportedOperationException();
}
@Override
public void setMediaItems(List<MediaItem> mediaItems) {
throw new UnsupportedOperationException();
}
@Override
public void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition) {
throw new UnsupportedOperationException();
}
@Override
public void setMediaItems(
List<MediaItem> mediaItems, int startWindowIndex, long startPositionMs) {
throw new UnsupportedOperationException();
}
@Override
public void setMediaSource(MediaSource mediaSource) {
throw new UnsupportedOperationException();
@ -166,6 +198,26 @@ public abstract class StubExoPlayer extends BasePlayer implements ExoPlayer {
throw new UnsupportedOperationException();
}
@Override
public void addMediaItem(MediaItem mediaItem) {
throw new UnsupportedOperationException();
}
@Override
public void addMediaItem(int index, MediaItem mediaItem) {
throw new UnsupportedOperationException();
}
@Override
public void addMediaItems(List<MediaItem> mediaItems) {
throw new UnsupportedOperationException();
}
@Override
public void addMediaItems(int index, List<MediaItem> mediaItems) {
throw new UnsupportedOperationException();
}
@Override
public void addMediaSource(MediaSource mediaSource) {
throw new UnsupportedOperationException();