HLS

O ExoPlayer oferece suporte a HLS com vários formatos de contêiner. Os formatos de amostra de áudio e vídeo contidos também precisam ser aceitos (consulte a seção de formatos de amostra para mais detalhes). Incentivamos os produtores de conteúdo HLS a gerar transmissões HLS de alta qualidade, conforme descrito neste post do blog.

Recurso Compatível Comentários
Contêineres
MPEG-TS SIM
FMP4/CMAF SIM
ADTS (AAC) SIM
MP3 SIM
Legendas ocultas / subtítulos
CEA-608 SIM
CEA-708 SIM
WebVTT SIM
Metadados
ID3 SIM
SCTE-35 NÃO
Proteção de conteúdo
AES-128 SIM
Amostra AES-128 NÃO
Widevine SIM API 19 ou mais recente (esquema "cenc") e 25 ou mais recente (esquema "cbcs")
PlayReady SL2000 SIM Somente no Android TV
Controle do servidor
Atualizações delta SIM
Bloqueio da recarga da playlist SIM
Bloqueio do carregamento de dicas de pré-carregamento SIM Exceto para 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. Transmissões ao vivo e X-ASSET-LIST serão adicionadas mais tarde.
Anúncios do IMA do lado do servidor e do lado do cliente SIM Guia de inserção de anúncios
Reprodução ao vivo
Reprodução ao vivo normal 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

Como usar MediaItem

Para reproduzir uma transmissão HLS, é necessário depender do módulo HLS.

Kotlin

implementation("androidx.media3:media3-exoplayer-hls:1.10.0")

Groovy

implementation "androidx.media3:media3-exoplayer-hls:1.10.0"

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 de 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 as 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

Você pode recuperar o manifesto atual chamando Player.getCurrentManifest. Para HLS, converta o objeto retornado para HlsManifest. O callback onTimelineChanged de Player.Listener também é chamado sempre que o manifesto é carregado. Isso acontece uma vez para conteúdo on demand e possivelmente várias 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,
      @Player.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 transmissões HLS com intersticiais

A especificação HLS define intersticiais HLS que podem ser usados para incluir informações intersticiais em uma playlist de mídia. O ExoPlayer ignora esses intersticiais por padrão. 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 tiver suporte para sua transmissão, registre um problema no GitHub e envie o URI da transmissão para que possamos adicionar suporte a ela.

Usar um MediaItem com a API Playlist

A maneira mais conveniente de reproduzir transmissões HLS com intersticiais é criar uma instância do ExoPlayer com uma HlsInterstitialsAdsLoader.AdsMediaSourceFactory. Isso permite usar a API MediaItem baseada em playlist da interface Player para reproduzir intersticiais HLS.

O MediaSource.Factory do ExoPlayer pode ser injetado no builder ao criar a instância do player:

Kotlin

val hlsInterstitialsAdsLoader = HlsInterstitialsAdsLoader(context)
// Create a MediaSource.Factory for HLS streams with interstitials.
val hlsMediaSourceFactory =
  HlsInterstitialsAdsLoader.AdsMediaSourceFactory(
    hlsInterstitialsAdsLoader,
    playerView,
    DefaultMediaSourceFactory(context),
  )

// Build player with interstitials media source factory
val player = ExoPlayer.Builder(context).setMediaSourceFactory(hlsMediaSourceFactory).build()

// Set the player on the ads loader.
hlsInterstitialsAdsLoader.setPlayer(player)
playerView.setPlayer(player)

Java

HlsInterstitialsAdsLoader 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
ExoPlayer 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 do player, a reprodução de intersticiais HLS é apenas sobre a configuração de um item de mídia com uma AdsConfiguration no player:

Kotlin

// Build an HLS media item with ads configuration to be played.
player.setMediaItem(
  MediaItem.Builder()
    .setUri("https://www.example.com/media.m3u8")
    .setAdsConfiguration(
      MediaItem.AdsConfiguration.Builder("hls://interstitials".toUri())
        .setAdsId("ad-tag-0") // must be unique within playlist
        .build()
    )
    .build()
)

player.prepare()
player.play()

Java

// Build an HLS media item with ads configuration to be played.
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 na origem de mídia

Como alternativa, a instância do ExoPlayer pode ser criada sem substituir a fábrica de origem de mídia padrão. Para oferecer suporte a intersticiais, um app pode então usar HlsInterstitialsAdsLoader.AdsMediaSourceFactory diretamente para criar um MediaSource e fornecê-lo ao ExoPlayer usando a API Playlist baseada na origem de mídia:

Kotlin

val hlsInterstitialsAdsLoader = HlsInterstitialsAdsLoader(context)
// Create a MediaSource.Factory for HLS streams with interstitials.
val hlsMediaSourceFactory =
  HlsInterstitialsAdsLoader.AdsMediaSourceFactory(
    hlsInterstitialsAdsLoader,
    playerView,
    context,
  )

// Build player with default media source factory.
val player = 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("hls://interstitials".toUri())
          .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.
