mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Fix discontinuity reporting in ClippingMediaPeriod
The initial discontinuity is currently only reported if the period is prepared at the clip start position. However, we need the discontinuity whenever we prepare at a non-zero position (unless we know all samples are sync samples). PiperOrigin-RevId: 713994155
This commit is contained in:
parent
d0b757886e
commit
f6eb2e6dd5
@ -10,6 +10,8 @@
|
|||||||
provide a secondary `MediaCodecVideoRenderer` to `ExoPlayer`. If
|
provide a secondary `MediaCodecVideoRenderer` to `ExoPlayer`. If
|
||||||
enabled, `ExoPlayer` will pre-process the video of consecutive media
|
enabled, `ExoPlayer` will pre-process the video of consecutive media
|
||||||
items during playback to reduce media item transition latency.
|
items during playback to reduce media item transition latency.
|
||||||
|
* Fix issue where additional decode-only frames may be displayed in quick
|
||||||
|
succession when transitioning to content media after a mid-roll ad.
|
||||||
* Transformer:
|
* Transformer:
|
||||||
* Enable support for Android platform diagnostics via
|
* Enable support for Android platform diagnostics via
|
||||||
`MediaMetricsManager`. Transformer will forward editing events and
|
`MediaMetricsManager`. Transformer will forward editing events and
|
||||||
|
@ -137,8 +137,7 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
|||||||
selections, mayRetainStreamFlags, childStreams, streamResetFlags, positionUs);
|
selections, mayRetainStreamFlags, childStreams, streamResetFlags, positionUs);
|
||||||
pendingInitialDiscontinuityPositionUs =
|
pendingInitialDiscontinuityPositionUs =
|
||||||
isPendingInitialDiscontinuity()
|
isPendingInitialDiscontinuity()
|
||||||
&& positionUs == startUs
|
&& shouldKeepInitialDiscontinuity(enablePositionUs, selections)
|
||||||
&& shouldKeepInitialDiscontinuity(startUs, selections)
|
|
||||||
? enablePositionUs
|
? enablePositionUs
|
||||||
: C.TIME_UNSET;
|
: C.TIME_UNSET;
|
||||||
Assertions.checkState(
|
Assertions.checkState(
|
||||||
|
@ -69,6 +69,7 @@ import static androidx.media3.test.utils.robolectric.TestPlayerRunHelper.runUnti
|
|||||||
import static androidx.media3.test.utils.robolectric.TestPlayerRunHelper.runUntilPositionDiscontinuity;
|
import static androidx.media3.test.utils.robolectric.TestPlayerRunHelper.runUntilPositionDiscontinuity;
|
||||||
import static androidx.media3.test.utils.robolectric.TestPlayerRunHelper.runUntilSleepingForOffload;
|
import static androidx.media3.test.utils.robolectric.TestPlayerRunHelper.runUntilSleepingForOffload;
|
||||||
import static androidx.media3.test.utils.robolectric.TestPlayerRunHelper.runUntilTimelineChanged;
|
import static androidx.media3.test.utils.robolectric.TestPlayerRunHelper.runUntilTimelineChanged;
|
||||||
|
import static com.google.common.collect.Iterables.getLast;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static java.util.Arrays.stream;
|
import static java.util.Arrays.stream;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
@ -12022,6 +12023,9 @@ public class ExoPlayerTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPlaybackParameters(PlaybackParameters parameters) {
|
public void setPlaybackParameters(PlaybackParameters parameters) {
|
||||||
|
if (!playbackParameters.isEmpty() && getLast(playbackParameters).equals(parameters)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
playbackParameters.add(parameters);
|
playbackParameters.add(parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12029,7 +12033,7 @@ public class ExoPlayerTest {
|
|||||||
public PlaybackParameters getPlaybackParameters() {
|
public PlaybackParameters getPlaybackParameters() {
|
||||||
return playbackParameters.isEmpty()
|
return playbackParameters.isEmpty()
|
||||||
? PlaybackParameters.DEFAULT
|
? PlaybackParameters.DEFAULT
|
||||||
: Iterables.getLast(playbackParameters);
|
: getLast(playbackParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -12477,7 +12481,7 @@ public class ExoPlayerTest {
|
|||||||
verify(listener).onRepeatModeChanged(anyInt());
|
verify(listener).onRepeatModeChanged(anyInt());
|
||||||
verify(listener).onShuffleModeEnabledChanged(anyBoolean());
|
verify(listener).onShuffleModeEnabledChanged(anyBoolean());
|
||||||
verify(listener, times(2)).onEvents(eq(player), eventCaptor.capture());
|
verify(listener, times(2)).onEvents(eq(player), eventCaptor.capture());
|
||||||
events = Iterables.getLast(eventCaptor.getAllValues());
|
events = getLast(eventCaptor.getAllValues());
|
||||||
assertThat(events.contains(Player.EVENT_REPEAT_MODE_CHANGED)).isTrue();
|
assertThat(events.contains(Player.EVENT_REPEAT_MODE_CHANGED)).isTrue();
|
||||||
assertThat(events.contains(Player.EVENT_SHUFFLE_MODE_ENABLED_CHANGED)).isTrue();
|
assertThat(events.contains(Player.EVENT_SHUFFLE_MODE_ENABLED_CHANGED)).isTrue();
|
||||||
|
|
||||||
|
@ -1253,7 +1253,10 @@ public final class DefaultAnalyticsCollectorTest {
|
|||||||
postrollAd,
|
postrollAd,
|
||||||
contentAfterPostroll)
|
contentAfterPostroll)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
assertThat(listener.getEvents(EVENT_VIDEO_ENABLED)).containsExactly(prerollAd);
|
assertThat(listener.getEvents(EVENT_VIDEO_ENABLED))
|
||||||
|
.containsExactly(prerollAd, contentAfterPreroll, contentAfterMidroll);
|
||||||
|
assertThat(listener.getEvents(EVENT_VIDEO_DISABLED))
|
||||||
|
.containsExactly(prerollAd, contentAfterPreroll);
|
||||||
assertThat(listener.getEvents(EVENT_VIDEO_DECODER_INITIALIZED))
|
assertThat(listener.getEvents(EVENT_VIDEO_DECODER_INITIALIZED))
|
||||||
.containsExactly(
|
.containsExactly(
|
||||||
prerollAd,
|
prerollAd,
|
||||||
@ -1273,9 +1276,14 @@ public final class DefaultAnalyticsCollectorTest {
|
|||||||
contentAfterPostroll)
|
contentAfterPostroll)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
assertThat(listener.getEvents(EVENT_DROPPED_VIDEO_FRAMES))
|
assertThat(listener.getEvents(EVENT_DROPPED_VIDEO_FRAMES))
|
||||||
.containsExactly(contentAfterPostroll);
|
.containsExactly(contentAfterPreroll, contentAfterPostroll);
|
||||||
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED))
|
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED))
|
||||||
.containsExactly(prerollAd) // First frame rendered
|
.containsExactly(
|
||||||
|
prerollAd, // First frame rendered
|
||||||
|
contentAfterPreroll, // Size unknown for renderer reset
|
||||||
|
contentAfterPreroll, // Content size
|
||||||
|
contentAfterMidroll, // Size unknown for renderer reset
|
||||||
|
contentAfterMidroll) // Content size
|
||||||
.inOrder();
|
.inOrder();
|
||||||
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME))
|
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME))
|
||||||
.containsExactly(
|
.containsExactly(
|
||||||
@ -1287,7 +1295,7 @@ public final class DefaultAnalyticsCollectorTest {
|
|||||||
contentAfterPostroll)
|
contentAfterPostroll)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
assertThat(listener.getEvents(EVENT_VIDEO_FRAME_PROCESSING_OFFSET))
|
assertThat(listener.getEvents(EVENT_VIDEO_FRAME_PROCESSING_OFFSET))
|
||||||
.containsExactly(contentAfterPostroll);
|
.containsExactly(contentAfterPreroll, contentAfterPostroll);
|
||||||
assertThat(listener.getEvents(EVENT_RENDERER_READY_CHANGED))
|
assertThat(listener.getEvents(EVENT_RENDERER_READY_CHANGED))
|
||||||
.containsExactly(prerollAd /* videoTrue */);
|
.containsExactly(prerollAd /* videoTrue */);
|
||||||
listener.assertNoMoreEvents();
|
listener.assertNoMoreEvents();
|
||||||
|
@ -22,6 +22,7 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.TrackGroup;
|
import androidx.media3.common.TrackGroup;
|
||||||
import androidx.media3.decoder.DecoderInputBuffer;
|
import androidx.media3.decoder.DecoderInputBuffer;
|
||||||
import androidx.media3.exoplayer.FormatHolder;
|
import androidx.media3.exoplayer.FormatHolder;
|
||||||
@ -39,6 +40,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@ -47,13 +49,21 @@ import org.junit.runner.RunWith;
|
|||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class ClippingMediaPeriodTest {
|
public class ClippingMediaPeriodTest {
|
||||||
|
|
||||||
|
private static final Format VIDEO_FORMAT =
|
||||||
|
new Format.Builder().setSampleMimeType(MimeTypes.VIDEO_H264).build();
|
||||||
|
private static final Format AUDIO_FORMAT_ALL_SYNC_SAMPLES =
|
||||||
|
new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AC3).build();
|
||||||
|
private static final TrackGroup VIDEO_TRACK_GROUP = new TrackGroup(VIDEO_FORMAT);
|
||||||
|
private static final TrackGroup AUDIO_TRACK_GROUP_ALL_SYNC_SAMPLES =
|
||||||
|
new TrackGroup(AUDIO_FORMAT_ALL_SYNC_SAMPLES);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void fastLoadingStreamAfterFirstRead_canBeReadFully() throws Exception {
|
public void fastLoadingStreamAfterFirstRead_canBeReadFully() throws Exception {
|
||||||
TrackGroup trackGroup = new TrackGroup(new Format.Builder().build());
|
TrackGroupArray trackGroups = new TrackGroupArray(VIDEO_TRACK_GROUP);
|
||||||
// Set up MediaPeriod with no samples and only add samples after the first SampleStream read.
|
// Set up MediaPeriod with no samples and only add samples after the first SampleStream read.
|
||||||
FakeMediaPeriod mediaPeriod =
|
FakeMediaPeriod mediaPeriod =
|
||||||
new FakeMediaPeriod(
|
new FakeMediaPeriod(
|
||||||
new TrackGroupArray(trackGroup),
|
trackGroups,
|
||||||
new DefaultAllocator(/* trimOnReset= */ true, /* individualAllocationSize= */ 1024),
|
new DefaultAllocator(/* trimOnReset= */ true, /* individualAllocationSize= */ 1024),
|
||||||
/* trackDataFactory= */ (format, mediaPeriodId) -> ImmutableList.of(),
|
/* trackDataFactory= */ (format, mediaPeriodId) -> ImmutableList.of(),
|
||||||
new MediaSourceEventListener.EventDispatcher()
|
new MediaSourceEventListener.EventDispatcher()
|
||||||
@ -107,29 +117,9 @@ public class ClippingMediaPeriodTest {
|
|||||||
/* enableInitialDiscontinuity= */ true,
|
/* enableInitialDiscontinuity= */ true,
|
||||||
/* startUs= */ 0,
|
/* startUs= */ 0,
|
||||||
/* endUs= */ 500);
|
/* endUs= */ 500);
|
||||||
AtomicBoolean periodPrepared = new AtomicBoolean();
|
SampleStream[] sampleStreams =
|
||||||
clippingMediaPeriod.prepare(
|
prepareMediaPeriodAndSelectTracks(
|
||||||
new MediaPeriod.Callback() {
|
clippingMediaPeriod, /* preparePositionUs= */ 0, trackGroups);
|
||||||
@Override
|
|
||||||
public void onPrepared(MediaPeriod mediaPeriod) {
|
|
||||||
periodPrepared.set(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onContinueLoadingRequested(MediaPeriod source) {
|
|
||||||
clippingMediaPeriod.continueLoading(
|
|
||||||
new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* positionUs= */ 0);
|
|
||||||
RobolectricUtil.runMainLooperUntil(periodPrepared::get);
|
|
||||||
SampleStream[] sampleStreams = new SampleStream[1];
|
|
||||||
clippingMediaPeriod.selectTracks(
|
|
||||||
new ExoTrackSelection[] {new FixedTrackSelection(trackGroup, /* track= */ 0)},
|
|
||||||
/* mayRetainStreamFlags= */ new boolean[] {false},
|
|
||||||
sampleStreams,
|
|
||||||
/* streamResetFlags= */ new boolean[] {true},
|
|
||||||
/* positionUs= */ 0);
|
|
||||||
FormatHolder formatHolder = new FormatHolder();
|
FormatHolder formatHolder = new FormatHolder();
|
||||||
DecoderInputBuffer buffer =
|
DecoderInputBuffer buffer =
|
||||||
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
|
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
|
||||||
@ -145,4 +135,176 @@ public class ClippingMediaPeriodTest {
|
|||||||
|
|
||||||
assertThat(readSamples).containsExactly(0L, 200L, 400L).inOrder();
|
assertThat(readSamples).containsExactly(0L, 200L, 400L).inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readDiscontinuity_prepareFromNonZero_returnsPreparePosition() throws Exception {
|
||||||
|
TrackGroupArray trackGroups =
|
||||||
|
new TrackGroupArray(AUDIO_TRACK_GROUP_ALL_SYNC_SAMPLES, VIDEO_TRACK_GROUP);
|
||||||
|
ClippingMediaPeriod clippingMediaPeriod =
|
||||||
|
new ClippingMediaPeriod(
|
||||||
|
getFakeMediaPeriod(trackGroups),
|
||||||
|
/* enableInitialDiscontinuity= */ true,
|
||||||
|
/* startUs= */ 0,
|
||||||
|
/* endUs= */ 500);
|
||||||
|
|
||||||
|
prepareMediaPeriodAndSelectTracks(
|
||||||
|
clippingMediaPeriod, /* preparePositionUs= */ 250, trackGroups);
|
||||||
|
long discontinuityPositionUs = clippingMediaPeriod.readDiscontinuity();
|
||||||
|
|
||||||
|
assertThat(discontinuityPositionUs).isEqualTo(250);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readDiscontinuity_prepareFromNonZeroClipStartPosition_returnsPreparePosition()
|
||||||
|
throws Exception {
|
||||||
|
TrackGroupArray trackGroups =
|
||||||
|
new TrackGroupArray(AUDIO_TRACK_GROUP_ALL_SYNC_SAMPLES, VIDEO_TRACK_GROUP);
|
||||||
|
ClippingMediaPeriod clippingMediaPeriod =
|
||||||
|
new ClippingMediaPeriod(
|
||||||
|
getFakeMediaPeriod(trackGroups),
|
||||||
|
/* enableInitialDiscontinuity= */ true,
|
||||||
|
/* startUs= */ 250,
|
||||||
|
/* endUs= */ 500);
|
||||||
|
|
||||||
|
prepareMediaPeriodAndSelectTracks(
|
||||||
|
clippingMediaPeriod, /* preparePositionUs= */ 250, trackGroups);
|
||||||
|
long discontinuityPositionUs = clippingMediaPeriod.readDiscontinuity();
|
||||||
|
|
||||||
|
assertThat(discontinuityPositionUs).isEqualTo(250);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readDiscontinuity_prepareFromZero_returnsUnset() throws Exception {
|
||||||
|
TrackGroupArray trackGroups =
|
||||||
|
new TrackGroupArray(AUDIO_TRACK_GROUP_ALL_SYNC_SAMPLES, VIDEO_TRACK_GROUP);
|
||||||
|
ClippingMediaPeriod clippingMediaPeriod =
|
||||||
|
new ClippingMediaPeriod(
|
||||||
|
getFakeMediaPeriod(trackGroups),
|
||||||
|
/* enableInitialDiscontinuity= */ true,
|
||||||
|
/* startUs= */ 0,
|
||||||
|
/* endUs= */ 500);
|
||||||
|
|
||||||
|
prepareMediaPeriodAndSelectTracks(clippingMediaPeriod, /* preparePositionUs= */ 0, trackGroups);
|
||||||
|
long discontinuityPositionUs = clippingMediaPeriod.readDiscontinuity();
|
||||||
|
|
||||||
|
assertThat(discontinuityPositionUs).isEqualTo(C.TIME_UNSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readDiscontinuity_withSyncSamplesOnly_returnsUnset() throws Exception {
|
||||||
|
TrackGroupArray trackGroups = new TrackGroupArray(AUDIO_TRACK_GROUP_ALL_SYNC_SAMPLES);
|
||||||
|
ClippingMediaPeriod clippingMediaPeriod =
|
||||||
|
new ClippingMediaPeriod(
|
||||||
|
getFakeMediaPeriod(trackGroups),
|
||||||
|
/* enableInitialDiscontinuity= */ true,
|
||||||
|
/* startUs= */ 0,
|
||||||
|
/* endUs= */ 500);
|
||||||
|
|
||||||
|
prepareMediaPeriodAndSelectTracks(
|
||||||
|
clippingMediaPeriod, /* preparePositionUs= */ 250, trackGroups);
|
||||||
|
long discontinuityPositionUs = clippingMediaPeriod.readDiscontinuity();
|
||||||
|
|
||||||
|
assertThat(discontinuityPositionUs).isEqualTo(C.TIME_UNSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readDiscontinuity_repeatedCalls_returnsUnset() throws Exception {
|
||||||
|
TrackGroupArray trackGroups =
|
||||||
|
new TrackGroupArray(AUDIO_TRACK_GROUP_ALL_SYNC_SAMPLES, VIDEO_TRACK_GROUP);
|
||||||
|
ClippingMediaPeriod clippingMediaPeriod =
|
||||||
|
new ClippingMediaPeriod(
|
||||||
|
getFakeMediaPeriod(trackGroups),
|
||||||
|
/* enableInitialDiscontinuity= */ true,
|
||||||
|
/* startUs= */ 0,
|
||||||
|
/* endUs= */ 500);
|
||||||
|
|
||||||
|
prepareMediaPeriodAndSelectTracks(
|
||||||
|
clippingMediaPeriod, /* preparePositionUs= */ 250, trackGroups);
|
||||||
|
clippingMediaPeriod.readDiscontinuity();
|
||||||
|
long discontinuityPositionUs = clippingMediaPeriod.readDiscontinuity();
|
||||||
|
|
||||||
|
assertThat(discontinuityPositionUs).isEqualTo(C.TIME_UNSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readDiscontinuity_withInitialDiscontinuityDisabled_returnsUnset() throws Exception {
|
||||||
|
TrackGroupArray trackGroups =
|
||||||
|
new TrackGroupArray(AUDIO_TRACK_GROUP_ALL_SYNC_SAMPLES, VIDEO_TRACK_GROUP);
|
||||||
|
ClippingMediaPeriod clippingMediaPeriod =
|
||||||
|
new ClippingMediaPeriod(
|
||||||
|
getFakeMediaPeriod(trackGroups),
|
||||||
|
/* enableInitialDiscontinuity= */ false,
|
||||||
|
/* startUs= */ 0,
|
||||||
|
/* endUs= */ 500);
|
||||||
|
|
||||||
|
prepareMediaPeriodAndSelectTracks(
|
||||||
|
clippingMediaPeriod, /* preparePositionUs= */ 250, trackGroups);
|
||||||
|
long discontinuityPositionUs = clippingMediaPeriod.readDiscontinuity();
|
||||||
|
|
||||||
|
assertThat(discontinuityPositionUs).isEqualTo(C.TIME_UNSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readDiscontinuity_afterInitialSeek_returnsUnset() throws Exception {
|
||||||
|
TrackGroupArray trackGroups =
|
||||||
|
new TrackGroupArray(AUDIO_TRACK_GROUP_ALL_SYNC_SAMPLES, VIDEO_TRACK_GROUP);
|
||||||
|
ClippingMediaPeriod clippingMediaPeriod =
|
||||||
|
new ClippingMediaPeriod(
|
||||||
|
getFakeMediaPeriod(trackGroups),
|
||||||
|
/* enableInitialDiscontinuity= */ true,
|
||||||
|
/* startUs= */ 0,
|
||||||
|
/* endUs= */ 500);
|
||||||
|
|
||||||
|
prepareMediaPeriodAndSelectTracks(
|
||||||
|
clippingMediaPeriod, /* preparePositionUs= */ 250, trackGroups);
|
||||||
|
clippingMediaPeriod.seekToUs(400);
|
||||||
|
long discontinuityPositionUs = clippingMediaPeriod.readDiscontinuity();
|
||||||
|
|
||||||
|
assertThat(discontinuityPositionUs).isEqualTo(C.TIME_UNSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SampleStream[] prepareMediaPeriodAndSelectTracks(
|
||||||
|
MediaPeriod mediaPeriod, long preparePositionUs, TrackGroupArray trackGroups)
|
||||||
|
throws TimeoutException {
|
||||||
|
AtomicBoolean periodPrepared = new AtomicBoolean();
|
||||||
|
mediaPeriod.prepare(
|
||||||
|
new MediaPeriod.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onPrepared(MediaPeriod mediaPeriod) {
|
||||||
|
periodPrepared.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onContinueLoadingRequested(MediaPeriod source) {
|
||||||
|
mediaPeriod.continueLoading(new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
preparePositionUs);
|
||||||
|
RobolectricUtil.runMainLooperUntil(periodPrepared::get);
|
||||||
|
SampleStream[] sampleStreams = new SampleStream[trackGroups.length];
|
||||||
|
ExoTrackSelection[] trackSelections = new ExoTrackSelection[trackGroups.length];
|
||||||
|
for (int i = 0; i < trackGroups.length; i++) {
|
||||||
|
trackSelections[i] = new FixedTrackSelection(trackGroups.get(i), /* track= */ 0);
|
||||||
|
}
|
||||||
|
mediaPeriod.selectTracks(
|
||||||
|
trackSelections,
|
||||||
|
/* mayRetainStreamFlags= */ new boolean[trackGroups.length],
|
||||||
|
sampleStreams,
|
||||||
|
/* streamResetFlags= */ new boolean[trackGroups.length],
|
||||||
|
preparePositionUs);
|
||||||
|
return sampleStreams;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FakeMediaPeriod getFakeMediaPeriod(TrackGroupArray trackGroups) {
|
||||||
|
return new FakeMediaPeriod(
|
||||||
|
trackGroups,
|
||||||
|
new DefaultAllocator(/* trimOnReset= */ true, /* individualAllocationSize= */ 1024),
|
||||||
|
/* trackDataFactory= */ (format, mediaPeriodId) -> ImmutableList.of(),
|
||||||
|
new MediaSourceEventListener.EventDispatcher()
|
||||||
|
.withParameters(
|
||||||
|
/* windowIndex= */ 0, new MediaSource.MediaPeriodId(/* periodUid= */ new Object())),
|
||||||
|
DrmSessionManager.DRM_UNSUPPORTED,
|
||||||
|
new DrmSessionEventListener.EventDispatcher(),
|
||||||
|
/* deferOnPrepared= */ false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -647,6 +647,7 @@ public class MediaCodecVideoRendererTest {
|
|||||||
sampleStreams,
|
sampleStreams,
|
||||||
/* streamResetFlags= */ new boolean[] {true},
|
/* streamResetFlags= */ new boolean[] {true},
|
||||||
/* positionUs= */ 100);
|
/* positionUs= */ 100);
|
||||||
|
clippingMediaPeriod.readDiscontinuity();
|
||||||
mediaCodecVideoRenderer =
|
mediaCodecVideoRenderer =
|
||||||
new MediaCodecVideoRenderer(
|
new MediaCodecVideoRenderer(
|
||||||
ApplicationProvider.getApplicationContext(),
|
ApplicationProvider.getApplicationContext(),
|
||||||
@ -752,6 +753,7 @@ public class MediaCodecVideoRendererTest {
|
|||||||
sampleStreams,
|
sampleStreams,
|
||||||
/* streamResetFlags= */ new boolean[] {true},
|
/* streamResetFlags= */ new boolean[] {true},
|
||||||
/* positionUs= */ 100);
|
/* positionUs= */ 100);
|
||||||
|
clippingMediaPeriod.readDiscontinuity();
|
||||||
mediaCodecVideoRenderer =
|
mediaCodecVideoRenderer =
|
||||||
new MediaCodecVideoRenderer(
|
new MediaCodecVideoRenderer(
|
||||||
ApplicationProvider.getApplicationContext(),
|
ApplicationProvider.getApplicationContext(),
|
||||||
|
@ -83,6 +83,10 @@ public class FakeRenderer extends BaseRenderer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
|
protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
|
||||||
|
if (playbackPositionUs == positionUs && lastSamplePositionUs == Long.MIN_VALUE && !isEnded) {
|
||||||
|
// Nothing change, ignore reset operation.
|
||||||
|
return;
|
||||||
|
}
|
||||||
playbackPositionUs = positionUs;
|
playbackPositionUs = positionUs;
|
||||||
lastSamplePositionUs = Long.MIN_VALUE;
|
lastSamplePositionUs = Long.MIN_VALUE;
|
||||||
hasPendingBuffer = false;
|
hasPendingBuffer = false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user