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 à medida que faz a transição entre a reprodução de conteúdo e anúncios. As informações sobre anúncios são carregadas separadamente da mídia, como de uma tag de anúncio XML VAST ou VMAP. Isso pode incluir posições de indicação de anúncio em relação ao início do conteúdo, os URIs de mídia de anúncio 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 a API dele.
- Os componentes da interface do ExoPlayer podem mostrar marcadores para posições de anúncios automaticamente e mudar o comportamento dependendo se o anúncio está sendo veiculado.
- Internamente, o player pode manter um buffer consistente nas transições entre anúncios e conteúdo.
Nessa configuração, o player cuida da troca 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 devem ser posicionados em amostras de sincronização (frames-chave) no vídeo de conteúdo para que o player possa retomar a reprodução de conteúdo sem problemas.
Suporte a anúncios declarativos
Um URI de 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 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 encapsular 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 de anúncio do item
de mídia.
O PlayerView do ExoPlayer implementa 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 uma vez para cada combinação de ID de mídia, URI de conteúdo e URI de 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 tenha um ID de mídia ou URI de conteúdo distinto, mesmo que os URIs de tag de anúncio sejam iguais. 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 veiculados, para que sejam pulados após a primeira ocorrência.
É possível personalizar esse comportamento transmitindo um identificador de anúncios opaco com o qual o estado de reprodução de anúncios de um determinado item de mídia está vinculado, com base na igualdade de objetos. Este é um exemplo em que o estado de reprodução do anúncio é vinculado apenas ao URI da tag de anúncio, e não à combinação do ID da 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 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);
Inserção de anúncios do lado do cliente guiada pelo servidor
O ExoPlayer vem com um HlsInterstitialsAdsLoader que permite inserir automaticamente no lado do cliente anúncios definidos na
playlist HLS. Consulte a seção sobre HlsInterstitialsAdsLoader na página do HLS.
Biblioteca IMA do ExoPlayer
A biblioteca do IMA do ExoPlayer oferece ImaAdsLoader, facilitando a
integração da inserção de anúncios do lado do cliente ao 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 lidar com o segundo plano
e retomar a reprodução, consulte o README.
O aplicativo de demonstração usa a biblioteca IMA e inclui várias tags de anúncio VAST/VMAP de exemplo na lista de amostras.
Considerações sobre a interface
Por padrão, o PlayerView oculta os controles de transporte durante a reprodução de anúncios, mas
os apps podem alternar esse comportamento chamando setControllerHideDuringAds. O SDK da IMA
mostra outras visualizações na parte de cima do player enquanto um anúncio está sendo veiculado (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 estão sendo ocultados por visualizações fornecidas pelo aplicativo
renderizadas na parte de cima do player. Os apps que precisam sobrepor visualizações essenciais para controlar a reprodução precisam registrá-las com o SDK do IMA para que possam ser omitidas dos cálculos de visibilidade. Ao usar PlayerView como
o AdViewProvider, ele vai registrar 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 IMA.
Anúncios complementares
Algumas tags de anúncio contêm anúncios complementares adicionais que podem ser mostrados em "slots" em uma interface do usuário do app. Esses slots podem ser transmitidos via
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 veicular 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.
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 do ExoPlayer. Caso contrário, a abordagem recomendada é implementar um AdsLoader personalizado
que encapsula o SDK de anúncios de terceiros,
já que ele oferece os benefícios do AdsMediaSource descritos acima.
O ImaAdsLoader funciona como um exemplo de implementação.
Como alternativa, use 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( 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);
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úncio, possivelmente em períodos separados. Para HLS, consulte a documentação da Apple sobre incorporação de anúncios em 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 costurado, exibir 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 que usam 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 IMA do ExoPlayer
A biblioteca do 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
usar métodos como Player.isPlayingAd(), ouvir transições de conteúdo para anúncio
e deixar que o player processe a lógica de reprodução de anúncios, como pular anúncios já veiculados.
Para usar essa classe, configure o
ImaServerSideAdInsertionMediaSource.AdsLoader e o
ImaServerSideAdInsertionMediaSource.Factory e conecte-os 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 adicionais que podem ser mostrados em "slots" em uma interface do usuário do app. Esses slots podem ser transmitidos via
ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots).
Para mais informações, consulte Adicionar anúncios complementares.
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, recomendamos fornecer um MediaSource personalizado que aceite URIs com o esquema ssai://, semelhante a ImaServerSideAdInsertionMediaSource.
A lógica real de criação da estrutura de anúncio pode ser delegada ao ServerSideAdInsertionMediaSource de uso geral, que encapsula um fluxo MediaSource e permite que o usuário defina e atualize o AdPlaybackState que representa os metadados do anúncio.
Muitas vezes, os fluxos de anúncios inseridos no lado do servidor contêm eventos programados para notificar o jogador
sobre metadados de anúncios. Consulte formatos compatíveis para saber quais formatos de metadados com carimbo de data/hora são aceitos pelo ExoPlayer. As implementações do SDK de anúncios personalizados MediaSource
podem detectar eventos de metadados com marcação de tempo do player usando
Player.Listener.onMetadata.