mirror of
https://github.com/androidx/media.git
synced 2025-05-03 21:57:46 +08:00
Enable SeekParameters functionality for ExtractorMediaSource
Also fix ClippingMediaSource to consider the start position an artificial key-frame, and to properly offset the value returned by getAdjustedSeekPositionUs. Issue: #2882 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=179032243
This commit is contained in:
parent
a17375b7d3
commit
37a275f67e
@ -16,6 +16,12 @@
|
||||
sub-streams, by allowing injection of custom `CompositeSequenceableLoader`
|
||||
factories through `DashMediaSource.Factory`, `HlsMediaSource.Factory`,
|
||||
`SsMediaSource.Factory`, and `MergingMediaSource`.
|
||||
* Add `ExoPlayer.setSeekParameters` for controlling how seek operations are
|
||||
performed. The `SeekParameters` class contains defaults for exact seeking and
|
||||
seeking to the closest sync points before, either side or after specified seek
|
||||
positions.
|
||||
* Note: `SeekParameters` are only currently effective when playing
|
||||
`ExtractorMediaSource`s (i.e. progressive streams).
|
||||
* DASH: Support DASH manifest EventStream elements.
|
||||
* HLS: Add opt-in support for chunkless preparation in HLS. This allows an
|
||||
HLS source to finish preparation without downloading any chunks, which can
|
||||
|
@ -678,20 +678,20 @@ import java.io.IOException;
|
||||
periodPositionUs = 0;
|
||||
}
|
||||
try {
|
||||
long newPeriodPositionUs = periodPositionUs;
|
||||
if (periodId.equals(playbackInfo.periodId)) {
|
||||
long adjustedPeriodPositionUs = periodPositionUs;
|
||||
if (playingPeriodHolder != null) {
|
||||
adjustedPeriodPositionUs =
|
||||
if (playingPeriodHolder != null && newPeriodPositionUs != 0) {
|
||||
newPeriodPositionUs =
|
||||
playingPeriodHolder.mediaPeriod.getAdjustedSeekPositionUs(
|
||||
adjustedPeriodPositionUs, SeekParameters.DEFAULT);
|
||||
newPeriodPositionUs, seekParameters);
|
||||
}
|
||||
if ((adjustedPeriodPositionUs / 1000) == (playbackInfo.positionUs / 1000)) {
|
||||
if ((newPeriodPositionUs / 1000) == (playbackInfo.positionUs / 1000)) {
|
||||
// Seek will be performed to the current position. Do nothing.
|
||||
periodPositionUs = playbackInfo.positionUs;
|
||||
return;
|
||||
}
|
||||
}
|
||||
long newPeriodPositionUs = seekToPeriodPosition(periodId, periodPositionUs);
|
||||
newPeriodPositionUs = seekToPeriodPosition(periodId, newPeriodPositionUs);
|
||||
seekPositionAdjusted |= periodPositionUs != newPeriodPositionUs;
|
||||
periodPositionUs = newPeriodPositionUs;
|
||||
} finally {
|
||||
|
@ -165,16 +165,23 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
||||
sampleStream.clearSentEos();
|
||||
}
|
||||
}
|
||||
long seekUs = mediaPeriod.seekToUs(positionUs + startUs);
|
||||
Assertions.checkState(seekUs == positionUs + startUs
|
||||
long offsetPositionUs = positionUs + startUs;
|
||||
long seekUs = mediaPeriod.seekToUs(offsetPositionUs);
|
||||
Assertions.checkState(
|
||||
seekUs == offsetPositionUs
|
||||
|| (seekUs >= startUs && (endUs == C.TIME_END_OF_SOURCE || seekUs <= endUs)));
|
||||
return seekUs - startUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) {
|
||||
return mediaPeriod.getAdjustedSeekPositionUs(
|
||||
positionUs + startUs, adjustSeekParameters(positionUs + startUs, seekParameters));
|
||||
if (positionUs == startUs) {
|
||||
// Never adjust seeks to the start of the clipped view.
|
||||
return 0;
|
||||
}
|
||||
long offsetPositionUs = positionUs + startUs;
|
||||
SeekParameters clippedSeekParameters = clipSeekParameters(offsetPositionUs, seekParameters);
|
||||
return mediaPeriod.getAdjustedSeekPositionUs(offsetPositionUs, clippedSeekParameters) - startUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -209,12 +216,12 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
||||
return pendingInitialDiscontinuityPositionUs != C.TIME_UNSET;
|
||||
}
|
||||
|
||||
private SeekParameters adjustSeekParameters(long positionUs, SeekParameters seekParameters) {
|
||||
long toleranceBeforeMs = Math.min(positionUs - startUs, seekParameters.toleranceBeforeUs);
|
||||
private SeekParameters clipSeekParameters(long offsetPositionUs, SeekParameters seekParameters) {
|
||||
long toleranceBeforeMs = Math.min(offsetPositionUs - startUs, seekParameters.toleranceBeforeUs);
|
||||
long toleranceAfterMs =
|
||||
endUs == C.TIME_END_OF_SOURCE
|
||||
? seekParameters.toleranceAfterUs
|
||||
: Math.min(endUs - positionUs, seekParameters.toleranceAfterUs);
|
||||
: Math.min(endUs - offsetPositionUs, seekParameters.toleranceAfterUs);
|
||||
if (toleranceBeforeMs == seekParameters.toleranceBeforeUs
|
||||
&& toleranceAfterMs == seekParameters.toleranceAfterUs) {
|
||||
return seekParameters;
|
||||
|
@ -29,6 +29,7 @@ import com.google.android.exoplayer2.extractor.ExtractorInput;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.extractor.PositionHolder;
|
||||
import com.google.android.exoplayer2.extractor.SeekMap;
|
||||
import com.google.android.exoplayer2.extractor.SeekMap.SeekPoints;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.SampleQueue.UpstreamFormatChangedListener;
|
||||
@ -372,8 +373,33 @@ import java.util.Arrays;
|
||||
|
||||
@Override
|
||||
public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) {
|
||||
if (!seekMap.isSeekable()) {
|
||||
// Treat all seeks into non-seekable media as being to t=0.
|
||||
return seekMap.isSeekable() ? positionUs : 0;
|
||||
return 0;
|
||||
}
|
||||
SeekPoints seekPoints = seekMap.getSeekPoints(positionUs);
|
||||
long minPositionUs =
|
||||
Util.subtractWithOverflowDefault(
|
||||
positionUs, seekParameters.toleranceBeforeUs, Long.MIN_VALUE);
|
||||
long maxPositionUs =
|
||||
Util.addWithOverflowDefault(positionUs, seekParameters.toleranceAfterUs, Long.MAX_VALUE);
|
||||
long firstPointUs = seekPoints.first.timeUs;
|
||||
boolean firstPointValid = minPositionUs <= firstPointUs && firstPointUs <= maxPositionUs;
|
||||
long secondPointUs = seekPoints.second.timeUs;
|
||||
boolean secondPointValid = minPositionUs <= secondPointUs && secondPointUs <= maxPositionUs;
|
||||
if (firstPointValid && secondPointValid) {
|
||||
if (Math.abs(firstPointUs - positionUs) <= Math.abs(secondPointUs - positionUs)) {
|
||||
return firstPointUs;
|
||||
} else {
|
||||
return secondPointUs;
|
||||
}
|
||||
} else if (firstPointValid) {
|
||||
return firstPointUs;
|
||||
} else if (secondPointValid) {
|
||||
return secondPointUs;
|
||||
} else {
|
||||
return minPositionUs;
|
||||
}
|
||||
}
|
||||
|
||||
// SampleStream methods.
|
||||
@ -657,7 +683,7 @@ import java.util.Arrays;
|
||||
return pendingResetPositionUs != C.TIME_UNSET;
|
||||
}
|
||||
|
||||
private boolean isLoadableExceptionFatal(IOException e) {
|
||||
private static boolean isLoadableExceptionFatal(IOException e) {
|
||||
return e instanceof UnrecognizedInputFormatException;
|
||||
}
|
||||
|
||||
|
@ -362,6 +362,40 @@ public final class Util {
|
||||
return Math.max(min, Math.min(value, max));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sum of two arguments, or a third argument if the result overflows.
|
||||
*
|
||||
* @param x The first value.
|
||||
* @param y The second value.
|
||||
* @param overflowResult The return value if {@code x + y} overflows.
|
||||
* @return {@code x + y}, or {@code overflowResult} if the result overflows.
|
||||
*/
|
||||
public static long addWithOverflowDefault(long x, long y, long overflowResult) {
|
||||
long result = x + y;
|
||||
// See Hacker's Delight 2-13 (H. Warren Jr).
|
||||
if (((x ^ result) & (y ^ result)) < 0) {
|
||||
return overflowResult;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the difference between two arguments, or a third argument if the result overflows.
|
||||
*
|
||||
* @param x The first value.
|
||||
* @param y The second value.
|
||||
* @param overflowResult The return value if {@code x - y} overflows.
|
||||
* @return {@code x - y}, or {@code overflowResult} if the result overflows.
|
||||
*/
|
||||
public static long subtractWithOverflowDefault(long x, long y, long overflowResult) {
|
||||
long result = x - y;
|
||||
// See Hacker's Delight 2-13 (H. Warren Jr).
|
||||
if (((x ^ y) & (x ^ result)) < 0) {
|
||||
return overflowResult;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the largest element in {@code array} that is less than (or optionally
|
||||
* equal to) a specified {@code value}.
|
||||
|
@ -41,6 +41,42 @@ import org.robolectric.annotation.Config;
|
||||
@Config(sdk = Config.TARGET_SDK, manifest = Config.NONE)
|
||||
public class UtilTest {
|
||||
|
||||
@Test
|
||||
public void testAddWithOverflowDefault() {
|
||||
long res = Util.addWithOverflowDefault(5, 10, /* overflowResult= */ 0);
|
||||
assertThat(res).isEqualTo(15);
|
||||
|
||||
res = Util.addWithOverflowDefault(Long.MAX_VALUE - 1, 1, /* overflowResult= */ 12345);
|
||||
assertThat(res).isEqualTo(Long.MAX_VALUE);
|
||||
|
||||
res = Util.addWithOverflowDefault(Long.MIN_VALUE + 1, -1, /* overflowResult= */ 12345);
|
||||
assertThat(res).isEqualTo(Long.MIN_VALUE);
|
||||
|
||||
res = Util.addWithOverflowDefault(Long.MAX_VALUE, 1, /* overflowResult= */ 12345);
|
||||
assertThat(res).isEqualTo(12345);
|
||||
|
||||
res = Util.addWithOverflowDefault(Long.MIN_VALUE, -1, /* overflowResult= */ 12345);
|
||||
assertThat(res).isEqualTo(12345);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubtrackWithOverflowDefault() {
|
||||
long res = Util.subtractWithOverflowDefault(5, 10, /* overflowResult= */ 0);
|
||||
assertThat(res).isEqualTo(-5);
|
||||
|
||||
res = Util.subtractWithOverflowDefault(Long.MIN_VALUE + 1, 1, /* overflowResult= */ 12345);
|
||||
assertThat(res).isEqualTo(Long.MIN_VALUE);
|
||||
|
||||
res = Util.subtractWithOverflowDefault(Long.MAX_VALUE - 1, -1, /* overflowResult= */ 12345);
|
||||
assertThat(res).isEqualTo(Long.MAX_VALUE);
|
||||
|
||||
res = Util.subtractWithOverflowDefault(Long.MIN_VALUE, 1, /* overflowResult= */ 12345);
|
||||
assertThat(res).isEqualTo(12345);
|
||||
|
||||
res = Util.subtractWithOverflowDefault(Long.MAX_VALUE, -1, /* overflowResult= */ 12345);
|
||||
assertThat(res).isEqualTo(12345);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInferContentType() {
|
||||
assertThat(Util.inferContentType("http://a.b/c.ism")).isEqualTo(C.TYPE_SS);
|
||||
|
Loading…
x
Reference in New Issue
Block a user