ExoPlayer kann sowohl für die clientseitige als auch für die serverseitige Anzeigenbereitstellung verwendet werden.
Clientseitige Anzeigenbereitstellung
Bei der clientseitigen Anzeigenbereitstellung wechselt der Player beim Wechsel zwischen der Wiedergabe von Inhalten und Anzeigen zwischen dem Laden von Medien von verschiedenen URLs. Informationen zu Anzeigen werden getrennt von den Medien geladen, beispielsweise aus einem XML-VAST- oder VMAP-Anzeigen-Tag. Dazu gehören die Positionen von Cues im Verhältnis zum Anfang des Inhalts, die tatsächlichen Medien-URIs der Anzeige und Metadaten, z. B. ob eine bestimmte Anzeige überspringbar ist.
Wird der ExoPlayer-AdsMediaSource
für die clientseitige Anzeigenbereitstellung verwendet, verfügt der Player über Informationen zu den Anzeigen, die wiedergegeben werden sollen. Das hat mehrere Vorteile:
- Über die API des Players können Metadaten und Funktionen für Anzeigen bereitgestellt werden.
- ExoPlayer-UI-Komponenten können automatisch Markierungen für Anzeigenpositionen anzeigen und ihr Verhalten ändern, je nachdem, ob eine Anzeige wiedergegeben wird.
- Intern kann der Player für die Übergänge zwischen Anzeigen und Inhalten einen einheitlichen Puffer beibehalten.
Bei dieser Einrichtung sorgt der Player für den Wechsel zwischen Werbung und Content. Das bedeutet, dass Apps nicht mehrere separate Hintergrund-/Vordergrund-Player für Anzeigen und Inhalte steuern müssen.
Bei der Vorbereitung von Contentvideos und Anzeigen-Tags für die clientseitige Anzeigenbereitstellung sollten Anzeigen idealerweise an Synchronisierungsbeispielen (Keyframes) im Contentvideo positioniert werden, damit der Player die Contentwiedergabe nahtlos fortsetzen kann.
Deklarative Unterstützung von Anzeigen
Beim Erstellen eines MediaItem
kann ein Anzeigen-Tag-URI angegeben werden:
Kotlin
val mediaItem = MediaItem.Builder() .setUri(videoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).build()) .build()
Java
MediaItem mediaItem = new MediaItem.Builder() .setUri(videoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).build()) .build();
Damit der Player für Medienelemente mit Anzeigen-Tags unterstützt wird, muss beim Erstellen des Players ein DefaultMediaSourceFactory
mit einem AdsLoader.Provider
und einem AdViewProvider
konfiguriert und eingefügt werden:
Kotlin
val mediaSourceFactory: MediaSource.Factory = DefaultMediaSourceFactory(context).setLocalAdInsertionComponents(adsLoaderProvider, playerView) val player = ExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build()
Java
MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(context) .setLocalAdInsertionComponents(adsLoaderProvider, /* adViewProvider= */ playerView); ExoPlayer player = new ExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build();
Intern schließt DefaultMediaSourceFactory
die Inhaltsmedienquelle in eine AdsMediaSource
ein. Das AdsMediaSource
ruft ein AdsLoader
vom AdsLoader.Provider
ab und verwendet es, um Anzeigen gemäß dem Anzeigen-Tag des Medienelements einzufügen.
PlayerView
von ExoPlayer implementiert AdViewProvider
. Die ExoPlayer IMA-Bibliothek bietet eine nutzerfreundliche AdsLoader
(siehe unten).
Playlists mit Anzeigen
Beim Abspielen einer Playlist mit mehreren Mediaelementen wird das Anzeigen-Tag standardmäßig angefordert und der Wiedergabestatus der Anzeige einmal für jede Kombination aus Media-ID, Content-URI und Anzeigen-Tag-URI gespeichert. Das bedeutet, dass Nutzer für jedes Medienelement mit Anzeigen, die eine eigene Media-ID oder einen eigenen Content-URI haben, Anzeigen sehen, selbst wenn die Anzeigen-Tag-URIs übereinstimmen. Wenn ein Medienelement wiederholt wird, sieht der Nutzer die entsprechenden Anzeigen nur einmal. Im Wiedergabestatus der Anzeige wird gespeichert, ob Anzeigen wiedergegeben wurden. Daher werden sie nach dem ersten Mal übersprungen.
Dieses Verhalten lässt sich anpassen, indem eine intransparente Anzeigen-ID übergeben wird, mit der basierend auf der Objektgleichheit ein bestimmtes Medienelement mit dem Anzeigenwiedergabestatus verknüpft ist. In diesem Beispiel wird der Anzeigen-Wiedergabestatus nur mit dem Anzeigen-Tag-URI und nicht mit der Kombination aus Media-ID und Anzeigen-Tag-URI verknüpft, wobei der Anzeigen-Tag-URI als Anzeigen-ID übergeben wird. Das hat zur Folge, dass Anzeigen nur einmal geladen werden und der Nutzer auf dem zweiten Element keine Anzeigen sieht, wenn er die Playlist von Anfang bis Ende abspielt.
Kotlin
// Build the media items, passing the same ads identifier for both items, // which means they share ad playback state so ads play only once. val firstItem = MediaItem.Builder() .setUri(firstVideoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build() val secondItem = MediaItem.Builder() .setUri(secondVideoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build() player.addMediaItem(firstItem) player.addMediaItem(secondItem)
Java
// Build the media items, passing the same ads identifier for both items, // which means they share ad playback state so ads play only once. MediaItem firstItem = new MediaItem.Builder() .setUri(firstVideoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build(); MediaItem secondItem = new MediaItem.Builder() .setUri(secondVideoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build(); player.addMediaItem(firstItem); player.addMediaItem(secondItem);
ExoPlayer-IMA-Bibliothek
Die ExoPlayer IMA-Bibliothek bietet ImaAdsLoader
. Damit können Sie die clientseitige Anzeigenbereitstellung in Ihre App einbinden. Sie umfasst die Funktionen des clientseitigen IMA SDK, um das Einfügen von VAST/VMAP-Anzeigen zu unterstützen. Eine Anleitung zur Verwendung der Bibliothek, darunter auch die Hintergrundwiedergabe und die Fortsetzung der Wiedergabe, findest du in der Readme-Datei.
In der Demoanwendung wird die IMA-Bibliothek verwendet. Die Beispielliste enthält mehrere Beispiel-VAST/VMAP-Anzeigen-Tags.
Hinweise zur Benutzeroberfläche
PlayerView
blendet die Transportsteuerelemente während der Wiedergabe von Anzeigen standardmäßig aus. Apps können dies jedoch durch Aufrufen von setControllerHideDuringAds
ändern. Mit dem IMA SDK werden zusätzliche Ansichten über dem Player eingeblendet, während eine Anzeige wiedergegeben wird, etwa ein Link mit der Bezeichnung "Weitere Informationen" und gegebenenfalls eine Schaltfläche zum Überspringen.
Das IMA SDK kann melden, ob Anzeigen durch von Apps bereitgestellte Ansichten verdeckt werden, die über dem Player gerendert werden. Bei Apps, die Ansichten einblenden müssen, die für die Steuerung der Wiedergabe unerlässlich sind, müssen sie beim IMA SDK registriert werden, damit sie bei den Berechnungen der Sichtbarkeit weggelassen werden können. Wenn Sie PlayerView
als AdViewProvider
verwenden, werden automatisch die zugehörigen Steuerelement-Overlays registriert. Apps, die die Benutzeroberfläche eines benutzerdefinierten Players verwenden, müssen Overlay-Ansichten registrieren, indem sie von AdViewProvider.getAdOverlayInfos
zurückgegeben werden.
Weitere Informationen zu Overlay-Ansichten finden Sie unter Open Measurement im IMA SDK.
Companion-Anzeigen
Einige Anzeigen-Tags enthalten zusätzliche Companion-Anzeigen, die in Anzeigenflächen einer App-Benutzeroberfläche angezeigt werden können. Diese Slots können über ImaAdsLoader.Builder.setCompanionAdSlots(slots)
übergeben werden. Weitere Informationen finden Sie unter Companion-Anzeigen hinzufügen.
Eigenständige Anzeigen
Das IMA SDK wurde für das Einfügen von Anzeigen in Mediacontent entwickelt, nicht für die Wiedergabe eigenständiger Anzeigen. Daher wird die Wiedergabe eigenständiger Anzeigen von der IMA-Bibliothek nicht unterstützt. Für diesen Anwendungsfall empfehlen wir stattdessen das Google Mobile Ads SDK.
Anzeigen-SDK eines Drittanbieters verwenden
Wenn Sie Anzeigen über das SDK eines Drittanbieters laden müssen, sollten Sie prüfen, ob es bereits eine ExoPlayer-Integration bietet. Ist dies nicht der Fall, sollten Sie ein benutzerdefiniertes AdsLoader
implementieren, das das Drittanbieter-Anzeigen-SDK umschließt, da es die oben beschriebenen Vorteile des AdsMediaSource
bietet.
ImaAdsLoader
dient als Beispielimplementierung.
Alternativ können Sie die Playlist-Unterstützung von ExoPlayer verwenden, um eine Sequenz von Anzeigen und Inhaltsclips zu erstellen:
Kotlin
// A pre-roll ad. val preRollAd = MediaItem.fromUri(preRollAdUri) // The start of the content. val contentStart = MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration(ClippingConfiguration.Builder().setEndPositionMs(120000).build()) .build() // A mid-roll ad. val midRollAd = MediaItem.fromUri(midRollAdUri) // The rest of the content val contentEnd = MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration(ClippingConfiguration.Builder().setStartPositionMs(120000).build()) .build() // Build the playlist. player.addMediaItem(preRollAd) player.addMediaItem(contentStart) player.addMediaItem(midRollAd) player.addMediaItem(contentEnd)
Java
// A pre-roll ad. MediaItem preRollAd = MediaItem.fromUri(preRollAdUri); // The start of the content. MediaItem contentStart = new MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration( new ClippingConfiguration.Builder().setEndPositionMs(120_000).build()) .build(); // A mid-roll ad. MediaItem midRollAd = MediaItem.fromUri(midRollAdUri); // The rest of the content MediaItem contentEnd = new MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration( new ClippingConfiguration.Builder().setStartPositionMs(120_000).build()) .build(); // Build the playlist. player.addMediaItem(preRollAd); player.addMediaItem(contentStart); player.addMediaItem(midRollAd); player.addMediaItem(contentEnd);
Serverseitige Anzeigenbereitstellung
Bei der serverseitigen Anzeigenbereitstellung (auch dynamische Anzeigenbereitstellung genannt) enthält der Mediastream sowohl Anzeigen als auch Inhalte. Ein DASH-Manifest kann sowohl auf Content als auch auf Anzeigensegmente verweisen, möglicherweise in unterschiedlichen Zeiträumen. Informationen zu HLS finden Sie in der Apple-Dokumentation unter Anzeigen in Playlists einbinden.
Wenn Sie die serverseitige Anzeigenbereitstellung verwenden, muss der Client die Medien-URL möglicherweise dynamisch auflösen, um den kombinierten Stream zu erhalten. Außerdem müssen auf der Benutzeroberfläche Anzeigen-Overlays eingeblendet oder Ereignisse an ein Anzeigen-SDK oder einen Ad-Server gesendet werden.
Der DefaultMediaSourceFactory
von ExoPlayer kann alle diese Aufgaben an eine serverseitige MediaSource
für die Anzeigenbereitstellung für URIs delegieren, die das Schema ssai://
verwendet:
Kotlin
val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setServerSideAdInsertionMediaSourceFactory(ssaiFactory) ) .build()
Java
Player player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context) .setServerSideAdInsertionMediaSourceFactory(ssaiFactory)) .build();
ExoPlayer-IMA-Bibliothek
Die ExoPlayer IMA-Bibliothek enthält ImaServerSideAdInsertionMediaSource
. Damit können Sie die serverseitig eingefügten Datenstreams von IMA in Ihre App einbinden. Sie umfasst die Funktionen des IMA DAI SDKs für Android und integriert die bereitgestellten Anzeigenmetadaten vollständig in den Player. So können Sie beispielsweise Methoden wie Player.isPlayingAd()
verwenden, Übergänge bei Contentanzeigen erfassen und dem Player die Anzeigenwiedergabelogik wie das Überspringen bereits wiedergegebener Anzeigen überlassen.
Damit Sie diese Klasse verwenden können, müssen Sie ImaServerSideAdInsertionMediaSource.AdsLoader
und ImaServerSideAdInsertionMediaSource.Factory
einrichten und mit dem Player verbinden:
Kotlin
// MediaSource.Factory to load the actual media stream. val defaultMediaSourceFactory = DefaultMediaSourceFactory(context) // AdsLoader that can be reused for multiple playbacks. val adsLoader = ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, adViewProvider).build() // MediaSource.Factory to create the ad sources for the current player. val adsMediaSourceFactory = ImaServerSideAdInsertionMediaSource.Factory(adsLoader, defaultMediaSourceFactory) // Configure DefaultMediaSourceFactory to create both IMA DAI sources and // regular media sources. If you just play IMA DAI streams, you can also use // adsMediaSourceFactory directly. defaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory) // Set the MediaSource.Factory on the Player. val player = ExoPlayer.Builder(context).setMediaSourceFactory(defaultMediaSourceFactory).build() // Set the player on the AdsLoader adsLoader.setPlayer(player)
Java
// MediaSource.Factory to load the actual media stream. DefaultMediaSourceFactory defaultMediaSourceFactory = new DefaultMediaSourceFactory(context); // AdsLoader that can be reused for multiple playbacks. ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader = new ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, adViewProvider).build(); // MediaSource.Factory to create the ad sources for the current player. ImaServerSideAdInsertionMediaSource.Factory adsMediaSourceFactory = new ImaServerSideAdInsertionMediaSource.Factory(adsLoader, defaultMediaSourceFactory); // Configure DefaultMediaSourceFactory to create both IMA DAI sources and // regular media sources. If you just play IMA DAI streams, you can also use // adsMediaSourceFactory directly. defaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory); // Set the MediaSource.Factory on the Player. Player player = new ExoPlayer.Builder(context).setMediaSourceFactory(defaultMediaSourceFactory).build(); // Set the player on the AdsLoader adsLoader.setPlayer(player);
Laden Sie den IMA-Asset-Schlüssel oder die ID der Contentquelle und die Video-ID, indem Sie eine URL mit ImaServerSideAdInsertionUriBuilder
erstellen:
Kotlin
val ssaiUri = ImaServerSideAdInsertionUriBuilder() .setAssetKey(assetKey) .setFormat(C.CONTENT_TYPE_HLS) .build() player.setMediaItem(MediaItem.fromUri(ssaiUri))
Java
Uri ssaiUri = new ImaServerSideAdInsertionUriBuilder() .setAssetKey(assetKey) .setFormat(C.CONTENT_TYPE_HLS) .build(); player.setMediaItem(MediaItem.fromUri(ssaiUri));
Lassen Sie das Ladeprogramm für Anzeigen los, sobald es nicht mehr verwendet wird:
Kotlin
adsLoader.release()
Java
adsLoader.release();
Hinweise zur Benutzeroberfläche
Für die serverseitige Anzeigenbereitstellung gelten die gleichen Überlegungen zur Benutzeroberfläche wie bei der clientseitigen Anzeigenbereitstellung.
Companion-Anzeigen
Einige Anzeigen-Tags enthalten zusätzliche Companion-Anzeigen, die in Anzeigenflächen einer App-Benutzeroberfläche angezeigt werden können. Diese Slots können über ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots)
übergeben werden.
Weitere Informationen finden Sie unter Companion-Anzeigen hinzufügen.
Anzeigen-SDK eines Drittanbieters verwenden
Wenn Sie Anzeigen mit dem SDK eines Drittanbieters laden müssen, sollten Sie prüfen, ob es bereits eine ExoPlayer-Integration bietet. Falls nicht, empfiehlt es sich, einen benutzerdefinierten MediaSource
anzugeben, der URIs mit dem ssai://
-Schema akzeptiert, das ImaServerSideAdInsertionMediaSource
ähnelt.
Die eigentliche Logik beim Erstellen der Anzeigenstruktur kann an die allgemeine ServerSideAdInsertionMediaSource
delegiert werden, die einen Stream-MediaSource
umschließt und es dem Nutzer ermöglicht, die AdPlaybackState
für die Anzeigenmetadaten festzulegen und zu aktualisieren.
Serverseitig eingefügte Datenstreams enthalten oft zeitlich festgelegte Ereignisse, um den Player über Anzeigenmetadaten zu informieren. Informationen dazu, welche Formate für zeitgesteuerte Metadaten von ExoPlayer unterstützt werden, findest du unter Unterstützte Formate. Bei Implementierungen des benutzerdefinierten Anzeigen-SDKs MediaSource
können Sie mithilfe von Player.Listener.onMetadata
auf zeitgesteuerte Metadatenereignisse vom Player warten.