Add a way to override ad media MIME types

Issue: #7961
PiperOrigin-RevId: 337069152
This commit is contained in:
andrewlewis 2020-10-14 13:17:20 +01:00 committed by Oliver Woodman
parent cfe267a568
commit eccc00bca8
4 changed files with 85 additions and 30 deletions

View File

@ -31,13 +31,15 @@
* Fix NPE in `TextRenderer` when playing content with a single subtitle * Fix NPE in `TextRenderer` when playing content with a single subtitle
buffer ([#8017](https://github.com/google/ExoPlayer/issues/8017)). buffer ([#8017](https://github.com/google/ExoPlayer/issues/8017)).
* UI: * UI:
* Do not require subtitleButton in custom layouts of StyledPlayerView * Show overflow button in `StyledPlayerControlView` only when there is not
enough space.
* Fix animation when `StyledPlayerView` first shows its playback controls.
* Allow subtitleButton to be omitted in custom `StyledPlayerView` layouts
([#7962](https://github.com/google/ExoPlayer/issues/7962)). ([#7962](https://github.com/google/ExoPlayer/issues/7962)).
* Add the option to sort tracks by `Format` in `TrackSelectionView` and * Add an option to sort tracks by `Format` in `TrackSelectionView` and
`TrackSelectionDialogBuilder` `TrackSelectionDialogBuilder`
([#7709](https://github.com/google/ExoPlayer/issues/7709)). ([#7709](https://github.com/google/ExoPlayer/issues/7709)).
* Adjusted bottom buttons' heights and paddings in StyledPlayerView for * Improve touch targets in `StyledPlayerView` to make tapping easier.
easy tapping.
* Audio: * Audio:
* Retry playback after some types of `AudioTrack` error. * Retry playback after some types of `AudioTrack` error.
* Fix the default audio sink position not advancing correctly when using * Fix the default audio sink position not advancing correctly when using
@ -62,7 +64,6 @@
with an I-FRAME only variant with an I-FRAME only variant
([#8025](https://github.com/google/ExoPlayer/issues/8025)). ([#8025](https://github.com/google/ExoPlayer/issues/8025)).
* IMA extension: * IMA extension:
* Fix position reporting after fetch errors * Fix position reporting after fetch errors
([#7956](https://github.com/google/ExoPlayer/issues/7956)). ([#7956](https://github.com/google/ExoPlayer/issues/7956)).
* Allow apps to specify a `VideoAdPlayerCallback` * Allow apps to specify a `VideoAdPlayerCallback`
@ -72,13 +73,8 @@
tag via media item playback properties continues to be supported. This tag via media item playback properties continues to be supported. This
is in preparation for supporting ads in playlists is in preparation for supporting ads in playlists
([#3750](https://github.com/google/ExoPlayer/issues/3750)). ([#3750](https://github.com/google/ExoPlayer/issues/3750)).
* Add a way to override ad media MIME types
* UI: ([#7961)(https://github.com/google/ExoPlayer/issues/7961)).
* Show overflow button in `StyledPlayerControlView` only when there is no
enough space.
* UI:
* Fix animation when `StyledPlayerView` first shows its playback controls.
### 2.12.0 (2020-09-11) ### ### 2.12.0 (2020-09-11) ###

View File

@ -59,7 +59,9 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaSourceFactory;
import com.google.android.exoplayer2.source.ads.AdPlaybackState; import com.google.android.exoplayer2.source.ads.AdPlaybackState;
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
import com.google.android.exoplayer2.source.ads.AdsMediaSource.AdLoadException; import com.google.android.exoplayer2.source.ads.AdsMediaSource.AdLoadException;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
@ -94,18 +96,17 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* <p>See https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for * <p>See https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for
* information on compatible ad tag formats. Pass the ad tag URI when setting media item playback * information on compatible ad tag formats. Pass the ad tag URI when setting media item playback
* properties (if using the media item API) or as a {@link DataSpec} when constructing the {@link * properties (if using the media item API) or as a {@link DataSpec} when constructing the {@link
* com.google.android.exoplayer2.source.ads.AdsMediaSource} (if using media sources directly). For * AdsMediaSource} (if using media sources directly). For the latter case, please note that this
* the latter case, please note that this implementation delegates loading of the data spec to the * implementation delegates loading of the data spec to the IMA SDK, so range and headers
* IMA SDK, so range and headers specifications will be ignored in ad tag URIs. Literal ads * specifications will be ignored in ad tag URIs. Literal ads responses can be encoded as data
* responses can be encoded as data scheme data specs, for example, by constructing the data spec * scheme data specs, for example, by constructing the data spec using a URI generated via {@link
* using a URI generated via {@link Util#getDataUriForString(String, String)}. * Util#getDataUriForString(String, String)}.
* *
* <p>The IMA SDK can report obstructions to the ad view for accurate viewability measurement. This * <p>The IMA SDK can report obstructions to the ad view for accurate viewability measurement. This
* means that any overlay views that obstruct the ad overlay but are essential for playback need to * means that any overlay views that obstruct the ad overlay but are essential for playback need to
* be registered via the {@link AdViewProvider} passed to the {@link * be registered via the {@link AdViewProvider} passed to the {@link AdsMediaSource}. See the <a
* com.google.android.exoplayer2.source.ads.AdsMediaSource}. See the <a * href="https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/omsdk">IMA
* href="https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/omsdk"> * SDK Open Measurement documentation</a> for more information.
* IMA SDK Open Measurement documentation</a> for more information.
*/ */
public final class ImaAdsLoader public final class ImaAdsLoader
implements Player.EventListener, com.google.android.exoplayer2.source.ads.AdsLoader { implements Player.EventListener, com.google.android.exoplayer2.source.ads.AdsLoader {
@ -134,6 +135,7 @@ public final class ImaAdsLoader
@Nullable private AdErrorListener adErrorListener; @Nullable private AdErrorListener adErrorListener;
@Nullable private AdEventListener adEventListener; @Nullable private AdEventListener adEventListener;
@Nullable private VideoAdPlayer.VideoAdPlayerCallback videoAdPlayerCallback; @Nullable private VideoAdPlayer.VideoAdPlayerCallback videoAdPlayerCallback;
@Nullable private List<String> adMediaMimeTypes;
@Nullable private Set<UiElement> adUiElements; @Nullable private Set<UiElement> adUiElements;
@Nullable private Collection<CompanionAdSlot> companionAdSlots; @Nullable private Collection<CompanionAdSlot> companionAdSlots;
private long adPreloadTimeoutMs; private long adPreloadTimeoutMs;
@ -239,6 +241,23 @@ public final class ImaAdsLoader
return this; return this;
} }
/**
* Sets the MIME types to prioritize for linear ad media. If not specified, MIME types supported
* by the {@link MediaSourceFactory adMediaSourceFactory} used to construct the {@link
* AdsMediaSource} will be used.
*
* @param adMediaMimeTypes The MIME types to prioritize for linear ad media. May contain {@link
* MimeTypes#APPLICATION_MPD}, {@link MimeTypes#APPLICATION_M3U8}, {@link
* MimeTypes#VIDEO_MP4}, {@link MimeTypes#VIDEO_WEBM}, {@link MimeTypes#VIDEO_H263}, {@link
* MimeTypes#AUDIO_MP4} and {@link MimeTypes#AUDIO_MPEG}.
* @return This builder, for convenience.
* @see AdsRenderingSettings#setMimeTypes(List)
*/
public Builder setAdMediaMimeTypes(List<String> adMediaMimeTypes) {
this.adMediaMimeTypes = ImmutableList.copyOf(checkNotNull(adMediaMimeTypes));
return this;
}
/** /**
* Sets the duration in milliseconds for which the player must buffer while preloading an ad * Sets the duration in milliseconds for which the player must buffer while preloading an ad
* group before that ad group is skipped and marked as having failed to load. Pass {@link * group before that ad group is skipped and marked as having failed to load. Pass {@link
@ -340,9 +359,8 @@ public final class ImaAdsLoader
* information on compatible ad tags. * information on compatible ad tags.
* @return The new {@link ImaAdsLoader}. * @return The new {@link ImaAdsLoader}.
* @deprecated Pass the ad tag URI when setting media item playback properties (if using the * @deprecated Pass the ad tag URI when setting media item playback properties (if using the
* media item API) or as a {@link DataSpec} when constructing the {@link * media item API) or as a {@link DataSpec} when constructing the {@link AdsMediaSource} (if
* com.google.android.exoplayer2.source.ads.AdsMediaSource} (if using media sources * using media sources directly).
* directly).
*/ */
@Deprecated @Deprecated
public ImaAdsLoader buildForAdTag(Uri adTagUri) { public ImaAdsLoader buildForAdTag(Uri adTagUri) {
@ -362,9 +380,9 @@ public final class ImaAdsLoader
* @return The new {@link ImaAdsLoader}. * @return The new {@link ImaAdsLoader}.
* @deprecated Pass the ads response as a data URI when setting media item playback properties * @deprecated Pass the ads response as a data URI when setting media item playback properties
* (if using the media item API) or as a {@link DataSpec} when constructing the {@link * (if using the media item API) or as a {@link DataSpec} when constructing the {@link
* com.google.android.exoplayer2.source.ads.AdsMediaSource} (if using media sources * AdsMediaSource} (if using media sources directly). {@link
* directly). {@link Util#getDataUriForString(String, String)} can be used to construct a * Util#getDataUriForString(String, String)} can be used to construct a data URI from
* data URI from literal string ads response (with MIME type text/xml). * literal string ads response (with MIME type text/xml).
*/ */
@Deprecated @Deprecated
public ImaAdsLoader buildForAdsResponse(String adsResponse) { public ImaAdsLoader buildForAdsResponse(String adsResponse) {
@ -387,6 +405,7 @@ public final class ImaAdsLoader
focusSkipButtonWhenAvailable, focusSkipButtonWhenAvailable,
playAdBeforeStartPosition, playAdBeforeStartPosition,
mediaBitrate, mediaBitrate,
adMediaMimeTypes,
adUiElements, adUiElements,
companionAdSlots, companionAdSlots,
adErrorListener, adErrorListener,
@ -548,8 +567,7 @@ public final class ImaAdsLoader
* more information. * more information.
* @deprecated Use {@link Builder} to create an instance. Pass the ad tag URI when setting media * @deprecated Use {@link Builder} to create an instance. Pass the ad tag URI when setting media
* item playback properties (if using the media item API) or as a {@link DataSpec} when * item playback properties (if using the media item API) or as a {@link DataSpec} when
* constructing the {@link com.google.android.exoplayer2.source.ads.AdsMediaSource} (if using * constructing the {@link AdsMediaSource} (if using media sources directly).
* media sources directly).
*/ */
@Deprecated @Deprecated
public ImaAdsLoader(Context context, Uri adTagUri) { public ImaAdsLoader(Context context, Uri adTagUri) {
@ -988,7 +1006,10 @@ public final class ImaAdsLoader
private AdsRenderingSettings setupAdsRendering() { private AdsRenderingSettings setupAdsRendering() {
AdsRenderingSettings adsRenderingSettings = imaFactory.createAdsRenderingSettings(); AdsRenderingSettings adsRenderingSettings = imaFactory.createAdsRenderingSettings();
adsRenderingSettings.setEnablePreloading(true); adsRenderingSettings.setEnablePreloading(true);
adsRenderingSettings.setMimeTypes(supportedMimeTypes); adsRenderingSettings.setMimeTypes(
configuration.adMediaMimeTypes != null
? configuration.adMediaMimeTypes
: supportedMimeTypes);
if (configuration.mediaLoadTimeoutMs != TIMEOUT_UNSET) { if (configuration.mediaLoadTimeoutMs != TIMEOUT_UNSET) {
adsRenderingSettings.setLoadVideoTimeout(configuration.mediaLoadTimeoutMs); adsRenderingSettings.setLoadVideoTimeout(configuration.mediaLoadTimeoutMs);
} }

View File

@ -88,6 +88,7 @@ import java.util.Set;
public final boolean focusSkipButtonWhenAvailable; public final boolean focusSkipButtonWhenAvailable;
public final boolean playAdBeforeStartPosition; public final boolean playAdBeforeStartPosition;
public final int mediaBitrate; public final int mediaBitrate;
@Nullable public final List<String> adMediaMimeTypes;
@Nullable public final Set<UiElement> adUiElements; @Nullable public final Set<UiElement> adUiElements;
@Nullable public final Collection<CompanionAdSlot> companionAdSlots; @Nullable public final Collection<CompanionAdSlot> companionAdSlots;
@Nullable public final AdErrorEvent.AdErrorListener applicationAdErrorListener; @Nullable public final AdErrorEvent.AdErrorListener applicationAdErrorListener;
@ -102,6 +103,7 @@ import java.util.Set;
boolean focusSkipButtonWhenAvailable, boolean focusSkipButtonWhenAvailable,
boolean playAdBeforeStartPosition, boolean playAdBeforeStartPosition,
int mediaBitrate, int mediaBitrate,
@Nullable List<String> adMediaMimeTypes,
@Nullable Set<UiElement> adUiElements, @Nullable Set<UiElement> adUiElements,
@Nullable Collection<CompanionAdSlot> companionAdSlots, @Nullable Collection<CompanionAdSlot> companionAdSlots,
@Nullable AdErrorEvent.AdErrorListener applicationAdErrorListener, @Nullable AdErrorEvent.AdErrorListener applicationAdErrorListener,
@ -114,6 +116,7 @@ import java.util.Set;
this.focusSkipButtonWhenAvailable = focusSkipButtonWhenAvailable; this.focusSkipButtonWhenAvailable = focusSkipButtonWhenAvailable;
this.playAdBeforeStartPosition = playAdBeforeStartPosition; this.playAdBeforeStartPosition = playAdBeforeStartPosition;
this.mediaBitrate = mediaBitrate; this.mediaBitrate = mediaBitrate;
this.adMediaMimeTypes = adMediaMimeTypes;
this.adUiElements = adUiElements; this.adUiElements = adUiElements;
this.companionAdSlots = companionAdSlots; this.companionAdSlots = companionAdSlots;
this.applicationAdErrorListener = applicationAdErrorListener; this.applicationAdErrorListener = applicationAdErrorListener;

View File

@ -64,6 +64,7 @@ import com.google.android.exoplayer2.source.ads.SinglePeriodAdTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
@ -754,6 +755,40 @@ public final class ImaAdsLoaderTest {
verify(mockAdsRequest).setAdTagUrl(TEST_DATA_SPEC.uri.toString()); verify(mockAdsRequest).setAdTagUrl(TEST_DATA_SPEC.uri.toString());
} }
@Test
public void setsDefaultMimeTypes() throws Exception {
setupPlayback(CONTENT_TIMELINE, ImmutableList.of(0f));
imaAdsLoader.setSupportedContentTypes(C.TYPE_DASH, C.TYPE_OTHER);
imaAdsLoader.start(adsLoaderListener, adViewProvider);
verify(mockAdsRenderingSettings)
.setMimeTypes(
ImmutableList.of(
MimeTypes.APPLICATION_MPD,
MimeTypes.VIDEO_MP4,
MimeTypes.VIDEO_WEBM,
MimeTypes.VIDEO_H263,
MimeTypes.AUDIO_MP4,
MimeTypes.AUDIO_MPEG));
}
@Test
public void buildWithAdMediaMimeTypes_setsMimeTypes() throws Exception {
setupPlayback(
CONTENT_TIMELINE,
ImmutableList.of(0f),
new ImaAdsLoader.Builder(getApplicationContext())
.setImaFactory(mockImaFactory)
.setImaSdkSettings(mockImaSdkSettings)
.setAdMediaMimeTypes(ImmutableList.of(MimeTypes.AUDIO_MPEG))
.build(),
TEST_DATA_SPEC);
imaAdsLoader.setSupportedContentTypes(C.TYPE_OTHER);
imaAdsLoader.start(adsLoaderListener, adViewProvider);
verify(mockAdsRenderingSettings).setMimeTypes(ImmutableList.of(MimeTypes.AUDIO_MPEG));
}
@Test @Test
public void stop_unregistersAllVideoControlOverlays() { public void stop_unregistersAllVideoControlOverlays() {
setupPlayback(CONTENT_TIMELINE, PREROLL_CUE_POINTS_SECONDS); setupPlayback(CONTENT_TIMELINE, PREROLL_CUE_POINTS_SECONDS);