mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Allow clipping offset windows
ClippingMediaSource provides a timeline where the period and window have the same start/end positions, so when clipping a child timeline with a non-zero offset between the window and period it is necessary to clear the offset then apply the offset to the start/end positions used in the ClippingMediaPeriod. Also add a message to clipping exceptions. Also fix adjustment of seeks to the start of the clipped view. Issue: #3888 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=187292506
This commit is contained in:
parent
b2c445776a
commit
38914f0ba5
3 changed files with 50 additions and 44 deletions
|
|
@ -7,6 +7,9 @@
|
||||||
* MediaSources: Allow reusing media sources after they have been released and
|
* MediaSources: Allow reusing media sources after they have been released and
|
||||||
also in parallel to allow adding them multiple times to a concatenation.
|
also in parallel to allow adding them multiple times to a concatenation.
|
||||||
([#3498](https://github.com/google/ExoPlayer/issues/3498)).
|
([#3498](https://github.com/google/ExoPlayer/issues/3498)).
|
||||||
|
* Allow clipping of child media sources where the period and window have a
|
||||||
|
non-zero offset with `ClippingMediaSource`
|
||||||
|
([#3888](https://github.com/google/ExoPlayer/issues/3888)).
|
||||||
|
|
||||||
### 2.7.0 ###
|
### 2.7.0 ###
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) {
|
public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) {
|
||||||
if (positionUs == startUs) {
|
if (positionUs == 0) {
|
||||||
// Never adjust seeks to the start of the clipped view.
|
// Never adjust seeks to the start of the clipped view.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,53 +29,47 @@ import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link MediaSource} that wraps a source and clips its timeline based on specified start/end
|
* {@link MediaSource} that wraps a source and clips its timeline based on specified start/end
|
||||||
* positions. The wrapped source must consist of a single period that starts at the beginning of the
|
* positions. The wrapped source must consist of a single period.
|
||||||
* corresponding window.
|
|
||||||
*/
|
*/
|
||||||
public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
||||||
|
|
||||||
/**
|
/** Thrown when a {@link ClippingMediaSource} cannot clip its wrapped source. */
|
||||||
* Thrown when a {@link ClippingMediaSource} cannot clip its wrapped source.
|
|
||||||
*/
|
|
||||||
public static final class IllegalClippingException extends IOException {
|
public static final class IllegalClippingException extends IOException {
|
||||||
|
|
||||||
/**
|
/** The reason clipping failed. */
|
||||||
* The reason the clipping failed.
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@IntDef({REASON_INVALID_PERIOD_COUNT, REASON_PERIOD_OFFSET_IN_WINDOW,
|
@IntDef({REASON_INVALID_PERIOD_COUNT, REASON_NOT_SEEKABLE_TO_START, REASON_START_EXCEEDS_END})
|
||||||
REASON_NOT_SEEKABLE_TO_START, REASON_START_EXCEEDS_END})
|
|
||||||
public @interface Reason {}
|
public @interface Reason {}
|
||||||
/**
|
/** The wrapped source doesn't consist of a single period. */
|
||||||
* The wrapped source doesn't consist of a single period.
|
|
||||||
*/
|
|
||||||
public static final int REASON_INVALID_PERIOD_COUNT = 0;
|
public static final int REASON_INVALID_PERIOD_COUNT = 0;
|
||||||
/**
|
/** The wrapped source is not seekable and a non-zero clipping start position was specified. */
|
||||||
* The wrapped source period doesn't start at the beginning of the corresponding window.
|
public static final int REASON_NOT_SEEKABLE_TO_START = 1;
|
||||||
*/
|
/** The wrapped source ends before the specified clipping start position. */
|
||||||
public static final int REASON_PERIOD_OFFSET_IN_WINDOW = 1;
|
public static final int REASON_START_EXCEEDS_END = 2;
|
||||||
/**
|
|
||||||
* The wrapped source is not seekable and a non-zero clipping start position was specified.
|
|
||||||
*/
|
|
||||||
public static final int REASON_NOT_SEEKABLE_TO_START = 2;
|
|
||||||
/**
|
|
||||||
* The wrapped source ends before the specified clipping start position.
|
|
||||||
*/
|
|
||||||
public static final int REASON_START_EXCEEDS_END = 3;
|
|
||||||
|
|
||||||
/**
|
/** The reason clipping failed. */
|
||||||
* The reason clipping failed.
|
public final @Reason int reason;
|
||||||
*/
|
|
||||||
@Reason
|
|
||||||
public final int reason;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param reason The reason clipping failed.
|
* @param reason The reason clipping failed.
|
||||||
*/
|
*/
|
||||||
public IllegalClippingException(@Reason int reason) {
|
public IllegalClippingException(@Reason int reason) {
|
||||||
|
super("Illegal clipping: " + getReasonDescription(reason));
|
||||||
this.reason = reason;
|
this.reason = reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getReasonDescription(@Reason int reason) {
|
||||||
|
switch (reason) {
|
||||||
|
case REASON_INVALID_PERIOD_COUNT:
|
||||||
|
return "invalid period count";
|
||||||
|
case REASON_NOT_SEEKABLE_TO_START:
|
||||||
|
return "not seekable to start";
|
||||||
|
case REASON_START_EXCEEDS_END:
|
||||||
|
return "start exceeds end";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final MediaSource mediaSource;
|
private final MediaSource mediaSource;
|
||||||
|
|
@ -85,14 +79,16 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
||||||
private final ArrayList<ClippingMediaPeriod> mediaPeriods;
|
private final ArrayList<ClippingMediaPeriod> mediaPeriods;
|
||||||
|
|
||||||
private IllegalClippingException clippingError;
|
private IllegalClippingException clippingError;
|
||||||
|
private long periodStartUs;
|
||||||
|
private long periodEndUs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new clipping source that wraps the specified source.
|
* Creates a new clipping source that wraps the specified source.
|
||||||
*
|
*
|
||||||
* @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 within {@code mediaSource}'s window at which to start
|
||||||
* start providing samples, in microseconds.
|
* providing samples, in microseconds.
|
||||||
* @param endPositionUs The end position within {@code mediaSource}'s timeline at which to stop
|
* @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
|
* 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
|
* 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
|
* exceeds the {@code mediaSource}'s duration will also result in the end of the source not
|
||||||
|
|
@ -148,7 +144,7 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
||||||
ClippingMediaPeriod mediaPeriod = new ClippingMediaPeriod(
|
ClippingMediaPeriod mediaPeriod = new ClippingMediaPeriod(
|
||||||
mediaSource.createPeriod(id, allocator), enableInitialDiscontinuity);
|
mediaSource.createPeriod(id, allocator), enableInitialDiscontinuity);
|
||||||
mediaPeriods.add(mediaPeriod);
|
mediaPeriods.add(mediaPeriod);
|
||||||
mediaPeriod.setClipping(startUs, endUs);
|
mediaPeriod.setClipping(periodStartUs, periodEndUs);
|
||||||
return mediaPeriod;
|
return mediaPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -178,9 +174,16 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
||||||
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();
|
int count = mediaPeriods.size();
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
mediaPeriods.get(i).setClipping(startUs, endUs);
|
mediaPeriods.get(i).setClipping(periodStartUs, periodEndUs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,6 +194,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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new clipping timeline that wraps the specified timeline.
|
* Creates a new clipping timeline that wraps the specified timeline.
|
||||||
|
|
@ -207,9 +211,6 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
||||||
if (timeline.getPeriodCount() != 1) {
|
if (timeline.getPeriodCount() != 1) {
|
||||||
throw new IllegalClippingException(IllegalClippingException.REASON_INVALID_PERIOD_COUNT);
|
throw new IllegalClippingException(IllegalClippingException.REASON_INVALID_PERIOD_COUNT);
|
||||||
}
|
}
|
||||||
if (timeline.getPeriod(0, new Period()).getPositionInWindowUs() != 0) {
|
|
||||||
throw new IllegalClippingException(IllegalClippingException.REASON_PERIOD_OFFSET_IN_WINDOW);
|
|
||||||
}
|
|
||||||
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;
|
long resolvedEndUs = endUs == C.TIME_END_OF_SOURCE ? window.durationUs : endUs;
|
||||||
if (window.durationUs != C.TIME_UNSET) {
|
if (window.durationUs != C.TIME_UNSET) {
|
||||||
|
|
@ -225,13 +226,15 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
|
||||||
}
|
}
|
||||||
this.startUs = startUs;
|
this.startUs = startUs;
|
||||||
this.endUs = resolvedEndUs;
|
this.endUs = resolvedEndUs;
|
||||||
|
durationUs = endUs == C.TIME_UNSET ? C.TIME_UNSET : endUs - startUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Window getWindow(int windowIndex, Window window, boolean setIds,
|
public Window getWindow(int windowIndex, Window window, boolean setIds,
|
||||||
long defaultPositionProjectionUs) {
|
long defaultPositionProjectionUs) {
|
||||||
window = timeline.getWindow(0, window, setIds, defaultPositionProjectionUs);
|
timeline.getWindow(/* windowIndex= */ 0, window, setIds, defaultPositionProjectionUs);
|
||||||
window.durationUs = endUs != C.TIME_UNSET ? endUs - startUs : C.TIME_UNSET;
|
window.positionInFirstPeriodUs = 0;
|
||||||
|
window.durationUs = durationUs;
|
||||||
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
|
||||||
|
|
@ -250,9 +253,9 @@ 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) {
|
||||||
period = timeline.getPeriod(0, period, setIds);
|
timeline.getPeriod(/* periodIndex= */ 0, period, setIds);
|
||||||
period.durationUs = endUs != C.TIME_UNSET ? endUs - startUs : C.TIME_UNSET;
|
return period.set(
|
||||||
return period;
|
period.id, period.uid, /* windowIndex= */ 0, durationUs, /* positionInWindowUs= */ 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue