O ExoPlayer é compatível com HLS com vários formatos de contêiner. Os formatos de amostra de áudio e vídeo contidos também precisam ser compatíveis. Consulte a seção Formatos de amostra para mais detalhes. Recomendamos que os produtores de conteúdo HLS gerem streams HLS de alta qualidade, conforme descrito nesta postagem do blog.
Recurso | Compatível | Comentários |
---|---|---|
Contêineres | ||
MPEG-TS | SIM | |
FMP4/CMAF | SIM | |
ADTS (AAC) | SIM | |
MP3 | SIM | |
Legendas ocultas / legendas | ||
CEA-608 | SIM | |
CEA-708 | SIM | |
WebVTT | SIM | |
Metadados | ||
ID3 | SIM | |
SCTE-35 | NÃO | |
Proteção de conteúdo | ||
AES-128 | SIM | |
Exemplo de AES-128 | NÃO | |
Widevine | SIM | API 19+ (esquema "cenc") e 25+ (esquema "cbcs") |
PlayReady SL2000 | SIM | Somente no Android TV |
Controle do servidor | ||
Atualizações delta | SIM | |
Bloqueio da atualização da playlist | SIM | |
Bloqueio do carregamento de dicas de pré-carregamento | SIM | Exceto intervalos de bytes com comprimentos indefinidos |
Inserção de anúncios | ||
Inserção de anúncios guiada pelo servidor (intersticiais) | Parcialmente | Somente VOD com X-ASSET-URI .
As transmissões ao vivo e o
X-ASSET-LIST serão adicionados
depois. |
Anúncios do lado do cliente e do servidor da IMA | SIM | Guia de inserção de anúncios |
Reprodução ao vivo | ||
Reprodução regular ao vivo | SIM | |
HLS de baixa latência (Apple) | SIM | |
HLS de baixa latência (comunidade) | NÃO | |
Dados comuns do cliente de mídia CMCD | SIM | Guia de integração do CMCD |
Usar MediaItem
Para reproduzir uma transmissão HLS, você precisa depender do módulo HLS.
Kotlin
implementation("androidx.media3:media3-exoplayer-hls:1.7.1")
Groovy
implementation "androidx.media3:media3-exoplayer-hls:1.7.1"
Em seguida, crie um MediaItem
para um URI de playlist HLS e transmita-o ao
player.
Kotlin
// Create a player instance.
val player = ExoPlayer.Builder(context).build()
// Set the media item to be played.
player.setMediaItem(MediaItem.fromUri(hlsUri))
// Prepare the player.
player.prepare()
Java
// Create a player instance.
ExoPlayer player = new ExoPlayer.Builder(context).build();
// Set the media item to be played.
player.setMediaItem(MediaItem.fromUri(hlsUri));
// Prepare the player.
player.prepare();
Se o URI não terminar com .m3u8
, transmita MimeTypes.APPLICATION_M3U8
para setMimeType
de MediaItem.Builder
para indicar explicitamente o tipo do
conteúdo.
O URI do item de mídia pode apontar para uma playlist de mídia ou uma playlist
multivariante. Se o URI apontar para uma playlist multivariante que declara várias tags
#EXT-X-STREAM-INF
, o ExoPlayer vai se adaptar automaticamente entre
variantes, considerando a largura de banda disponível e os recursos do dispositivo.
Como usar HlsMediaSource
Para mais opções de personalização, crie um HlsMediaSource
e transmita-o
diretamente ao player em vez de um MediaItem
.
Kotlin
// Create a data source factory.
val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory()
// Create a HLS media source pointing to a playlist uri.
val hlsMediaSource =
HlsMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(hlsUri))
// Create a player instance.
val player = ExoPlayer.Builder(context).build()
// Set the HLS media source as the playlist with a single media item.
player.setMediaSource(hlsMediaSource)
// Prepare the player.
player.prepare()
Java
// Create a data source factory.
DataSource.Factory dataSourceFactory = new DefaultHttpDataSource.Factory();
// Create a HLS media source pointing to a playlist uri.
HlsMediaSource hlsMediaSource =
new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(hlsUri));
// Create a player instance.
ExoPlayer player = new ExoPlayer.Builder(context).build();
// Set the HLS media source as the playlist with a single media item.
player.setMediaSource(hlsMediaSource);
// Prepare the player.
player.prepare();
Como acessar o manifesto
Para recuperar o manifesto atual, chame Player.getCurrentManifest
.
Para HLS, transmita o objeto retornado para HlsManifest
. O callback
onTimelineChanged
de Player.Listener
também é chamado sempre que
o manifesto é carregado. Isso vai acontecer uma vez para conteúdo on demand e
possivelmente muitas vezes para conteúdo ao vivo. O snippet de código a seguir mostra como um app
pode fazer algo sempre que o manifesto é carregado.
Kotlin
player.addListener(
object : Player.Listener {
override fun onTimelineChanged(timeline: Timeline, @TimelineChangeReason reason: Int) {
val manifest = player.currentManifest
if (manifest is HlsManifest) {
// Do something with the manifest.
}
}
}
)
Java
player.addListener(
new Player.Listener() {
@Override
public void onTimelineChanged(
Timeline timeline, @Player.TimelineChangeReason int reason) {
Object manifest = player.getCurrentManifest();
if (manifest != null) {
HlsManifest hlsManifest = (HlsManifest) manifest;
// Do something with the manifest.
}
}
});
Reproduzir streams HLS com anúncios intersticiais
A especificação HLS define intersticiais que podem ser usados para incluir
informações em uma playlist de mídia. Por padrão, o ExoPlayer ignora esses
anúncios intersticiais. O suporte pode ser adicionado usando HlsInterstitialsAdsLoader
. Não oferecemos suporte a todos os recursos da especificação desde o início. Se você não encontrar suporte para
seu stream, registre um problema no GitHub e envie o URI
do stream para que possamos adicionar suporte a ele.
Usar um MediaItem
com a API Playlist
A maneira mais conveniente de reproduzir fluxos HLS com intersticiais é criar uma instância do
ExoPlayer com um HlsInterstitialsAdsLoader.AdsMediaSourceFactory
.
Isso permite usar a API Playlist baseada em MediaItem
da interface Player
para reproduzir anúncios intersticiais HLS.
O MediaSource.Factory
de ExoPlayer
pode ser injetado no builder ao
criar a instância do player:
Kotlin
hlsInterstitialsAdsLoader = HlsInterstitialsAdsLoader(context)
// Create a MediaSource.Factory for HLS streams with interstitials.
var hlsMediaSourceFactory =
HlsInterstitialsAdsLoader.AdsMediaSourceFactory(
hlsInterstitialsAdsLoader,
playerView,
DefaultMediaSourceFactory(context),
)
// Build player with interstitials media source factory
player =
ExoPlayer.Builder(context)
.setMediaSourceFactory(hlsMediaSourceFactory)
.build()
// Set the player on the ads loader.
hlsInterstitialsAdsLoader.setPlayer(player)
playerView.setPlayer(player)
Java
hlsInterstitialsAdsLoader = new HlsInterstitialsAdsLoader(context);
// Create a MediaSource.Factory for HLS streams with interstitials.
MediaSource.Factory hlsMediaSourceFactory =
new HlsInterstitialsAdsLoader.AdsMediaSourceFactory(
hlsInterstitialsAdsLoader, playerView, new DefaultMediaSourceFactory(context));
// Build player with interstitials media source factory
player =
new ExoPlayer.Builder(context)
.setMediaSourceFactory(hlsMediaSourceFactory)
.build();
// Set the player on the ads loader.
hlsInterstitialsAdsLoader.setPlayer(player);
playerView.setPlayer(player);
Com essa configuração de player, para reproduzir anúncios intersticiais HLS, basta definir um
item de mídia com um AdsConfiguration
no player:
Kotlin
player.setMediaItem(
MediaItem.Builder()
.setUri("https://www.example.com/media.m3u8")
.setAdsConfiguration(
AdsConfiguration.Builder(Uri.parse("hls://interstitials"))
.setAdsId("ad-tag-0") // must be unique within playlist
.build())
.build())
player.prepare();
player.play();
Java
player.setMediaItem(
new MediaItem.Builder()
.setUri("https://www.example.com/media.m3u8")
.setAdsConfiguration(
new AdsConfiguration.Builder(Uri.parse("hls://interstitials"))
.setAdsId("ad-tag-0") // must be unique within playlist
.build())
.build());
player.prepare();
player.play();
Usar a API baseada em fonte de mídia
Como alternativa, a instância do ExoPlayer pode ser criada sem substituir a
fábrica de fontes de mídia padrão. Para oferecer suporte a intersticiais, um app pode
usar HlsInterstitialsAdsLoader.AdsMediaSourceFactory
diretamente para criar um
MediaSource
e fornecê-lo ao ExoPlayer usando a API
de lista de reprodução baseada em fonte de mídia:
Kotlin
hlsInterstitialsAdsLoader = HlsInterstitialsAdsLoader(context)
// Create a MediaSource.Factory for HLS streams with interstitials.
var hlsMediaSourceFactory =
HlsInterstitialsAdsLoader.AdsMediaSourceFactory(hlsInterstitialsAdsLoader, playerView, context)
// Build player with default media source factory.
player = new ExoPlayer.Builder(context).build();
// Create an media source from an HLS media item with ads configuration.
val mediaSource =
hlsMediaSourceFactory.createMediaSource(
MediaItem.Builder()
.setUri("https://www.example.com/media.m3u8")
.setAdsConfiguration(
MediaItem.AdsConfiguration.Builder(Uri.parse("hls://interstitials"))
.setAdsId("ad-tag-0")
.build()
)
.build()
)
// Set the media source on the player.
player.setMediaSource(mediaSource)
player.prepare()
player.play()
Java
HlsInterstitialsAdsLoader hlsInterstitialsAdsLoader = new HlsInterstitialsAdsLoader(context);
// Create a MediaSource.Factory for HLS streams with interstitials.
MediaSource.Factory hlsMediaSourceFactory =
new HlsInterstitialsAdsLoader.AdsMediaSourceFactory(
hlsInterstitialsAdsLoader, playerView, context);
// Build player with default media source factory.
player = new ExoPlayer.Builder(context).build();
// Create an media source from an HLS media item with ads configuration.
MediaSource mediaSource =
hlsMediaSourceFactory.createMediaSource(
new MediaItem.Builder()
.setUri("https://www.example.com/media.m3u8")
.setAdsConfiguration(
new MediaItem.AdsConfiguration.Builder(Uri.parse("hls://interstitials"))
.setAdsId("ad-tag-0")
.build())
.build());
// Set the media source on the player.
exoPlayer.setMediaSource(mediaSource);
exoPlayer.prepare();
exoPlayer.play();
Detectar eventos de anúncios
Um Listener
pode ser adicionado ao HlsInterstitialsAdsLoader
para monitorar eventos
relacionados a mudanças de status na reprodução de intersticiais HLS. Isso permite que um
app ou SDK rastreie anúncios veiculados, listas de recursos carregadas, origens de mídia de anúncios sendo
preparadas ou detecte erros de preparação de anúncios e carregamento de listas de recursos. Além disso, os metadados
emitidos por fontes de mídia de anúncios podem ser recebidos para verificação
detalhada da reprodução de anúncios ou para acompanhar o progresso da reprodução.
Kotlin
class AdsLoaderListener : HlsInterstitialsAdsLoader.Listener {
override fun onStart(mediaItem: MediaItem, adsId: Any, adViewProvider: AdViewProvider) {
// Do something when HLS media item with interstitials is started.
}
override fun onMetadata(
mediaItem: MediaItem,
adsId: Any,
adGroupIndex: Int,
adIndexInAdGroup: Int,
metadata: Metadata,
) {
// Do something with metadata that is emitted by the ad media source of the given ad.
}
override fun onAdCompleted(
mediaItem: MediaItem,
adsId: Any,
adGroupIndex: Int,
adIndexInAdGroup: Int,
) {
// Do something when ad completed playback.
}
// ... See JavaDoc for further callbacks of HlsInterstitialsAdsLoader.Listener.
override fun onStop(mediaItem: MediaItem, adsId: Any, adPlaybackState: AdPlaybackState) {
// Do something with the resulting ad playback state when stopped.
}
}
Java
private class AdsLoaderListener
implements HlsInterstitialsAdsLoader.Listener {
// implement HlsInterstitialsAdsLoader.Listener
@Override
public void onStart(MediaItem mediaItem, Object adsId, AdViewProvider adViewProvider) {
// Do something when HLS media item with interstitials is started.
}
@Override
public void onMetadata(
MediaItem mediaItem,
Object adsId,
int adGroupIndex,
int adIndexInAdGroup,
Metadata metadata) {
// Do something with metadata that is emitted by the ad media source of the given ad.
}
@Override
public void onAdCompleted(
MediaItem mediaItem, Object adsId, int adGroupIndex, int adIndexInAdGroup) {
// Do something when ad completed playback.
}
// ... See JavaDoc for further callbacks
@Override
public void onStop(MediaItem mediaItem, Object adsId, AdPlaybackState adPlaybackState) {
// Do something with the resulting ad playback state when stopped.
}
}
Consulte o JavaDoc de HlsInterstitialsAdsLoader.Listener
para ver a documentação detalhada de todos os callbacks disponíveis.
Em seguida, o listener pode ser adicionado ao carregador de anúncios:
Kotlin
var listener = AdsLoaderListener();
// Add the listener to the ads loader to receive ad loader events.
hlsInterstitialsAdsLoader.addListener(listener);
Java
AdsLoaderListener listener = new AdsLoaderListener();
// Add the listener to the ads loader to receive ad loader events.
hlsInterstitialsAdsLoader.addListener(listener);
Ciclo de vida do HlsInterstitialsAdsLoader
Uma instância de HlsInterstitialsAdsLoader
ou HlsInterstitialsAdsLoader.AdsMediaSourceFactory
pode ser reutilizada para várias instâncias de player que criam várias origens de mídia para as quais os anúncios precisam ser carregados.
Uma instância pode ser criada, por exemplo, no método onCreate
de um Activity
e reutilizada para várias instâncias de jogador. Isso funciona desde que esteja em uso por uma única instância de jogador ao mesmo tempo. Isso é útil para o
caso de uso comum em que o app é colocado em segundo plano, a instância do player
é destruída e uma nova instância é criada quando o app é colocado em primeiro plano
de novo.
Kotlin
// Create the ads loader instance (for example onCreate).
hlsInterstitialsAdsLoader = HlsInterstitialsAdsLoader(context);
// Build a player and set it on the ads loader (for example onStart).
player = ExoPlayer.Builder(context).build();
hlsInterstitialsAdsLoader.setPlayer(player);
// Release the player and unset it on the ads loader (for example onStop).
player.release();
hlsInterstitialsAdsLoader.setPlayer(null);
// Build another player and set it on the ads loader (for example onStart).
player = ExoPlayer.Builder(context).build();
hlsInterstitialsAdsLoader.setPlayer(player);
// Release the player and unset it on the ads loader (for example onStop).
player.release();
hlsInterstitialsAdsLoader.setPlayer(null);
// Release the ads loader when not used anymore (for example onDestroy).
hlsInterstitialsAdsLoader.release();
Java
// Create the ads loader instance (for example onCreate).
hlsInterstitialsAdsLoader = new HlsInterstitialsAdsLoader(context);
// Build a player and set it on the ads loader (for example onStart).
player = new ExoPlayer.Builder(context).build();
hlsInterstitialsAdsLoader.setPlayer(player);
// Release the player and unset it on the ads loader (for example onStop).
player.release();
hlsInterstitialsAdsLoader.setPlayer(null);
// Build another player and set it on the ads loader (for example onStart).
player = new ExoPlayer.Builder(context).build();
hlsInterstitialsAdsLoader.setPlayer(player);
// Release the player and unset it on the ads loader (for example onStop).
player.release();
hlsInterstitialsAdsLoader.setPlayer(null);
// Release the ads loader when not used anymore (for example onDestroy).
hlsInterstitialsAdsLoader.release();
Em geral, libere a instância do player antigo antes de definir a próxima instância do player no carregador de anúncios. Depois que o carregador de anúncios for lançado, ele não poderá mais ser usado.
Personalizar a reprodução
O ExoPlayer oferece várias maneiras de personalizar a experiência de reprodução de acordo com as necessidades do seu app. Consulte a página de personalização para ver exemplos.
Como desativar a preparação sem partes
Por padrão, o ExoPlayer usa a preparação sem separações em blocos. Isso significa que o ExoPlayer
só vai usar as informações na playlist multivariante para preparar o
stream, o que funciona se as tags #EXT-X-STREAM-INF
contiverem o atributo CODECS
.
Talvez seja necessário desativar esse recurso se os segmentos de mídia tiverem faixas de legenda descritiva multiplexadas que não foram declaradas na playlist multivariante com uma tag #EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS
. Caso contrário, essas faixas de legenda descritiva
não serão detectadas nem reproduzidas. É possível desativar a preparação sem partes no
HlsMediaSource.Factory
, conforme mostrado no snippet a seguir. Isso vai aumentar o tempo de inicialização, já que o ExoPlayer precisa baixar um segmento de mídia para descobrir essas faixas extras. É preferível declarar as faixas de legenda descritiva na playlist multivariante.
Kotlin
val hlsMediaSource =
HlsMediaSource.Factory(dataSourceFactory)
.setAllowChunklessPreparation(false)
.createMediaSource(MediaItem.fromUri(hlsUri))
Java
HlsMediaSource hlsMediaSource =
new HlsMediaSource.Factory(dataSourceFactory)
.setAllowChunklessPreparation(false)
.createMediaSource(MediaItem.fromUri(hlsUri));
Como criar conteúdo HLS de alta qualidade
Para aproveitar ao máximo o ExoPlayer, siga algumas diretrizes para melhorar seu conteúdo HLS. Leia nossa postagem no Medium sobre a reprodução de HLS no ExoPlayer para uma explicação completa. Os principais pontos são:
- Use durações de segmento precisas.
- Use um fluxo de mídia contínuo e evite mudanças na estrutura da mídia entre os segmentos.
- Use a tag
#EXT-X-INDEPENDENT-SEGMENTS
. - Prefira streams demuxados em vez de arquivos que incluem vídeo e áudio.
- Inclua todas as informações possíveis na playlist multivariante.
As seguintes diretrizes se aplicam especificamente a transmissões ao vivo:
- Use a tag
#EXT-X-PROGRAM-DATE-TIME
. - Use a tag
#EXT-X-DISCONTINUITY-SEQUENCE
. - Oferecer uma janela de longa duração. Um minuto ou mais é ótimo.