Skip ads before the initial player position

Issue: #3527

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=178218391
This commit is contained in:
andrewlewis 2017-12-07 03:05:22 -08:00 committed by Oliver Woodman
parent 2f6a497d44
commit 8b4b01c7f6
2 changed files with 54 additions and 6 deletions

View File

@ -41,6 +41,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 ###

View File

@ -65,7 +65,6 @@ import java.util.Map;
*/
public final class ImaAdsLoader extends Player.DefaultEventListener implements AdsLoader,
VideoAdPlayer, ContentProgressProvider, AdErrorListener, AdsLoadedListener, AdEventListener {
static {
ExoPlayerLibraryInfo.registerModule("goog.exo.ima");
}
@ -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.
@ -274,6 +274,7 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
adsManager.resume();
}
} else {
pendingContentPositionMs = player.getCurrentPosition();
requestAds();
}
}
@ -311,19 +312,45 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
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();
}
@ -351,13 +378,15 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
// 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();
@ -741,4 +770,20 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
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);
}
}