ExoPlayer 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.
player.setMediaSource(mediaSource);
player.prepare();
player.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 reproduzidos, listas de recursos carregadas, origens de mídia de anúncios sendo preparadas ou detecte erros de carregamento de listas de recursos e preparação de anúncios. Além disso, os metadados emitidos por origens 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 de anúncios.

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

@OptIn(markerClass = UnstableApi.class)
private static 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 conferir a documentação detalhada de todos os callbacks disponíveis.

O listener pode ser adicionado ao carregador de anúncios:

Kotlin

val 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 uma Activity e reutilizada para várias instâncias de player. Isso funciona desde que esteja em uso por uma única instância de um jogador ao mesmo tempo. Isso é útil para o caso de uso comum quando 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 novamente.

Retomada da reprodução com um estado de reprodução de anúncios

Para evitar que os usuários precisem assistir anúncios novamente, o estado de reprodução de anúncios pode ser salvo e restaurado quando o player é recriado. Isso é feito chamando getAdsResumptionStates() quando o player está prestes a ser lançado e armazenando os objetos AdsResumptionState retornados. Quando o player é recriado, o estado pode ser restaurado chamando addAdResumptionState() na instância do carregador de anúncios. AdsResumptionState pode ser agrupado, então ele pode ser armazenado em um pacote onSaveInstanceState de uma Activity. A retomada de anúncios só é aceita para transmissões VOD.

Kotlin

class HlsInterstitialsActivity : Activity() {

  companion object {
    const val ADS_RESUMPTION_STATE_KEY = "ads_resumption_state"
  }

  private var hlsInterstitialsAdsLoader: HlsInterstitialsAdsLoader? = null
  private var playerView: PlayerView? = null
  private var player: ExoPlayer? = null
  private var adsResumptionStates: List<HlsInterstitialsAdsLoader.AdsResumptionState>? = null

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // Create the ads loader instance.
    hlsInterstitialsAdsLoader = HlsInterstitialsAdsLoader(this)
    // Restore ad resumption states.
    savedInstanceState?.getParcelableArrayList<Bundle>(ADS_RESUMPTION_STATE_KEY)?.let { bundles ->
      adsResumptionStates =
        bundles.map { HlsInterstitialsAdsLoader.AdsResumptionState.fromBundle(it) }
    }
  }

  override fun onStart() {
    super.onStart()
    // Build a player and set it on the ads loader.
    initializePlayer()
    hlsInterstitialsAdsLoader?.setPlayer(player)
    // Add any stored ad resumption states to the ads loader.
    adsResumptionStates?.forEach { hlsInterstitialsAdsLoader?.addAdResumptionState(it) }
    adsResumptionStates = null // Consume the states
  }

  override fun onStop() {
    super.onStop()
    // Get ad resumption states.
    adsResumptionStates = hlsInterstitialsAdsLoader?.adsResumptionStates
    releasePlayer()
  }

  override fun onDestroy() {
    // Release the ads loader when not used anymore.
    hlsInterstitialsAdsLoader?.release()
    hlsInterstitialsAdsLoader = null
    super.onDestroy()
  }

  override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    // Store the ad resumption states.
    adsResumptionStates?.let {
      outState.putParcelableArrayList(
        ADS_RESUMPTION_STATE_KEY,
        ArrayList(it.map(HlsInterstitialsAdsLoader.AdsResumptionState::toBundle)),
      )
    }
  }

  fun initializePlayer() {
    if (player == null) {
      // Create a media source factory for HLS streams.
      val hlsMediaSourceFactory =
        HlsInterstitialsAdsLoader.AdsMediaSourceFactory(
          checkNotNull(hlsInterstitialsAdsLoader),
          playerView!!,
          /* context= */ this,
        )
      // Build player with interstitials media source
      player =
        ExoPlayer.Builder(/* context= */ this)
          .setMediaSourceFactory(hlsMediaSourceFactory)
          .build()
      // Set the player on the ads loader.
      hlsInterstitialsAdsLoader?.setPlayer(player)
      playerView?.player = player
    }

    // Use a media item with an HLS stream URI, an ad tag URI and ads ID.
    player?.setMediaItem(
      MediaItem.Builder()
        .setUri("https://www.example.com/media.m3u8")
        .setMimeType(MimeTypes.APPLICATION_M3U8)
        .setAdsConfiguration(
          MediaItem.AdsConfiguration.Builder("hls://interstitials".toUri())
            .setAdsId("ad-tag-0") // must be unique within ExoPlayer playlist
            .build()
        )
        .build()
    )
    player?.prepare()
    player?.play()
  }

  fun releasePlayer() {
    player?.release()
    player = null
    hlsInterstitialsAdsLoader?.setPlayer(null)
    playerView?.player = null
  }
}

Java

@OptIn(markerClass = UnstableApi.class)
public static class HlsInterstitialsActivity extends Activity {

  public static final String ADS_RESUMPTION_STATE_KEY = "ads_resumption_state";

  @Nullable private HlsInterstitialsAdsLoader hlsInterstitialsAdsLoader;
  @Nullable private PlayerView playerView;
  @Nullable private ExoPlayer player;

