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 Übergang zwischen der Wiedergabe von Inhalten und Anzeigen zwischen dem Laden von Medien aus verschiedenen URLs. Informationen zu Anzeigen werden getrennt von den Medien geladen, z. B. aus einem XML-Anzeigen-Tag vom Typ VAST oder VMAP. Dazu gehören die Positionen der Anzeigen-Cues relativ zum Beginn des Inhalts, die tatsächlichen URIs der Anzeigenmedien und Metadaten wie etwa, ob eine bestimmte Anzeige überspringbar ist.

Wenn du die AdsMediaSource von ExoPlayer für die clientseitige Anzeigenbereitstellung verwendest, hat der Player Informationen zu den wiederzugebenden Anzeigen. Das hat mehrere Vorteile:

  • Der Player kann über seine API Metadaten und Funktionen im Zusammenhang mit Anzeigen freigeben.
  • ExoPlayer-UI-Komponenten können Markierungen für Anzeigenpositionen automatisch anzeigen und ihr Verhalten ändern, je nachdem, ob eine Anzeige wiedergegeben wird.
  • Intern kann der Player bei Übergängen zwischen Anzeigen und Inhalten einen konstanten Puffer beibehalten.

Bei dieser Konfiguration kümmert sich der Player um den Wechsel zwischen Anzeigen und Inhalten. Das bedeutet, dass Apps nicht mehrere separate Player für Hintergrund-/Vordergrundanzeigen und Inhalte steuern müssen.

Wenn du Videoinhalte und Anzeigen-Tags für die clientseitige Anzeigenbereitstellung vorbereitest, sollten Anzeigen idealerweise an Synchronisierungsproben (Keyframes) im Videoinhalt platziert werden, damit die Wiedergabe des Inhalts nahtlos fortgesetzt werden kann.

Unterstützung für deklarative Anzeigen

Ein Anzeigen-Tag-URI kann beim Erstellen eines MediaItem 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();

Wenn du die Player-Unterstützung für Medienelemente mit Anzeigen-Tags aktivieren möchtest, musst du beim Erstellen des Players ein DefaultMediaSourceFactory mit einem AdsLoader.Provider und einem AdViewProvider erstellen und einfügen:

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 umschließt DefaultMediaSourceFactory die Content-Medienquelle in einem AdsMediaSource. Die AdsMediaSource ruft eine AdsLoader von der AdsLoader.Provider ab und verwendet sie, um Anzeigen einzufügen, wie im Anzeigen-Tag des Medienelements definiert.

PlayerView von ExoPlayer implementiert AdViewProvider. Die ExoPlayer IMA-Bibliothek bietet eine nutzerfreundliche AdsLoader, wie unten beschrieben.

Playlists mit Werbung

Wenn eine Playlist mit mehreren Medienelementen wiedergegeben wird, wird standardmäßig das Anzeigen-Tag angefordert und der Wiedergabestatus der Anzeige einmal für jede Kombination aus Medien-ID, Inhalts-URI und Anzeigen-Tag-URI gespeichert. Das bedeutet, dass Nutzern Anzeigen für jedes Medienelement mit Anzeigen mit einer eindeutigen Medien-ID oder einem eindeutigen Inhalts-URI präsentiert werden, auch wenn die URIs der Anzeigen-Tags übereinstimmen. Wenn ein Medienelement wiederholt wird, sieht der Nutzer die entsprechenden Anzeigen nur einmal. Im Wiedergabestatus der Anzeigen wird gespeichert, ob Anzeigen bereits wiedergegeben wurden. Sie werden also nach dem ersten Vorkommen übersprungen.

Du kannst dieses Verhalten anpassen, indem du eine opake Anzeigen-ID übergibst, die mit dem Wiedergabestatus der Anzeige für ein bestimmtes Medienelement verknüpft ist, basierend auf der Objektgleichheit. Hier ein Beispiel, in dem der Wiedergabestatus der Anzeige nur mit dem Anzeigen-Tag-URI verknüpft ist, nicht mit der Kombination aus Medien-ID und Anzeigen-Tag-URI. Dazu wird der Anzeigen-Tag-URI als Anzeigen-ID übergeben. Das hat zur Folge, dass Anzeigen nur einmal geladen werden und der Nutzer beim Abspielen der Playlist von Anfang bis Ende keine Anzeigen für den zweiten Titel sieht.

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);

Servergestützte clientseitige Anzeigenbereitstellung

ExoPlayer enthält HlsInterstitialsAdsLoader, das Anzeigen unterstützt, die in der HLS-Playlist definiert sind und automatisch auf der Clientseite eingefügt werden. Weitere Informationen findest du im Abschnitt zu HlsInterstitialsAdsLoader auf der HLS-Seite.

ExoPlayer IMA-Bibliothek

Die ExoPlayer IMA-Bibliothek bietet ImaAdsLoader, wodurch die clientseitige Anzeigenbereitstellung in Ihre App ganz einfach eingebunden werden kann. Sie umschließt die Funktionen des clientseitigen IMA SDK, um die Einbindung von VAST-/VMAP-Anzeigen zu unterstützen. Eine Anleitung zur Verwendung der Bibliothek, einschließlich der Wiedergabe im Hintergrund und der Wiederaufnahme der Wiedergabe, findest du in der README-Datei.

Die Demoanwendung verwendet die IMA-Bibliothek und enthält mehrere Beispiel-VAST-/VMAP-Anzeigen-Tags in der Beispielliste.

Hinweise zur Benutzeroberfläche

PlayerView blendet seine Transportsteuerungen während der Wiedergabe von Anzeigen standardmäßig aus. Apps können dieses Verhalten jedoch durch Aufrufen von setControllerHideDuringAds umschalten. Das IMA SDK zeigt während der Wiedergabe einer Anzeige zusätzliche Ansichten über dem Player an, z. B. einen Link „Weitere Informationen“ und gegebenenfalls eine Schaltfläche zum Überspringen.

