Make use of MediaItem in ProgressiveMediaSource

PiperOrigin-RevId: 310889726
This commit is contained in:
bachinger 2020-05-11 12:58:27 +01:00 committed by Oliver Woodman
parent 1241c8c321
commit 19d639eb9a
5 changed files with 253 additions and 60 deletions

View File

@ -321,14 +321,16 @@ public final class ExtractorMediaSource extends CompositeMediaSource<Void> {
@Nullable Object tag) {
progressiveMediaSource =
new ProgressiveMediaSource(
uri,
new MediaItem.Builder()
.setUri(uri)
.setCustomCacheKey(customCacheKey)
.setTag(tag)
.build(),
dataSourceFactory,
extractorsFactory,
DrmSessionManager.getDummyDrmSessionManager(),
loadableLoadErrorHandlingPolicy,
customCacheKey,
continueLoadingCheckIntervalBytes,
tag);
continueLoadingCheckIntervalBytes);
}
@Override

View File

@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.source;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
@ -30,7 +32,6 @@ import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy;
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Assertions;
/**
* Provides one period that loads data from a {@link Uri} and extracted using an {@link Extractor}.
@ -178,18 +179,21 @@ public final class ProgressiveMediaSource extends BaseMediaSource
*/
@Override
public ProgressiveMediaSource createMediaSource(MediaItem mediaItem) {
Assertions.checkNotNull(mediaItem.playbackProperties);
checkNotNull(mediaItem.playbackProperties);
MediaItem.Builder builder = mediaItem.buildUpon();
if (mediaItem.playbackProperties.tag == null) {
builder.setTag(tag);
}
if (mediaItem.playbackProperties.customCacheKey == null) {
builder.setCustomCacheKey(customCacheKey);
}
return new ProgressiveMediaSource(
mediaItem.playbackProperties.uri,
builder.build(),
dataSourceFactory,
extractorsFactory,
drmSessionManager,
loadErrorHandlingPolicy,
mediaItem.playbackProperties.customCacheKey != null
? mediaItem.playbackProperties.customCacheKey
: customCacheKey,
continueLoadingCheckIntervalBytes,
mediaItem.playbackProperties.tag != null ? mediaItem.playbackProperties.tag : tag);
continueLoadingCheckIntervalBytes);
}
@Override
@ -204,14 +208,13 @@ public final class ProgressiveMediaSource extends BaseMediaSource
*/
public static final int DEFAULT_LOADING_CHECK_INTERVAL_BYTES = 1024 * 1024;
private final Uri uri;
private final MediaItem mediaItem;
private final MediaItem.PlaybackProperties playbackProperties;
private final DataSource.Factory dataSourceFactory;
private final ExtractorsFactory extractorsFactory;
private final DrmSessionManager drmSessionManager;
private final LoadErrorHandlingPolicy loadableLoadErrorHandlingPolicy;
@Nullable private final String customCacheKey;
private final int continueLoadingCheckIntervalBytes;
@Nullable private final Object tag;
private boolean timelineIsPlaceholder;
private long timelineDurationUs;
@ -221,30 +224,32 @@ public final class ProgressiveMediaSource extends BaseMediaSource
// TODO: Make private when ExtractorMediaSource is deleted.
/* package */ ProgressiveMediaSource(
Uri uri,
MediaItem mediaItem,
DataSource.Factory dataSourceFactory,
ExtractorsFactory extractorsFactory,
DrmSessionManager drmSessionManager,
LoadErrorHandlingPolicy loadableLoadErrorHandlingPolicy,
@Nullable String customCacheKey,
int continueLoadingCheckIntervalBytes,
@Nullable Object tag) {
this.uri = uri;
int continueLoadingCheckIntervalBytes) {
this.playbackProperties = checkNotNull(mediaItem.playbackProperties);
this.mediaItem = mediaItem;
this.dataSourceFactory = dataSourceFactory;
this.extractorsFactory = extractorsFactory;
this.drmSessionManager = drmSessionManager;
this.loadableLoadErrorHandlingPolicy = loadableLoadErrorHandlingPolicy;
this.customCacheKey = customCacheKey;
this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes;
this.timelineIsPlaceholder = true;
this.timelineDurationUs = C.TIME_UNSET;
this.tag = tag;
}
@Override
@Nullable
public Object getTag() {
return tag;
return playbackProperties.tag;
}
@Nullable
public Object getMediaItem() {
return mediaItem;
}
@Override
@ -266,7 +271,7 @@ public final class ProgressiveMediaSource extends BaseMediaSource
dataSource.addTransferListener(transferListener);
}
return new ProgressiveMediaPeriod(
uri,
playbackProperties.uri,
dataSource,
extractorsFactory.createExtractors(),
drmSessionManager,
@ -274,7 +279,7 @@ public final class ProgressiveMediaSource extends BaseMediaSource
createEventDispatcher(id),
this,
allocator,
customCacheKey,
playbackProperties.customCacheKey,
continueLoadingCheckIntervalBytes);
}
@ -320,7 +325,7 @@ public final class ProgressiveMediaSource extends BaseMediaSource
/* isDynamic= */ false,
/* isLive= */ timelineIsLive,
/* manifest= */ null,
tag);
mediaItem);
if (timelineIsPlaceholder) {
// TODO: Actually prepare the extractors during prepatation so that we don't need a
// placeholder. See https://github.com/google/ExoPlayer/issues/4727.

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer2.source;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.util.Assertions;
@ -39,6 +40,7 @@ public final class SinglePeriodTimeline extends Timeline {
private final boolean isLive;
@Nullable private final Object tag;
@Nullable private final Object manifest;
@Nullable private final MediaItem mediaItem;
/**
* Creates a timeline containing a single period and a window that spans it.
@ -50,19 +52,16 @@ public final class SinglePeriodTimeline extends Timeline {
*/
public SinglePeriodTimeline(
long durationUs, boolean isSeekable, boolean isDynamic, boolean isLive) {
this(durationUs, isSeekable, isDynamic, isLive, /* manifest= */ null, /* tag= */ null);
this(durationUs, isSeekable, isDynamic, isLive, /* manifest= */ null, /* mediaItem= */ null);
}
/**
* Creates a timeline containing a single period and a window that spans it.
*
* @param durationUs The duration of the period, in microseconds.
* @param isSeekable Whether seeking is supported within the period.
* @param isDynamic Whether the window may change when the timeline is updated.
* @param isLive Whether the window is live.
* @param manifest The manifest. May be {@code null}.
* @param tag A tag used for {@link Window#tag}.
* @deprecated Use {@link #SinglePeriodTimeline(long, boolean, boolean, boolean, Object,
* MediaItem)} instead.
*/
// Provide backwards compatibility.
@SuppressWarnings("deprecation")
@Deprecated
public SinglePeriodTimeline(
long durationUs,
boolean isSeekable,
@ -83,21 +82,41 @@ public final class SinglePeriodTimeline extends Timeline {
}
/**
* Creates a timeline with one period, and a window of known duration starting at a specified
* position in the period.
* Creates a timeline containing a single period and a window that spans it.
*
* @param periodDurationUs The duration of the period in microseconds.
* @param windowDurationUs The duration of the window in microseconds.
* @param windowPositionInPeriodUs The position of the start of the window in the period, in
* microseconds.
* @param windowDefaultStartPositionUs The default position relative to the start of the window at
* which to begin playback, in microseconds.
* @param isSeekable Whether seeking is supported within the window.
* @param durationUs The duration of the period, in microseconds.
* @param isSeekable Whether seeking is supported within the period.
* @param isDynamic Whether the window may change when the timeline is updated.
* @param isLive Whether the window is live.
* @param manifest The manifest. May be (@code null}.
* @param tag A tag used for {@link Timeline.Window#tag}.
* @param manifest The manifest. May be {@code null}.
* @param mediaItem A media item used for {@link Window#mediaItem}.
*/
public SinglePeriodTimeline(
long durationUs,
boolean isSeekable,
boolean isDynamic,
boolean isLive,
@Nullable Object manifest,
@Nullable MediaItem mediaItem) {
this(
durationUs,
durationUs,
/* windowPositionInPeriodUs= */ 0,
/* windowDefaultStartPositionUs= */ 0,
isSeekable,
isDynamic,
isLive,
manifest,
mediaItem);
}
/**
* @deprecated Use {@link #SinglePeriodTimeline(long, long, long, long, boolean, boolean, boolean,
* Object, MediaItem)} instead.
*/
// Provide backwards compatibility.
@SuppressWarnings("deprecation")
@Deprecated
public SinglePeriodTimeline(
long periodDurationUs,
long windowDurationUs,
@ -123,6 +142,81 @@ public final class SinglePeriodTimeline extends Timeline {
tag);
}
/**
* Creates a timeline with one period, and a window of known duration starting at a specified
* position in the period.
*
* @param periodDurationUs The duration of the period in microseconds.
* @param windowDurationUs The duration of the window in microseconds.
* @param windowPositionInPeriodUs The position of the start of the window in the period, in
* microseconds.
* @param windowDefaultStartPositionUs The default position relative to the start of the window at
* which to begin playback, in microseconds.
* @param isSeekable Whether seeking is supported within the window.
* @param isDynamic Whether the window may change when the timeline is updated.
* @param isLive Whether the window is live.
* @param manifest The manifest. May be (@code null}.
* @param mediaItem A media item used for {@link Timeline.Window#mediaItem}.
*/
public SinglePeriodTimeline(
long periodDurationUs,
long windowDurationUs,
long windowPositionInPeriodUs,
long windowDefaultStartPositionUs,
boolean isSeekable,
boolean isDynamic,
boolean isLive,
@Nullable Object manifest,
@Nullable MediaItem mediaItem) {
this(
/* presentationStartTimeMs= */ C.TIME_UNSET,
/* windowStartTimeMs= */ C.TIME_UNSET,
/* elapsedRealtimeEpochOffsetMs= */ C.TIME_UNSET,
periodDurationUs,
windowDurationUs,
windowPositionInPeriodUs,
windowDefaultStartPositionUs,
isSeekable,
isDynamic,
isLive,
manifest,
mediaItem);
}
/**
* @deprecated Use {@link #SinglePeriodTimeline(long, long, long, long, long, long, long, boolean,
* boolean, boolean, Object, MediaItem)} instead.
*/
@Deprecated
public SinglePeriodTimeline(
long presentationStartTimeMs,
long windowStartTimeMs,
long elapsedRealtimeEpochOffsetMs,
long periodDurationUs,
long windowDurationUs,
long windowPositionInPeriodUs,
long windowDefaultStartPositionUs,
boolean isSeekable,
boolean isDynamic,
boolean isLive,
@Nullable Object manifest,
@Nullable Object tag) {
this(
presentationStartTimeMs,
windowStartTimeMs,
elapsedRealtimeEpochOffsetMs,
periodDurationUs,
windowDurationUs,
windowPositionInPeriodUs,
windowDefaultStartPositionUs,
isSeekable,
isDynamic,
isLive,
manifest,
/* mediaItem= */ null,
tag);
}
/**
* Creates a timeline with one period, and a window of known duration starting at a specified
* position in the period.
@ -144,7 +238,7 @@ public final class SinglePeriodTimeline extends Timeline {
* @param isDynamic Whether the window may change when the timeline is updated.
* @param isLive Whether the window is live.
* @param manifest The manifest. May be {@code null}.
* @param tag A tag used for {@link Timeline.Window#tag}.
* @param mediaItem A media item used for {@link Timeline.Window#mediaItem}.
*/
public SinglePeriodTimeline(
long presentationStartTimeMs,
@ -158,6 +252,36 @@ public final class SinglePeriodTimeline extends Timeline {
boolean isDynamic,
boolean isLive,
@Nullable Object manifest,
@Nullable MediaItem mediaItem) {
this(
presentationStartTimeMs,
windowStartTimeMs,
elapsedRealtimeEpochOffsetMs,
periodDurationUs,
windowDurationUs,
windowPositionInPeriodUs,
windowDefaultStartPositionUs,
isSeekable,
isDynamic,
isLive,
manifest,
mediaItem,
/* tag= */ null);
}
private SinglePeriodTimeline(
long presentationStartTimeMs,
long windowStartTimeMs,
long elapsedRealtimeEpochOffsetMs,
long periodDurationUs,
long windowDurationUs,
long windowPositionInPeriodUs,
long windowDefaultStartPositionUs,
boolean isSeekable,
boolean isDynamic,
boolean isLive,
@Nullable Object manifest,
@Nullable MediaItem mediaItem,
@Nullable Object tag) {
this.presentationStartTimeMs = presentationStartTimeMs;
this.windowStartTimeMs = windowStartTimeMs;
@ -170,6 +294,7 @@ public final class SinglePeriodTimeline extends Timeline {
this.isDynamic = isDynamic;
this.isLive = isLive;
this.manifest = manifest;
this.mediaItem = mediaItem;
this.tag = tag;
}
@ -178,6 +303,8 @@ public final class SinglePeriodTimeline extends Timeline {
return 1;
}
// Provide backwards compatibility.
@SuppressWarnings("deprecation")
@Override
public Window getWindow(int windowIndex, Window window, long defaultPositionProjectionUs) {
Assertions.checkIndex(windowIndex, 0, 1);
@ -194,6 +321,8 @@ public final class SinglePeriodTimeline extends Timeline {
}
}
}
if (tag != null) {
// Support deprecated constructors.
return window.set(
Window.SINGLE_WINDOW_UID,
tag,
@ -210,6 +339,22 @@ public final class SinglePeriodTimeline extends Timeline {
/* lastPeriodIndex= */ 0,
windowPositionInPeriodUs);
}
return window.set(
Window.SINGLE_WINDOW_UID,
mediaItem,
manifest,
presentationStartTimeMs,
windowStartTimeMs,
elapsedRealtimeEpochOffsetMs,
isSeekable,
isDynamic,
isLive,
windowDefaultStartPositionUs,
windowDurationUs,
/* firstPeriodIndex= */ 0,
/* lastPeriodIndex= */ 0,
windowPositionInPeriodUs);
}
@Override
public int getPeriodCount() {

View File

@ -235,7 +235,7 @@ public final class ClippingMediaSourceTest {
/* isDynamic= */ true,
/* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
/* mediaItem= */ null);
Timeline clippedTimeline = getClippedTimeline(timeline, /* durationUs= */ TEST_CLIP_AMOUNT_US);
assertThat(clippedTimeline.getWindow(0, window).getDurationUs()).isEqualTo(TEST_CLIP_AMOUNT_US);
@ -258,7 +258,7 @@ public final class ClippingMediaSourceTest {
/* isDynamic= */ true,
/* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
/* mediaItem= */ null);
Timeline timeline2 =
new SinglePeriodTimeline(
/* periodDurationUs= */ 3 * TEST_PERIOD_DURATION_US,
@ -269,7 +269,7 @@ public final class ClippingMediaSourceTest {
/* isDynamic= */ true,
/* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
/* mediaItem= */ null);
Timeline[] clippedTimelines =
getClippedTimelines(
@ -309,7 +309,7 @@ public final class ClippingMediaSourceTest {
/* isDynamic= */ true,
/* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
/* mediaItem= */ null);
Timeline timeline2 =
new SinglePeriodTimeline(
/* periodDurationUs= */ 4 * TEST_PERIOD_DURATION_US,
@ -320,7 +320,7 @@ public final class ClippingMediaSourceTest {
/* isDynamic= */ true,
/* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
/* mediaItem= */ null);
Timeline[] clippedTimelines =
getClippedTimelines(
@ -360,7 +360,7 @@ public final class ClippingMediaSourceTest {
/* isDynamic= */ true,
/* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
/* mediaItem= */ null);
Timeline timeline2 =
new SinglePeriodTimeline(
/* periodDurationUs= */ 3 * TEST_PERIOD_DURATION_US,
@ -371,7 +371,7 @@ public final class ClippingMediaSourceTest {
/* isDynamic= */ true,
/* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
/* mediaItem= */ null);
Timeline[] clippedTimelines =
getClippedTimelines(
@ -412,7 +412,7 @@ public final class ClippingMediaSourceTest {
/* isDynamic= */ true,
/* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
/* mediaItem= */ null);
Timeline timeline2 =
new SinglePeriodTimeline(
/* periodDurationUs= */ 4 * TEST_PERIOD_DURATION_US,
@ -423,7 +423,7 @@ public final class ClippingMediaSourceTest {
/* isDynamic= */ true,
/* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
/* mediaItem= */ null);
Timeline[] clippedTimelines =
getClippedTimelines(

View File

@ -17,9 +17,11 @@ package com.google.android.exoplayer2.source;
import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
import android.util.Pair;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.Timeline.Window;
import org.junit.Before;
@ -66,7 +68,7 @@ public final class SinglePeriodTimelineTest {
/* isDynamic= */ true,
/* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
/* mediaItem= */ null);
// Should return null with a positive position projection beyond window duration.
Pair<Object, Long> position =
timeline.getPeriodPosition(window, period, 0, C.TIME_UNSET, windowDurationUs + 1);
@ -90,7 +92,7 @@ public final class SinglePeriodTimelineTest {
/* isDynamic= */ false,
/* isLive= */ false,
/* manifest= */ null,
/* tag= */ null);
/* tag= */ (Object) null);
assertThat(timeline.getWindow(/* windowIndex= */ 0, window).tag).isNull();
assertThat(timeline.getPeriod(/* periodIndex= */ 0, period, /* setIds= */ false).id).isNull();
@ -100,6 +102,25 @@ public final class SinglePeriodTimelineTest {
.isNotNull();
}
@Test
public void setNullMediaItem_returnsNullMediaItem_butUsesDefaultUid() {
SinglePeriodTimeline timeline =
new SinglePeriodTimeline(
/* durationUs= */ C.TIME_UNSET,
/* isSeekable= */ false,
/* isDynamic= */ false,
/* isLive= */ false,
/* manifest= */ null,
/* mediaItem= */ null);
assertThat(timeline.getWindow(/* windowIndex= */ 0, window).mediaItem).isNull();
assertThat(timeline.getPeriod(/* periodIndex= */ 0, period, /* setIds= */ false).id).isNull();
assertThat(timeline.getPeriod(/* periodIndex= */ 0, period, /* setIds= */ true).id).isNull();
assertThat(timeline.getPeriod(/* periodIndex= */ 0, period, /* setIds= */ false).uid).isNull();
assertThat(timeline.getPeriod(/* periodIndex= */ 0, period, /* setIds= */ true).uid)
.isNotNull();
}
@Test
public void getWindow_setsTag() {
Object tag = new Object();
@ -115,6 +136,26 @@ public final class SinglePeriodTimelineTest {
assertThat(timeline.getWindow(/* windowIndex= */ 0, window).tag).isEqualTo(tag);
}
// Tests backward compatibility.
@SuppressWarnings("deprecation")
@Test
public void getWindow_setsMediaItemAndTag() {
MediaItem mediaItem = new MediaItem.Builder().setUri(Uri.EMPTY).setTag(new Object()).build();
SinglePeriodTimeline timeline =
new SinglePeriodTimeline(
/* durationUs= */ C.TIME_UNSET,
/* isSeekable= */ false,
/* isDynamic= */ false,
/* isLive= */ false,
/* manifest= */ null,
mediaItem);
Window window = timeline.getWindow(/* windowIndex= */ 0, this.window);
assertThat(window.mediaItem).isEqualTo(mediaItem);
assertThat(window.tag).isEqualTo(mediaItem.playbackProperties.tag);
}
@Test
public void getIndexOfPeriod_returnsPeriod() {
SinglePeriodTimeline timeline =
@ -124,7 +165,7 @@ public final class SinglePeriodTimelineTest {
/* isDynamic= */ false,
/* isLive= */ false,
/* manifest= */ null,
/* tag= */ null);
/* mediaItem= */ null);
Object uid = timeline.getPeriod(/* periodIndex= */ 0, period, /* setIds= */ true).uid;
assertThat(timeline.getIndexOfPeriod(uid)).isEqualTo(0);