mirror of
https://github.com/androidx/media.git
synced 2025-05-03 21:57:46 +08:00
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:
parent
2f6a497d44
commit
8b4b01c7f6
@ -41,6 +41,9 @@
|
|||||||
implementations.
|
implementations.
|
||||||
* CEA-608: Fix handling of row count changes in roll-up mode
|
* CEA-608: Fix handling of row count changes in roll-up mode
|
||||||
([#3513](https://github.com/google/ExoPlayer/issues/3513)).
|
([#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 ###
|
### 2.6.0 ###
|
||||||
|
|
||||||
|
@ -65,7 +65,6 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public final class ImaAdsLoader extends Player.DefaultEventListener implements AdsLoader,
|
public final class ImaAdsLoader extends Player.DefaultEventListener implements AdsLoader,
|
||||||
VideoAdPlayer, ContentProgressProvider, AdErrorListener, AdsLoadedListener, AdEventListener {
|
VideoAdPlayer, ContentProgressProvider, AdErrorListener, AdsLoadedListener, AdEventListener {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ExoPlayerLibraryInfo.registerModule("goog.exo.ima");
|
ExoPlayerLibraryInfo.registerModule("goog.exo.ima");
|
||||||
}
|
}
|
||||||
@ -132,6 +131,7 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
private AdsManager adsManager;
|
private AdsManager adsManager;
|
||||||
private Timeline timeline;
|
private Timeline timeline;
|
||||||
private long contentDurationMs;
|
private long contentDurationMs;
|
||||||
|
private int podIndexOffset;
|
||||||
private AdPlaybackState adPlaybackState;
|
private AdPlaybackState adPlaybackState;
|
||||||
|
|
||||||
// Fields tracking IMA's state.
|
// Fields tracking IMA's state.
|
||||||
@ -274,6 +274,7 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
adsManager.resume();
|
adsManager.resume();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
pendingContentPositionMs = player.getCurrentPosition();
|
||||||
requestAds();
|
requestAds();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,19 +312,45 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pendingAdRequestContext = null;
|
pendingAdRequestContext = null;
|
||||||
|
|
||||||
|
long[] adGroupTimesUs = getAdGroupTimesUs(adsManager.getAdCuePoints());
|
||||||
|
adPlaybackState = new AdPlaybackState(adGroupTimesUs);
|
||||||
|
|
||||||
this.adsManager = adsManager;
|
this.adsManager = adsManager;
|
||||||
adsManager.addAdErrorListener(this);
|
adsManager.addAdErrorListener(this);
|
||||||
adsManager.addAdEventListener(this);
|
adsManager.addAdEventListener(this);
|
||||||
|
|
||||||
ImaSdkFactory imaSdkFactory = ImaSdkFactory.getInstance();
|
ImaSdkFactory imaSdkFactory = ImaSdkFactory.getInstance();
|
||||||
AdsRenderingSettings adsRenderingSettings = imaSdkFactory.createAdsRenderingSettings();
|
AdsRenderingSettings adsRenderingSettings = imaSdkFactory.createAdsRenderingSettings();
|
||||||
adsRenderingSettings.setEnablePreloading(ENABLE_PRELOADING);
|
adsRenderingSettings.setEnablePreloading(ENABLE_PRELOADING);
|
||||||
adsRenderingSettings.setMimeTypes(supportedMimeTypes);
|
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);
|
adsManager.init(adsRenderingSettings);
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "Initialized with ads rendering settings: " + adsRenderingSettings);
|
Log.d(TAG, "Initialized with ads rendering settings: " + adsRenderingSettings);
|
||||||
}
|
}
|
||||||
long[] adGroupTimesUs = getAdGroupTimesUs(adsManager.getAdCuePoints());
|
|
||||||
adPlaybackState = new AdPlaybackState(adGroupTimesUs);
|
|
||||||
updateAdPlaybackState();
|
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].
|
// The ad position is not always accurate when using preloading. See [Internal: b/62613240].
|
||||||
AdPodInfo adPodInfo = ad.getAdPodInfo();
|
AdPodInfo adPodInfo = ad.getAdPodInfo();
|
||||||
int podIndex = adPodInfo.getPodIndex();
|
int podIndex = adPodInfo.getPodIndex();
|
||||||
adGroupIndex = podIndex == -1 ? adPlaybackState.adGroupCount - 1 : podIndex;
|
adGroupIndex =
|
||||||
|
podIndex == -1 ? (adPlaybackState.adGroupCount - 1) : (podIndex + podIndexOffset);
|
||||||
int adPosition = adPodInfo.getAdPosition();
|
int adPosition = adPodInfo.getAdPosition();
|
||||||
int adCountInAdGroup = adPodInfo.getTotalAds();
|
int adCountInAdGroup = adPodInfo.getTotalAds();
|
||||||
adsManager.start();
|
adsManager.start();
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "Loaded ad " + adPosition + " of " + adCountInAdGroup + " in ad group "
|
Log.d(
|
||||||
+ adGroupIndex);
|
TAG,
|
||||||
|
"Loaded ad " + adPosition + " of " + adCountInAdGroup + " in group " + adGroupIndex);
|
||||||
}
|
}
|
||||||
adPlaybackState.setAdCount(adGroupIndex, adCountInAdGroup);
|
adPlaybackState.setAdCount(adGroupIndex, adCountInAdGroup);
|
||||||
updateAdPlaybackState();
|
updateAdPlaybackState();
|
||||||
@ -741,4 +770,20 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
return adGroupTimesUs;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user