Report correct discontinuity from ClippingMediaPeriod

It currently always reports 0, but it should report the position
passed through selectTracks. Reporting should also be disabled if
there's a seekToUs call.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176644228
This commit is contained in:
olly 2017-11-22 05:36:20 -08:00 committed by Oliver Woodman
parent b5480e0e97
commit d909dc1863

View file

@ -36,10 +36,10 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
public final MediaPeriod mediaPeriod; public final MediaPeriod mediaPeriod;
private MediaPeriod.Callback callback; private MediaPeriod.Callback callback;
private long startUs;
private long endUs;
private ClippingSampleStream[] sampleStreams; private ClippingSampleStream[] sampleStreams;
private boolean pendingInitialDiscontinuity; private long pendingInitialDiscontinuityPositionUs;
/* package */ long startUs;
/* 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
@ -57,10 +57,10 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
*/ */
public ClippingMediaPeriod(MediaPeriod mediaPeriod, boolean enableInitialDiscontinuity) { public ClippingMediaPeriod(MediaPeriod mediaPeriod, boolean enableInitialDiscontinuity) {
this.mediaPeriod = mediaPeriod; this.mediaPeriod = mediaPeriod;
sampleStreams = new ClippingSampleStream[0];
pendingInitialDiscontinuityPositionUs = enableInitialDiscontinuity ? 0 : C.TIME_UNSET;
startUs = C.TIME_UNSET; startUs = C.TIME_UNSET;
endUs = C.TIME_UNSET; endUs = C.TIME_UNSET;
sampleStreams = new ClippingSampleStream[0];
pendingInitialDiscontinuity = enableInitialDiscontinuity;
} }
/** /**
@ -95,29 +95,27 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags,
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) { SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
sampleStreams = new ClippingSampleStream[streams.length]; sampleStreams = new ClippingSampleStream[streams.length];
SampleStream[] internalStreams = new SampleStream[streams.length]; SampleStream[] childStreams = new SampleStream[streams.length];
for (int i = 0; i < streams.length; i++) { for (int i = 0; i < streams.length; i++) {
sampleStreams[i] = (ClippingSampleStream) streams[i]; sampleStreams[i] = (ClippingSampleStream) streams[i];
internalStreams[i] = sampleStreams[i] != null ? sampleStreams[i].stream : null; childStreams[i] = sampleStreams[i] != null ? sampleStreams[i].childStream : null;
} }
long enablePositionUs = mediaPeriod.selectTracks(selections, mayRetainStreamFlags, long enablePositionUs = mediaPeriod.selectTracks(selections, mayRetainStreamFlags,
internalStreams, streamResetFlags, positionUs + startUs); childStreams, streamResetFlags, positionUs + startUs) - startUs;
if (pendingInitialDiscontinuity) { pendingInitialDiscontinuityPositionUs = isPendingInitialDiscontinuity() && positionUs == 0
pendingInitialDiscontinuity = startUs != 0 && shouldKeepInitialDiscontinuity(selections); && shouldKeepInitialDiscontinuity(startUs, selections) ? enablePositionUs : C.TIME_UNSET;
} Assertions.checkState(enablePositionUs == positionUs
Assertions.checkState(enablePositionUs == positionUs + startUs || (enablePositionUs >= 0
|| (enablePositionUs >= startUs && (endUs == C.TIME_END_OF_SOURCE || startUs + enablePositionUs <= endUs)));
&& (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 (internalStreams[i] == null) { if (childStreams[i] == null) {
sampleStreams[i] = null; sampleStreams[i] = null;
} else if (streams[i] == null || sampleStreams[i].stream != internalStreams[i]) { } else if (streams[i] == null || sampleStreams[i].childStream != childStreams[i]) {
sampleStreams[i] = new ClippingSampleStream(this, internalStreams[i], startUs, endUs, sampleStreams[i] = new ClippingSampleStream(childStreams[i]);
pendingInitialDiscontinuity);
} }
streams[i] = sampleStreams[i]; streams[i] = sampleStreams[i];
} }
return enablePositionUs - startUs; return enablePositionUs;
} }
@Override @Override
@ -127,16 +125,12 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
@Override @Override
public long readDiscontinuity() { public long readDiscontinuity() {
if (pendingInitialDiscontinuity) { if (isPendingInitialDiscontinuity()) {
for (ClippingSampleStream sampleStream : sampleStreams) { long initialDiscontinuityUs = pendingInitialDiscontinuityPositionUs;
if (sampleStream != null) { pendingInitialDiscontinuityPositionUs = C.TIME_UNSET;
sampleStream.clearPendingDiscontinuity(); // Always read an initial discontinuity from the child, and use it if set.
} long childDiscontinuityUs = readDiscontinuity();
} return childDiscontinuityUs != C.TIME_UNSET ? childDiscontinuityUs : initialDiscontinuityUs;
pendingInitialDiscontinuity = false;
// Always read an initial discontinuity, using mediaPeriod's discontinuity if set.
long discontinuityUs = readDiscontinuity();
return discontinuityUs != C.TIME_UNSET ? discontinuityUs : 0;
} }
long discontinuityUs = mediaPeriod.readDiscontinuity(); long discontinuityUs = mediaPeriod.readDiscontinuity();
if (discontinuityUs == C.TIME_UNSET) { if (discontinuityUs == C.TIME_UNSET) {
@ -159,6 +153,7 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
@Override @Override
public long seekToUs(long positionUs) { public long seekToUs(long positionUs) {
pendingInitialDiscontinuityPositionUs = C.TIME_UNSET;
for (ClippingSampleStream sampleStream : sampleStreams) { for (ClippingSampleStream sampleStream : sampleStreams) {
if (sampleStream != null) { if (sampleStream != null) {
sampleStream.clearSentEos(); sampleStream.clearSentEos();
@ -198,7 +193,11 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
callback.onContinueLoadingRequested(this); callback.onContinueLoadingRequested(this);
} }
private static boolean shouldKeepInitialDiscontinuity(TrackSelection[] selections) { /* package */ boolean isPendingInitialDiscontinuity() {
return pendingInitialDiscontinuityPositionUs != C.TIME_UNSET;
}
private static boolean shouldKeepInitialDiscontinuity(long startUs, TrackSelection[] selections) {
// If the clipping start position is non-zero, the clipping sample streams will adjust // If the clipping start position is non-zero, the clipping sample streams will adjust
// timestamps on buffers they read from the unclipped sample streams. These adjusted buffer // timestamps on buffers they read from the unclipped sample streams. These adjusted buffer
// timestamps can be negative, because sample streams provide buffers starting at a key-frame, // timestamps can be negative, because sample streams provide buffers starting at a key-frame,
@ -208,6 +207,7 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
// discontinuity which resets the renderers before they read the clipping sample stream. // discontinuity which resets the renderers before they read the clipping sample stream.
// However, for audio-only track selections we assume to have random access seek behaviour and // However, for audio-only track selections we assume to have random access seek behaviour and
// do not need an initial discontinuity to reset the renderer. // do not need an initial discontinuity to reset the renderer.
if (startUs != 0) {
for (TrackSelection trackSelection : selections) { for (TrackSelection trackSelection : selections) {
if (trackSelection != null) { if (trackSelection != null) {
Format selectedFormat = trackSelection.getSelectedFormat(); Format selectedFormat = trackSelection.getSelectedFormat();
@ -216,33 +216,21 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
} }
} }
} }
}
return false; return false;
} }
/** /**
* Wraps a {@link SampleStream} and clips its samples. * Wraps a {@link SampleStream} and clips its samples.
*/ */
private static final class ClippingSampleStream implements SampleStream { private final class ClippingSampleStream implements SampleStream {
private final MediaPeriod mediaPeriod; public final SampleStream childStream;
private final SampleStream stream;
private final long startUs;
private final long endUs;
private boolean pendingDiscontinuity;
private boolean sentEos; private boolean sentEos;
public ClippingSampleStream(MediaPeriod mediaPeriod, SampleStream stream, long startUs, public ClippingSampleStream(SampleStream childStream) {
long endUs, boolean pendingDiscontinuity) { this.childStream = childStream;
this.mediaPeriod = mediaPeriod;
this.stream = stream;
this.startUs = startUs;
this.endUs = endUs;
this.pendingDiscontinuity = pendingDiscontinuity;
}
public void clearPendingDiscontinuity() {
pendingDiscontinuity = false;
} }
public void clearSentEos() { public void clearSentEos() {
@ -251,25 +239,25 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
@Override @Override
public boolean isReady() { public boolean isReady() {
return stream.isReady(); return !isPendingInitialDiscontinuity() && childStream.isReady();
} }
@Override @Override
public void maybeThrowError() throws IOException { public void maybeThrowError() throws IOException {
stream.maybeThrowError(); childStream.maybeThrowError();
} }
@Override @Override
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer,
boolean requireFormat) { boolean requireFormat) {
if (pendingDiscontinuity) { if (isPendingInitialDiscontinuity()) {
return C.RESULT_NOTHING_READ; return C.RESULT_NOTHING_READ;
} }
if (sentEos) { if (sentEos) {
buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM); buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
return C.RESULT_BUFFER_READ; return C.RESULT_BUFFER_READ;
} }
int result = stream.readData(formatHolder, buffer, requireFormat); int result = childStream.readData(formatHolder, buffer, requireFormat);
if (result == C.RESULT_FORMAT_READ) { if (result == C.RESULT_FORMAT_READ) {
// Clear gapless playback metadata if the start/end points don't match the media. // Clear gapless playback metadata if the start/end points don't match the media.
Format format = formatHolder.format; Format format = formatHolder.format;
@ -294,7 +282,10 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
@Override @Override
public int skipData(long positionUs) { public int skipData(long positionUs) {
return stream.skipData(startUs + positionUs); if (isPendingInitialDiscontinuity()) {
return C.RESULT_NOTHING_READ;
}
return childStream.skipData(startUs + positionUs);
} }
} }