use of com.google.android.exoplayer2.Format in project ExoPlayer by google.
the class ServerSideAdInsertionMediaSourceTest method playbackWithNewlyInsertedAds_playsSuccessfulWithoutRendererResets.
@Test
public void playbackWithNewlyInsertedAds_playsSuccessfulWithoutRendererResets() throws Exception {
Context context = ApplicationProvider.getApplicationContext();
AtomicReference<Object> periodUid = new AtomicReference<>();
CapturingRenderersFactory renderersFactory = new CapturingRenderersFactory(context);
ExoPlayer player = new ExoPlayer.Builder(context, renderersFactory).setClock(new FakeClock(/* isAutoAdvancing= */
true)).build();
player.setVideoSurface(new Surface(new SurfaceTexture(/* texName= */
1)));
PlaybackOutput playbackOutput = PlaybackOutput.register(player, renderersFactory);
AdPlaybackState firstAdPlaybackState = addAdGroupToAdPlaybackState(new AdPlaybackState(/* adsId= */
new Object()), /* fromPositionUs= */
900_000, /* contentResumeOffsetUs= */
0, /* adDurationsUs...= */
100_000);
AtomicReference<ServerSideAdInsertionMediaSource> mediaSourceRef = new AtomicReference<>();
mediaSourceRef.set(new ServerSideAdInsertionMediaSource(new DefaultMediaSourceFactory(context).createMediaSource(MediaItem.fromUri(TEST_ASSET)), /* adPlaybackStateUpdater= */
contentTimeline -> {
periodUid.set(checkNotNull(contentTimeline.getPeriod(/* periodIndex= */
0, new Timeline.Period(), /* setIds= */
true).uid));
mediaSourceRef.get().setAdPlaybackStates(ImmutableMap.of(periodUid.get(), firstAdPlaybackState));
return true;
}));
AnalyticsListener listener = mock(AnalyticsListener.class);
player.addAnalyticsListener(listener);
player.setMediaSource(mediaSourceRef.get());
player.prepare();
// Add ad at the current playback position during playback.
runUntilPlaybackState(player, Player.STATE_READY);
AdPlaybackState secondAdPlaybackState = addAdGroupToAdPlaybackState(firstAdPlaybackState, /* fromPositionUs= */
0, /* contentResumeOffsetUs= */
0, /* adDurationsUs...= */
500_000);
mediaSourceRef.get().setAdPlaybackStates(ImmutableMap.of(periodUid.get(), secondAdPlaybackState));
runUntilPendingCommandsAreFullyHandled(player);
player.play();
runUntilPlaybackState(player, Player.STATE_ENDED);
player.release();
// Assert all samples have been played.
DumpFileAsserts.assertOutput(context, playbackOutput, TEST_ASSET_DUMP);
// Assert playback has been reported with ads: [content][ad0][content][ad1][content]
// 5*2(audio+video) format changes, 4 discontinuities between parts.
verify(listener, times(4)).onPositionDiscontinuity(any(), any(), any(), eq(Player.DISCONTINUITY_REASON_AUTO_TRANSITION));
verify(listener, times(10)).onDownstreamFormatChanged(any(), any());
// Assert renderers played through without reset (=decoders have been enabled only once).
verify(listener).onVideoEnabled(any(), any());
verify(listener).onAudioEnabled(any(), any());
// Assert playback progression was smooth (=no unexpected delays that cause audio to underrun)
verify(listener, never()).onAudioUnderrun(any(), anyInt(), anyLong(), anyLong());
}
use of com.google.android.exoplayer2.Format in project ExoPlayer by google.
the class ServerSideAdInsertionMediaSourceTest method playbackWithAdditionalAdsInAdGroup_playsSuccessfulWithoutRendererResets.
@Test
public void playbackWithAdditionalAdsInAdGroup_playsSuccessfulWithoutRendererResets() throws Exception {
Context context = ApplicationProvider.getApplicationContext();
AtomicReference<Object> periodUid = new AtomicReference<>();
CapturingRenderersFactory renderersFactory = new CapturingRenderersFactory(context);
ExoPlayer player = new ExoPlayer.Builder(context, renderersFactory).setClock(new FakeClock(/* isAutoAdvancing= */
true)).build();
player.setVideoSurface(new Surface(new SurfaceTexture(/* texName= */
1)));
PlaybackOutput playbackOutput = PlaybackOutput.register(player, renderersFactory);
AdPlaybackState firstAdPlaybackState = addAdGroupToAdPlaybackState(new AdPlaybackState(/* adsId= */
new Object()), /* fromPositionUs= */
0, /* contentResumeOffsetUs= */
0, /* adDurationsUs...= */
500_000);
AtomicReference<ServerSideAdInsertionMediaSource> mediaSourceRef = new AtomicReference<>();
mediaSourceRef.set(new ServerSideAdInsertionMediaSource(new DefaultMediaSourceFactory(context).createMediaSource(MediaItem.fromUri(TEST_ASSET)), /* adPlaybackStateUpdater= */
contentTimeline -> {
if (periodUid.get() == null) {
periodUid.set(checkNotNull(contentTimeline.getPeriod(/* periodIndex= */
0, new Timeline.Period(), /* setIds= */
true).uid));
mediaSourceRef.get().setAdPlaybackStates(ImmutableMap.of(periodUid.get(), firstAdPlaybackState));
}
return true;
}));
AnalyticsListener listener = mock(AnalyticsListener.class);
player.addAnalyticsListener(listener);
player.setMediaSource(mediaSourceRef.get());
player.prepare();
// Wait until playback is ready with first ad and then replace by 3 ads.
runUntilPlaybackState(player, Player.STATE_READY);
AdPlaybackState secondAdPlaybackState = firstAdPlaybackState.withAdCount(/* adGroupIndex= */
0, /* adCount= */
3).withAdDurationsUs(/* adGroupIndex= */
0, /* adDurationsUs...= */
50_000, 250_000, 200_000);
mediaSourceRef.get().setAdPlaybackStates(ImmutableMap.of(periodUid.get(), secondAdPlaybackState));
runUntilPendingCommandsAreFullyHandled(player);
player.play();
runUntilPlaybackState(player, Player.STATE_ENDED);
player.release();
// Assert all samples have been played.
DumpFileAsserts.assertOutput(context, playbackOutput, TEST_ASSET_DUMP);
// Assert playback has been reported with ads: [ad0][ad1][ad2][content]
// 4*2(audio+video) format changes, 3 discontinuities between parts.
verify(listener, times(3)).onPositionDiscontinuity(any(), any(), any(), eq(Player.DISCONTINUITY_REASON_AUTO_TRANSITION));
verify(listener, times(8)).onDownstreamFormatChanged(any(), any());
// Assert renderers played through without reset (=decoders have been enabled only once).
verify(listener).onVideoEnabled(any(), any());
verify(listener).onAudioEnabled(any(), any());
// Assert playback progression was smooth (=no unexpected delays that cause audio to underrun)
verify(listener, never()).onAudioUnderrun(any(), anyInt(), anyLong(), anyLong());
}
use of com.google.android.exoplayer2.Format in project ExoPlayer by google.
the class AdaptiveTrackSelectionTest method initial_updateSelectedTrack_selectsHighestBitrateWithinBandwidthAndTimeToFirstByte.
@Test
public void initial_updateSelectedTrack_selectsHighestBitrateWithinBandwidthAndTimeToFirstByte() {
Format format1 = videoFormat(/* bitrate= */
500, /* width= */
320, /* height= */
240);
Format format2 = videoFormat(/* bitrate= */
1000, /* width= */
640, /* height= */
480);
Format format3 = videoFormat(/* bitrate= */
2000, /* width= */
960, /* height= */
720);
TrackGroup trackGroup = new TrackGroup(format1, format2, format3);
when(mockBandwidthMeter.getBitrateEstimate()).thenReturn(2000L);
when(mockBandwidthMeter.getTimeToFirstByteEstimateUs()).thenReturn(1_000_000L);
AdaptiveTrackSelection adaptiveTrackSelection = prepareAdaptiveTrackSelectionWithBandwidthFraction(trackGroup, /* bandwidthFraction= */
1f);
assertThat(adaptiveTrackSelection.getSelectedFormat()).isEqualTo(format2);
assertThat(adaptiveTrackSelection.getSelectionReason()).isEqualTo(C.SELECTION_REASON_INITIAL);
}
use of com.google.android.exoplayer2.Format in project ExoPlayer by google.
the class AdaptiveTrackSelectionTest method updateSelectedTrack_liveStream_switchesUpWhenBufferedFractionToLiveEdgeReached.
@Test
public void updateSelectedTrack_liveStream_switchesUpWhenBufferedFractionToLiveEdgeReached() {
Format format1 = videoFormat(/* bitrate= */
500, /* width= */
320, /* height= */
240);
Format format2 = videoFormat(/* bitrate= */
1000, /* width= */
640, /* height= */
480);
Format format3 = videoFormat(/* bitrate= */
2000, /* width= */
960, /* height= */
720);
TrackGroup trackGroup = new TrackGroup(format1, format2, format3);
// The second measurement onward returns 2000L, which prompts the track selection to switch up
// if possible.
when(mockBandwidthMeter.getBitrateEstimate()).thenReturn(1000L, 2000L);
AdaptiveTrackSelection adaptiveTrackSelection = prepareAdaptiveTrackSelectionWithBufferedFractionToLiveEdgeForQualiyIncrease(trackGroup, /* bufferedFractionToLiveEdgeForQualityIncrease= */
0.75f, /* minDurationForQualityIncreaseMs= */
5000);
// Not buffered close to live edge yet.
adaptiveTrackSelection.updateSelectedTrack(/* playbackPositionUs= */
0, /* bufferedDurationUs= */
1_600_000, /* availableDurationUs= */
5_600_000, /* queue= */
ImmutableList.of(), createMediaChunkIterators(trackGroup, /* chunkDurationUs= */
2_000_000));
assertThat(adaptiveTrackSelection.getSelectedFormat()).isEqualTo(format2);
// Buffered all possible chunks (except for newly added chunk of 2 seconds).
// Intentionally choose a situation where availableDurationUs > minDurationForQualityIncreaseMs
// to ensure the live calculation is used regardless.
adaptiveTrackSelection.updateSelectedTrack(/* playbackPositionUs= */
0, /* bufferedDurationUs= */
3_600_000, /* availableDurationUs= */
5_600_000, /* queue= */
ImmutableList.of(), createMediaChunkIterators(trackGroup, /* chunkDurationUs= */
2_000_000));
assertThat(adaptiveTrackSelection.getSelectedFormat()).isEqualTo(format3);
}
use of com.google.android.exoplayer2.Format in project ExoPlayer by google.
the class AdaptiveTrackSelectionTest method updateSelectedTrack_withQueueOfUnknownFormats_doesntThrow.
@Test
public void updateSelectedTrack_withQueueOfUnknownFormats_doesntThrow() {
Format format1 = videoFormat(/* bitrate= */
500, /* width= */
320, /* height= */
240);
Format format2 = videoFormat(/* bitrate= */
1000, /* width= */
640, /* height= */
480);
TrackGroup trackGroup = new TrackGroup(format1, format2);
AdaptiveTrackSelection adaptiveTrackSelection = prepareTrackSelection(prepareAdaptiveTrackSelection(trackGroup));
Format unknownFormat = videoFormat(/* bitrate= */
42, /* width= */
300, /* height= */
123);
FakeMediaChunk chunk = new FakeMediaChunk(unknownFormat, /* startTimeUs= */
0, /* endTimeUs= */
2_000_000);
List<FakeMediaChunk> queue = ImmutableList.of(chunk);
adaptiveTrackSelection.updateSelectedTrack(/* playbackPositionUs= */
0, /* bufferedDurationUs= */
2_000_000, /* availableDurationUs= */
C.TIME_UNSET, queue, createMediaChunkIterators(trackGroup, TEST_CHUNK_DURATION_US));
assertThat(adaptiveTrackSelection.getSelectedFormat()).isAnyOf(format1, format2);
}
Aggregations