Wstawianie reklam

ExoPlayer może być używany zarówno do wstawiania reklam po stronie klienta, jak i po stronie serwera.

Wstawianie reklam po stronie klienta

W przypadku wstawiania reklam po stronie klienta odtwarzacz przełącza się między wczytywaniem multimediów z różnych adresów URL podczas przechodzenia od treści do reklam i z powrotem. Informacje o reklamach są ładowane oddzielnie od multimediów, np. z tagu reklamy XML VAST lub VMAP. Może to obejmować pozycje sygnałów reklamowych w stosunku do początku treści, rzeczywiste identyfikatory URI multimediów reklamy oraz metadane, takie jak informacja o tym, czy dana reklama jest możliwa do pominięcia.

Jeśli do wstawiania reklam po stronie klienta używasz komponentu AdsMediaSource ExoPlayera, odtwarzacz ma informacje o reklamach, które chce odtworzyć. Ma to kilka zalet:

  • Odtwarzacz może ujawnić metadane i funkcje związane z reklamami za pomocą swojego interfejsu API.
  • Komponenty interfejsu ExoPlayera mogą automatycznie wyświetlać znaczniki pozycji reklamy i zmieniać swoje zachowanie w zależności od tego, czy reklama jest odtwarzana.
  • Odtwarzacz może utrzymywać stały bufor podczas przechodzenia między reklamami a treścią.

W takim przypadku odtwarzacz zajmuje się przełączaniem między reklamami a treściami, co oznacza, że aplikacje nie muszą kontrolować wielu odrębnych odtwarzaczy reklam i treści w tle lub na pierwszym planie.

Przygotowując filmy z treściami i tagi reklam do użycia z wstawianiem reklam po stronie klienta, reklamy powinny być umieszczone w punktach synchronizacji (kluczowych klatkach) w filmie z treściami, aby odtwarzacz mógł płynnie wznowić odtwarzanie treści.

Deklaracyjne wsparcie reklam

Identyfikator URI tagu reklamy można określić podczas tworzenia MediaItem:

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

Aby umożliwić obsługę odtwarzacza w przypadku elementów multimedialnych, które określają tagi reklam, podczas tworzenia odtwarzacza musisz skonfigurować i wstrzyknąć DefaultMediaSourceFactory z AdsLoader.Provider i AdViewProvider:

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

Wewnętrznie DefaultMediaSourceFactory owija źródło multimediów treści w element AdsMediaSource. AdsMediaSource pobiera AdsLoader z AdsLoader.Provider i używa go do wstawiania reklam zgodnie z tagiem reklamy elementu multimedialnego.

PlayerView w ExoPlayer implementuje AdViewProvider. Biblioteka ExoPlayer IMA udostępnia łatwy w użyciu AdsLoader, jak opisano poniżej.

Playlisty z reklamami

Podczas odtwarzania playlisty zawierającej wiele elementów multimedialnych domyślnie wysyłane jest żądanie tagu reklamy i stan odtwarzania reklamy jest przechowywany raz dla każdej kombinacji identyfikatora multimediów, identyfikatora URI treści i identyfikatora URI tagu reklamy. Oznacza to, że użytkownicy będą widzieć reklamy dla każdego elementu multimedialnego z reklamami, który ma odrębny identyfikator multimediów lub adres URI treści, nawet jeśli adresy URI tagów reklamy są takie same. Jeśli element multimediów jest powtarzany, użytkownik zobaczy odpowiednie reklamy tylko raz (stan odtwarzania reklam przechowuje informacje o tym, czy reklamy zostały odtworzone, więc są one pomijane po pierwszym wystąpieniu).

To zachowanie można dostosować, przekazując nieprzezroczysty identyfikator reklamy, z którym stan odtwarzania reklamy dla danego elementu multimedialnego jest powiązany na podstawie równości obiektów. Oto przykład, w którym stan odtwarzania reklamy jest powiązany tylko z identyfikatorem URI tagu reklamy, a nie kombinacją identyfikatora multimediów i identyfikatora URI tagu reklamy. W tym celu jako identyfikator reklamy przekazywano identyfikator URI tagu reklamy. Efektem jest to, że reklamy wczytują się tylko raz i użytkownik nie widzi reklam w drugim elemencie podczas odtwarzania playlisty.

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

Biblioteka ExoPlayer IMA

Biblioteka IMA ExoPlayera zapewnia ImaAdsLoader, co ułatwia integrację wstawiania reklam po stronie klienta w aplikacji. Opisuje ona funkcjonalność pakietu IMA SDK po stronie klienta, aby obsługiwać wstawianie reklam VAST/VMAP. Instrukcje dotyczące korzystania z biblioteki, w tym informacje o odtwarzaniu w tle i wznawianiu odtwarzania, znajdziesz w README.

Aplikacja demonstracyjna korzysta z biblioteki IMA i zawiera na liście przykładów kilka przykładowych tagów reklam VAST/VMAP.

Interfejs użytkownika

PlayerView domyślnie ukrywa elementy sterujące transportem podczas odtwarzania reklam, ale aplikacje mogą zmienić to zachowanie, wywołując metodę setControllerHideDuringAds. Podczas wyświetlania reklamy pakiet IMA SDK będzie wyświetlać dodatkowe widoki u góry odtwarzacza (np. link „Więcej informacji” i przycisk pominięcia, jeśli to możliwe).

Pakiet IMA SDK może zgłaszać, czy reklamy są zasłonięte przez widoki aplikacji renderowane na górze odtwarzacza. Aplikacje, które wymagają nakładania widoków niezbędnych do kontrolowania odtwarzania, muszą zarejestrować je w pakiecie IMA SDK, aby można je było pominąć w obliczeniach widoczności. Gdy używasz PlayerView jako AdViewProvider, automatycznie rejestruje on nakładki sterowania. Aplikacje, które korzystają z niestandardowego interfejsu odtwarzacza, muszą rejestrować widoki nakładki, zwracając je z funkcji AdViewProvider.getAdOverlayInfos.

