Skip to content

Commit

Permalink
Skip ads before the initial player position
Browse files Browse the repository at this point in the history
Issue: #3527

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=178218391
  • Loading branch information
andrewlewis authored and ojw28 committed Dec 12, 2017
1 parent e7d4524 commit a4a02f7
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 6 deletions.
3 changes: 3 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
implementations.
* CEA-608: Fix handling of row count changes in roll-up mode
([#3513](https://github.com/google/ExoPlayer/issues/3513)).
* IMA extension:
* Skip ads before the ad preceding the player's initial seek position
([#3527](https://github.com/google/ExoPlayer/issues/3527)).

### 2.6.0 ###

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@
*/
public final class ImaAdsLoader extends Player.DefaultEventListener implements AdsLoader,
VideoAdPlayer, ContentProgressProvider, AdErrorListener, AdsLoadedListener, AdEventListener {

static {
ExoPlayerLibraryInfo.registerModule("goog.exo.ima");
}
Expand Down Expand Up @@ -132,6 +131,7 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
private AdsManager adsManager;
private Timeline timeline;
private long contentDurationMs;
private int podIndexOffset;
private AdPlaybackState adPlaybackState;

// Fields tracking IMA's state.
Expand Down Expand Up @@ -274,6 +274,7 @@ public void attachPlayer(ExoPlayer player, EventListener eventListener, ViewGrou
adsManager.resume();
}
} else {
pendingContentPositionMs = player.getCurrentPosition();
requestAds();
}
}
Expand Down Expand Up @@ -311,19 +312,45 @@ public void onAdsManagerLoaded(AdsManagerLoadedEvent adsManagerLoadedEvent) {
return;
}
pendingAdRequestContext = null;

long[] adGroupTimesUs = getAdGroupTimesUs(adsManager.getAdCuePoints());
adPlaybackState = new AdPlaybackState(adGroupTimesUs);

this.adsManager = adsManager;
adsManager.addAdErrorListener(this);
adsManager.addAdEventListener(this);

ImaSdkFactory imaSdkFactory = ImaSdkFactory.getInstance();
AdsRenderingSettings adsRenderingSettings = imaSdkFactory.createAdsRenderingSettings();
adsRenderingSettings.setEnablePreloading(ENABLE_PRELOADING);
adsRenderingSettings.setMimeTypes(supportedMimeTypes);
int adGroupIndexForPosition =
getAdGroupIndexForPosition(adGroupTimesUs, C.msToUs(pendingContentPositionMs));
if (adGroupIndexForPosition == C.INDEX_UNSET) {
pendingContentPositionMs = C.TIME_UNSET;
} else if (adGroupIndexForPosition > 0) {
// Skip ad groups before the one at or immediately before the playback position.
for (int i = 0; i < adGroupIndexForPosition; i++) {
adPlaybackState.playedAdGroup(i);
}
// Play ads after the midpoint between the ad to play and the one before it, to avoid issues
// with rounding one of the two ad times.
long adGroupForPositionTimeUs = adGroupTimesUs[adGroupIndexForPosition];
long adGroupBeforeTimeUs = adGroupTimesUs[adGroupIndexForPosition - 1];
double midpointTimeUs = (adGroupForPositionTimeUs + adGroupBeforeTimeUs) / 2d;
adsRenderingSettings.setPlayAdsAfterTime(midpointTimeUs / C.MICROS_PER_SECOND);

// We're removing one or more ads, which means that the earliest ad (if any) will be a
// midroll/postroll. According to the AdPodInfo documentation, midroll pod indices always
// start at 1, so take this into account when offsetting the pod index for the skipped ads.
podIndexOffset = adGroupIndexForPosition - 1;
}

adsManager.init(adsRenderingSettings);
if (DEBUG) {
Log.d(TAG, "Initialized with ads rendering settings: " + adsRenderingSettings);
}
long[] adGroupTimesUs = getAdGroupTimesUs(adsManager.getAdCuePoints());
adPlaybackState = new AdPlaybackState(adGroupTimesUs);

updateAdPlaybackState();
}

Expand Down Expand Up @@ -351,13 +378,15 @@ public void onAdEvent(AdEvent adEvent) {
// The ad position is not always accurate when using preloading. See [Internal: b/62613240].
AdPodInfo adPodInfo = ad.getAdPodInfo();
int podIndex = adPodInfo.getPodIndex();
adGroupIndex = podIndex == -1 ? adPlaybackState.adGroupCount - 1 : podIndex;
adGroupIndex =
podIndex == -1 ? (adPlaybackState.adGroupCount - 1) : (podIndex + podIndexOffset);
int adPosition = adPodInfo.getAdPosition();
int adCountInAdGroup = adPodInfo.getTotalAds();
adsManager.start();
if (DEBUG) {
Log.d(TAG, "Loaded ad " + adPosition + " of " + adCountInAdGroup + " in ad group "
+ adGroupIndex);
Log.d(
TAG,
"Loaded ad " + adPosition + " of " + adCountInAdGroup + " in group " + adGroupIndex);
}
adPlaybackState.setAdCount(adGroupIndex, adCountInAdGroup);
updateAdPlaybackState();
Expand Down Expand Up @@ -740,4 +769,20 @@ private static long[] getAdGroupTimesUs(List<Float> cuePoints) {
return adGroupTimesUs;
}

/**
* Returns the index of the ad group that should be played before playing the content at {@code
* playbackPositionUs} when starting playback for the first time. This is the latest ad group at
* or before the specified playback position. If the first ad is after the playback position,
* returns {@link C#INDEX_UNSET}.
*/
private int getAdGroupIndexForPosition(long[] adGroupTimesUs, long playbackPositionUs) {
for (int i = 0; i < adGroupTimesUs.length; i++) {
long adGroupTimeUs = adGroupTimesUs[i];
// A postroll ad is after any position in the content.
if (adGroupTimeUs == C.TIME_END_OF_SOURCE || playbackPositionUs < adGroupTimeUs) {
return i == 0 ? C.INDEX_UNSET : (i - 1);
}
}
return adGroupTimesUs.length == 0 ? C.INDEX_UNSET : (adGroupTimesUs.length - 1);
}
}

0 comments on commit a4a02f7

Please sign in to comment.