  private List<HlsInterstitialsAdsLoader.AdsResumptionState> adsResumptionStates;

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Create the ads loader instance.
    hlsInterstitialsAdsLoader = new HlsInterstitialsAdsLoader(this);
    // Restore ad resumption states.
    if (savedInstanceState != null) {
      ArrayList<Bundle> bundles =
          savedInstanceState.getParcelableArrayList(ADS_RESUMPTION_STATE_KEY);
      if (bundles != null) {
        adsResumptionStates = new ArrayList<>();
        for (Bundle bundle : bundles) {
          adsResumptionStates.add(
              HlsInterstitialsAdsLoader.AdsResumptionState.fromBundle(bundle));
        }
      }
    }
  }

  @Override
  protected void onStart() {
    super.onStart();
    // Build a player and set it on the ads loader.
    initializePlayer();
    // Add any stored ad resumption states to the ads loader.
    if (adsResumptionStates != null) {
      for (HlsInterstitialsAdsLoader.AdsResumptionState state : adsResumptionStates) {
        hlsInterstitialsAdsLoader.addAdResumptionState(state);
      }
      adsResumptionStates = null; // Consume the states
    }
  }

  @Override
  protected void onStop() {
    super.onStop();
    // Get ad resumption states before releasing the player.
    if (hlsInterstitialsAdsLoader != null) {
      adsResumptionStates = hlsInterstitialsAdsLoader.getAdsResumptionStates();
    }
    releasePlayer();
  }

  @Override
  protected void onDestroy() {
    // Release the ads loader when not used anymore.
    if (hlsInterstitialsAdsLoader != null) {
      hlsInterstitialsAdsLoader.release();
      hlsInterstitialsAdsLoader = null;
    }
    super.onDestroy();
  }

  @Override
  protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    // Store the ad resumption states.
    if (adsResumptionStates != null) {
      ArrayList<Bundle> bundles = new ArrayList<>();
      for (HlsInterstitialsAdsLoader.AdsResumptionState state : adsResumptionStates) {
        bundles.add(state.toBundle());
      }
      outState.putParcelableArrayList(ADS_RESUMPTION_STATE_KEY, bundles);
    }
  }

  private void initializePlayer() {
    if (player == null) {
      // Create a media source factory for HLS streams.
      MediaSource.Factory hlsMediaSourceFactory =
          new HlsInterstitialsAdsLoader.AdsMediaSourceFactory(
              checkNotNull(hlsInterstitialsAdsLoader), playerView, /* context= */ this);
      // Build player with interstitials media source
      player =
          new ExoPlayer.Builder(/* context= */ this)
              .setMediaSourceFactory(hlsMediaSourceFactory)
              .build();
      // Set the player on the ads loader.
      hlsInterstitialsAdsLoader.setPlayer(player);
      playerView.setPlayer(player);
    }

    // Use a media item with an HLS stream URI, an ad tag URI and ads ID.
    player.setMediaItem(
        new MediaItem.Builder()
            .setUri("https://www.example.com/media.m3u8")
            .setMimeType(MimeTypes.APPLICATION_M3U8)
            .setAdsConfiguration(
                new MediaItem.AdsConfiguration.Builder(Uri.parse("hls://interstitials"))
                    .setAdsId("ad-tag-0") // must be unique within ExoPlayer playlist
                    .build())
            .build());
    player.prepare();
    player.play();
  }

  private void releasePlayer() {
    if (player != null) {
      player.release();
      player = null;
    }
    if (hlsInterstitialsAdsLoader != null) {
      hlsInterstitialsAdsLoader.setPlayer(null);
    }
    if (playerView != null) {
      playerView.setPlayer(null);
    }
  }
}

Como 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 conferir exemplos.

Como desativar a preparação sem blocos

Por padrão, o ExoPlayer usa a preparação sem blocos. Isso significa que o ExoPlayer só vai usar as informações na playlist multivariante para preparar a transmissão, 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 contiverem faixas de legendas ocultas muxadas que não são declaradas na playlist multivariante com uma tag #EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS. Caso contrário, essas faixas de legendas ocultas não serão detectadas e reproduzidas. Você pode desativar a preparação sem blocos na HlsMediaSource.Factory, conforme mostrado no snippet a seguir. Isso vai aumentar o tempo de inicialização, já que o ExoPlayer precisa fazer o download de um segmento de mídia para descobrir essas faixas adicionais. É preferível declarar as faixas de legendas ocultas 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 nosso post do Medium sobre a reprodução de HLS no ExoPlayer para conferir uma explicação completa. Os principais pontos são:

  • Use durações de segmento precisas.
  • Use uma transmissão de mídia contínua. Evite mudanças na estrutura de mídia em segmentos.
  • Use a tag #EXT-X-INDEPENDENT-SEGMENTS.
  • Prefira transmissões demuxadas, em vez de arquivos que incluem vídeo e áudio.
  • Inclua todas as informações possíveis na playlist multivariante.

As diretrizes a seguir se aplicam especificamente a transmissões ao vivo:

  • Use a tag #EXT-X-PROGRAM-DATE-TIME.
  • Use a tag #EXT-X-DISCONTINUITY-SEQUENCE.
  • Forneça uma janela ao vivo longa. Um minuto ou mais é ótimo.