Das IMA SDK kann melden, ob Anzeigen von vom App-Anbieter bereitgestellten Ansichten verdeckt werden, die über dem Player gerendert werden. In Apps, in denen Ansichten eingeblendet werden müssen, die für die Wiedergabesteuerung unerlässlich sind, müssen diese Ansichten im IMA SDK registriert werden, damit sie bei der Sichtbarkeitsberechnung nicht berücksichtigt werden. Wenn Sie PlayerView als AdViewProvider verwenden, werden die Steuerelement-Overlays automatisch registriert. Apps, die eine benutzerdefinierte Player-Benutzeroberfläche verwenden, müssen Overlay-Ansichten registrieren, indem sie sie von AdViewProvider.getAdOverlayInfos zurückgeben.

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 „Slots“ in der App-Benutzeroberfläche ausgeliefert werden können. Diese Slots können über ImaAdsLoader.Builder.setCompanionAdSlots(slots) übergeben werden. Weitere Informationen finden Sie unter Komplementaranzeigen hinzufügen.

Eigenständige Anzeigen

Das IMA SDK ist zum Einfügen von Anzeigen in Mediacontent gedacht, nicht zum eigenständigen Abspielen von Anzeigen. Daher wird die Wiedergabe von eigenständigen 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 ein Anzeigen-SDK eines Drittanbieters laden müssen, sollten Sie prüfen, ob es bereits eine ExoPlayer-Integration bietet. Andernfalls wird empfohlen, eine benutzerdefinierte AdsLoader zu implementieren, die das SDK für Drittanbieteranzeigen umschließt. Sie bietet die oben beschriebenen Vorteile von AdsMediaSource. ImaAdsLoader dient als Beispielimplementierung.

Alternativ kannst du die Playlist-Unterstützung von ExoPlayer verwenden, um eine Abfolge 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, DAI) enthält der Mediastream sowohl Anzeigen als auch Inhalte. Ein DASH-Manifest kann sowohl auf Inhalts- als auch auf Anzeigensegmente verweisen, möglicherweise in separaten Zeiträumen. Informationen zu HLS findest du in der Apple-Dokumentation zum Einfügen von Anzeigen in eine Playlist.

Bei der serverseitigen Anzeigenbereitstellung muss der Client möglicherweise die Medien-URL dynamisch auflösen, um den zusammengefügten Stream abzurufen. Außerdem muss er möglicherweise Anzeigen-Overlays in der Benutzeroberfläche anzeigen oder Ereignisse an ein Anzeigen-SDK oder einen Anzeigenserver melden.

Die DefaultMediaSourceFactory von ExoPlayer kann alle diese Aufgaben an eine serverseitige Anzeigenbereitstellung MediaSource für URIs mit dem ssai://-Schema delegieren:

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 bietet ImaServerSideAdInsertionMediaSource, sodass sich die serverseitig eingefügten Anzeigenstreams von IMA ganz einfach in deine App einbinden lassen. Sie umschließt die Funktionen des IMA DAI SDK für Android und integriert die bereitgestellten Anzeigenmetadaten vollständig in den Player. So kannst du beispielsweise Methoden wie Player.isPlayingAd() verwenden, Übergänge zwischen Inhalten und Anzeigen überwachen und den Player die Logik für die Anzeigenwiedergabe steuern lassen, z. B. das Überspringen bereits wiedergegebener Anzeigen.

Wenn du diese Klasse verwenden möchtest, musst du 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);

Lade deinen IMA-Asset-Schlüssel oder die Content-Quell-ID und die Video-ID, indem du eine URL mit ImaServerSideAdInsertionUriBuilder erstellst:

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));

Entfernen Sie den Anzeigen-Lademechanismus, sobald er nicht mehr verwendet wird:

Kotlin

adsLoader.release()

Java

adsLoader.release();

Hinweise zur Benutzeroberfläche

Für die serverseitige Anzeigenbereitstellung gelten dieselben Überlegungen zur Benutzeroberfläche wie bei der clientseitigen Anzeigenbereitstellung.

Companion-Anzeigen

Einige Anzeigen-Tags enthalten zusätzliche Companion-Anzeigen, die in „Slots“ in der App-Benutzeroberfläche ausgeliefert werden können. Diese Slots können über ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots) übergeben werden. Weitere Informationen finden Sie unter Komplementaranzeigen hinzufügen.

Anzeigen-SDK eines Drittanbieters verwenden

Wenn du Anzeigen über ein Anzeigen-SDK eines Drittanbieters laden musst, solltest du prüfen, ob es bereits eine ExoPlayer-Integration bietet. Andernfalls sollten Sie eine benutzerdefinierte MediaSource angeben, die URIs mit dem ssai://-Schema akzeptiert, ähnlich wie ImaServerSideAdInsertionMediaSource.

Die eigentliche Logik zum Erstellen der Anzeigenstruktur kann an den allgemeinen Zweck ServerSideAdInsertionMediaSource delegiert werden, der einen Stream MediaSource umschließt und es dem Nutzer ermöglicht, die AdPlaybackState festzulegen und zu aktualisieren, die die Anzeigenmetadaten darstellen.

Serverseitig eingefügte Anzeigenstreams enthalten häufig zeitgesteuerte Ereignisse, um den Player über Anzeigenmetadaten zu informieren. Informationen zu den von ExoPlayer unterstützten Zeitmetadatenformaten findest du unter Unterstützte Formate. Bei MediaSource-Implementierungen des Custom Ads SDK kann mit Player.Listener.onMetadata auf zeitgesteuerte Metadatenereignisse vom Player gewartet werden.