Support non-extractor ads in AdsMediaSource and demo apps
Issue: #3302 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=178615074
This commit is contained in:
parent
2e3667eeff
commit
a4ae206ebe
@ -44,6 +44,8 @@
|
|||||||
* Use surfaceless context for secure DummySurface, if available
|
* Use surfaceless context for secure DummySurface, if available
|
||||||
([#3558](https://github.com/google/ExoPlayer/issues/3558)).
|
([#3558](https://github.com/google/ExoPlayer/issues/3558)).
|
||||||
* IMA extension:
|
* IMA extension:
|
||||||
|
* Support non-ExtractorMediaSource ads
|
||||||
|
([#3302](https://github.com/google/ExoPlayer/issues/3302)).
|
||||||
* Skip ads before the ad preceding the player's initial seek position
|
* Skip ads before the ad preceding the player's initial seek position
|
||||||
([#3527](https://github.com/google/ExoPlayer/issues/3527)).
|
([#3527](https://github.com/google/ExoPlayer/issues/3527)).
|
||||||
* Fix ad loading when there is no preroll.
|
* Fix ad loading when there is no preroll.
|
||||||
|
@ -43,5 +43,7 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile project(modulePrefix + 'library-core')
|
compile project(modulePrefix + 'library-core')
|
||||||
compile project(modulePrefix + 'library-ui')
|
compile project(modulePrefix + 'library-ui')
|
||||||
|
compile project(modulePrefix + 'library-dash')
|
||||||
|
compile project(modulePrefix + 'library-hls')
|
||||||
compile project(modulePrefix + 'extension-ima')
|
compile project(modulePrefix + 'extension-ima')
|
||||||
}
|
}
|
||||||
|
@ -17,13 +17,21 @@ package com.google.android.exoplayer2.imademo;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.C.ContentType;
|
||||||
import com.google.android.exoplayer2.ExoPlayer;
|
import com.google.android.exoplayer2.ExoPlayer;
|
||||||
import com.google.android.exoplayer2.ExoPlayerFactory;
|
import com.google.android.exoplayer2.ExoPlayerFactory;
|
||||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||||
import com.google.android.exoplayer2.ext.ima.ImaAdsLoader;
|
import com.google.android.exoplayer2.ext.ima.ImaAdsLoader;
|
||||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
|
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||||
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
||||||
|
import com.google.android.exoplayer2.source.dash.DashMediaSource;
|
||||||
|
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
|
||||||
|
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
|
||||||
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
|
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||||
@ -35,12 +43,12 @@ import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
|||||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
||||||
/**
|
/** Manages the {@link ExoPlayer}, the IMA plugin and all video playback. */
|
||||||
* Manages the {@link ExoPlayer}, the IMA plugin and all video playback.
|
/* package */ final class PlayerManager implements AdsMediaSource.MediaSourceFactory {
|
||||||
*/
|
|
||||||
/* package */ final class PlayerManager {
|
|
||||||
|
|
||||||
private final ImaAdsLoader adsLoader;
|
private final ImaAdsLoader adsLoader;
|
||||||
|
private final DataSource.Factory manifestDataSourceFactory;
|
||||||
|
private final DataSource.Factory mediaDataSourceFactory;
|
||||||
|
|
||||||
private SimpleExoPlayer player;
|
private SimpleExoPlayer player;
|
||||||
private long contentPosition;
|
private long contentPosition;
|
||||||
@ -48,6 +56,14 @@ import com.google.android.exoplayer2.util.Util;
|
|||||||
public PlayerManager(Context context) {
|
public PlayerManager(Context context) {
|
||||||
String adTag = context.getString(R.string.ad_tag_url);
|
String adTag = context.getString(R.string.ad_tag_url);
|
||||||
adsLoader = new ImaAdsLoader(context, Uri.parse(adTag));
|
adsLoader = new ImaAdsLoader(context, Uri.parse(adTag));
|
||||||
|
manifestDataSourceFactory =
|
||||||
|
new DefaultDataSourceFactory(
|
||||||
|
context, Util.getUserAgent(context, context.getString(R.string.application_name)));
|
||||||
|
mediaDataSourceFactory =
|
||||||
|
new DefaultDataSourceFactory(
|
||||||
|
context,
|
||||||
|
Util.getUserAgent(context, context.getString(R.string.application_name)),
|
||||||
|
new DefaultBandwidthMeter());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(Context context, SimpleExoPlayerView simpleExoPlayerView) {
|
public void init(Context context, SimpleExoPlayerView simpleExoPlayerView) {
|
||||||
@ -74,8 +90,14 @@ import com.google.android.exoplayer2.util.Util;
|
|||||||
.createMediaSource(Uri.parse(contentUrl));
|
.createMediaSource(Uri.parse(contentUrl));
|
||||||
|
|
||||||
// Compose the content media source into a new AdsMediaSource with both ads and content.
|
// Compose the content media source into a new AdsMediaSource with both ads and content.
|
||||||
MediaSource mediaSourceWithAds = new AdsMediaSource(contentMediaSource, dataSourceFactory,
|
MediaSource mediaSourceWithAds =
|
||||||
adsLoader, simpleExoPlayerView.getOverlayFrameLayout());
|
new AdsMediaSource(
|
||||||
|
contentMediaSource,
|
||||||
|
/* adMediaSourceFactory= */ this,
|
||||||
|
adsLoader,
|
||||||
|
simpleExoPlayerView.getOverlayFrameLayout(),
|
||||||
|
/* eventHandler= */ null,
|
||||||
|
/* eventListener= */ null);
|
||||||
|
|
||||||
// Prepare the player with the source.
|
// Prepare the player with the source.
|
||||||
player.seekTo(contentPosition);
|
player.seekTo(contentPosition);
|
||||||
@ -99,4 +121,32 @@ import com.google.android.exoplayer2.util.Util;
|
|||||||
adsLoader.release();
|
adsLoader.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AdsMediaSource.MediaSourceFactory implementation.
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaSource createMediaSource(
|
||||||
|
Uri uri, @Nullable Handler handler, @Nullable MediaSourceEventListener listener) {
|
||||||
|
@ContentType int type = Util.inferContentType(uri);
|
||||||
|
switch (type) {
|
||||||
|
case C.TYPE_DASH:
|
||||||
|
return new DashMediaSource.Factory(
|
||||||
|
new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
|
||||||
|
manifestDataSourceFactory)
|
||||||
|
.createMediaSource(uri, handler, listener);
|
||||||
|
case C.TYPE_HLS:
|
||||||
|
return new HlsMediaSource.Factory(mediaDataSourceFactory)
|
||||||
|
.createMediaSource(uri, handler, listener);
|
||||||
|
case C.TYPE_OTHER:
|
||||||
|
return new ExtractorMediaSource.Factory(mediaDataSourceFactory)
|
||||||
|
.createMediaSource(uri, handler, listener);
|
||||||
|
case C.TYPE_SS:
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unsupported type: " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] getSupportedTypes() {
|
||||||
|
return new int[] {C.TYPE_DASH, C.TYPE_HLS, C.TYPE_OTHER};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import android.net.Uri;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -52,6 +53,7 @@ import com.google.android.exoplayer2.source.BehindLiveWindowException;
|
|||||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
||||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
|
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
import com.google.android.exoplayer2.source.ads.AdsLoader;
|
import com.google.android.exoplayer2.source.ads.AdsLoader;
|
||||||
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
||||||
@ -332,7 +334,7 @@ public class PlayerActivity extends Activity implements OnClickListener,
|
|||||||
}
|
}
|
||||||
MediaSource[] mediaSources = new MediaSource[uris.length];
|
MediaSource[] mediaSources = new MediaSource[uris.length];
|
||||||
for (int i = 0; i < uris.length; i++) {
|
for (int i = 0; i < uris.length; i++) {
|
||||||
mediaSources[i] = buildMediaSource(uris[i], extensions[i]);
|
mediaSources[i] = buildMediaSource(uris[i], extensions[i], mainHandler, eventLogger);
|
||||||
}
|
}
|
||||||
MediaSource mediaSource = mediaSources.length == 1 ? mediaSources[0]
|
MediaSource mediaSource = mediaSources.length == 1 ? mediaSources[0]
|
||||||
: new ConcatenatingMediaSource(mediaSources);
|
: new ConcatenatingMediaSource(mediaSources);
|
||||||
@ -360,26 +362,30 @@ public class PlayerActivity extends Activity implements OnClickListener,
|
|||||||
updateButtonVisibilities();
|
updateButtonVisibilities();
|
||||||
}
|
}
|
||||||
|
|
||||||
private MediaSource buildMediaSource(Uri uri, String overrideExtension) {
|
private MediaSource buildMediaSource(
|
||||||
|
Uri uri,
|
||||||
|
String overrideExtension,
|
||||||
|
@Nullable Handler handler,
|
||||||
|
@Nullable MediaSourceEventListener listener) {
|
||||||
@ContentType int type = TextUtils.isEmpty(overrideExtension) ? Util.inferContentType(uri)
|
@ContentType int type = TextUtils.isEmpty(overrideExtension) ? Util.inferContentType(uri)
|
||||||
: Util.inferContentType("." + overrideExtension);
|
: Util.inferContentType("." + overrideExtension);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case C.TYPE_SS:
|
|
||||||
return new SsMediaSource.Factory(
|
|
||||||
new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
|
|
||||||
buildDataSourceFactory(false))
|
|
||||||
.createMediaSource(uri, mainHandler, eventLogger);
|
|
||||||
case C.TYPE_DASH:
|
case C.TYPE_DASH:
|
||||||
return new DashMediaSource.Factory(
|
return new DashMediaSource.Factory(
|
||||||
new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
|
new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
|
||||||
buildDataSourceFactory(false))
|
buildDataSourceFactory(false))
|
||||||
.createMediaSource(uri, mainHandler, eventLogger);
|
.createMediaSource(uri, handler, listener);
|
||||||
|
case C.TYPE_SS:
|
||||||
|
return new SsMediaSource.Factory(
|
||||||
|
new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
|
||||||
|
buildDataSourceFactory(false))
|
||||||
|
.createMediaSource(uri, handler, listener);
|
||||||
case C.TYPE_HLS:
|
case C.TYPE_HLS:
|
||||||
return new HlsMediaSource.Factory(mediaDataSourceFactory)
|
return new HlsMediaSource.Factory(mediaDataSourceFactory)
|
||||||
.createMediaSource(uri, mainHandler, eventLogger);
|
.createMediaSource(uri, handler, listener);
|
||||||
case C.TYPE_OTHER:
|
case C.TYPE_OTHER:
|
||||||
return new ExtractorMediaSource.Factory(mediaDataSourceFactory)
|
return new ExtractorMediaSource.Factory(mediaDataSourceFactory)
|
||||||
.createMediaSource(uri, mainHandler, eventLogger);
|
.createMediaSource(uri, handler, listener);
|
||||||
default: {
|
default: {
|
||||||
throw new IllegalStateException("Unsupported type: " + type);
|
throw new IllegalStateException("Unsupported type: " + type);
|
||||||
}
|
}
|
||||||
@ -466,8 +472,22 @@ public class PlayerActivity extends Activity implements OnClickListener,
|
|||||||
// The demo app has a non-null overlay frame layout.
|
// The demo app has a non-null overlay frame layout.
|
||||||
simpleExoPlayerView.getOverlayFrameLayout().addView(adUiViewGroup);
|
simpleExoPlayerView.getOverlayFrameLayout().addView(adUiViewGroup);
|
||||||
}
|
}
|
||||||
return new AdsMediaSource(mediaSource, mediaDataSourceFactory, adsLoader, adUiViewGroup,
|
AdsMediaSource.MediaSourceFactory adMediaSourceFactory =
|
||||||
mainHandler, eventLogger);
|
new AdsMediaSource.MediaSourceFactory() {
|
||||||
|
@Override
|
||||||
|
public MediaSource createMediaSource(
|
||||||
|
Uri uri, @Nullable Handler handler, @Nullable MediaSourceEventListener listener) {
|
||||||
|
return PlayerActivity.this.buildMediaSource(
|
||||||
|
uri, /* overrideExtension= */ null, handler, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] getSupportedTypes() {
|
||||||
|
return new int[] {C.TYPE_DASH, C.TYPE_SS, C.TYPE_HLS, C.TYPE_OTHER};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return new AdsMediaSource(
|
||||||
|
mediaSource, adMediaSourceFactory, adsLoader, adUiViewGroup, mainHandler, eventLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void releaseAdsLoader() {
|
private void releaseAdsLoader() {
|
||||||
|
@ -96,13 +96,13 @@ public final class AdsMediaSource implements MediaSource {
|
|||||||
private static final String TAG = "AdsMediaSource";
|
private static final String TAG = "AdsMediaSource";
|
||||||
|
|
||||||
private final MediaSource contentMediaSource;
|
private final MediaSource contentMediaSource;
|
||||||
|
private final MediaSourceFactory adMediaSourceFactory;
|
||||||
private final AdsLoader adsLoader;
|
private final AdsLoader adsLoader;
|
||||||
private final ViewGroup adUiViewGroup;
|
private final ViewGroup adUiViewGroup;
|
||||||
@Nullable private final Handler eventHandler;
|
@Nullable private final Handler eventHandler;
|
||||||
@Nullable private final EventListener eventListener;
|
@Nullable private final EventListener eventListener;
|
||||||
private final Handler mainHandler;
|
private final Handler mainHandler;
|
||||||
private final ComponentListener componentListener;
|
private final ComponentListener componentListener;
|
||||||
private final MediaSourceFactory adMediaSourceFactory;
|
|
||||||
private final Map<MediaSource, List<DeferredMediaPeriod>> deferredMediaPeriodByAdMediaSource;
|
private final Map<MediaSource, List<DeferredMediaPeriod>> deferredMediaPeriodByAdMediaSource;
|
||||||
private final Timeline.Period period;
|
private final Timeline.Period period;
|
||||||
|
|
||||||
@ -119,28 +119,31 @@ public final class AdsMediaSource implements MediaSource {
|
|||||||
private MediaSource.Listener listener;
|
private MediaSource.Listener listener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new source that inserts ads linearly with the content specified by
|
* Constructs a new source that inserts ads linearly with the content specified by {@code
|
||||||
* {@code contentMediaSource}.
|
* contentMediaSource}. Ad media is loaded using {@link ExtractorMediaSource}.
|
||||||
* <p>
|
|
||||||
* Ad media is loaded using {@link ExtractorMediaSource}. If {@code eventListener} is
|
|
||||||
* non-{@code null} it will be notified of both ad tag and ad media load errors.
|
|
||||||
*
|
*
|
||||||
* @param contentMediaSource The {@link MediaSource} providing the content to play.
|
* @param contentMediaSource The {@link MediaSource} providing the content to play.
|
||||||
* @param dataSourceFactory Factory for data sources used to load ad media.
|
* @param dataSourceFactory Factory for data sources used to load ad media.
|
||||||
* @param adsLoader The loader for ads.
|
* @param adsLoader The loader for ads.
|
||||||
* @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI.
|
* @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI.
|
||||||
*/
|
*/
|
||||||
public AdsMediaSource(MediaSource contentMediaSource, DataSource.Factory dataSourceFactory,
|
public AdsMediaSource(
|
||||||
AdsLoader adsLoader, ViewGroup adUiViewGroup) {
|
MediaSource contentMediaSource,
|
||||||
this(contentMediaSource, dataSourceFactory, adsLoader, adUiViewGroup, null, null);
|
DataSource.Factory dataSourceFactory,
|
||||||
|
AdsLoader adsLoader,
|
||||||
|
ViewGroup adUiViewGroup) {
|
||||||
|
this(
|
||||||
|
contentMediaSource,
|
||||||
|
dataSourceFactory,
|
||||||
|
adsLoader,
|
||||||
|
adUiViewGroup,
|
||||||
|
/* eventHandler= */ null,
|
||||||
|
/* eventListener= */ null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new source that inserts ads linearly with the content specified by {@code
|
* Constructs a new source that inserts ads linearly with the content specified by {@code
|
||||||
* contentMediaSource}.
|
* contentMediaSource}. Ad media is loaded using {@link ExtractorMediaSource}.
|
||||||
*
|
|
||||||
* <p>Ad media is loaded using {@link ExtractorMediaSource}. If {@code eventListener} is
|
|
||||||
* non-{@code null} it will be notified of both ad tag and ad media load errors.
|
|
||||||
*
|
*
|
||||||
* @param contentMediaSource The {@link MediaSource} providing the content to play.
|
* @param contentMediaSource The {@link MediaSource} providing the content to play.
|
||||||
* @param dataSourceFactory Factory for data sources used to load ad media.
|
* @param dataSourceFactory Factory for data sources used to load ad media.
|
||||||
@ -156,14 +159,41 @@ public final class AdsMediaSource implements MediaSource {
|
|||||||
ViewGroup adUiViewGroup,
|
ViewGroup adUiViewGroup,
|
||||||
@Nullable Handler eventHandler,
|
@Nullable Handler eventHandler,
|
||||||
@Nullable EventListener eventListener) {
|
@Nullable EventListener eventListener) {
|
||||||
|
this(
|
||||||
|
contentMediaSource,
|
||||||
|
new ExtractorMediaSource.Factory(dataSourceFactory),
|
||||||
|
adsLoader,
|
||||||
|
adUiViewGroup,
|
||||||
|
eventHandler,
|
||||||
|
eventListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new source that inserts ads linearly with the content specified by {@code
|
||||||
|
* contentMediaSource}.
|
||||||
|
*
|
||||||
|
* @param contentMediaSource The {@link MediaSource} providing the content to play.
|
||||||
|
* @param adMediaSourceFactory Factory for media sources used to load ad media.
|
||||||
|
* @param adsLoader The loader for ads.
|
||||||
|
* @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI.
|
||||||
|
* @param eventHandler A handler for events. May be null if delivery of events is not required.
|
||||||
|
* @param eventListener A listener of events. May be null if delivery of events is not required.
|
||||||
|
*/
|
||||||
|
public AdsMediaSource(
|
||||||
|
MediaSource contentMediaSource,
|
||||||
|
MediaSourceFactory adMediaSourceFactory,
|
||||||
|
AdsLoader adsLoader,
|
||||||
|
ViewGroup adUiViewGroup,
|
||||||
|
@Nullable Handler eventHandler,
|
||||||
|
@Nullable EventListener eventListener) {
|
||||||
this.contentMediaSource = contentMediaSource;
|
this.contentMediaSource = contentMediaSource;
|
||||||
|
this.adMediaSourceFactory = adMediaSourceFactory;
|
||||||
this.adsLoader = adsLoader;
|
this.adsLoader = adsLoader;
|
||||||
this.adUiViewGroup = adUiViewGroup;
|
this.adUiViewGroup = adUiViewGroup;
|
||||||
this.eventHandler = eventHandler;
|
this.eventHandler = eventHandler;
|
||||||
this.eventListener = eventListener;
|
this.eventListener = eventListener;
|
||||||
mainHandler = new Handler(Looper.getMainLooper());
|
mainHandler = new Handler(Looper.getMainLooper());
|
||||||
componentListener = new ComponentListener();
|
componentListener = new ComponentListener();
|
||||||
adMediaSourceFactory = new ExtractorMediaSource.Factory(dataSourceFactory);
|
|
||||||
deferredMediaPeriodByAdMediaSource = new HashMap<>();
|
deferredMediaPeriodByAdMediaSource = new HashMap<>();
|
||||||
period = new Timeline.Period();
|
period = new Timeline.Period();
|
||||||
adGroupMediaSources = new MediaSource[0][];
|
adGroupMediaSources = new MediaSource[0][];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user