use of com.google.android.exoplayer2.Timeline in project ExoPlayer by google.
the class AdTagLoader method isWaitingForAdToLoad.
/**
* Returns whether this instance is expecting the first ad in an the upcoming ad group to load
* within the {@link ImaUtil.Configuration#adPreloadTimeoutMs preload timeout}.
*/
private boolean isWaitingForAdToLoad() {
@Nullable Player player = this.player;
if (player == null) {
return false;
}
int adGroupIndex = getLoadingAdGroupIndex();
if (adGroupIndex == C.INDEX_UNSET) {
return false;
}
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adGroupIndex);
if (adGroup.count != C.LENGTH_UNSET && adGroup.count != 0 && adGroup.states[0] != AdPlaybackState.AD_STATE_UNAVAILABLE) {
// An ad is available already.
return false;
}
long adGroupTimeMs = Util.usToMs(adGroup.timeUs);
long contentPositionMs = getContentPeriodPositionMs(player, timeline, period);
long timeUntilAdMs = adGroupTimeMs - contentPositionMs;
return timeUntilAdMs < configuration.adPreloadTimeoutMs;
}
use of com.google.android.exoplayer2.Timeline in project ExoPlayer by google.
the class ImaUtil method splitAdPlaybackStateForPeriods.
/**
* Splits an {@link AdPlaybackState} into a separate {@link AdPlaybackState} for each period of a
* content timeline.
*
* <p>If a period is enclosed by an ad group, the period is considered an ad period. Splitting
* results in a separate {@link AdPlaybackState ad playback state} for each period that has either
* no ads or a single ad. In the latter case, the duration of the single ad is set to the duration
* of the period consuming the entire duration of the period. Accordingly an ad period does not
* contribute to the duration of the containing window.
*
* @param adPlaybackState The ad playback state to be split.
* @param contentTimeline The content timeline for each period of which to create an {@link
* AdPlaybackState}.
* @return A map of ad playback states for each period UID in the content timeline.
*/
public static ImmutableMap<Object, AdPlaybackState> splitAdPlaybackStateForPeriods(AdPlaybackState adPlaybackState, Timeline contentTimeline) {
Timeline.Period period = new Timeline.Period();
if (contentTimeline.getPeriodCount() == 1) {
// A single period gets the entire ad playback state that may contain multiple ad groups.
return ImmutableMap.of(checkNotNull(contentTimeline.getPeriod(/* periodIndex= */
0, period, /* setIds= */
true).uid), adPlaybackState);
}
int periodIndex = 0;
long totalElapsedContentDurationUs = 0;
Object adsId = checkNotNull(adPlaybackState.adsId);
AdPlaybackState contentOnlyAdPlaybackState = new AdPlaybackState(adsId);
Map<Object, AdPlaybackState> adPlaybackStates = new HashMap<>();
for (int i = adPlaybackState.removedAdGroupCount; i < adPlaybackState.adGroupCount; i++) {
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(/* adGroupIndex= */
i);
if (adGroup.timeUs == C.TIME_END_OF_SOURCE) {
checkState(i == adPlaybackState.adGroupCount - 1);
// The last ad group is a placeholder for a potential post roll. We can just stop here.
break;
}
// The ad group start timeUs is in content position. We need to add the ad
// duration before the ad group to translate the start time to the position in the period.
long adGroupDurationUs = sum(adGroup.durationsUs);
long elapsedAdGroupAdDurationUs = 0;
for (int j = periodIndex; j < contentTimeline.getPeriodCount(); j++) {
contentTimeline.getPeriod(j, period, /* setIds= */
true);
// Subtract one microsecond to work around rounding errors with adGroup.timeUs.
if (totalElapsedContentDurationUs < adGroup.timeUs - 1) {
// Period starts before the ad group, so it is a content period.
adPlaybackStates.put(checkNotNull(period.uid), contentOnlyAdPlaybackState);
totalElapsedContentDurationUs += period.durationUs;
} else {
long periodStartUs = totalElapsedContentDurationUs + elapsedAdGroupAdDurationUs;
// Add one microsecond to work around rounding errors with adGroup.timeUs.
if (periodStartUs + period.durationUs <= adGroup.timeUs + adGroupDurationUs + 1) {
// The period ends before the end of the ad group, so it is an ad period (Note: A VOD ad
// reported by the IMA SDK spans multiple periods before the LOADED event arrives).
adPlaybackStates.put(checkNotNull(period.uid), splitAdGroupForPeriod(adsId, adGroup, periodStartUs, period.durationUs));
elapsedAdGroupAdDurationUs += period.durationUs;
} else {
// Period is after the current ad group. Continue with next ad group.
break;
}
}
// Increment the period index to the next unclassified period.
periodIndex++;
}
}
// The remaining periods end after the last ad group, so these are content periods.
for (int i = periodIndex; i < contentTimeline.getPeriodCount(); i++) {
contentTimeline.getPeriod(i, period, /* setIds= */
true);
adPlaybackStates.put(checkNotNull(period.uid), contentOnlyAdPlaybackState);
}
return ImmutableMap.copyOf(adPlaybackStates);
}
use of com.google.android.exoplayer2.Timeline in project ExoPlayer by google.
the class ImaUtilTest method splitAdPlaybackStateForPeriods_oneMidrollAdGroupOneAd_adSpansTwoPeriods.
@Test
public void splitAdPlaybackStateForPeriods_oneMidrollAdGroupOneAd_adSpansTwoPeriods() {
int periodCount = 5;
long periodDurationUs = DEFAULT_WINDOW_DURATION_US / periodCount;
AdPlaybackState adPlaybackState = new AdPlaybackState(/* adsId= */
"adsId", DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US + periodDurationUs).withAdCount(/* adGroupIndex= */
0, 1).withAdDurationsUs(/* adGroupIndex= */
0, 2 * periodDurationUs).withIsServerSideInserted(/* adGroupIndex= */
0, true);
FakeTimeline timeline = new FakeTimeline(new FakeTimeline.TimelineWindowDefinition(/* periodCount= */
periodCount, /* id= */
0L));
ImmutableMap<Object, AdPlaybackState> adPlaybackStates = ImaUtil.splitAdPlaybackStateForPeriods(adPlaybackState, timeline);
assertThat(adPlaybackStates).hasSize(periodCount);
assertThat(adPlaybackStates.get(new Pair<>(0L, 0)).adGroupCount).isEqualTo(0);
for (int i = 1; i < 3; i++) {
Pair<Long, Integer> periodUid = new Pair<>(0L, i);
AdPlaybackState periodAdPlaybackState = adPlaybackStates.get(periodUid);
assertThat(periodAdPlaybackState.adGroupCount).isEqualTo(1);
assertThat(periodAdPlaybackState.getAdGroup(0).durationsUs).hasLength(1);
assertThat(periodAdPlaybackState.getAdGroup(0).durationsUs[0]).isEqualTo(2_000_000);
}
assertThat(adPlaybackStates.get(new Pair<>(0L, 3)).adGroupCount).isEqualTo(0);
assertThat(adPlaybackStates.get(new Pair<>(0L, 4)).adGroupCount).isEqualTo(0);
}
use of com.google.android.exoplayer2.Timeline in project ExoPlayer by google.
the class PlayerWrapper method updatePlaylist.
private void updatePlaylist(Timeline timeline) {
List<androidx.media2.common.MediaItem> media2MediaItemToBeRemoved = new ArrayList<>(media2Playlist);
media2Playlist.clear();
exoPlayerPlaylist.clear();
Timeline.Window window = new Timeline.Window();
int windowCount = timeline.getWindowCount();
for (int i = 0; i < windowCount; i++) {
timeline.getWindow(i, window);
MediaItem exoPlayerMediaItem = window.mediaItem;
androidx.media2.common.MediaItem media2MediaItem = Assertions.checkNotNull(mediaItemConverter.convertToMedia2MediaItem(exoPlayerMediaItem));
exoPlayerPlaylist.add(exoPlayerMediaItem);
media2Playlist.add(media2MediaItem);
media2MediaItemToBeRemoved.remove(media2MediaItem);
}
for (androidx.media2.common.MediaItem item : media2MediaItemToBeRemoved) {
releaseMediaItem(item);
}
}
use of com.google.android.exoplayer2.Timeline in project ExoPlayer by google.
the class ImaAdsLoader method maybePreloadNextPeriodAds.
private void maybePreloadNextPeriodAds() {
@Nullable Player player = ImaAdsLoader.this.player;
if (player == null) {
return;
}
Timeline timeline = player.getCurrentTimeline();
if (timeline.isEmpty()) {
return;
}
int nextPeriodIndex = timeline.getNextPeriodIndex(player.getCurrentPeriodIndex(), period, window, player.getRepeatMode(), player.getShuffleModeEnabled());
if (nextPeriodIndex == C.INDEX_UNSET) {
return;
}
timeline.getPeriod(nextPeriodIndex, period);
@Nullable Object nextAdsId = period.getAdsId();
if (nextAdsId == null) {
return;
}
@Nullable AdTagLoader nextAdTagLoader = adTagLoaderByAdsId.get(nextAdsId);
if (nextAdTagLoader == null || nextAdTagLoader == currentAdTagLoader) {
return;
}
long periodPositionUs = timeline.getPeriodPositionUs(window, period, period.windowIndex, /* windowPositionUs= */
C.TIME_UNSET).second;
nextAdTagLoader.maybePreloadAds(Util.usToMs(periodPositionUs), Util.usToMs(period.durationUs));
}
Aggregations