mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Avoid clipping live offset override to min/max offsets
The live offset override is used to replace the media-defined
live offset after user seeks to ensure the live adjustment adjusts
to the new user-provided live offset and doesn't go back to the
original one.
However, the code currently clips the override to the min/max
live offsets defined in LiveConfiguration. This is useful to
clip the default value (in case of inconsistent values in the media),
but the clipping shouldn't be applied to user overrides as
the player will then adjust the position back to the min/max
and doesn't stay at the desired user position.
See 2416d99857 (r132871601)
#minor-release
PiperOrigin-RevId: 584311004
This commit is contained in:
parent
fde142d66e
commit
af0282b9db
@ -24,6 +24,9 @@
|
|||||||
by default with null `ImageOutput` and `ImageDecoder.Factory.DEFAULT`.
|
by default with null `ImageOutput` and `ImageDecoder.Factory.DEFAULT`.
|
||||||
* Emit `Player.Listener.onPositionDiscontinuity` event when silence is
|
* Emit `Player.Listener.onPositionDiscontinuity` event when silence is
|
||||||
skipped ([#765](https://github.com/androidx/media/issues/765)).
|
skipped ([#765](https://github.com/androidx/media/issues/765)).
|
||||||
|
* Fix issue where manual seeks outside of the
|
||||||
|
`LiveConfiguration.min/maxOffset` range keep adjusting the offset back
|
||||||
|
to `min/maxOffset`.
|
||||||
* Transformer:
|
* Transformer:
|
||||||
* Add support for flattening H.265/HEVC SEF slow motion videos.
|
* Add support for flattening H.265/HEVC SEF slow motion videos.
|
||||||
* Increase transmuxing speed, especially for 'remove video' edits.
|
* Increase transmuxing speed, especially for 'remove video' edits.
|
||||||
|
@ -379,15 +379,16 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC
|
|||||||
private void maybeResetTargetLiveOffsetUs() {
|
private void maybeResetTargetLiveOffsetUs() {
|
||||||
long idealOffsetUs = C.TIME_UNSET;
|
long idealOffsetUs = C.TIME_UNSET;
|
||||||
if (mediaConfigurationTargetLiveOffsetUs != C.TIME_UNSET) {
|
if (mediaConfigurationTargetLiveOffsetUs != C.TIME_UNSET) {
|
||||||
idealOffsetUs =
|
if (targetLiveOffsetOverrideUs != C.TIME_UNSET) {
|
||||||
targetLiveOffsetOverrideUs != C.TIME_UNSET
|
idealOffsetUs = targetLiveOffsetOverrideUs;
|
||||||
? targetLiveOffsetOverrideUs
|
} else {
|
||||||
: mediaConfigurationTargetLiveOffsetUs;
|
idealOffsetUs = mediaConfigurationTargetLiveOffsetUs;
|
||||||
if (minTargetLiveOffsetUs != C.TIME_UNSET && idealOffsetUs < minTargetLiveOffsetUs) {
|
if (minTargetLiveOffsetUs != C.TIME_UNSET && idealOffsetUs < minTargetLiveOffsetUs) {
|
||||||
idealOffsetUs = minTargetLiveOffsetUs;
|
idealOffsetUs = minTargetLiveOffsetUs;
|
||||||
}
|
}
|
||||||
if (maxTargetLiveOffsetUs != C.TIME_UNSET && idealOffsetUs > maxTargetLiveOffsetUs) {
|
if (maxTargetLiveOffsetUs != C.TIME_UNSET && idealOffsetUs > maxTargetLiveOffsetUs) {
|
||||||
idealOffsetUs = maxTargetLiveOffsetUs;
|
idealOffsetUs = maxTargetLiveOffsetUs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (idealTargetLiveOffsetUs == idealOffsetUs) {
|
if (idealTargetLiveOffsetUs == idealOffsetUs) {
|
||||||
|
@ -112,7 +112,7 @@ public class DefaultLivePlaybackSpeedControlTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void
|
public void
|
||||||
getTargetLiveOffsetUs_afterSetTargetLiveOffsetOverrideUsGreaterThanMax_returnsMaxLiveOffset() {
|
getTargetLiveOffsetUs_afterSetTargetLiveOffsetOverrideUsGreaterThanMax_returnsOverride() {
|
||||||
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
|
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
|
||||||
new DefaultLivePlaybackSpeedControl.Builder().build();
|
new DefaultLivePlaybackSpeedControl.Builder().build();
|
||||||
|
|
||||||
@ -128,12 +128,12 @@ public class DefaultLivePlaybackSpeedControlTest {
|
|||||||
|
|
||||||
long targetLiveOffsetUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs();
|
long targetLiveOffsetUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs();
|
||||||
|
|
||||||
assertThat(targetLiveOffsetUs).isEqualTo(400_000);
|
assertThat(targetLiveOffsetUs).isEqualTo(123_456_789);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void
|
public void
|
||||||
getTargetLiveOffsetUs_afterSetTargetLiveOffsetOverrideUsLessThanMin_returnsMinLiveOffset() {
|
getTargetLiveOffsetUs_afterSetTargetLiveOffsetOverrideUsLessThanMin_returnsOverride() {
|
||||||
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
|
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
|
||||||
new DefaultLivePlaybackSpeedControl.Builder().build();
|
new DefaultLivePlaybackSpeedControl.Builder().build();
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ public class DefaultLivePlaybackSpeedControlTest {
|
|||||||
|
|
||||||
long targetLiveOffsetUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs();
|
long targetLiveOffsetUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs();
|
||||||
|
|
||||||
assertThat(targetLiveOffsetUs).isEqualTo(5_000);
|
assertThat(targetLiveOffsetUs).isEqualTo(3_141);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -10598,6 +10598,57 @@ public final class ExoPlayerTest {
|
|||||||
assertThat(liveOffsetAtEnd).isIn(Range.closed(1_900L, 2_100L));
|
assertThat(liveOffsetAtEnd).isIn(Range.closed(1_900L, 2_100L));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void targetLiveOffsetInMedia_withUserSeekOutsideMaxLivOffset_adjustsLiveOffsetToSeek()
|
||||||
|
throws Exception {
|
||||||
|
long windowStartUnixTimeMs = 987_654_321_000L;
|
||||||
|
long nowUnixTimeMs = windowStartUnixTimeMs + 20_000;
|
||||||
|
ExoPlayer player =
|
||||||
|
new TestExoPlayerBuilder(context)
|
||||||
|
.setClock(
|
||||||
|
new FakeClock(/* initialTimeMs= */ nowUnixTimeMs, /* isAutoAdvancing= */ true))
|
||||||
|
.build();
|
||||||
|
Timeline timeline =
|
||||||
|
new FakeTimeline(
|
||||||
|
new TimelineWindowDefinition(
|
||||||
|
/* periodCount= */ 1,
|
||||||
|
/* id= */ 0,
|
||||||
|
/* isSeekable= */ true,
|
||||||
|
/* isDynamic= */ true,
|
||||||
|
/* isLive= */ true,
|
||||||
|
/* isPlaceholder= */ false,
|
||||||
|
/* durationUs= */ 1000 * C.MICROS_PER_SECOND,
|
||||||
|
/* defaultPositionUs= */ 8 * C.MICROS_PER_SECOND,
|
||||||
|
/* windowOffsetInFirstPeriodUs= */ Util.msToUs(windowStartUnixTimeMs),
|
||||||
|
ImmutableList.of(AdPlaybackState.NONE),
|
||||||
|
new MediaItem.Builder()
|
||||||
|
.setUri(Uri.EMPTY)
|
||||||
|
.setLiveConfiguration(
|
||||||
|
new MediaItem.LiveConfiguration.Builder()
|
||||||
|
.setTargetOffsetMs(9_000)
|
||||||
|
.setMaxOffsetMs(10_000)
|
||||||
|
.build())
|
||||||
|
.build()));
|
||||||
|
player.pause();
|
||||||
|
player.setMediaSource(new FakeMediaSource(timeline));
|
||||||
|
player.prepare();
|
||||||
|
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_READY);
|
||||||
|
long liveOffsetAtStart = player.getCurrentLiveOffset();
|
||||||
|
// Verify test setup (now = 20 seconds in live window, default start position = 8 seconds).
|
||||||
|
assertThat(liveOffsetAtStart).isIn(Range.closed(11_900L, 12_100L));
|
||||||
|
|
||||||
|
// Seek to a live offset of 15 seconds (outside of declared max offset of 10 seconds).
|
||||||
|
player.seekTo(5_000);
|
||||||
|
// Play until close to the end of the available live window.
|
||||||
|
TestPlayerRunHelper.playUntilPosition(
|
||||||
|
player, /* mediaItemIndex= */ 0, /* positionMs= */ 999_000);
|
||||||
|
long liveOffsetAtEnd = player.getCurrentLiveOffset();
|
||||||
|
player.release();
|
||||||
|
|
||||||
|
// Assert the live offset adjustment was permanent.
|
||||||
|
assertThat(liveOffsetAtEnd).isIn(Range.closed(14_100L, 15_900L));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void targetLiveOffsetInMedia_withTimelineUpdate_adjustsLiveOffsetToLatestTimeline()
|
public void targetLiveOffsetInMedia_withTimelineUpdate_adjustsLiveOffsetToLatestTimeline()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user