O ExoPlayer pode ser usado para inserção de anúncios do lado do cliente e do servidor.
Inserção de anúncios do lado do cliente
Na inserção de anúncios do lado do cliente, o player alterna entre o carregamento de mídia de diferentes URLs durante a transição entre o conteúdo e os anúncios. As informações sobre anúncios são carregadas separadamente da mídia, como por uma tag de anúncio XML VAST ou VMAP. Isso pode incluir posições de indicação do anúncio relacionadas ao início do conteúdo, aos URIs e metadados reais da mídia do anúncio, por exemplo, se um determinado anúncio é pulável.
Ao usar o AdsMediaSource
do ExoPlayer para inserção de anúncios do lado do cliente, o player
tem informações sobre os anúncios que serão reproduzidos. Essa mudança gera vários benefícios:
- O player pode expor metadados e funcionalidades relacionadas aos anúncios usando a API.
- Os componentes da interface do ExoPlayer podem mostrar marcadores de posições de anúncio automaticamente e mudar o comportamento deles dependendo da reprodução do anúncio.
- Internamente, o player pode manter um buffer consistente nas transições entre anúncios e conteúdo.
Nessa configuração, o player é responsável por alternar entre anúncios e conteúdo, o que significa que os apps não precisam controlar vários players separados em segundo plano/primeiro plano para anúncios e conteúdo.
Ao preparar vídeos de conteúdo e tags de anúncio para uso com a inserção de anúncios do lado do cliente, os anúncios precisam ser posicionados em amostras de sincronização (frames-chave) no conteúdo em vídeo para que o player possa retomar a reprodução do conteúdo sem problemas.
Suporte a anúncios declarativos
Um URI da tag de anúncio pode ser especificado ao criar um 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();
Para ativar o suporte ao player para itens de mídia que especificam tags de anúncio, é necessário
criar e injetar um DefaultMediaSourceFactory
configurado com um
AdsLoader.Provider
e um AdViewProvider
ao criar o player:
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();
Internamente, DefaultMediaSourceFactory
vai envolver a fonte de mídia de conteúdo em um
AdsMediaSource
. O AdsMediaSource
recebe um AdsLoader
da
AdsLoader.Provider
e o usa para inserir anúncios conforme definido pela tag de anúncio do
item de mídia.
O PlayerView
do ExoPlayer implementa o AdViewProvider
. A biblioteca IMA
do ExoPlayer fornece um AdsLoader
fácil de usar, conforme descrito abaixo.
Playlists com anúncios
Ao reproduzir uma playlist com vários itens de mídia, o comportamento padrão é solicitar a tag de anúncio e armazenar o estado de reprodução do anúncio uma vez para cada ID de mídia, URI de conteúdo e combinação de URI da tag de anúncio. Isso significa que os usuários vão ver anúncios para cada item de mídia com anúncios que tenham um ID de mídia ou URI de conteúdo diferente, mesmo que os URIs da tag de anúncio sejam correspondentes. Se um item de mídia for repetido, o usuário verá os anúncios correspondentes apenas uma vez. O estado de reprodução do anúncio armazena se os anúncios foram reproduzidos, portanto, eles são ignorados após a primeira ocorrência.
É possível personalizar esse comportamento transmitindo um identificador de anúncios opaco ao qual o estado de reprodução do anúncio de determinado item de mídia está vinculado, com base na igualdade do objeto. Veja um exemplo em que o estado de reprodução do anúncio é vinculado somente ao URI da tag de anúncio, em vez da combinação do ID de mídia e do URI da tag de anúncio, transmitindo o URI da tag de anúncio como o identificador de anúncios. Assim, os anúncios serão carregados apenas uma vez e o usuário não verá anúncios no segundo item ao reproduzir a playlist do início ao fim.
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);
Biblioteca de IMA do ExoPlayer
A biblioteca do IMA do ExoPlayer fornece ImaAdsLoader
, facilitando
a integração da inserção de anúncios do lado do cliente no seu app. Ela envolve a funcionalidade do
SDK do IMA do lado do cliente para oferecer suporte à inserção de anúncios VAST/VMAP. Para
instruções sobre como usar a biblioteca, incluindo como processar o segundo plano
e retomar a reprodução, consulte o README (em inglês).
O aplicativo de demonstração usa a biblioteca do IMA e inclui várias amostras de tags de anúncio VAST/VMAP na lista de amostras.
Considerações sobre a interface
PlayerView
oculta os controles de transporte durante a reprodução de anúncios por
padrão, mas os apps podem alternar esse comportamento chamando
setControllerHideDuringAds
. O SDK do IMA vai mostrar mais visualizações na parte de cima do player durante a reprodução de um anúncio. Por exemplo, um link "Mais informações" e um botão "Pular", se aplicável.
O SDK do IMA pode informar se os anúncios são obscurecidos pelas visualizações fornecidas pelo aplicativo
renderizadas sobre o player. Os apps que precisam sobrepor visualizações
essenciais para controlar a reprodução precisam registrá-las no SDK do IMA para que
sejam omitidas dos cálculos de visibilidade. Ao usar PlayerView
como
AdViewProvider
, ele registra automaticamente as sobreposições de controle. Os apps
que usam uma interface de player personalizada precisam registrar visualizações de sobreposição retornando-as de
AdViewProvider.getAdOverlayInfos
.
Para mais informações sobre as visualizações de sobreposição, consulte Open Measurement no SDK do IMA.
Anúncios complementares
Algumas tags de anúncio contêm anúncios complementares que podem ser exibidos em "espaços" na interface do aplicativo. Esses slots podem ser transmitidos por
ImaAdsLoader.Builder.setCompanionAdSlots(slots)
. Para mais informações, consulte Adicionar anúncios complementares.
Anúncios autônomos
O SDK do IMA foi projetado para inserir anúncios em conteúdo de mídia, e não para reproduzir anúncios independentes por conta própria. Portanto, a reprodução de anúncios independentes não é compatível com a biblioteca do IMA. Recomendamos usar o SDK dos anúncios para dispositivos móveis do Google nesse caso de uso.
Uso de um SDK de anúncios de terceiros
Se você precisar carregar anúncios usando um SDK de anúncios de terceiros, verifique se
ele já fornece uma integração do ExoPlayer. Caso contrário, a implementação de um
AdsLoader
personalizado que envolva o SDK de anúncios de terceiros é a abordagem recomendada,
já que ela oferece os benefícios da AdsMediaSource
descritos acima.
ImaAdsLoader
atua como um exemplo de implementação.
Como alternativa, você pode usar o suporte a playlists do ExoPlayer para criar uma sequência de anúncios e clipes de conteúdo:
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);
Inserção de anúncios do lado do servidor
Na inserção de anúncios do lado do servidor (também chamada de inserção de anúncios dinâmicos ou DAI), o stream de mídia contém anúncios e conteúdo. Um manifesto DASH pode apontar para conteúdo e segmentos de anúncios, possivelmente em períodos separados. Para HLS, consulte a documentação da Apple sobre como incorporar anúncios a uma playlist.
Ao usar a inserção de anúncios do lado do servidor, o cliente pode precisar resolver o URL de mídia dinamicamente para receber o stream agrupado, pode ser necessário mostrar sobreposições de anúncios na interface ou relatar eventos para um SDK ou servidor de anúncios.
O DefaultMediaSourceFactory
do ExoPlayer pode delegar todas essas tarefas a uma
inserção de anúncios do lado do servidor MediaSource
para URIs usando o esquema 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();
Biblioteca de IMA do ExoPlayer
A biblioteca do IMA do ExoPlayer fornece ImaServerSideAdInsertionMediaSource
,
facilitando a integração com os streams de anúncios inseridos do lado do servidor do IMA no seu
app. Ela envolve a funcionalidade do SDK de DAI do IMA para Android e integra
totalmente os metadados do anúncio fornecidos ao player. Por exemplo, isso permite
que você use métodos como Player.isPlayingAd()
, ouça transições de anúncio de conteúdo
e deixe que o player processe a lógica de reprodução de anúncios, como pular anúncios já reproduzidos.
Para usar essa classe, você precisa configurar
ImaServerSideAdInsertionMediaSource.AdsLoader
e
ImaServerSideAdInsertionMediaSource.Factory
e conectá-los ao player:
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);
Carregue sua chave de recurso do IMA ou o ID da origem do conteúdo e o ID do vídeo criando um URL
com 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));
Por fim, libere o carregador de anúncios quando ele não for mais usado:
Kotlin
adsLoader.release()
Java
adsLoader.release();
Considerações sobre a interface
As mesmas considerações de interface da inserção de anúncios do lado do cliente também se aplicam à inserção de anúncios do lado do servidor.
Anúncios complementares
Algumas tags de anúncio contêm anúncios complementares que podem ser exibidos em "espaços" na interface do aplicativo. Esses slots podem ser transmitidos por
ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots)
.
Para mais informações, consulte Adicionar anúncios complementares.
Uso de um SDK de anúncios de terceiros
Se você precisar carregar anúncios usando um SDK de anúncios de terceiros, verifique se
ele já fornece uma integração do ExoPlayer. Caso contrário, é recomendável
fornecer um MediaSource
personalizado que aceite URIs com o esquema ssai://
semelhante a ImaServerSideAdInsertionMediaSource
.
A lógica real da criação da estrutura de anúncios pode ser delegada ao ServerSideAdInsertionMediaSource
de uso geral, que une um stream MediaSource
e permite que o usuário defina e atualize o AdPlaybackState
que representa os metadados
do anúncio.
Muitas vezes, os streams de anúncios inseridos do lado do servidor contêm eventos com tempo determinado para notificar o jogador
sobre os metadados do anúncio. Consulte os formatos compatíveis para mais informações sobre quais
formatos de metadados com marcação de tempo oferecem suporte ao ExoPlayer. As implementações de MediaSource
do SDK de anúncios personalizados podem detectar eventos de metadados com marcação de tempo do player usando Player.Listener.onMetadata
.