Integrate IMA SSAI samples in main demo app
PiperOrigin-RevId: 429059793
This commit is contained in:
parent
0842295a88
commit
5ee9c48244
@ -76,6 +76,7 @@
|
|||||||
<data android:scheme="content"/>
|
<data android:scheme="content"/>
|
||||||
<data android:scheme="asset"/>
|
<data android:scheme="asset"/>
|
||||||
<data android:scheme="file"/>
|
<data android:scheme="file"/>
|
||||||
|
<data android:scheme="ssai"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="androidx.media3.demo.main.action.VIEW_LIST"/>
|
<action android:name="androidx.media3.demo.main.action.VIEW_LIST"/>
|
||||||
|
@ -387,6 +387,98 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "IMA DAI streams",
|
||||||
|
"samples": [
|
||||||
|
{
|
||||||
|
"name": "HLS VOD: Demo (skippable pre/post), single ads [30 s]",
|
||||||
|
"uri": "ssai://dai.google.com/?contentSourceId=2483977&videoId=ima-vod-skippable-test&format=2&adsId=1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HLS VOD: Tears of Steel (pre/mid/mid/mid/post), single ads [10s]",
|
||||||
|
"uri": "ssai://dai.google.com/?contentSourceId=2528370&videoId=tears-of-steel&format=2&adsId=1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HLS Live: Big Buck Bunny (mid), 3 ads each [10 s]",
|
||||||
|
"uri": "ssai://dai.google.com/?assetKey=sN_IYUG8STe1ZzhIIE_ksA&format=2&adsId=3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DASH VOD: Tears of Steel (11 periods, pre/mid/post), 2/5/2 ads [5/10s]",
|
||||||
|
"uri": "ssai://dai.google.com/?contentSourceId=2559737&videoId=tos-dash&format=0&adsId=1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Playlist: No ads - HLS VOD: Demo (skippable pre/post) - No ads",
|
||||||
|
"playlist": [
|
||||||
|
{
|
||||||
|
"uri": "https://html5demos.com/assets/dizzy.mp4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "ssai://dai.google.com/?contentSourceId=2483977&videoId=ima-vod-skippable-test&format=2&adsId=1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "https://html5demos.com/assets/dizzy.mp4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Playlist: No ads - HLS VOD: Tears of steel (pre/mid/mid/mid/post) - No ads",
|
||||||
|
"playlist": [
|
||||||
|
{
|
||||||
|
"uri": "https://html5demos.com/assets/dizzy.mp4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "ssai://dai.google.com/?contentSourceId=2528370&videoId=tears-of-steel&format=2&adsId=1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "https://html5demos.com/assets/dizzy.mp4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Playlist: No ads - HLS Live: Big Buck Bunny (mid) - No ads",
|
||||||
|
"playlist": [
|
||||||
|
{
|
||||||
|
"uri": "https://html5demos.com/assets/dizzy.mp4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "ssai://dai.google.com/?assetKey=sN_IYUG8STe1ZzhIIE_ksA&format=2&adsId=3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "https://html5demos.com/assets/dizzy.mp4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Playlist: No ads - DASH VOD: Tears of Steel (11 periods, pre/mid/post) - No ads",
|
||||||
|
"playlist": [
|
||||||
|
{
|
||||||
|
"uri": "https://html5demos.com/assets/dizzy.mp4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "ssai://dai.google.com/?contentSourceId=2559737&videoId=tos-dash&format=0&adsId=1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "https://html5demos.com/assets/dizzy.mp4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Playlist: Client-side Ads - DASH VOD: Tears of Steel (11 periods, pre/mid/post) - No ads",
|
||||||
|
"playlist": [
|
||||||
|
{
|
||||||
|
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv",
|
||||||
|
"ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpost&cmsid=496&vid=short_onecue&correlator="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "ssai://dai.google.com/?contentSourceId=2559737&videoId=tos-dash&format=0&adsId=1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "https://html5demos.com/assets/dizzy.mp4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Playlists",
|
"name": "Playlists",
|
||||||
"samples": [
|
"samples": [
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.demo.main;
|
package androidx.media3.demo.main;
|
||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@ -43,6 +41,7 @@ import androidx.media3.exoplayer.ExoPlayer;
|
|||||||
import androidx.media3.exoplayer.RenderersFactory;
|
import androidx.media3.exoplayer.RenderersFactory;
|
||||||
import androidx.media3.exoplayer.drm.FrameworkMediaDrm;
|
import androidx.media3.exoplayer.drm.FrameworkMediaDrm;
|
||||||
import androidx.media3.exoplayer.ima.ImaAdsLoader;
|
import androidx.media3.exoplayer.ima.ImaAdsLoader;
|
||||||
|
import androidx.media3.exoplayer.ima.ImaServerSideAdInsertionMediaSource;
|
||||||
import androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.DecoderInitializationException;
|
import androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.DecoderInitializationException;
|
||||||
import androidx.media3.exoplayer.mediacodec.MediaCodecUtil.DecoderQueryException;
|
import androidx.media3.exoplayer.mediacodec.MediaCodecUtil.DecoderQueryException;
|
||||||
import androidx.media3.exoplayer.offline.DownloadRequest;
|
import androidx.media3.exoplayer.offline.DownloadRequest;
|
||||||
@ -57,6 +56,7 @@ import androidx.media3.ui.PlayerView;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
/** An activity that plays media using {@link ExoPlayer}. */
|
/** An activity that plays media using {@link ExoPlayer}. */
|
||||||
public class PlayerActivity extends AppCompatActivity
|
public class PlayerActivity extends AppCompatActivity
|
||||||
@ -65,6 +65,7 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
// Saved instance state keys.
|
// Saved instance state keys.
|
||||||
|
|
||||||
private static final String KEY_TRACK_SELECTION_PARAMETERS = "track_selection_parameters";
|
private static final String KEY_TRACK_SELECTION_PARAMETERS = "track_selection_parameters";
|
||||||
|
private static final String KEY_SERVER_SIDE_ADS_LOADER_STATE = "server_side_ads_loader_state";
|
||||||
private static final String KEY_ITEM_INDEX = "item_index";
|
private static final String KEY_ITEM_INDEX = "item_index";
|
||||||
private static final String KEY_POSITION = "position";
|
private static final String KEY_POSITION = "position";
|
||||||
private static final String KEY_AUTO_PLAY = "auto_play";
|
private static final String KEY_AUTO_PLAY = "auto_play";
|
||||||
@ -88,7 +89,10 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
|
|
||||||
// For ad playback only.
|
// For ad playback only.
|
||||||
|
|
||||||
private AdsLoader adsLoader;
|
@Nullable private AdsLoader clientSideAdsLoader;
|
||||||
|
@Nullable private ImaServerSideAdInsertionMediaSource.AdsLoader serverSideAdsLoader;
|
||||||
|
private ImaServerSideAdInsertionMediaSource.AdsLoader.@MonotonicNonNull State
|
||||||
|
serverSideAdsLoaderState;
|
||||||
|
|
||||||
// Activity lifecycle.
|
// Activity lifecycle.
|
||||||
|
|
||||||
@ -116,6 +120,12 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
startAutoPlay = savedInstanceState.getBoolean(KEY_AUTO_PLAY);
|
startAutoPlay = savedInstanceState.getBoolean(KEY_AUTO_PLAY);
|
||||||
startItemIndex = savedInstanceState.getInt(KEY_ITEM_INDEX);
|
startItemIndex = savedInstanceState.getInt(KEY_ITEM_INDEX);
|
||||||
startPosition = savedInstanceState.getLong(KEY_POSITION);
|
startPosition = savedInstanceState.getLong(KEY_POSITION);
|
||||||
|
Bundle adsLoaderStateBundle = savedInstanceState.getBundle(KEY_SERVER_SIDE_ADS_LOADER_STATE);
|
||||||
|
if (adsLoaderStateBundle != null) {
|
||||||
|
serverSideAdsLoaderState =
|
||||||
|
ImaServerSideAdInsertionMediaSource.AdsLoader.State.CREATOR.fromBundle(
|
||||||
|
adsLoaderStateBundle);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
trackSelectionParameters =
|
trackSelectionParameters =
|
||||||
new DefaultTrackSelector.ParametersBuilder(/* context= */ this).build();
|
new DefaultTrackSelector.ParametersBuilder(/* context= */ this).build();
|
||||||
@ -127,7 +137,7 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
public void onNewIntent(Intent intent) {
|
public void onNewIntent(Intent intent) {
|
||||||
super.onNewIntent(intent);
|
super.onNewIntent(intent);
|
||||||
releasePlayer();
|
releasePlayer();
|
||||||
releaseAdsLoader();
|
releaseClientSideAdsLoader();
|
||||||
clearStartPosition();
|
clearStartPosition();
|
||||||
setIntent(intent);
|
setIntent(intent);
|
||||||
}
|
}
|
||||||
@ -179,7 +189,7 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
releaseAdsLoader();
|
releaseClientSideAdsLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -208,6 +218,9 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
outState.putBoolean(KEY_AUTO_PLAY, startAutoPlay);
|
outState.putBoolean(KEY_AUTO_PLAY, startAutoPlay);
|
||||||
outState.putInt(KEY_ITEM_INDEX, startItemIndex);
|
outState.putInt(KEY_ITEM_INDEX, startItemIndex);
|
||||||
outState.putLong(KEY_POSITION, startPosition);
|
outState.putLong(KEY_POSITION, startPosition);
|
||||||
|
if (serverSideAdsLoaderState != null) {
|
||||||
|
outState.putBundle(KEY_SERVER_SIDE_ADS_LOADER_STATE, serverSideAdsLoaderState.toBundle());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activity input
|
// Activity input
|
||||||
@ -261,17 +274,13 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
intent.getBooleanExtra(IntentUtil.PREFER_EXTENSION_DECODERS_EXTRA, false);
|
intent.getBooleanExtra(IntentUtil.PREFER_EXTENSION_DECODERS_EXTRA, false);
|
||||||
RenderersFactory renderersFactory =
|
RenderersFactory renderersFactory =
|
||||||
DemoUtil.buildRenderersFactory(/* context= */ this, preferExtensionDecoders);
|
DemoUtil.buildRenderersFactory(/* context= */ this, preferExtensionDecoders);
|
||||||
MediaSource.Factory mediaSourceFactory =
|
|
||||||
new DefaultMediaSourceFactory(dataSourceFactory)
|
|
||||||
.setAdsLoaderProvider(this::getAdsLoader)
|
|
||||||
.setAdViewProvider(playerView);
|
|
||||||
|
|
||||||
trackSelector = new DefaultTrackSelector(/* context= */ this);
|
trackSelector = new DefaultTrackSelector(/* context= */ this);
|
||||||
lastSeenTracksInfo = TracksInfo.EMPTY;
|
lastSeenTracksInfo = TracksInfo.EMPTY;
|
||||||
player =
|
player =
|
||||||
new ExoPlayer.Builder(/* context= */ this)
|
new ExoPlayer.Builder(/* context= */ this)
|
||||||
.setRenderersFactory(renderersFactory)
|
.setRenderersFactory(renderersFactory)
|
||||||
.setMediaSourceFactory(mediaSourceFactory)
|
.setMediaSourceFactory(createMediaSourceFactory())
|
||||||
.setTrackSelector(trackSelector)
|
.setTrackSelector(trackSelector)
|
||||||
.build();
|
.build();
|
||||||
player.setTrackSelectionParameters(trackSelectionParameters);
|
player.setTrackSelectionParameters(trackSelectionParameters);
|
||||||
@ -280,6 +289,7 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
player.setAudioAttributes(AudioAttributes.DEFAULT, /* handleAudioFocus= */ true);
|
player.setAudioAttributes(AudioAttributes.DEFAULT, /* handleAudioFocus= */ true);
|
||||||
player.setPlayWhenReady(startAutoPlay);
|
player.setPlayWhenReady(startAutoPlay);
|
||||||
playerView.setPlayer(player);
|
playerView.setPlayer(player);
|
||||||
|
serverSideAdsLoader.setPlayer(player);
|
||||||
debugViewHelper = new DebugTextViewHelper(player, debugTextView);
|
debugViewHelper = new DebugTextViewHelper(player, debugTextView);
|
||||||
debugViewHelper.start();
|
debugViewHelper.start();
|
||||||
}
|
}
|
||||||
@ -293,6 +303,22 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MediaSource.Factory createMediaSourceFactory() {
|
||||||
|
ImaServerSideAdInsertionMediaSource.AdsLoader.Builder serverSideAdLoaderBuilder =
|
||||||
|
new ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(/* context= */ this, playerView);
|
||||||
|
if (serverSideAdsLoaderState != null) {
|
||||||
|
serverSideAdLoaderBuilder.setAdsLoaderState(serverSideAdsLoaderState);
|
||||||
|
}
|
||||||
|
serverSideAdsLoader = serverSideAdLoaderBuilder.build();
|
||||||
|
ImaServerSideAdInsertionMediaSource.Factory imaServerSideAdInsertionMediaSourceFactory =
|
||||||
|
new ImaServerSideAdInsertionMediaSource.Factory(
|
||||||
|
serverSideAdsLoader, new DefaultMediaSourceFactory(dataSourceFactory));
|
||||||
|
return new DefaultMediaSourceFactory(dataSourceFactory)
|
||||||
|
.setAdsLoaderProvider(this::getClientSideAdsLoader)
|
||||||
|
.setAdViewProvider(playerView)
|
||||||
|
.setServerSideAdInsertionMediaSourceFactory(imaServerSideAdInsertionMediaSourceFactory);
|
||||||
|
}
|
||||||
|
|
||||||
private List<MediaItem> createMediaItems(Intent intent) {
|
private List<MediaItem> createMediaItems(Intent intent) {
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
boolean actionIsListView = IntentUtil.ACTION_VIEW_LIST.equals(action);
|
boolean actionIsListView = IntentUtil.ACTION_VIEW_LIST.equals(action);
|
||||||
@ -304,7 +330,6 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
|
|
||||||
List<MediaItem> mediaItems =
|
List<MediaItem> mediaItems =
|
||||||
createMediaItems(intent, DemoUtil.getDownloadTracker(/* context= */ this));
|
createMediaItems(intent, DemoUtil.getDownloadTracker(/* context= */ this));
|
||||||
boolean hasAds = false;
|
|
||||||
for (int i = 0; i < mediaItems.size(); i++) {
|
for (int i = 0; i < mediaItems.size(); i++) {
|
||||||
MediaItem mediaItem = mediaItems.get(i);
|
MediaItem mediaItem = mediaItems.get(i);
|
||||||
|
|
||||||
@ -318,8 +343,7 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaItem.DrmConfiguration drmConfiguration =
|
MediaItem.DrmConfiguration drmConfiguration = mediaItem.localConfiguration.drmConfiguration;
|
||||||
checkNotNull(mediaItem.localConfiguration).drmConfiguration;
|
|
||||||
if (drmConfiguration != null) {
|
if (drmConfiguration != null) {
|
||||||
if (Util.SDK_INT < 18) {
|
if (Util.SDK_INT < 18) {
|
||||||
showToast(R.string.error_drm_unsupported_before_api_18);
|
showToast(R.string.error_drm_unsupported_before_api_18);
|
||||||
@ -331,43 +355,44 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hasAds |= mediaItem.localConfiguration.adsConfiguration != null;
|
|
||||||
}
|
|
||||||
if (!hasAds) {
|
|
||||||
releaseAdsLoader();
|
|
||||||
}
|
}
|
||||||
return mediaItems;
|
return mediaItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AdsLoader getAdsLoader(MediaItem.AdsConfiguration adsConfiguration) {
|
private AdsLoader getClientSideAdsLoader(MediaItem.AdsConfiguration adsConfiguration) {
|
||||||
// The ads loader is reused for multiple playbacks, so that ad playback can resume.
|
// The ads loader is reused for multiple playbacks, so that ad playback can resume.
|
||||||
if (adsLoader == null) {
|
if (clientSideAdsLoader == null) {
|
||||||
adsLoader = new ImaAdsLoader.Builder(/* context= */ this).build();
|
clientSideAdsLoader = new ImaAdsLoader.Builder(/* context= */ this).build();
|
||||||
}
|
}
|
||||||
adsLoader.setPlayer(player);
|
clientSideAdsLoader.setPlayer(player);
|
||||||
return adsLoader;
|
return clientSideAdsLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void releasePlayer() {
|
protected void releasePlayer() {
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
updateTrackSelectorParameters();
|
updateTrackSelectorParameters();
|
||||||
updateStartPosition();
|
updateStartPosition();
|
||||||
|
serverSideAdsLoaderState = serverSideAdsLoader.release();
|
||||||
|
serverSideAdsLoader = null;
|
||||||
debugViewHelper.stop();
|
debugViewHelper.stop();
|
||||||
debugViewHelper = null;
|
debugViewHelper = null;
|
||||||
player.release();
|
player.release();
|
||||||
player = null;
|
player = null;
|
||||||
|
playerView.setPlayer(/* player= */ null);
|
||||||
mediaItems = Collections.emptyList();
|
mediaItems = Collections.emptyList();
|
||||||
}
|
}
|
||||||
if (adsLoader != null) {
|
if (clientSideAdsLoader != null) {
|
||||||
adsLoader.setPlayer(null);
|
clientSideAdsLoader.setPlayer(null);
|
||||||
|
} else {
|
||||||
|
playerView.getAdViewGroup().removeAllViews();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void releaseAdsLoader() {
|
private void releaseClientSideAdsLoader() {
|
||||||
if (adsLoader != null) {
|
if (clientSideAdsLoader != null) {
|
||||||
adsLoader.release();
|
clientSideAdsLoader.release();
|
||||||
adsLoader = null;
|
clientSideAdsLoader = null;
|
||||||
playerView.getOverlayFrameLayout().removeAllViews();
|
playerView.getAdViewGroup().removeAllViews();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,7 +515,7 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
for (MediaItem item : IntentUtil.createMediaItemsFromIntent(intent)) {
|
for (MediaItem item : IntentUtil.createMediaItemsFromIntent(intent)) {
|
||||||
@Nullable
|
@Nullable
|
||||||
DownloadRequest downloadRequest =
|
DownloadRequest downloadRequest =
|
||||||
downloadTracker.getDownloadRequest(checkNotNull(item.localConfiguration).uri);
|
downloadTracker.getDownloadRequest(item.localConfiguration.uri);
|
||||||
if (downloadRequest != null) {
|
if (downloadRequest != null) {
|
||||||
MediaItem.Builder builder = item.buildUpon();
|
MediaItem.Builder builder = item.buildUpon();
|
||||||
builder
|
builder
|
||||||
|
Loading…
x
Reference in New Issue
Block a user