Anzeigenbereitstellung

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.