Anzeigenbereitstellung

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

Clientseitiges Einfügen von Anzeigen

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

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

  • Der Player kann Metadaten und Funktionen im Zusammenhang mit Anzeigen über seine API bereitstellen.
  • 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 einen konsistenten Zwischenspeicher für Übergänge zwischen Anzeigen und Inhalten beibehalten.

In dieser Konfiguration übernimmt der Player das Wechseln zwischen Anzeigen und Inhalten. Das bedeutet, dass Apps nicht mehrere separate Hintergrund- und Vordergrundplayer für Anzeigen und Inhalte steuern müssen.

Wenn Sie Contentvideos und Anzeigen-Tags für die clientseitige Anzeigenbereitstellung vorbereiten, sollten Anzeigen idealerweise an Synchronisations-Samples (Keyframes) im Contentvideo positioniert werden, damit der Player die Wiedergabe des Contents nahtlos fortsetzen kann.

Unterstützung für deklarative 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 Mediendateien unterstützt, die Anzeigen-Tags angeben, musst du beim Erstellen des Players einen DefaultMediaSourceFactory erstellen und einfügen, der mit einem AdsLoader.Provider und einem AdViewProvider konfiguriert ist:

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 Content-MediaSource von DefaultMediaSourceFactory in eine AdsMediaSource eingebunden. Der AdsMediaSource ruft einen AdsLoader vom AdsLoader.Provider ab und verwendet ihn, um Anzeigen gemäß dem Anzeigen-Tag der Mediendatei einzufügen.

PlayerView von ExoPlayer implementiert AdViewProvider. Die ExoPlayer-IMA-Bibliothek bietet eine AdsLoader, wie später beschrieben.

Playlists mit Werbung

Wenn eine Playlist mit mehreren Mediendateien 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 für jede Mediendatei mit Anzeigen, die eine eindeutige Medien-ID oder einen eindeutigen Content-URI hat, Anzeigen präsentiert werden, auch wenn die Anzeigen-Tag-URIs übereinstimmen. Wenn eine Mediendatei wiederholt wird, sieht der Nutzer die entsprechenden Anzeigen nur einmal. Der Wiedergabestatus der Anzeige speichert, ob Anzeigen abgespielt wurden, sodass sie nach dem ersten Auftreten übersprungen werden.

Dieses Verhalten kann angepasst werden, indem eine intransparente Anzeigen-ID übergeben wird, mit der der Wiedergabestatus der Anzeige für eine bestimmte Mediendatei verknüpft ist, basierend auf der Objektgleichheit. Hier ist ein Beispiel, bei dem der Wiedergabestatus der Anzeige nur mit dem Anzeigen-Tag-URI verknüpft ist, anstatt 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 beim zweiten Element 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);

Servergesteuerte clientseitige Anzeigenbereitstellung

ExoPlayer enthält HlsInterstitialsAdsLoader, das die automatische clientseitige Einfügung von Anzeigen unterstützt, die in der HLS-Playlist definiert sind. Weitere Informationen finden Sie im Abschnitt zu HlsInterstitialsAdsLoader auf der HLS-Seite.

ExoPlayer IMA-Bibliothek

Die ExoPlayer IMA-Bibliothek bietet ImaAdsLoader, um die clientseitige Anzeigenbereitstellung in Ihre App einzubinden. 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 Handhabung der Hintergrundwiedergabe und der Fortsetzung der Wiedergabe, findest du in der README-Datei.

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

Überlegungen zur Benutzeroberfläche

PlayerView blendet die Steuerelemente für die Wiedergabe 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 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 durch von der Anwendung bereitgestellte Ansichten verdeckt werden, die ü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 weggelassen werden können. Wenn Sie PlayerView als AdViewProvider verwenden, werden die Steuerungsoverlays automatisch registriert. Apps, die eine benutzerdefinierte Player-UI 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 „Flächen“ in der Benutzeroberfläche einer App ausgeliefert werden können. Diese Slots können mit ImaAdsLoader.Builder.setCompanionAdSlots(slots) übergeben werden. Weitere Informationen finden Sie unter Companion-Anzeigen hinzufügen.

Eigenständige Anzeigen

Das IMA SDK ist für das Einfügen von Anzeigen in Medieninhalte konzipiert, 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 die Verwendung des Google Mobile Ads SDK.

Anzeigen-SDK eines Drittanbieters verwenden

Wenn du Anzeigen mit einem Anzeigen-SDK eines Drittanbieters laden musst, solltest du prüfen, ob es bereits eine ExoPlayer-Integration bietet. Andernfalls wird empfohlen, einen benutzerdefinierten AdsLoader zu implementieren, der das Anzeigen-SDK des Drittanbieters 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 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(
      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 als dynamische Anzeigenbereitstellung bezeichnet) enthält der Mediastream 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 Medien-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 melden.

Der DefaultMediaSourceFactory von ExoPlayer kann alle diese Aufgaben an einen serverseitigen MediaSource für Anzeigenbereitstellung 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, um serverseitig eingefügte Anzeigenstreams von IMA in Ihre App einzubinden. Sie umschließt die Funktionen des IMA DAI SDK für Android und bindet die bereitgestellten Anzeigenmetadaten vollständig in den Player ein. So können Sie beispielsweise Methoden wie Player.isPlayingAd() verwenden, Übergänge zwischen Inhalten und Anzeigen abhören und die Logik für die Anzeigenwiedergabe, z. B. das Überspringen bereits wiedergegebener Anzeigen, dem Player überlassen.

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

Laden Sie Ihren IMA-Asset-Schlüssel oder Ihre Contentquellen-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 schließlich den Anzeigen-Loader frei, wenn er nicht mehr verwendet wird:

Kotlin

adsLoader.release()

Java

adsLoader.release();

Überlegungen zur Benutzeroberfläche

Für die serverseitige Anzeigenbereitstellung gelten dieselben Überlegungen zur Benutzeroberfläche wie für die clientseitige Anzeigenbereitstellung.

Companion-Anzeigen

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

Anzeigen-SDK eines Drittanbieters verwenden

Wenn du Anzeigen mit einem Anzeigen-SDK eines Drittanbieters laden musst, solltest du prüfen, ob es bereits eine ExoPlayer-Integration bietet. Andernfalls wird empfohlen, einen benutzerdefinierten MediaSource bereitzustellen, der URIs mit dem ssai://-Schema ähnlich wie ImaServerSideAdInsertionMediaSource akzeptiert.

Die eigentliche Logik zum Erstellen der Anzeigenstruktur kann an den allgemeinen 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.

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-MediaSource-Implementierungen können mit Player.Listener.onMetadata auf zeitgesteuerte Metadatenereignisse vom Player warten.