mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add AdsMediaSourceFactory for HLS interstitials
PiperOrigin-RevId: 707109323
This commit is contained in:
parent
acc41cb5f7
commit
3dede2415d
@ -101,6 +101,13 @@
|
||||
* Cronet Extension:
|
||||
* RTMP Extension:
|
||||
* HLS Extension:
|
||||
* Add a first version of `HlsInterstitialsAdsLoader`. The ads loader reads
|
||||
the HLS interstitials of an HLS media playlist and maps them to the
|
||||
`AdPlaybackState` that is passed to the `AdsMediaSource`. This initial
|
||||
version only supports HLS VOD streams with `X-ASSET-URI` attributes.
|
||||
* Add `HlsInterstitialsAdsLoader.AdsMediaSourceFactory`. Apps can use it
|
||||
to create `AdsMediaSource` instances that use an
|
||||
`HlsInterstitialsAdsLoader` in a convenient and safe way.
|
||||
* DASH Extension:
|
||||
* Add AC-4 Level-4 format support for DASH
|
||||
([#1898](https://github.com/androidx/media/pull/1898)).
|
||||
|
@ -16,11 +16,13 @@
|
||||
package androidx.media3.exoplayer.hls;
|
||||
|
||||
import static androidx.media3.common.Player.DISCONTINUITY_REASON_AUTO_TRANSITION;
|
||||
import static androidx.media3.common.util.Assertions.checkArgument;
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
import static androidx.media3.common.util.Assertions.checkState;
|
||||
import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
||||
import static java.lang.Math.max;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.AdPlaybackState;
|
||||
import androidx.media3.common.AdViewProvider;
|
||||
@ -38,10 +40,15 @@ import androidx.media3.common.util.Log;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.datasource.DataSpec;
|
||||
import androidx.media3.datasource.DefaultDataSource;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionManagerProvider;
|
||||
import androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist;
|
||||
import androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist.Interstitial;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.source.ads.AdsLoader;
|
||||
import androidx.media3.exoplayer.source.ads.AdsMediaSource;
|
||||
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy;
|
||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -64,6 +71,110 @@ import java.util.Set;
|
||||
@UnstableApi
|
||||
public final class HlsInterstitialsAdsLoader implements AdsLoader {
|
||||
|
||||
/**
|
||||
* A {@link MediaSource.Factory} to create a media source to play HLS streams with interstitials.
|
||||
*/
|
||||
public static final class AdsMediaSourceFactory implements MediaSource.Factory {
|
||||
|
||||
private final MediaSource.Factory mediaSourceFactory;
|
||||
private final AdViewProvider adViewProvider;
|
||||
private final HlsInterstitialsAdsLoader adsLoader;
|
||||
|
||||
/**
|
||||
* Creates an instance with a {@link
|
||||
* androidx.media3.exoplayer.source.DefaultMediaSourceFactory}.
|
||||
*
|
||||
* @param adsLoader The {@link HlsInterstitialsAdsLoader}.
|
||||
* @param adViewProvider Provider of views for the ad UI.
|
||||
* @param context The {@link Context}.
|
||||
*/
|
||||
public AdsMediaSourceFactory(
|
||||
HlsInterstitialsAdsLoader adsLoader, AdViewProvider adViewProvider, Context context) {
|
||||
this(adsLoader, context, /* mediaSourceFactory= */ null, adViewProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance with a custom {@link MediaSource.Factory}.
|
||||
*
|
||||
* @param adsLoader The {@link HlsInterstitialsAdsLoader}.
|
||||
* @param adViewProvider Provider of views for the ad UI.
|
||||
* @param mediaSourceFactory The {@link MediaSource.Factory} used to create content and ad media
|
||||
* sources.
|
||||
* @throws IllegalStateException If the provided {@linkplain MediaSource.Factory media source
|
||||
* factory} doesn't support content type {@link C#CONTENT_TYPE_HLS}.
|
||||
*/
|
||||
public AdsMediaSourceFactory(
|
||||
HlsInterstitialsAdsLoader adsLoader,
|
||||
AdViewProvider adViewProvider,
|
||||
MediaSource.Factory mediaSourceFactory) {
|
||||
this(adsLoader, /* context= */ null, mediaSourceFactory, adViewProvider);
|
||||
}
|
||||
|
||||
private AdsMediaSourceFactory(
|
||||
HlsInterstitialsAdsLoader adsLoader,
|
||||
@Nullable Context context,
|
||||
@Nullable MediaSource.Factory mediaSourceFactory,
|
||||
AdViewProvider adViewProvider) {
|
||||
checkArgument(context != null || mediaSourceFactory != null);
|
||||
this.adsLoader = adsLoader;
|
||||
this.mediaSourceFactory =
|
||||
mediaSourceFactory != null
|
||||
? mediaSourceFactory
|
||||
: new HlsMediaSource.Factory(new DefaultDataSource.Factory(checkNotNull(context)));
|
||||
this.adViewProvider = adViewProvider;
|
||||
boolean supportsHls = false;
|
||||
for (int supportedType : this.mediaSourceFactory.getSupportedTypes()) {
|
||||
if (supportedType == C.CONTENT_TYPE_HLS) {
|
||||
supportsHls = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
checkState(supportsHls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @C.ContentType int[] getSupportedTypes() {
|
||||
return new int[] {C.CONTENT_TYPE_HLS};
|
||||
}
|
||||
|
||||
@Override
|
||||
@CanIgnoreReturnValue
|
||||
public AdsMediaSourceFactory setDrmSessionManagerProvider(
|
||||
DrmSessionManagerProvider drmSessionManagerProvider) {
|
||||
mediaSourceFactory.setDrmSessionManagerProvider(drmSessionManagerProvider);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@CanIgnoreReturnValue
|
||||
public AdsMediaSourceFactory setLoadErrorHandlingPolicy(
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
mediaSourceFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaSource createMediaSource(MediaItem mediaItem) {
|
||||
checkNotNull(mediaItem.localConfiguration);
|
||||
MediaSource contentMediaSource = mediaSourceFactory.createMediaSource(mediaItem);
|
||||
if (mediaItem.localConfiguration.adsConfiguration == null) {
|
||||
return contentMediaSource;
|
||||
} else if (!(mediaItem.localConfiguration.adsConfiguration.adsId instanceof String)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Please use an AdsConfiguration with an adsId of type String when using"
|
||||
+ " HlsInterstitialsAdsLoader");
|
||||
}
|
||||
return new AdsMediaSource(
|
||||
contentMediaSource,
|
||||
new DataSpec(mediaItem.localConfiguration.adsConfiguration.adTagUri), // unused
|
||||
checkNotNull(mediaItem.localConfiguration.adsConfiguration.adsId),
|
||||
mediaSourceFactory,
|
||||
adsLoader,
|
||||
adViewProvider,
|
||||
/* useLazyContentSourcePreparation= */ false);
|
||||
}
|
||||
}
|
||||
|
||||
/** A listener to be notified of events emitted by the ads loader. */
|
||||
public interface Listener {
|
||||
|
||||
|
@ -90,18 +90,15 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
.setAdsConfiguration(
|
||||
new MediaItem.AdsConfiguration.Builder(Uri.EMPTY).setAdsId("adsId").build())
|
||||
.build();
|
||||
adTagDataSpec = new DataSpec(contentMediaItem.localConfiguration.adsConfiguration.adTagUri);
|
||||
DefaultMediaSourceFactory defaultMediaSourceFactory =
|
||||
new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext());
|
||||
adTagDataSpec = new DataSpec(Uri.EMPTY);
|
||||
// The ads media source using the ads loader.
|
||||
adsMediaSource =
|
||||
new AdsMediaSource(
|
||||
defaultMediaSourceFactory.createMediaSource(contentMediaItem),
|
||||
new DataSpec(Uri.EMPTY),
|
||||
"adsId",
|
||||
defaultMediaSourceFactory,
|
||||
adsLoader,
|
||||
mockAdViewProvider);
|
||||
(AdsMediaSource)
|
||||
new HlsInterstitialsAdsLoader.AdsMediaSourceFactory(
|
||||
adsLoader,
|
||||
mockAdViewProvider,
|
||||
(Context) ApplicationProvider.getApplicationContext())
|
||||
.createMediaSource(contentMediaItem);
|
||||
// The content timeline with empty ad playback state.
|
||||
contentWindowDefinition =
|
||||
new FakeTimeline.TimelineWindowDefinition(
|
||||
|
Loading…
x
Reference in New Issue
Block a user