mirror of
https://github.com/samsonjs/media.git
synced 2026-03-26 09:35:47 +00:00
add default methods isSingleWindow and getInitialTimeline to MediaSource interface
PiperOrigin-RevId: 277695826
This commit is contained in:
parent
df251ad1be
commit
01a4cf98d5
7 changed files with 352 additions and 25 deletions
|
|
@ -19,6 +19,7 @@ import android.util.Pair;
|
|||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
/**
|
||||
* A flexible representation of the structure of media. A timeline is able to represent the
|
||||
|
|
@ -278,6 +279,48 @@ public abstract class Timeline {
|
|||
return positionInFirstPeriodUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || !getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
Window that = (Window) obj;
|
||||
return Util.areEqual(uid, that.uid)
|
||||
&& Util.areEqual(tag, that.tag)
|
||||
&& Util.areEqual(manifest, that.manifest)
|
||||
&& presentationStartTimeMs == that.presentationStartTimeMs
|
||||
&& windowStartTimeMs == that.windowStartTimeMs
|
||||
&& isSeekable == that.isSeekable
|
||||
&& isDynamic == that.isDynamic
|
||||
&& isLive == that.isLive
|
||||
&& defaultPositionUs == that.defaultPositionUs
|
||||
&& durationUs == that.durationUs
|
||||
&& firstPeriodIndex == that.firstPeriodIndex
|
||||
&& lastPeriodIndex == that.lastPeriodIndex
|
||||
&& positionInFirstPeriodUs == that.positionInFirstPeriodUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 7;
|
||||
result = 31 * result + uid.hashCode();
|
||||
result = 31 * result + (tag == null ? 0 : tag.hashCode());
|
||||
result = 31 * result + (manifest == null ? 0 : manifest.hashCode());
|
||||
result = 31 * result + (int) (presentationStartTimeMs ^ (presentationStartTimeMs >>> 32));
|
||||
result = 31 * result + (int) (windowStartTimeMs ^ (windowStartTimeMs >>> 32));
|
||||
result = 31 * result + (isSeekable ? 1 : 0);
|
||||
result = 31 * result + (isDynamic ? 1 : 0);
|
||||
result = 31 * result + (isLive ? 1 : 0);
|
||||
result = 31 * result + (int) (defaultPositionUs ^ (defaultPositionUs >>> 32));
|
||||
result = 31 * result + (int) (durationUs ^ (durationUs >>> 32));
|
||||
result = 31 * result + firstPeriodIndex;
|
||||
result = 31 * result + lastPeriodIndex;
|
||||
result = 31 * result + (int) (positionInFirstPeriodUs ^ (positionInFirstPeriodUs >>> 32));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -534,6 +577,34 @@ public abstract class Timeline {
|
|||
return adPlaybackState.adResumePositionUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || !getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
Period that = (Period) obj;
|
||||
return Util.areEqual(id, that.id)
|
||||
&& Util.areEqual(uid, that.uid)
|
||||
&& windowIndex == that.windowIndex
|
||||
&& durationUs == that.durationUs
|
||||
&& positionInWindowUs == that.positionInWindowUs
|
||||
&& Util.areEqual(adPlaybackState, that.adPlaybackState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 7;
|
||||
result = 31 * result + (id == null ? 0 : id.hashCode());
|
||||
result = 31 * result + (uid == null ? 0 : uid.hashCode());
|
||||
result = 31 * result + windowIndex;
|
||||
result = 31 * result + (int) (durationUs ^ (durationUs >>> 32));
|
||||
result = 31 * result + (int) (positionInWindowUs ^ (positionInWindowUs >>> 32));
|
||||
result = 31 * result + (adPlaybackState == null ? 0 : adPlaybackState.hashCode());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/** An empty timeline. */
|
||||
|
|
|
|||
|
|
@ -139,6 +139,23 @@ public final class ConcatenatingMediaSource extends CompositeMediaSource<MediaSo
|
|||
addMediaSources(Arrays.asList(mediaSources));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Timeline getInitialTimeline() {
|
||||
ShuffleOrder shuffleOrder =
|
||||
this.shuffleOrder.getLength() != mediaSourcesPublic.size()
|
||||
? this.shuffleOrder
|
||||
.cloneAndClear()
|
||||
.cloneAndInsert(
|
||||
/* insertionIndex= */ 0, /* insertionCount= */ mediaSourcesPublic.size())
|
||||
: this.shuffleOrder;
|
||||
return new ConcatenatedTimeline(mediaSourcesPublic, shuffleOrder, isAtomic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleWindow() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a {@link MediaSource} to the playlist.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import java.util.Map;
|
|||
*/
|
||||
public final class LoopingMediaSource extends CompositeMediaSource<Void> {
|
||||
|
||||
private final MediaSource childSource;
|
||||
private final MaskingMediaSource maskingMediaSource;
|
||||
private final int loopCount;
|
||||
private final Map<MediaPeriodId, MediaPeriodId> childMediaPeriodIdToMediaPeriodId;
|
||||
private final Map<MediaPeriod, MediaPeriodId> mediaPeriodToChildMediaPeriodId;
|
||||
|
|
@ -58,7 +58,7 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> {
|
|||
*/
|
||||
public LoopingMediaSource(MediaSource childSource, int loopCount) {
|
||||
Assertions.checkArgument(loopCount > 0);
|
||||
this.childSource = childSource;
|
||||
this.maskingMediaSource = new MaskingMediaSource(childSource, /* useLazyPreparation= */ false);
|
||||
this.loopCount = loopCount;
|
||||
childMediaPeriodIdToMediaPeriodId = new HashMap<>();
|
||||
mediaPeriodToChildMediaPeriodId = new HashMap<>();
|
||||
|
|
@ -67,32 +67,45 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> {
|
|||
@Override
|
||||
@Nullable
|
||||
public Object getTag() {
|
||||
return childSource.getTag();
|
||||
return maskingMediaSource.getTag();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Timeline getInitialTimeline() {
|
||||
return loopCount != Integer.MAX_VALUE
|
||||
? new LoopingTimeline(maskingMediaSource.getTimeline(), loopCount)
|
||||
: new InfinitelyLoopingTimeline(maskingMediaSource.getTimeline());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleWindow() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
|
||||
super.prepareSourceInternal(mediaTransferListener);
|
||||
prepareChildSource(/* id= */ null, childSource);
|
||||
prepareChildSource(/* id= */ null, maskingMediaSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
|
||||
if (loopCount == Integer.MAX_VALUE) {
|
||||
return childSource.createPeriod(id, allocator, startPositionUs);
|
||||
return maskingMediaSource.createPeriod(id, allocator, startPositionUs);
|
||||
}
|
||||
Object childPeriodUid = LoopingTimeline.getChildPeriodUidFromConcatenatedUid(id.periodUid);
|
||||
MediaPeriodId childMediaPeriodId = id.copyWithPeriodUid(childPeriodUid);
|
||||
childMediaPeriodIdToMediaPeriodId.put(childMediaPeriodId, id);
|
||||
MediaPeriod mediaPeriod =
|
||||
childSource.createPeriod(childMediaPeriodId, allocator, startPositionUs);
|
||||
maskingMediaSource.createPeriod(childMediaPeriodId, allocator, startPositionUs);
|
||||
mediaPeriodToChildMediaPeriodId.put(mediaPeriod, childMediaPeriodId);
|
||||
return mediaPeriod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releasePeriod(MediaPeriod mediaPeriod) {
|
||||
childSource.releasePeriod(mediaPeriod);
|
||||
maskingMediaSource.releasePeriod(mediaPeriod);
|
||||
MediaPeriodId childMediaPeriodId = mediaPeriodToChildMediaPeriodId.remove(mediaPeriod);
|
||||
if (childMediaPeriodId != null) {
|
||||
childMediaPeriodIdToMediaPeriodId.remove(childMediaPeriodId);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
|
|||
@Nullable private EventDispatcher unpreparedMaskingMediaPeriodEventDispatcher;
|
||||
private boolean hasStartedPreparing;
|
||||
private boolean isPrepared;
|
||||
private boolean hasRealTimeline;
|
||||
|
||||
/**
|
||||
* Creates the masking media source.
|
||||
|
|
@ -54,14 +55,22 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
|
|||
*/
|
||||
public MaskingMediaSource(MediaSource mediaSource, boolean useLazyPreparation) {
|
||||
this.mediaSource = mediaSource;
|
||||
this.useLazyPreparation = useLazyPreparation;
|
||||
this.useLazyPreparation = useLazyPreparation && mediaSource.isSingleWindow();
|
||||
window = new Timeline.Window();
|
||||
period = new Timeline.Period();
|
||||
timeline = MaskingTimeline.createWithDummyTimeline(mediaSource.getTag());
|
||||
Timeline initialTimeline = mediaSource.getInitialTimeline();
|
||||
if (initialTimeline != null) {
|
||||
timeline =
|
||||
MaskingTimeline.createWithRealTimeline(
|
||||
initialTimeline, /* firstWindowUid= */ null, /* firstPeriodUid= */ null);
|
||||
hasRealTimeline = true;
|
||||
} else {
|
||||
timeline = MaskingTimeline.createWithDummyTimeline(mediaSource.getTag());
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the {@link Timeline}. */
|
||||
public Timeline getTimeline() {
|
||||
public synchronized Timeline getTimeline() {
|
||||
return timeline;
|
||||
}
|
||||
|
||||
|
|
@ -129,14 +138,16 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onChildSourceInfoRefreshed(
|
||||
protected synchronized void onChildSourceInfoRefreshed(
|
||||
Void id, MediaSource mediaSource, Timeline newTimeline) {
|
||||
if (isPrepared) {
|
||||
timeline = timeline.cloneWithUpdatedTimeline(newTimeline);
|
||||
} else if (newTimeline.isEmpty()) {
|
||||
timeline =
|
||||
MaskingTimeline.createWithRealTimeline(
|
||||
newTimeline, Window.SINGLE_WINDOW_UID, MaskingTimeline.DUMMY_EXTERNAL_PERIOD_UID);
|
||||
hasRealTimeline
|
||||
? timeline.cloneWithUpdatedTimeline(newTimeline)
|
||||
: MaskingTimeline.createWithRealTimeline(
|
||||
newTimeline, Window.SINGLE_WINDOW_UID, MaskingTimeline.DUMMY_EXTERNAL_PERIOD_UID);
|
||||
} else {
|
||||
// Determine first period and the start position.
|
||||
// This will be:
|
||||
|
|
@ -164,7 +175,10 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
|
|||
window, period, /* windowIndex= */ 0, windowStartPositionUs);
|
||||
Object periodUid = periodPosition.first;
|
||||
long periodPositionUs = periodPosition.second;
|
||||
timeline = MaskingTimeline.createWithRealTimeline(newTimeline, windowUid, periodUid);
|
||||
timeline =
|
||||
hasRealTimeline
|
||||
? timeline.cloneWithUpdatedTimeline(newTimeline)
|
||||
: MaskingTimeline.createWithRealTimeline(newTimeline, windowUid, periodUid);
|
||||
if (unpreparedMaskingMediaPeriod != null) {
|
||||
MaskingMediaPeriod maskingPeriod = unpreparedMaskingMediaPeriod;
|
||||
maskingPeriod.overridePreparePositionUs(periodPositionUs);
|
||||
|
|
@ -173,6 +187,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
|
|||
maskingPeriod.createPeriod(idInSource);
|
||||
}
|
||||
}
|
||||
hasRealTimeline = true;
|
||||
isPrepared = true;
|
||||
refreshSourceInfo(this.timeline);
|
||||
}
|
||||
|
|
@ -193,13 +208,15 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
|
|||
}
|
||||
|
||||
private Object getInternalPeriodUid(Object externalPeriodUid) {
|
||||
return externalPeriodUid.equals(MaskingTimeline.DUMMY_EXTERNAL_PERIOD_UID)
|
||||
return timeline.replacedInternalPeriodUid != null
|
||||
&& externalPeriodUid.equals(MaskingTimeline.DUMMY_EXTERNAL_PERIOD_UID)
|
||||
? timeline.replacedInternalPeriodUid
|
||||
: externalPeriodUid;
|
||||
}
|
||||
|
||||
private Object getExternalPeriodUid(Object internalPeriodUid) {
|
||||
return timeline.replacedInternalPeriodUid.equals(internalPeriodUid)
|
||||
return timeline.replacedInternalPeriodUid != null
|
||||
&& timeline.replacedInternalPeriodUid.equals(internalPeriodUid)
|
||||
? MaskingTimeline.DUMMY_EXTERNAL_PERIOD_UID
|
||||
: internalPeriodUid;
|
||||
}
|
||||
|
|
@ -212,8 +229,8 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
|
|||
|
||||
public static final Object DUMMY_EXTERNAL_PERIOD_UID = new Object();
|
||||
|
||||
private final Object replacedInternalWindowUid;
|
||||
private final Object replacedInternalPeriodUid;
|
||||
@Nullable private final Object replacedInternalWindowUid;
|
||||
@Nullable private final Object replacedInternalPeriodUid;
|
||||
|
||||
/**
|
||||
* Returns an instance with a dummy timeline using the provided window tag.
|
||||
|
|
@ -236,12 +253,14 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
|
|||
* assigned {@link #DUMMY_EXTERNAL_PERIOD_UID}.
|
||||
*/
|
||||
public static MaskingTimeline createWithRealTimeline(
|
||||
Timeline timeline, Object firstWindowUid, Object firstPeriodUid) {
|
||||
Timeline timeline, @Nullable Object firstWindowUid, @Nullable Object firstPeriodUid) {
|
||||
return new MaskingTimeline(timeline, firstWindowUid, firstPeriodUid);
|
||||
}
|
||||
|
||||
private MaskingTimeline(
|
||||
Timeline timeline, Object replacedInternalWindowUid, Object replacedInternalPeriodUid) {
|
||||
Timeline timeline,
|
||||
@Nullable Object replacedInternalWindowUid,
|
||||
@Nullable Object replacedInternalPeriodUid) {
|
||||
super(timeline);
|
||||
this.replacedInternalWindowUid = replacedInternalWindowUid;
|
||||
this.replacedInternalPeriodUid = replacedInternalPeriodUid;
|
||||
|
|
@ -273,7 +292,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
|
|||
@Override
|
||||
public Period getPeriod(int periodIndex, Period period, boolean setIds) {
|
||||
timeline.getPeriod(periodIndex, period, setIds);
|
||||
if (Util.areEqual(period.uid, replacedInternalPeriodUid)) {
|
||||
if (Util.areEqual(period.uid, replacedInternalPeriodUid) && setIds) {
|
||||
period.uid = DUMMY_EXTERNAL_PERIOD_UID;
|
||||
}
|
||||
return period;
|
||||
|
|
@ -282,7 +301,9 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
|
|||
@Override
|
||||
public int getIndexOfPeriod(Object uid) {
|
||||
return timeline.getIndexOfPeriod(
|
||||
DUMMY_EXTERNAL_PERIOD_UID.equals(uid) ? replacedInternalPeriodUid : uid);
|
||||
DUMMY_EXTERNAL_PERIOD_UID.equals(uid) && replacedInternalPeriodUid != null
|
||||
? replacedInternalPeriodUid
|
||||
: uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -333,8 +354,8 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
|
|||
@Override
|
||||
public Period getPeriod(int periodIndex, Period period, boolean setIds) {
|
||||
return period.set(
|
||||
/* id= */ 0,
|
||||
/* uid= */ MaskingTimeline.DUMMY_EXTERNAL_PERIOD_UID,
|
||||
/* id= */ setIds ? 0 : null,
|
||||
/* uid= */ setIds ? MaskingTimeline.DUMMY_EXTERNAL_PERIOD_UID : null,
|
||||
/* windowIndex= */ 0,
|
||||
/* durationUs = */ C.TIME_UNSET,
|
||||
/* positionInWindowUs= */ 0);
|
||||
|
|
|
|||
|
|
@ -228,6 +228,33 @@ public interface MediaSource {
|
|||
*/
|
||||
void removeEventListener(MediaSourceEventListener eventListener);
|
||||
|
||||
/**
|
||||
* Returns the initial dummy timeline that is returned immediately when the real timeline is not
|
||||
* yet known, or null to let the player create an initial timeline.
|
||||
*
|
||||
* <p>The initial timeline must use the same uids for windows and periods that the real timeline
|
||||
* will use. It also must provide windows which are marked as dynamic to indicate that the window
|
||||
* is expected to change when the real timeline arrives.
|
||||
*
|
||||
* <p>Any media source which has multiple windows should typically provide such an initial
|
||||
* timeline to make sure the player reports the correct number of windows immediately.
|
||||
*/
|
||||
@Nullable
|
||||
default Timeline getInitialTimeline() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the media source is guaranteed to never have zero or more than one window.
|
||||
*
|
||||
* <p>The default implementation returns {@code true}.
|
||||
*
|
||||
* @return true if the source has exactly one window.
|
||||
*/
|
||||
default boolean isSingleWindow() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Returns the tag set on the media source, or null if none was set. */
|
||||
@Nullable
|
||||
default Object getTag() {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.testutil.FakeTimeline;
|
||||
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
|
||||
|
|
@ -58,4 +60,148 @@ public class TimelineTest {
|
|||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, false, 0);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, false, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWindowEquals() {
|
||||
Timeline.Window window = new Timeline.Window();
|
||||
assertThat(window).isEqualTo(new Timeline.Window());
|
||||
|
||||
Timeline.Window otherWindow = new Timeline.Window();
|
||||
otherWindow.tag = new Object();
|
||||
assertThat(window).isNotEqualTo(otherWindow);
|
||||
|
||||
otherWindow = new Timeline.Window();
|
||||
otherWindow.manifest = new Object();
|
||||
assertThat(window).isNotEqualTo(otherWindow);
|
||||
|
||||
otherWindow = new Timeline.Window();
|
||||
otherWindow.presentationStartTimeMs = C.TIME_UNSET;
|
||||
assertThat(window).isNotEqualTo(otherWindow);
|
||||
|
||||
otherWindow = new Timeline.Window();
|
||||
otherWindow.windowStartTimeMs = C.TIME_UNSET;
|
||||
assertThat(window).isNotEqualTo(otherWindow);
|
||||
|
||||
otherWindow = new Timeline.Window();
|
||||
otherWindow.isSeekable = true;
|
||||
assertThat(window).isNotEqualTo(otherWindow);
|
||||
|
||||
otherWindow = new Timeline.Window();
|
||||
otherWindow.isDynamic = true;
|
||||
assertThat(window).isNotEqualTo(otherWindow);
|
||||
|
||||
otherWindow = new Timeline.Window();
|
||||
otherWindow.isLive = true;
|
||||
assertThat(window).isNotEqualTo(otherWindow);
|
||||
|
||||
otherWindow = new Timeline.Window();
|
||||
otherWindow.defaultPositionUs = C.TIME_UNSET;
|
||||
assertThat(window).isNotEqualTo(otherWindow);
|
||||
|
||||
otherWindow = new Timeline.Window();
|
||||
otherWindow.durationUs = C.TIME_UNSET;
|
||||
assertThat(window).isNotEqualTo(otherWindow);
|
||||
|
||||
otherWindow = new Timeline.Window();
|
||||
otherWindow.firstPeriodIndex = 1;
|
||||
assertThat(window).isNotEqualTo(otherWindow);
|
||||
|
||||
otherWindow = new Timeline.Window();
|
||||
otherWindow.lastPeriodIndex = 1;
|
||||
assertThat(window).isNotEqualTo(otherWindow);
|
||||
|
||||
otherWindow = new Timeline.Window();
|
||||
otherWindow.positionInFirstPeriodUs = C.TIME_UNSET;
|
||||
assertThat(window).isNotEqualTo(otherWindow);
|
||||
|
||||
window.uid = new Object();
|
||||
window.tag = new Object();
|
||||
window.manifest = new Object();
|
||||
window.presentationStartTimeMs = C.TIME_UNSET;
|
||||
window.windowStartTimeMs = C.TIME_UNSET;
|
||||
window.isSeekable = true;
|
||||
window.isDynamic = true;
|
||||
window.isLive = true;
|
||||
window.defaultPositionUs = C.TIME_UNSET;
|
||||
window.durationUs = C.TIME_UNSET;
|
||||
window.firstPeriodIndex = 1;
|
||||
window.lastPeriodIndex = 1;
|
||||
window.positionInFirstPeriodUs = C.TIME_UNSET;
|
||||
otherWindow =
|
||||
otherWindow.set(
|
||||
window.uid,
|
||||
window.tag,
|
||||
window.manifest,
|
||||
window.presentationStartTimeMs,
|
||||
window.windowStartTimeMs,
|
||||
window.isSeekable,
|
||||
window.isDynamic,
|
||||
window.isLive,
|
||||
window.defaultPositionUs,
|
||||
window.durationUs,
|
||||
window.firstPeriodIndex,
|
||||
window.lastPeriodIndex,
|
||||
window.positionInFirstPeriodUs);
|
||||
assertThat(window).isEqualTo(otherWindow);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWindowHashCode() {
|
||||
Timeline.Window window = new Timeline.Window();
|
||||
Timeline.Window otherWindow = new Timeline.Window();
|
||||
assertThat(window.hashCode()).isEqualTo(otherWindow.hashCode());
|
||||
|
||||
window.tag = new Object();
|
||||
assertThat(window.hashCode()).isNotEqualTo(otherWindow.hashCode());
|
||||
otherWindow.tag = window.tag;
|
||||
assertThat(window.hashCode()).isEqualTo(otherWindow.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPeriodEquals() {
|
||||
Timeline.Period period = new Timeline.Period();
|
||||
assertThat(period).isEqualTo(new Timeline.Period());
|
||||
|
||||
Timeline.Period otherPeriod = new Timeline.Period();
|
||||
otherPeriod.id = new Object();
|
||||
assertThat(period).isNotEqualTo(otherPeriod);
|
||||
|
||||
otherPeriod = new Timeline.Period();
|
||||
otherPeriod.uid = new Object();
|
||||
assertThat(period).isNotEqualTo(otherPeriod);
|
||||
|
||||
otherPeriod = new Timeline.Period();
|
||||
otherPeriod.windowIndex = 12;
|
||||
assertThat(period).isNotEqualTo(otherPeriod);
|
||||
|
||||
otherPeriod = new Timeline.Period();
|
||||
otherPeriod.durationUs = 11L;
|
||||
assertThat(period).isNotEqualTo(otherPeriod);
|
||||
|
||||
otherPeriod = new Timeline.Period();
|
||||
period.id = new Object();
|
||||
period.uid = new Object();
|
||||
period.windowIndex = 1;
|
||||
period.durationUs = 123L;
|
||||
otherPeriod =
|
||||
otherPeriod.set(
|
||||
period.id,
|
||||
period.uid,
|
||||
period.windowIndex,
|
||||
period.durationUs,
|
||||
/* positionInWindowUs= */ 0);
|
||||
assertThat(period).isEqualTo(otherPeriod);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPeriodHashCode() {
|
||||
Timeline.Period period = new Timeline.Period();
|
||||
Timeline.Period otherPeriod = new Timeline.Period();
|
||||
assertThat(period.hashCode()).isEqualTo(otherPeriod.hashCode());
|
||||
|
||||
period.windowIndex = 12;
|
||||
assertThat(period.hashCode()).isNotEqualTo(otherPeriod.hashCode());
|
||||
otherPeriod.windowIndex = period.windowIndex;
|
||||
assertThat(period.hashCode()).isEqualTo(otherPeriod.hashCode());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ public final class FakeTimeline extends Timeline {
|
|||
public final Object id;
|
||||
public final boolean isSeekable;
|
||||
public final boolean isDynamic;
|
||||
public final boolean isLive;
|
||||
public final long durationUs;
|
||||
public final AdPlaybackState adPlaybackState;
|
||||
|
||||
|
|
@ -99,10 +100,41 @@ public final class FakeTimeline extends Timeline {
|
|||
boolean isDynamic,
|
||||
long durationUs,
|
||||
AdPlaybackState adPlaybackState) {
|
||||
this(
|
||||
periodCount,
|
||||
id,
|
||||
isSeekable,
|
||||
isDynamic,
|
||||
/* isLive= */ isDynamic,
|
||||
durationUs,
|
||||
adPlaybackState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a window definition with ad groups.
|
||||
*
|
||||
* @param periodCount The number of periods in the window. Each period get an equal slice of the
|
||||
* total window duration.
|
||||
* @param id The UID of the window.
|
||||
* @param isSeekable Whether the window is seekable.
|
||||
* @param isDynamic Whether the window is dynamic.
|
||||
* @param isLive Whether the window is live.
|
||||
* @param durationUs The duration of the window in microseconds.
|
||||
* @param adPlaybackState The ad playback state.
|
||||
*/
|
||||
public TimelineWindowDefinition(
|
||||
int periodCount,
|
||||
Object id,
|
||||
boolean isSeekable,
|
||||
boolean isDynamic,
|
||||
boolean isLive,
|
||||
long durationUs,
|
||||
AdPlaybackState adPlaybackState) {
|
||||
this.periodCount = periodCount;
|
||||
this.id = id;
|
||||
this.isSeekable = isSeekable;
|
||||
this.isDynamic = isDynamic;
|
||||
this.isLive = isLive;
|
||||
this.durationUs = durationUs;
|
||||
this.adPlaybackState = adPlaybackState;
|
||||
}
|
||||
|
|
@ -189,7 +221,7 @@ public final class FakeTimeline extends Timeline {
|
|||
/* windowStartTimeMs= */ C.TIME_UNSET,
|
||||
windowDefinition.isSeekable,
|
||||
windowDefinition.isDynamic,
|
||||
/* isLive= */ windowDefinition.isDynamic,
|
||||
windowDefinition.isLive,
|
||||
/* defaultPositionUs= */ 0,
|
||||
windowDefinition.durationUs,
|
||||
periodOffsets[windowIndex],
|
||||
|
|
|
|||
Loading…
Reference in a new issue