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 o carregamento de mídia de URLs diferentes à medida que transita entre a exibição de conteúdo e anúncios. As informações sobre os anúncios são carregadas separadamente da mídia, por exemplo, de uma tag de anúncio XML VAST ou VMAP. Isso pode incluir posições de comando de anúncio em relação ao início do conteúdo, os URIs de mídia de anúncios reais e metadados, como se um determinado anúncio pode ser pulado.
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 a serem veiculados. Essa mudança gera vários benefícios:
- O player pode expor metadados e funcionalidades relacionadas a anúncios usando sua API.
- Os componentes da interface do ExoPlayer podem mostrar marcadores para posições de anúncio automaticamente e mudar o comportamento dependendo se o anúncio está sendo reproduzido.
- Internamente, o player pode manter um buffer consistente nas transições entre anúncios e conteúdo.
Nessa configuração, o player cuida de alternar entre anúncios e conteúdo, o que significa que os apps não precisam controlar vários players em segundo plano/primeiro plano separados 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 vídeo para que o player possa retomar a reprodução sem problemas.
Suporte a anúncios declarativos
Um URI de tag de anúncio pode ser especificado ao criar uma 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 do player a 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 agrupar a origem de mídia de conteúdo em um
AdsMediaSource
. O AdsMediaSource
vai receber um AdsLoader
do
AdsLoader.Provider
e usá-lo para inserir anúncios conforme definido pela tag
do item de mídia.
O PlayerView
do ExoPlayer implementa AdViewProvider
. A biblioteca IMA do ExoPlayer
oferece 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 de tag de anúncio. Isso significa que os usuários vão receber anúncios de cada item de mídia com anúncios que tenham um ID de mídia ou URI de conteúdo distinto, mesmo que os URIs da tag de anúncio sejam iguais. Se um item de mídia for repetido, o usuário vai ver os anúncios correspondentes apenas uma vez. O estado de reprodução de anúncios armazena se os anúncios foram exibidos, então eles são pulados após a primeira ocorrência.
É possível personalizar esse comportamento transmitindo um identificador de anúncios opaco com o estado de reprodução do anúncio para um determinado item de mídia 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. O efeito é que os anúncios são carregados apenas uma vez, e o usuário não vê 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 IMA do ExoPlayer
A biblioteca IMA do ExoPlayer fornece ImaAdsLoader
, facilitando a
integração da inserção de anúncios do lado do cliente no 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 a execução em segundo plano
e retomar a reprodução, consulte o README.
O aplicativo de demonstração usa a biblioteca do IMA e inclui várias tags de anúncio VAST/VMAP de amostra na lista.
Considerações sobre a interface
O 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 visualizações adicionais na parte de cima
do player enquanto um anúncio está sendo veiculado (por exemplo, um link "Mais informações" e um botão de pular,
se aplicável).
O SDK do IMA pode informar se os anúncios estão obscurecidos por visualizações fornecidas pelo aplicativo
renderizadas sobre o player. Os apps que precisam sobrepor visualizações que são
essenciais para controlar a reprodução precisam registrá-las no SDK do IMA para que
possam ser 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 do player personalizada precisam registrar visualizações de sobreposição, retornando-as de
AdViewProvider.getAdOverlayInfos
.
Para mais informações sobre 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 adicionais que podem ser mostrados em "slots" na
interface do app. Esses slots podem ser transmitidos por
ImaAdsLoader.Builder.setCompanionAdSlots(slots)
. Para mais informações, consulte
Como adicionar anúncios complementares.
Anúncios independentes
O SDK do IMA foi criado para inserir anúncios em conteúdo de mídia, não para exibir anúncios independentes. Portanto, a reprodução de anúncios independentes não é compatível com a biblioteca IMA. Recomendamos usar o SDK dos anúncios para dispositivos móveis do Google para esse caso de uso.
Como usar 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á oferece uma integração com o ExoPlayer. Caso contrário, implementar um
AdsLoader
personalizado que una o SDK de anúncios de terceiros é a abordagem recomendada,
porque oferece os benefícios de 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 no servidor
Na inserção de anúncios do lado do servidor (também chamada de inserção de anúncios dinâmicos ou DAI, na sigla em inglês), 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 o 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 da mídia dinamicamente para receber o fluxo unido, mostrar sobreposições de anúncios na interface ou informar eventos a um SDK de anúncios 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 do IMA do ExoPlayer
A biblioteca IMA do ExoPlayer fornece ImaServerSideAdInsertionMediaSource
,
facilitando a integração com os fluxos de anúncios inseridos do lado do servidor do IMA no seu
app. Ela envolve a funcionalidade do SDK do IMA DAI para Android e integra
totalmente os metadados de anúncios fornecidos ao player. Por exemplo, isso permite
que você use métodos como Player.isPlayingAd()
, ouça transições de anúncios de conteúdo
e deixe que o player gerencie a lógica de reprodução de anúncios, como pular anúncios já reproduzidos.
Para usar essa classe, você precisa configurar o
ImaServerSideAdInsertionMediaSource.AdsLoader
e o
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 a chave de recurso do IMA ou o ID da origem do conteúdo e 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 mostrados em "slots" na
interface do app. Esses slots podem ser transmitidos por
ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots)
.
Para mais informações, consulte Adicionar anúncios complementares.
Como usar 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á oferece uma integração com o ExoPlayer. Caso contrário, é recomendável
fornecer um MediaSource
personalizado que aceite URIs com o esquema ssai://
semelhante ao ImaServerSideAdInsertionMediaSource
.
A lógica real de criação da estrutura do anúncio pode ser delegada à ServerSideAdInsertionMediaSource
de uso geral, que envolve um MediaSource
de stream
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 no lado do servidor contêm eventos cronometrados para notificar o player
sobre os metadados do anúncio. Consulte os formatos com suporte para saber quais
formatos de metadados cronometrados são compatíveis com o ExoPlayer. As implementações do SDK de anúncios personalizados MediaSource
podem detectar eventos de metadados cronometrados do player usando
Player.Listener.onMetadata
.