diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 23201b9b91b..ca4891ad37b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -16,16 +16,15 @@ * Fix NPE in `TextRenderer` when playing content with a single subtitle buffer ([#8017](https://github.com/google/ExoPlayer/issues/8017)). * 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)). - * Add the option to sort tracks by `Format` in `TrackSelectionView` and + * Add an option to sort tracks by `Format` in `TrackSelectionView` and `TrackSelectionDialogBuilder` ([#7709](https://github.com/google/ExoPlayer/issues/7709)). - * Adjusted bottom buttons' heights and paddings in StyledPlayerView for - easy tapping. - * Show overflow button in `StyledPlayerControlView` only when there is no - enough space. - * Fix animation when `StyledPlayerView` first shows its playback controls. + * Improve touch targets in `StyledPlayerView` to make tapping easier. * Audio: * Fix the default audio sink position not advancing correctly when using `AudioTrack`-based speed adjustment @@ -58,6 +57,8 @@ ad tag via media item playback properties continues to be supported. This is in preparation for supporting ads in playlists ([#3750](https://github.com/google/ExoPlayer/issues/3750)). + * Add a way to override ad media MIME types + ([#7961)(https://github.com/google/ExoPlayer/issues/7961)). ### 2.12.0 (2020-09-11) ### diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index f782443619b..08662ea3305 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -59,7 +59,9 @@ import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.Player; 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.AdsMediaSource; import com.google.android.exoplayer2.source.ads.AdsMediaSource.AdLoadException; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.upstream.DataSpec; @@ -94,18 +96,17 @@ *

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 * 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 - * the latter case, please note that this implementation delegates loading of the data spec to the - * IMA SDK, so range and headers specifications will be ignored in ad tag URIs. Literal ads - * responses can be encoded as data scheme data specs, for example, by constructing the data spec - * using a URI generated via {@link Util#getDataUriForString(String, String)}. + * AdsMediaSource} (if using media sources directly). For the latter case, please note that this + * implementation delegates loading of the data spec to the IMA SDK, so range and headers + * specifications will be ignored in ad tag URIs. Literal ads responses can be encoded as data + * scheme data specs, for example, by constructing the data spec using a URI generated via {@link + * Util#getDataUriForString(String, String)}. * *

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 - * be registered via the {@link AdViewProvider} passed to the {@link - * com.google.android.exoplayer2.source.ads.AdsMediaSource}. See the - * IMA SDK Open Measurement documentation for more information. + * be registered via the {@link AdViewProvider} passed to the {@link AdsMediaSource}. See the IMA + * SDK Open Measurement documentation for more information. */ public final class ImaAdsLoader implements Player.EventListener, com.google.android.exoplayer2.source.ads.AdsLoader { @@ -134,6 +135,7 @@ public static final class Builder { @Nullable private AdErrorListener adErrorListener; @Nullable private AdEventListener adEventListener; @Nullable private VideoAdPlayer.VideoAdPlayerCallback videoAdPlayerCallback; + @Nullable private List adMediaMimeTypes; @Nullable private Set adUiElements; @Nullable private Collection companionAdSlots; private long adPreloadTimeoutMs; @@ -239,6 +241,23 @@ public Builder setCompanionAdSlots(Collection companionAdSlots) 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 adMediaMimeTypes) { + this.adMediaMimeTypes = ImmutableList.copyOf(checkNotNull(adMediaMimeTypes)); + return this; + } + /** * 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 @@ -340,9 +359,8 @@ public Builder setPlayAdBeforeStartPosition(boolean playAdBeforeStartPosition) { * information on compatible ad tags. * @return The new {@link ImaAdsLoader}. * @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 - * com.google.android.exoplayer2.source.ads.AdsMediaSource} (if using media sources - * directly). + * media item API) or as a {@link DataSpec} when constructing the {@link AdsMediaSource} (if + * using media sources directly). */ @Deprecated public ImaAdsLoader buildForAdTag(Uri adTagUri) { @@ -362,9 +380,9 @@ public ImaAdsLoader buildForAdTag(Uri adTagUri) { * @return The new {@link ImaAdsLoader}. * @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 - * com.google.android.exoplayer2.source.ads.AdsMediaSource} (if using media sources - * directly). {@link Util#getDataUriForString(String, String)} can be used to construct a - * data URI from literal string ads response (with MIME type text/xml). + * AdsMediaSource} (if using media sources directly). {@link + * Util#getDataUriForString(String, String)} can be used to construct a data URI from + * literal string ads response (with MIME type text/xml). */ @Deprecated public ImaAdsLoader buildForAdsResponse(String adsResponse) { @@ -387,6 +405,7 @@ public ImaAdsLoader build() { focusSkipButtonWhenAvailable, playAdBeforeStartPosition, mediaBitrate, + adMediaMimeTypes, adUiElements, companionAdSlots, adErrorListener, @@ -548,8 +567,7 @@ public ImaAdsLoader build() { * more information. * @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 - * constructing the {@link com.google.android.exoplayer2.source.ads.AdsMediaSource} (if using - * media sources directly). + * constructing the {@link AdsMediaSource} (if using media sources directly). */ @Deprecated public ImaAdsLoader(Context context, Uri adTagUri) { @@ -988,7 +1006,10 @@ public void onPlayerError(ExoPlaybackException error) { private AdsRenderingSettings setupAdsRendering() { AdsRenderingSettings adsRenderingSettings = imaFactory.createAdsRenderingSettings(); adsRenderingSettings.setEnablePreloading(true); - adsRenderingSettings.setMimeTypes(supportedMimeTypes); + adsRenderingSettings.setMimeTypes( + configuration.adMediaMimeTypes != null + ? configuration.adMediaMimeTypes + : supportedMimeTypes); if (configuration.mediaLoadTimeoutMs != TIMEOUT_UNSET) { adsRenderingSettings.setLoadVideoTimeout(configuration.mediaLoadTimeoutMs); } diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaUtil.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaUtil.java index caaf6ae4bf0..2c7813bfd66 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaUtil.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaUtil.java @@ -88,6 +88,7 @@ public static final class Configuration { public final boolean focusSkipButtonWhenAvailable; public final boolean playAdBeforeStartPosition; public final int mediaBitrate; + @Nullable public final List adMediaMimeTypes; @Nullable public final Set adUiElements; @Nullable public final Collection companionAdSlots; @Nullable public final AdErrorEvent.AdErrorListener applicationAdErrorListener; @@ -102,6 +103,7 @@ public Configuration( boolean focusSkipButtonWhenAvailable, boolean playAdBeforeStartPosition, int mediaBitrate, + @Nullable List adMediaMimeTypes, @Nullable Set adUiElements, @Nullable Collection companionAdSlots, @Nullable AdErrorEvent.AdErrorListener applicationAdErrorListener, @@ -114,6 +116,7 @@ public Configuration( this.focusSkipButtonWhenAvailable = focusSkipButtonWhenAvailable; this.playAdBeforeStartPosition = playAdBeforeStartPosition; this.mediaBitrate = mediaBitrate; + this.adMediaMimeTypes = adMediaMimeTypes; this.adUiElements = adUiElements; this.companionAdSlots = companionAdSlots; this.applicationAdErrorListener = applicationAdErrorListener; diff --git a/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoaderTest.java b/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoaderTest.java index dc6f5b517c6..d894466091e 100644 --- a/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoaderTest.java +++ b/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoaderTest.java @@ -64,6 +64,7 @@ import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -754,6 +755,40 @@ public void requestAdTagWithUri_requestsWithAdTagUrl() throws Exception { 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 public void stop_unregistersAllVideoControlOverlays() { setupPlayback(CONTENT_TIMELINE, PREROLL_CUE_POINTS_SECONDS);