Anzeigenbereitstellung

ExoPlayer kann sowohl für die clientseitige als auch für die serverseitige Anzeigenbereitstellung verwendet werden.

Clientseitige Anzeigenbereitstellung

Bei der clientseitigen dynamischen Anzeigenbereitstellung wechselt der Player zwischen dem Laden von Media von verschiedenen URLs, wenn er zwischen der Wiedergabe von Content und Anzeigen wechselt. Informationen zu Anzeigen werden separat von den Media geladen, z. B. über ein XML-VAST- oder VMAP-Anzeigen-Tag. Dazu gehören unter anderem die Positionen der Anzeigen-Cues relativ zum Beginn des Inhalts, die tatsächlichen Media-URIs der Anzeigen und Metadaten wie die Information, ob eine bestimmte Anzeige übersprungen werden kann.

Wenn Sie AdsMediaSource von ExoPlayer für die clientseitige Anzeigenbereitstellung verwenden, hat der Player Informationen zu den Anzeigen, die wiedergegeben werden sollen. Das hat mehrere Vorteile:

  • Der Player kann über seine API Metadaten und Funktionen im Zusammenhang mit Anzeigen bereitstellen.
  • In ExoPlayer-UI-Komponenten können automatisch Markierungen für Anzeigenpositionen angezeigt werden. Das Verhalten der Komponenten ändert sich je nachdem, ob eine Anzeige wiedergegeben wird.
  • Intern kann der Player bei Übergängen zwischen Anzeigen und Inhalten einen konsistenten Puffer beibehalten.

Bei dieser Einrichtung kümmert sich der Player um das Umschalten zwischen Anzeigen und Inhalten. Apps müssen also nicht mehrere separate Hintergrund-/Vordergrundplayer für Anzeigen und Inhalte steuern.

Wenn Sie Contentvideos und Anzeigen-Tags für die clientseitige Anzeigenbereitstellung vorbereiten, sollten Anzeigen idealerweise an Synchronisationsbeispielen (Keyframes) im Contentvideo positioniert werden, damit der Player die Contentwiedergabe nahtlos fortsetzen 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();

Damit der Player Media-Elemente mit angegebenen Ad-Tags unterstützt, müssen Sie 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 wird die Media-Quelle für Inhalte von DefaultMediaSourceFactory in ein AdsMediaSource-Tag eingeschlossen. Der AdsMediaSource ruft ein AdsLoader vom AdsLoader.Provider ab und verwendet es, um Anzeigen gemäß dem Anzeigen-Tag des Media-Elements einzufügen.

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

Playlists mit Werbung

Wenn eine Playlist mit mehreren Media-Elementen wiedergegeben wird, wird das Anzeigen-Tag standardmäßig einmal für jede Kombination aus Media-ID, Content-URI und Anzeigen-Tag-URI angefordert und der Status der Anzeigenwiedergabe gespeichert. Das bedeutet, dass Nutzer Anzeigen für jedes Media-Element mit Anzeigen sehen, das eine eigene Media-ID oder einen eigenen Content-URI hat, auch wenn die Anzeigen-Tag-URIs übereinstimmen. Wenn ein Media-Element wiederholt wird, sieht der Nutzer die entsprechenden Anzeigen nur einmal. Im Wiedergabestatus der Anzeige wird gespeichert, ob Anzeigen bereits wiedergegeben wurden. Sie werden also nach dem ersten Auftreten übersprungen.

Sie können dieses Verhalten anpassen, indem Sie eine undurchsichtige Anzeigen-ID übergeben, mit der der Status der Anzeigenwiedergabe für ein bestimmtes Media-Element auf Grundlage der Objektgleichheit verknüpft wird. Hier ist ein Beispiel, in dem der Wiedergabestatus der Anzeige nur mit dem Anzeigen-Tag-URI verknüpft ist und nicht mit der Kombination aus Media-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 Nutzer beim Abspielen der Playlist von Anfang bis Ende keine Anzeigen auf dem zweiten Element sehen.

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, mit dem auf der Clientseite automatisch Anzeigen eingefügt werden können, die in der HLS-Playlist definiert sind. Weitere Informationen finden Sie im Abschnitt über HlsInterstitialsAdsLoader auf der HLS-Seite.

ExoPlayer IMA-Bibliothek

Die ExoPlayer IMA-Bibliothek bietet ImaAdsLoader, sodass Sie die clientseitige Anzeigenbereitstellung ganz einfach in Ihre App einbinden können. Sie umschließt die Funktionen des clientseitigen IMA SDK, um die Bereitstellung von VAST-/VMAP-Anzeigen zu unterstützen. Eine Anleitung zur Verwendung der Bibliothek, einschließlich der Behandlung von Hintergrund- und Fortsetzungsfunktionen, finden Sie in der README-Datei.