Więcej informacji o widokach nakładki znajdziesz w artykule Open Measurement w pakiecie IMA SDK.

Reklamy towarzyszące

Niektóre tagi reklam zawierają dodatkowe reklamy towarzyszące, które mogą się wyświetlać w „miejscach” w interfejsie aplikacji. Te przedziały można przekazać za pomocą funkcji ImaAdsLoader.Builder.setCompanionAdSlots(slots). Więcej informacji znajdziesz w artykule Dodawanie reklam towarzyszących.

Reklamy samodzielne

Pakiet IMA SDK jest przeznaczony do wstawiania reklam do treści multimedialnych, a nie do odtwarzania samodzielnych reklam. Biblioteka IMA nie obsługuje odtwarzania reklam samodzielnych. W tym przypadku zalecamy użycie pakietu SDK do reklam mobilnych Google.

Korzystanie z pakietu SDK do wyświetlania reklam innej firmy

Jeśli chcesz wczytywać reklamy za pomocą pakietu SDK do wyświetlania reklam innej firmy, sprawdź, czy zapewnia on już integrację z narzędziem ExoPlayer. Jeśli nie, zalecamy wdrożenie niestandardowego pakietu AdsLoader, który otacza zewnętrzny pakiet SDK reklam, ponieważ zapewnia to korzyści z użycia AdsMediaSource opisanego powyżej. ImaAdsLoader jest przykładową implementacją.

Możesz też użyć obsługi playlisty w ExoPlayerze, aby utworzyć sekwencję reklam i fragmentów treści:

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

Wstawianie reklam po stronie serwera

W przypadku wstawiania reklam po stronie serwera (nazywanego też dynamicznym wstawianiem reklam lub DAI) strumień multimediów zawiera zarówno reklamy, jak i treści. Plik manifestu DASH może wskazywać zarówno treści, jak i segmenty reklam, potencjalnie w osobnych przedziałach czasu. W przypadku HLS zapoznaj się z dokumentacją Apple dotyczącą włączania reklam do playlisty.

Gdy korzystasz z wstawiania reklam po stronie serwera i chcesz dynamicznie uzyskiwać adres URL multimediów, aby uzyskać połączony strumień, klient może potrzebować wyświetlania nakładek na reklamy w interfejsie lub zgłaszania zdarzeń do pakietu SDK do wyświetlania reklam lub serwera reklam.

Element DefaultMediaSourceFactory ExoPlayer może przekazać wszystkie te zadania do wstawiania reklam po stronie serwera MediaSource dla identyfikatorów URI przy użyciu schematu ssai://:

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

Biblioteka ExoPlayer IMA

Biblioteka IMA ExoPlayer zapewnia ImaServerSideAdInsertionMediaSource, co ułatwia integrację z reklamami wstawianymi po stronie serwera IMA w Twojej aplikacji. Zawiera ona funkcjonalność interfejsu IMA DAI SDK na Androida i pełną integrację dostarczonych metadanych reklam z odtwarzaczem. Dzięki temu możesz na przykład używać metod takich jak Player.isPlayingAd(), wykrywać przejścia między treściami a reklamami oraz pozwolić odtwarzaczowi obsługiwać logikę odtwarzania reklam, np. pomijanie już odtworzonych reklam.

Aby korzystać z tej klasy, musisz skonfigurować ImaServerSideAdInsertionMediaSource.AdsLoaderImaServerSideAdInsertionMediaSource.Factory oraz połączyć je z odtwarzaczem:

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

Załaduj klucz zasobu IMA lub identyfikator źródła treści i identyfikator filmu, tworząc adres URL z: ImaServerSideAdInsertionUriBuilder:

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

Na koniec zwolnij ładowarkę reklam, gdy nie jest już używana:

Kotlin

adsLoader.release()

Java

adsLoader.release();

Uwagi na temat interfejsu

W przypadku wstawiania reklam po stronie serwera obowiązują te same zasady dotyczące interfejsu użytkownika.

Reklamy towarzyszące

Niektóre tagi reklam zawierają dodatkowe reklamy towarzyszące, które mogą być wyświetlane w „boksach” w interfejsie aplikacji. Te przedziały można przekazać za pomocą funkcji ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots). Więcej informacji znajdziesz w artykule Dodawanie reklam towarzyszących.

Korzystanie z zewnętrznego pakietu SDK reklam

Jeśli musisz wczytywać reklamy za pomocą pakietu SDK reklam innej firmy, sprawdź, czy zawiera on już integrację z ExoPlayerem. Jeśli nie, zalecamy podanie niestandardowego adresu MediaSource, który akceptuje identyfikatory URI o schemacie ssai:// podobnym do ImaServerSideAdInsertionMediaSource.

Rzeczywista logika tworzenia struktury reklamy może zostać powierzona ogólnemu elementowi ServerSideAdInsertionMediaSource, który otacza strumień MediaSource i umożliwia użytkownikowi ustawianie i aktualizowanie wartości AdPlaybackState reprezentujących metadane reklamy.

Strumienie reklam wstawiane po stronie serwera często zawierają zdarzenia czasowe, które informują odtwarzacz o metadanych reklamy. Informacje o tym, jakie formaty metadanych synchronizowanych obsługuje ExoPlayer, znajdziesz w sekcji Obsługiwane formaty. Implementacje pakietu SDK do wyświetlania reklam niestandardowych MediaSource mogą nasłuchiwać zdarzeń metadanych z czasem pochodzących z odtwarzacza za pomocą interfejsu Player.Listener.onMetadata.