mirror of
https://github.com/androidx/media.git
synced 2025-05-07 07:30:22 +08:00
Automated g4 rollback of changelist 192621199.
*** Reason for rollback *** Rollback only needed to cherry-pick into Photos release. *** Original change description *** Automated g4 rollback of changelist 190906020. *** Reason for rollback *** Breaks looping. *** Original change description *** Automated g4 rollback of changelist 190628272. *** Reason for rollback *** b/76391022 was caused by a timestamp correction in StabilizableSimpleExoPlayer which will be fixed with this CL. *** Original change description *** Automated g4 rollback of changelist 189570277. *** Reason for rollback *** causes b/76391022, motion still playback in Photos is broken **... *** ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=192621719
This commit is contained in:
parent
692b7a674a
commit
0802ecfee3
@ -83,9 +83,12 @@ import com.google.android.exoplayer2.util.Assertions;
|
|||||||
mayRetainStreamFlags = new boolean[rendererCapabilities.length];
|
mayRetainStreamFlags = new boolean[rendererCapabilities.length];
|
||||||
MediaPeriod mediaPeriod = mediaSource.createPeriod(info.id, allocator);
|
MediaPeriod mediaPeriod = mediaSource.createPeriod(info.id, allocator);
|
||||||
if (info.endPositionUs != C.TIME_END_OF_SOURCE) {
|
if (info.endPositionUs != C.TIME_END_OF_SOURCE) {
|
||||||
ClippingMediaPeriod clippingMediaPeriod = new ClippingMediaPeriod(mediaPeriod, true);
|
mediaPeriod =
|
||||||
clippingMediaPeriod.setClipping(0, info.endPositionUs);
|
new ClippingMediaPeriod(
|
||||||
mediaPeriod = clippingMediaPeriod;
|
mediaPeriod,
|
||||||
|
/* enableInitialDiscontinuity= */ true,
|
||||||
|
/* startUs= */ 0,
|
||||||
|
info.endPositionUs);
|
||||||
}
|
}
|
||||||
this.mediaPeriod = mediaPeriod;
|
this.mediaPeriod = mediaPeriod;
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
|||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,35 +44,36 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
|||||||
/* package */ long endUs;
|
/* package */ long endUs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new clipping media period that provides a clipped view of the specified
|
* Creates a new clipping media period that provides a clipped view of the specified {@link
|
||||||
* {@link MediaPeriod}'s sample streams.
|
* MediaPeriod}'s sample streams.
|
||||||
* <p>
|
*
|
||||||
* The clipping start/end positions must be specified by calling {@link #setClipping(long, long)}
|
* <p>If the start point is guaranteed to be a key frame, pass {@code false} to {@code
|
||||||
* on the playback thread before preparation completes.
|
|
||||||
* <p>
|
|
||||||
* If the start point is guaranteed to be a key frame, pass {@code false} to {@code
|
|
||||||
* enableInitialPositionDiscontinuity} to suppress an initial discontinuity when the period is
|
* enableInitialPositionDiscontinuity} to suppress an initial discontinuity when the period is
|
||||||
* first read from.
|
* first read from.
|
||||||
*
|
*
|
||||||
* @param mediaPeriod The media period to clip.
|
* @param mediaPeriod The media period to clip.
|
||||||
* @param enableInitialDiscontinuity Whether the initial discontinuity should be enabled.
|
* @param enableInitialDiscontinuity Whether the initial discontinuity should be enabled.
|
||||||
|
* @param startUs The clipping start time, in microseconds.
|
||||||
|
* @param endUs The clipping end time, in microseconds, or {@link C#TIME_END_OF_SOURCE} to
|
||||||
|
* indicate the end of the period.
|
||||||
*/
|
*/
|
||||||
public ClippingMediaPeriod(MediaPeriod mediaPeriod, boolean enableInitialDiscontinuity) {
|
public ClippingMediaPeriod(
|
||||||
|
MediaPeriod mediaPeriod, boolean enableInitialDiscontinuity, long startUs, long endUs) {
|
||||||
this.mediaPeriod = mediaPeriod;
|
this.mediaPeriod = mediaPeriod;
|
||||||
sampleStreams = new ClippingSampleStream[0];
|
sampleStreams = new ClippingSampleStream[0];
|
||||||
pendingInitialDiscontinuityPositionUs = enableInitialDiscontinuity ? 0 : C.TIME_UNSET;
|
pendingInitialDiscontinuityPositionUs = enableInitialDiscontinuity ? startUs : C.TIME_UNSET;
|
||||||
startUs = C.TIME_UNSET;
|
this.startUs = startUs;
|
||||||
endUs = C.TIME_UNSET;
|
this.endUs = endUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the clipping start/end times for this period, in microseconds.
|
* Updates the clipping start/end times for this period, in microseconds.
|
||||||
*
|
*
|
||||||
* @param startUs The clipping start time, in microseconds.
|
* @param startUs The clipping start time, in microseconds.
|
||||||
* @param endUs The clipping end time, in microseconds, or {@link C#TIME_END_OF_SOURCE} to
|
* @param endUs The clipping end time, in microseconds, or {@link C#TIME_END_OF_SOURCE} to
|
||||||
* indicate the end of the period.
|
* indicate the end of the period.
|
||||||
*/
|
*/
|
||||||
public void setClipping(long startUs, long endUs) {
|
public void updateClipping(long startUs, long endUs) {
|
||||||
this.startUs = startUs;
|
this.startUs = startUs;
|
||||||
this.endUs = endUs;
|
this.endUs = endUs;
|
||||||
}
|
}
|
||||||
@ -79,7 +81,7 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
|||||||
@Override
|
@Override
|
||||||
public void prepare(MediaPeriod.Callback callback, long positionUs) {
|
public void prepare(MediaPeriod.Callback callback, long positionUs) {
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
mediaPeriod.prepare(this, startUs + positionUs);
|
mediaPeriod.prepare(this, positionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -101,13 +103,19 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
|||||||
sampleStreams[i] = (ClippingSampleStream) streams[i];
|
sampleStreams[i] = (ClippingSampleStream) streams[i];
|
||||||
childStreams[i] = sampleStreams[i] != null ? sampleStreams[i].childStream : null;
|
childStreams[i] = sampleStreams[i] != null ? sampleStreams[i].childStream : null;
|
||||||
}
|
}
|
||||||
long enablePositionUs = mediaPeriod.selectTracks(selections, mayRetainStreamFlags,
|
long enablePositionUs =
|
||||||
childStreams, streamResetFlags, positionUs + startUs) - startUs;
|
mediaPeriod.selectTracks(
|
||||||
pendingInitialDiscontinuityPositionUs = isPendingInitialDiscontinuity() && positionUs == 0
|
selections, mayRetainStreamFlags, childStreams, streamResetFlags, positionUs);
|
||||||
&& shouldKeepInitialDiscontinuity(startUs, selections) ? enablePositionUs : C.TIME_UNSET;
|
pendingInitialDiscontinuityPositionUs =
|
||||||
Assertions.checkState(enablePositionUs == positionUs
|
isPendingInitialDiscontinuity()
|
||||||
|| (enablePositionUs >= 0
|
&& positionUs == startUs
|
||||||
&& (endUs == C.TIME_END_OF_SOURCE || startUs + enablePositionUs <= endUs)));
|
&& shouldKeepInitialDiscontinuity(startUs, selections)
|
||||||
|
? enablePositionUs
|
||||||
|
: C.TIME_UNSET;
|
||||||
|
Assertions.checkState(
|
||||||
|
enablePositionUs == positionUs
|
||||||
|
|| (enablePositionUs >= startUs
|
||||||
|
&& (endUs == C.TIME_END_OF_SOURCE || enablePositionUs <= endUs)));
|
||||||
for (int i = 0; i < streams.length; i++) {
|
for (int i = 0; i < streams.length; i++) {
|
||||||
if (childStreams[i] == null) {
|
if (childStreams[i] == null) {
|
||||||
sampleStreams[i] = null;
|
sampleStreams[i] = null;
|
||||||
@ -121,12 +129,12 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void discardBuffer(long positionUs, boolean toKeyframe) {
|
public void discardBuffer(long positionUs, boolean toKeyframe) {
|
||||||
mediaPeriod.discardBuffer(positionUs + startUs, toKeyframe);
|
mediaPeriod.discardBuffer(positionUs, toKeyframe);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reevaluateBuffer(long positionUs) {
|
public void reevaluateBuffer(long positionUs) {
|
||||||
mediaPeriod.reevaluateBuffer(positionUs + startUs);
|
mediaPeriod.reevaluateBuffer(positionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -144,7 +152,7 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
|||||||
}
|
}
|
||||||
Assertions.checkState(discontinuityUs >= startUs);
|
Assertions.checkState(discontinuityUs >= startUs);
|
||||||
Assertions.checkState(endUs == C.TIME_END_OF_SOURCE || discontinuityUs <= endUs);
|
Assertions.checkState(endUs == C.TIME_END_OF_SOURCE || discontinuityUs <= endUs);
|
||||||
return discontinuityUs - startUs;
|
return discontinuityUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -154,7 +162,7 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
|||||||
|| (endUs != C.TIME_END_OF_SOURCE && bufferedPositionUs >= endUs)) {
|
|| (endUs != C.TIME_END_OF_SOURCE && bufferedPositionUs >= endUs)) {
|
||||||
return C.TIME_END_OF_SOURCE;
|
return C.TIME_END_OF_SOURCE;
|
||||||
}
|
}
|
||||||
return Math.max(0, bufferedPositionUs - startUs);
|
return bufferedPositionUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -165,23 +173,21 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
|||||||
sampleStream.clearSentEos();
|
sampleStream.clearSentEos();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
long offsetPositionUs = positionUs + startUs;
|
long seekUs = mediaPeriod.seekToUs(positionUs);
|
||||||
long seekUs = mediaPeriod.seekToUs(offsetPositionUs);
|
|
||||||
Assertions.checkState(
|
Assertions.checkState(
|
||||||
seekUs == offsetPositionUs
|
seekUs == positionUs
|
||||||
|| (seekUs >= startUs && (endUs == C.TIME_END_OF_SOURCE || seekUs <= endUs)));
|
|| (seekUs >= startUs && (endUs == C.TIME_END_OF_SOURCE || seekUs <= endUs)));
|
||||||
return seekUs - startUs;
|
return seekUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) {
|
public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) {
|
||||||
if (positionUs == 0) {
|
if (positionUs == startUs) {
|
||||||
// Never adjust seeks to the start of the clipped view.
|
// Never adjust seeks to the start of the clipped view.
|
||||||
return 0;
|
return startUs;
|
||||||
}
|
}
|
||||||
long offsetPositionUs = positionUs + startUs;
|
SeekParameters clippedSeekParameters = clipSeekParameters(positionUs, seekParameters);
|
||||||
SeekParameters clippedSeekParameters = clipSeekParameters(offsetPositionUs, seekParameters);
|
return mediaPeriod.getAdjustedSeekPositionUs(positionUs, clippedSeekParameters);
|
||||||
return mediaPeriod.getAdjustedSeekPositionUs(offsetPositionUs, clippedSeekParameters) - startUs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -191,19 +197,18 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
|||||||
|| (endUs != C.TIME_END_OF_SOURCE && nextLoadPositionUs >= endUs)) {
|
|| (endUs != C.TIME_END_OF_SOURCE && nextLoadPositionUs >= endUs)) {
|
||||||
return C.TIME_END_OF_SOURCE;
|
return C.TIME_END_OF_SOURCE;
|
||||||
}
|
}
|
||||||
return nextLoadPositionUs - startUs;
|
return nextLoadPositionUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean continueLoading(long positionUs) {
|
public boolean continueLoading(long positionUs) {
|
||||||
return mediaPeriod.continueLoading(positionUs + startUs);
|
return mediaPeriod.continueLoading(positionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MediaPeriod.Callback implementation.
|
// MediaPeriod.Callback implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPrepared(MediaPeriod mediaPeriod) {
|
public void onPrepared(MediaPeriod mediaPeriod) {
|
||||||
Assertions.checkState(startUs != C.TIME_UNSET && endUs != C.TIME_UNSET);
|
|
||||||
callback.onPrepared(this);
|
callback.onPrepared(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,17 +221,20 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
|||||||
return pendingInitialDiscontinuityPositionUs != C.TIME_UNSET;
|
return pendingInitialDiscontinuityPositionUs != C.TIME_UNSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SeekParameters clipSeekParameters(long offsetPositionUs, SeekParameters seekParameters) {
|
private SeekParameters clipSeekParameters(long positionUs, SeekParameters seekParameters) {
|
||||||
long toleranceBeforeMs = Math.min(offsetPositionUs - startUs, seekParameters.toleranceBeforeUs);
|
long toleranceBeforeUs =
|
||||||
long toleranceAfterMs =
|
Util.constrainValue(
|
||||||
endUs == C.TIME_END_OF_SOURCE
|
seekParameters.toleranceBeforeUs, /* min= */ 0, /* max= */ positionUs - startUs);
|
||||||
? seekParameters.toleranceAfterUs
|
long toleranceAfterUs =
|
||||||
: Math.min(endUs - offsetPositionUs, seekParameters.toleranceAfterUs);
|
Util.constrainValue(
|
||||||
if (toleranceBeforeMs == seekParameters.toleranceBeforeUs
|
seekParameters.toleranceAfterUs,
|
||||||
&& toleranceAfterMs == seekParameters.toleranceAfterUs) {
|
/* min= */ 0,
|
||||||
|
/* max= */ endUs == C.TIME_END_OF_SOURCE ? Long.MAX_VALUE : endUs - positionUs);
|
||||||
|
if (toleranceBeforeUs == seekParameters.toleranceBeforeUs
|
||||||
|
&& toleranceAfterUs == seekParameters.toleranceAfterUs) {
|
||||||
return seekParameters;
|
return seekParameters;
|
||||||
} else {
|
} else {
|
||||||
return new SeekParameters(toleranceBeforeMs, toleranceAfterMs);
|
return new SeekParameters(toleranceBeforeUs, toleranceAfterUs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,9 +318,6 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
|||||||
sentEos = true;
|
sentEos = true;
|
||||||
return C.RESULT_BUFFER_READ;
|
return C.RESULT_BUFFER_READ;
|
||||||
}
|
}
|
||||||
if (result == C.RESULT_BUFFER_READ && !buffer.isEndOfStream()) {
|
|
||||||
buffer.timeUs -= startUs;
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,7 +326,7 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
|||||||
if (isPendingInitialDiscontinuity()) {
|
if (isPendingInitialDiscontinuity()) {
|
||||||
return C.RESULT_NOTHING_READ;
|
return C.RESULT_NOTHING_READ;
|
||||||
}
|
}
|
||||||
return childStream.skipData(startUs + positionUs);
|
return childStream.skipData(positionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -76,14 +76,20 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
|||||||
private final long startUs;
|
private final long startUs;
|
||||||
private final long endUs;
|
private final long endUs;
|
||||||
private final boolean enableInitialDiscontinuity;
|
private final boolean enableInitialDiscontinuity;
|
||||||
|
private final boolean allowDynamicClippingUpdates;
|
||||||
|
private final boolean relativeToDefaultPosition;
|
||||||
private final ArrayList<ClippingMediaPeriod> mediaPeriods;
|
private final ArrayList<ClippingMediaPeriod> mediaPeriods;
|
||||||
|
private final Timeline.Window window;
|
||||||
|
|
||||||
|
private @Nullable Object manifest;
|
||||||
|
private ClippingTimeline clippingTimeline;
|
||||||
private IllegalClippingException clippingError;
|
private IllegalClippingException clippingError;
|
||||||
private long periodStartUs;
|
private long periodStartUs;
|
||||||
private long periodEndUs;
|
private long periodEndUs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new clipping source that wraps the specified source.
|
* Creates a new clipping source that wraps the specified source and provides samples between the
|
||||||
|
* specified start and end position.
|
||||||
*
|
*
|
||||||
* @param mediaSource The single-period source to wrap.
|
* @param mediaSource The single-period source to wrap.
|
||||||
* @param startPositionUs The start position within {@code mediaSource}'s window at which to start
|
* @param startPositionUs The start position within {@code mediaSource}'s window at which to start
|
||||||
@ -95,7 +101,62 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
|||||||
* being clipped.
|
* being clipped.
|
||||||
*/
|
*/
|
||||||
public ClippingMediaSource(MediaSource mediaSource, long startPositionUs, long endPositionUs) {
|
public ClippingMediaSource(MediaSource mediaSource, long startPositionUs, long endPositionUs) {
|
||||||
this(mediaSource, startPositionUs, endPositionUs, true);
|
this(
|
||||||
|
mediaSource,
|
||||||
|
startPositionUs,
|
||||||
|
endPositionUs,
|
||||||
|
/* enableInitialDiscontinuity= */ true,
|
||||||
|
/* allowDynamicClippingUpdates= */ false,
|
||||||
|
/* relativeToDefaultPosition= */ false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new clipping source that wraps the specified source and provides samples between the
|
||||||
|
* specified start and end position.
|
||||||
|
*
|
||||||
|
* @param mediaSource The single-period source to wrap.
|
||||||
|
* @param startPositionUs The start position within {@code mediaSource}'s window at which to start
|
||||||
|
* providing samples, in microseconds.
|
||||||
|
* @param endPositionUs The end position within {@code mediaSource}'s window at which to stop
|
||||||
|
* providing samples, in microseconds. Specify {@link C#TIME_END_OF_SOURCE} to provide samples
|
||||||
|
* from the specified start point up to the end of the source. Specifying a position that
|
||||||
|
* exceeds the {@code mediaSource}'s duration will also result in the end of the source not
|
||||||
|
* being clipped.
|
||||||
|
* @param enableInitialDiscontinuity Whether the initial discontinuity should be enabled.
|
||||||
|
*/
|
||||||
|
// TODO: remove this when the new API is public.
|
||||||
|
@Deprecated
|
||||||
|
public ClippingMediaSource(
|
||||||
|
MediaSource mediaSource,
|
||||||
|
long startPositionUs,
|
||||||
|
long endPositionUs,
|
||||||
|
boolean enableInitialDiscontinuity) {
|
||||||
|
this(
|
||||||
|
mediaSource,
|
||||||
|
startPositionUs,
|
||||||
|
endPositionUs,
|
||||||
|
enableInitialDiscontinuity,
|
||||||
|
/* allowDynamicClippingUpdates= */ false,
|
||||||
|
/* relativeToDefaultPosition= */ false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new clipping source that wraps the specified source and provides samples from the
|
||||||
|
* default position for the specified duration.
|
||||||
|
*
|
||||||
|
* @param mediaSource The single-period source to wrap.
|
||||||
|
* @param durationUs The duration from the default position in the window in {@code mediaSource}'s
|
||||||
|
* timeline at which to stop providing samples. Specifying a duration that exceeds the {@code
|
||||||
|
* mediaSource}'s duration will result in the end of the source not being clipped.
|
||||||
|
*/
|
||||||
|
public ClippingMediaSource(MediaSource mediaSource, long durationUs) {
|
||||||
|
this(
|
||||||
|
mediaSource,
|
||||||
|
/* startPositionUs= */ 0,
|
||||||
|
/* endPositionUs= */ durationUs,
|
||||||
|
/* enableInitialDiscontinuity= */ true,
|
||||||
|
/* allowDynamicClippingUpdates= */ false,
|
||||||
|
/* relativeToDefaultPosition= */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -105,27 +166,48 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
|||||||
* enableInitialPositionDiscontinuity} to suppress an initial discontinuity when a period is first
|
* enableInitialPositionDiscontinuity} to suppress an initial discontinuity when a period is first
|
||||||
* read from.
|
* read from.
|
||||||
*
|
*
|
||||||
|
* <p>For live streams, if the clipping positions should move with the live window, pass {@code
|
||||||
|
* true} to {@code allowDynamicClippingUpdates}. Otherwise, the live stream ends when the playback
|
||||||
|
* reaches {@code endPositionUs} in the last reported live window at the time a media period was
|
||||||
|
* created.
|
||||||
|
*
|
||||||
* @param mediaSource The single-period source to wrap.
|
* @param mediaSource The single-period source to wrap.
|
||||||
* @param startPositionUs The start position within {@code mediaSource}'s timeline at which to
|
* @param startPositionUs The start position at which to start providing samples, in microseconds.
|
||||||
* start providing samples, in microseconds.
|
* If {@code relativeToDefaultPosition} is {@code false}, this position is relative to the
|
||||||
* @param endPositionUs The end position within {@code mediaSource}'s timeline at which to stop
|
* start of the window in {@code mediaSource}'s timeline. If {@code relativeToDefaultPosition}
|
||||||
* providing samples, in microseconds. Specify {@link C#TIME_END_OF_SOURCE} to provide samples
|
* is {@code true}, this position is relative to the default position in the window in {@code
|
||||||
* from the specified start point up to the end of the source. Specifying a position that
|
* mediaSource}'s timeline.
|
||||||
* exceeds the {@code mediaSource}'s duration will also result in the end of the source not
|
* @param endPositionUs The end position at which to stop providing samples, in microseconds.
|
||||||
* being clipped.
|
* Specify {@link C#TIME_END_OF_SOURCE} to provide samples from the specified start point up
|
||||||
|
* to the end of the source. Specifying a position that exceeds the {@code mediaSource}'s
|
||||||
|
* duration will also result in the end of the source not being clipped. If {@code
|
||||||
|
* relativeToDefaultPosition} is {@code false}, the specified position is relative to the
|
||||||
|
* start of the window in {@code mediaSource}'s timeline. If {@code relativeToDefaultPosition}
|
||||||
|
* is {@code true}, this position is relative to the default position in the window in {@code
|
||||||
|
* mediaSource}'s timeline.
|
||||||
* @param enableInitialDiscontinuity Whether the initial discontinuity should be enabled.
|
* @param enableInitialDiscontinuity Whether the initial discontinuity should be enabled.
|
||||||
|
* @param allowDynamicClippingUpdates Whether the clipping of active media periods moves with a
|
||||||
|
* live window. If {@code false}, playback ends when it reaches {@code endPositionUs} in the
|
||||||
|
* last reported live window at the time a media period was created.
|
||||||
|
* @param relativeToDefaultPosition Whether {@code startPositionUs} and {@code endPositionUs} are
|
||||||
|
* relative to the default position in the window in {@code mediaSource}'s timeline.
|
||||||
*/
|
*/
|
||||||
public ClippingMediaSource(
|
public ClippingMediaSource(
|
||||||
MediaSource mediaSource,
|
MediaSource mediaSource,
|
||||||
long startPositionUs,
|
long startPositionUs,
|
||||||
long endPositionUs,
|
long endPositionUs,
|
||||||
boolean enableInitialDiscontinuity) {
|
boolean enableInitialDiscontinuity,
|
||||||
|
boolean allowDynamicClippingUpdates,
|
||||||
|
boolean relativeToDefaultPosition) {
|
||||||
Assertions.checkArgument(startPositionUs >= 0);
|
Assertions.checkArgument(startPositionUs >= 0);
|
||||||
this.mediaSource = Assertions.checkNotNull(mediaSource);
|
this.mediaSource = Assertions.checkNotNull(mediaSource);
|
||||||
startUs = startPositionUs;
|
startUs = startPositionUs;
|
||||||
endUs = endPositionUs;
|
endUs = endPositionUs;
|
||||||
this.enableInitialDiscontinuity = enableInitialDiscontinuity;
|
this.enableInitialDiscontinuity = enableInitialDiscontinuity;
|
||||||
|
this.allowDynamicClippingUpdates = allowDynamicClippingUpdates;
|
||||||
|
this.relativeToDefaultPosition = relativeToDefaultPosition;
|
||||||
mediaPeriods = new ArrayList<>();
|
mediaPeriods = new ArrayList<>();
|
||||||
|
window = new Timeline.Window();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -146,9 +228,11 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
|||||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
|
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
|
||||||
ClippingMediaPeriod mediaPeriod =
|
ClippingMediaPeriod mediaPeriod =
|
||||||
new ClippingMediaPeriod(
|
new ClippingMediaPeriod(
|
||||||
mediaSource.createPeriod(id, allocator), enableInitialDiscontinuity);
|
mediaSource.createPeriod(id, allocator),
|
||||||
|
enableInitialDiscontinuity,
|
||||||
|
periodStartUs,
|
||||||
|
periodEndUs);
|
||||||
mediaPeriods.add(mediaPeriod);
|
mediaPeriods.add(mediaPeriod);
|
||||||
mediaPeriod.setClipping(periodStartUs, periodEndUs);
|
|
||||||
return mediaPeriod;
|
return mediaPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,12 +240,16 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
|||||||
public void releasePeriod(MediaPeriod mediaPeriod) {
|
public void releasePeriod(MediaPeriod mediaPeriod) {
|
||||||
Assertions.checkState(mediaPeriods.remove(mediaPeriod));
|
Assertions.checkState(mediaPeriods.remove(mediaPeriod));
|
||||||
mediaSource.releasePeriod(((ClippingMediaPeriod) mediaPeriod).mediaPeriod);
|
mediaSource.releasePeriod(((ClippingMediaPeriod) mediaPeriod).mediaPeriod);
|
||||||
|
if (mediaPeriods.isEmpty() && !allowDynamicClippingUpdates) {
|
||||||
|
refreshClippedTimeline(clippingTimeline.timeline);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void releaseSourceInternal() {
|
public void releaseSourceInternal() {
|
||||||
super.releaseSourceInternal();
|
super.releaseSourceInternal();
|
||||||
clippingError = null;
|
clippingError = null;
|
||||||
|
clippingTimeline = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -170,25 +258,47 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
|||||||
if (clippingError != null) {
|
if (clippingError != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ClippingTimeline clippingTimeline;
|
this.manifest = manifest;
|
||||||
|
refreshClippedTimeline(timeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshClippedTimeline(Timeline timeline) {
|
||||||
|
long windowStartUs;
|
||||||
|
long windowEndUs;
|
||||||
|
timeline.getWindow(/* windowIndex= */ 0, window);
|
||||||
|
long windowPositionInPeriodUs = window.getPositionInFirstPeriodUs();
|
||||||
|
if (clippingTimeline == null || mediaPeriods.isEmpty() || allowDynamicClippingUpdates) {
|
||||||
|
windowStartUs = startUs;
|
||||||
|
windowEndUs = endUs;
|
||||||
|
if (relativeToDefaultPosition) {
|
||||||
|
long windowDefaultPositionUs = window.getDefaultPositionUs();
|
||||||
|
windowStartUs += windowDefaultPositionUs;
|
||||||
|
windowEndUs += windowDefaultPositionUs;
|
||||||
|
}
|
||||||
|
periodStartUs = windowPositionInPeriodUs + windowStartUs;
|
||||||
|
periodEndUs =
|
||||||
|
endUs == C.TIME_END_OF_SOURCE
|
||||||
|
? C.TIME_END_OF_SOURCE
|
||||||
|
: windowPositionInPeriodUs + windowEndUs;
|
||||||
|
int count = mediaPeriods.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
mediaPeriods.get(i).updateClipping(periodStartUs, periodEndUs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Keep window fixed at previous period position.
|
||||||
|
windowStartUs = periodStartUs - windowPositionInPeriodUs;
|
||||||
|
windowEndUs =
|
||||||
|
endUs == C.TIME_END_OF_SOURCE
|
||||||
|
? C.TIME_END_OF_SOURCE
|
||||||
|
: periodEndUs - windowPositionInPeriodUs;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
clippingTimeline = new ClippingTimeline(timeline, startUs, endUs);
|
clippingTimeline = new ClippingTimeline(timeline, windowStartUs, windowEndUs);
|
||||||
} catch (IllegalClippingException e) {
|
} catch (IllegalClippingException e) {
|
||||||
clippingError = e;
|
clippingError = e;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
refreshSourceInfo(clippingTimeline, manifest);
|
refreshSourceInfo(clippingTimeline, manifest);
|
||||||
long windowPositionInPeriodUs =
|
|
||||||
timeline
|
|
||||||
.getWindow(/* windowIndex= */ 0, new Timeline.Window())
|
|
||||||
.getPositionInFirstPeriodUs();
|
|
||||||
periodStartUs = windowPositionInPeriodUs + startUs;
|
|
||||||
periodEndUs =
|
|
||||||
endUs == C.TIME_END_OF_SOURCE ? C.TIME_END_OF_SOURCE : windowPositionInPeriodUs + endUs;
|
|
||||||
int count = mediaPeriods.size();
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
mediaPeriods.get(i).setClipping(periodStartUs, periodEndUs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -212,6 +322,7 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
|||||||
private final long startUs;
|
private final long startUs;
|
||||||
private final long endUs;
|
private final long endUs;
|
||||||
private final long durationUs;
|
private final long durationUs;
|
||||||
|
private final boolean isDynamic;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new clipping timeline that wraps the specified timeline.
|
* Creates a new clipping timeline that wraps the specified timeline.
|
||||||
@ -229,7 +340,8 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
|||||||
throw new IllegalClippingException(IllegalClippingException.REASON_INVALID_PERIOD_COUNT);
|
throw new IllegalClippingException(IllegalClippingException.REASON_INVALID_PERIOD_COUNT);
|
||||||
}
|
}
|
||||||
Window window = timeline.getWindow(0, new Window(), false);
|
Window window = timeline.getWindow(0, new Window(), false);
|
||||||
long resolvedEndUs = endUs == C.TIME_END_OF_SOURCE ? window.durationUs : endUs;
|
startUs = Math.max(0, startUs);
|
||||||
|
long resolvedEndUs = endUs == C.TIME_END_OF_SOURCE ? window.durationUs : Math.max(0, endUs);
|
||||||
if (window.durationUs != C.TIME_UNSET) {
|
if (window.durationUs != C.TIME_UNSET) {
|
||||||
if (resolvedEndUs > window.durationUs) {
|
if (resolvedEndUs > window.durationUs) {
|
||||||
resolvedEndUs = window.durationUs;
|
resolvedEndUs = window.durationUs;
|
||||||
@ -244,14 +356,20 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
|||||||
this.startUs = startUs;
|
this.startUs = startUs;
|
||||||
this.endUs = resolvedEndUs;
|
this.endUs = resolvedEndUs;
|
||||||
durationUs = resolvedEndUs == C.TIME_UNSET ? C.TIME_UNSET : (resolvedEndUs - startUs);
|
durationUs = resolvedEndUs == C.TIME_UNSET ? C.TIME_UNSET : (resolvedEndUs - startUs);
|
||||||
|
isDynamic =
|
||||||
|
window.isDynamic
|
||||||
|
&& (resolvedEndUs == C.TIME_UNSET
|
||||||
|
|| (window.durationUs != C.TIME_UNSET && resolvedEndUs == window.durationUs));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Window getWindow(
|
public Window getWindow(
|
||||||
int windowIndex, Window window, boolean setIds, long defaultPositionProjectionUs) {
|
int windowIndex, Window window, boolean setTag, long defaultPositionProjectionUs) {
|
||||||
timeline.getWindow(/* windowIndex= */ 0, window, setIds, defaultPositionProjectionUs);
|
timeline.getWindow(
|
||||||
window.positionInFirstPeriodUs = 0;
|
/* windowIndex= */ 0, window, setTag, /* defaultPositionProjectionUs= */ 0);
|
||||||
|
window.positionInFirstPeriodUs += startUs;
|
||||||
window.durationUs = durationUs;
|
window.durationUs = durationUs;
|
||||||
|
window.isDynamic = isDynamic;
|
||||||
if (window.defaultPositionUs != C.TIME_UNSET) {
|
if (window.defaultPositionUs != C.TIME_UNSET) {
|
||||||
window.defaultPositionUs = Math.max(window.defaultPositionUs, startUs);
|
window.defaultPositionUs = Math.max(window.defaultPositionUs, startUs);
|
||||||
window.defaultPositionUs = endUs == C.TIME_UNSET ? window.defaultPositionUs
|
window.defaultPositionUs = endUs == C.TIME_UNSET ? window.defaultPositionUs
|
||||||
@ -271,11 +389,11 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
|||||||
@Override
|
@Override
|
||||||
public Period getPeriod(int periodIndex, Period period, boolean setIds) {
|
public Period getPeriod(int periodIndex, Period period, boolean setIds) {
|
||||||
timeline.getPeriod(/* periodIndex= */ 0, period, setIds);
|
timeline.getPeriod(/* periodIndex= */ 0, period, setIds);
|
||||||
|
long positionInClippedWindowUs = period.getPositionInWindowUs() - startUs;
|
||||||
|
long periodDurationUs =
|
||||||
|
durationUs == C.TIME_UNSET ? C.TIME_UNSET : durationUs - positionInClippedWindowUs;
|
||||||
return period.set(
|
return period.set(
|
||||||
period.id, period.uid, /* windowIndex= */ 0, durationUs, /* positionInWindowUs= */ 0);
|
period.id, period.uid, /* windowIndex= */ 0, periodDurationUs, positionInClippedWindowUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ public final class ClippingMediaSourceTest {
|
|||||||
assertThat(clippedTimeline.getWindow(0, window).getDurationUs())
|
assertThat(clippedTimeline.getWindow(0, window).getDurationUs())
|
||||||
.isEqualTo(TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US);
|
.isEqualTo(TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US);
|
||||||
assertThat(clippedTimeline.getPeriod(0, period).getDurationUs())
|
assertThat(clippedTimeline.getPeriod(0, period).getDurationUs())
|
||||||
.isEqualTo(TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US);
|
.isEqualTo(TEST_PERIOD_DURATION_US);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -128,7 +128,7 @@ public final class ClippingMediaSourceTest {
|
|||||||
assertThat(clippedTimeline.getWindow(0, window).getDurationUs())
|
assertThat(clippedTimeline.getWindow(0, window).getDurationUs())
|
||||||
.isEqualTo(TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US * 3);
|
.isEqualTo(TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US * 3);
|
||||||
assertThat(clippedTimeline.getPeriod(0, period).getDurationUs())
|
assertThat(clippedTimeline.getPeriod(0, period).getDurationUs())
|
||||||
.isEqualTo(TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US * 3);
|
.isEqualTo(TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -171,7 +171,7 @@ public final class ClippingMediaSourceTest {
|
|||||||
assertThat(clippedTimeline.getWindow(0, window).getDurationUs())
|
assertThat(clippedTimeline.getWindow(0, window).getDurationUs())
|
||||||
.isEqualTo(TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US * 3);
|
.isEqualTo(TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US * 3);
|
||||||
assertThat(clippedTimeline.getPeriod(0, period).getDurationUs())
|
assertThat(clippedTimeline.getPeriod(0, period).getDurationUs())
|
||||||
.isEqualTo(TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US * 3);
|
.isEqualTo(TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
x
Reference in New Issue
Block a user