In der Demoanwendung wird die IMA-Bibliothek verwendet. Die Beispielliste enthält mehrere VAST-/VMAP-Anzeigen-Tags.

Überlegungen zur Benutzeroberfläche

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

Das IMA SDK kann melden, ob Anzeigen durch Ansichten verdeckt werden, die von der Anwendung bereitgestellt und über dem Player gerendert werden. Apps, die Ansichten überlagern müssen, die für die Steuerung der Wiedergabe unerlässlich sind, müssen diese beim IMA SDK registrieren, damit sie bei der Berechnung der Sichtbarkeit nicht berücksichtigt werden. Wenn Sie PlayerView als AdViewProvider verwenden, werden die zugehörigen Steuerungsoverlays automatisch registriert. Apps, die eine benutzerdefinierte Player-Benutzeroberfläche verwenden, müssen Overlay-Ansichten registrieren, indem sie sie über 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 einer App-Benutzeroberfläche ausgeliefert werden können. Diese Slots können über ImaAdsLoader.Builder.setCompanionAdSlots(slots) übergeben werden. Weitere Informationen zum Hinzufügen von Companion-Anzeigen

Eigenständige Anzeigen

Das IMA SDK ist für das Einfügen von Anzeigen in Mediacontent konzipiert, nicht für die Wiedergabe eigenständiger 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.

Verwendung eines Drittanbieter-SDK für Anzeigen

Wenn Sie Anzeigen über ein Drittanbieter-Anzeigen-SDK laden müssen, sollten Sie prüfen, ob es bereits eine ExoPlayer-Integration bietet. Andernfalls ist es empfehlenswert, eine benutzerdefinierte AdsLoader zu implementieren, die das Drittanbieter-SDK für Anzeigen umschließt, da dies die oben beschriebenen Vorteile von AdsMediaSource bietet. ImaAdsLoader dient als Beispielimplementierung.

Alternativ können Sie die Playlist-Unterstützung von ExoPlayer verwenden, um eine Sequenz aus 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(MediaItem.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(MediaItem.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 MediaItem.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 MediaItem.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 oder DAI genannt) enthält der Media-Stream sowohl Anzeigen als auch Inhalte. Ein DASH-Manifest kann sowohl auf Content- als auch auf Anzeigensegmente verweisen, möglicherweise in separaten Zeiträumen. Informationen zu HLS finden Sie in der Apple-Dokumentation zum Einbinden von Anzeigen in eine Playlist.

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

Mit DefaultMediaSourceFactory von ExoPlayer können alle diese Aufgaben an eine serverseitige Anzeigenbereitstellung MediaSource für URIs mit dem Schema ssai:// delegiert werden:

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 und ermöglicht so eine einfache Integration in die serverseitig eingefügten Anzeigenstreams von IMA in Ihrer App. Sie umschließt die Funktionen des IMA DAI SDK for Android und integriert die bereitgestellten Anzeigenmetadaten vollständig in den Player. So können Sie beispielsweise Methoden wie Player.isPlayingAd() verwenden, auf Übergänge zwischen Content und Anzeigen reagieren und dem Player die Logik für die Anzeigenwiedergabe überlassen, z. B. das Überspringen bereits wiedergegebener Anzeigen.

Wenn Sie diese Klasse verwenden möchten, 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 Ihren IMA-Asset-Schlüssel oder Ihre Content-Quell-ID und 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));

Geben Sie den Anzeigen-Loader schließlich frei, wenn er nicht mehr verwendet wird:

Kotlin

adsLoader.release()

Java

adsLoader.release();

Überlegungen zur Benutzeroberfläche

Dieselben Überlegungen zur Benutzeroberfläche wie bei der clientseitigen Anzeigenbereitstellung gelten auch für die serverseitige Anzeigenbereitstellung.

Companion-Anzeigen

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

Verwendung eines Drittanbieter-SDK für Anzeigen

Wenn Sie Anzeigen mit einem Anzeigen-SDK eines Drittanbieters laden müssen, sollten Sie prüfen, ob es bereits eine ExoPlayer-Integration bietet. Andernfalls empfiehlt es sich, einen benutzerdefinierten MediaSource anzugeben, der URIs mit dem Schema ssai:// akzeptiert, ähnlich wie ImaServerSideAdInsertionMediaSource.

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

Häufig enthalten serverseitig eingefügte Anzeigenstreams zeitgesteuerte Ereignisse, um den Player über Anzeigenmetadaten zu informieren. Informationen zu den von ExoPlayer unterstützten Formaten für zeitgesteuerte Metadaten finden Sie unter Unterstützte Formate. Benutzerdefinierte Anzeigen-SDK-Implementierungen können mit Player.Listener.onMetadata auf zeitgesteuerte Metadatenereignisse vom Player warten.MediaSource