ЗОЖ

ExoPlayer поддерживает HLS с несколькими форматами контейнеров. Необходимо также поддерживать содержащиеся в контейнере аудио- и видеоформаты (подробнее см. раздел « Форматы образцов »). Мы настоятельно рекомендуем производителям HLS-контента создавать высококачественные HLS-потоки, как описано в этой статье блога .

Особенность Поддерживается Комментарии
Контейнеры
MPEG-TS ДА
FMP4/CMAF ДА
ADTS (AAC) ДА
MP3 ДА
Субтитры / скрытые субтитры
CEA-608 ДА
CEA-708 ДА
WebVTT ДА
Метаданные
ID3 ДА
СКТЕ-35 НЕТ
Защита контента
АЭС-128 ДА
Образец AES-128 НЕТ
Уайдвин ДА API 19+ (схема "cenc") и 25+ (схема "cbcs")
PlayReady SL2000 ДА Только для Android TV
Управление сервером
Обновления Delta ДА
Блокировка перезагрузки плейлиста ДА
Блокировка загрузки подсказок предварительной загрузки ДА За исключением диапазонов байтов с неопределенной длиной.
Вставка рекламы
Вставка рекламы с управлением со стороны сервера (межстраничная реклама) Частично Только видео по запросу (VOD) с X-ASSET-URI . Прямые трансляции и X-ASSET-LIST будут добавлены позже.
Реклама на стороне сервера и на стороне клиента IMA ДА руководство по размещению рекламы
Воспроизведение в реальном времени
Обычное воспроизведение в прямом эфире ДА
Низкозадержечная HLS (Apple) ДА
Низкозадержечная HLS (Community) НЕТ
Данные клиента Common Media CMCD ДА руководство по интеграции CMCD

Использование MediaItem

Для воспроизведения HLS-потока необходимо использовать модуль HLS.

Котлин

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

Классный

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

Затем вы можете создать MediaItem для URI плейлиста HLS и передать его плееру.

Котлин

// 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();

Если ваш URI не заканчивается на .m3u8 , вы можете передать MimeTypes.APPLICATION_M3U8 в setMimeType объекта MediaItem.Builder , чтобы явно указать тип контента.

URI медиафайла может указывать либо на список воспроизведения, либо на многовариантный список воспроизведения. Если URI указывает на многовариантный список воспроизведения, содержащий несколько тегов #EXT-X-STREAM-INF , то ExoPlayer автоматически адаптируется между вариантами, учитывая как доступную пропускную способность, так и возможности устройства.

Использование HlsMediaSource

Для расширения возможностей настройки вы можете создать объект HlsMediaSource и передать его непосредственно плееру вместо MediaItem .

Котлин

// 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();

Доступ к манифесту

Текущий манифест можно получить, вызвав метод Player.getCurrentManifest . Для HLS следует привести возвращаемый объект к HlsManifest . Коллбэк onTimelineChanged метода Player.Listener также вызывается при каждой загрузке манифеста. Это произойдет один раз для контента по запросу и, возможно, много раз для контента в реальном времени. Следующий фрагмент кода показывает, как приложение может выполнить определенные действия при каждой загрузке манифеста.

Котлин

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.
        }
      }
    });

Воспроизводите HLS-трансляции с вставками.

Спецификация HLS определяет HLS-интерстициалы, которые можно использовать для включения промежуточной информации в плейлист медиафайлов. ExoPlayer по умолчанию игнорирует эти интерстициалы. Поддержку можно добавить с помощью HlsInterstitialsAdsLoader . Мы не поддерживаем все функции спецификации с самого начала. Если вам не хватает поддержки для вашего потока, сообщите нам об этом, создав проблему на GitHub и отправив нам URI вашего потока, чтобы мы могли добавить поддержку для вашего потока.

Используйте MediaItem с API плейлистов.

Наиболее удобный способ воспроизведения HLS-потоков с межстраничной рекламой — это создание экземпляра ExoPlayer с классом HlsInterstitialsAdsLoader.AdsMediaSourceFactory . Это позволяет использовать API плейлистов на основе MediaItem из интерфейса Player для воспроизведения HLS-межстраничной рекламы.

Компонент MediaSource.Factory объекта ExoPlayer можно внедрить в построитель при создании экземпляра проигрывателя:

Котлин

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);

При такой настройке плеера воспроизведение HLS-интерстициальной рекламы сводится к простой настройке медиафайла с параметром AdsConfiguration в плеере:

Котлин

// 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();

Используйте API на основе источника мультимедиа.

В качестве альтернативы, экземпляр ExoPlayer можно создать без переопределения фабрики источников мультимедиа по умолчанию. Для поддержки межстраничной рекламы приложение может использовать HlsInterstitialsAdsLoader.AdsMediaSourceFactory напрямую для создания MediaSource и предоставления его ExoPlayer с помощью API плейлистов на основе источников мультимедиа:

Котлин

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();

Слушайте рекламные события

К компоненту HlsInterstitialsAdsLoader можно добавить Listener для отслеживания событий, связанных с изменением статуса воспроизведения HLS-интерстициальной рекламы. Это позволяет приложению или SDK отслеживать воспроизведение рекламы, загрузку списков ресурсов, подготовку источников рекламного контента, а также выявлять ошибки загрузки списков ресурсов и подготовки рекламы. Кроме того, можно получать метаданные, передаваемые источниками рекламного контента, для более точной проверки воспроизведения рекламы или отслеживания прогресса воспроизведения.

Котлин

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.
  }
}

Подробное описание всех доступных функций обратного вызова см. в документации JavaDoc для HlsInterstitialsAdsLoader.Listener .

Затем обработчик событий можно добавить в загрузчик рекламы:

Котлин

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);

Жизненный цикл HlsInterstitialsAdsLoader

Экземпляр класса HlsInterstitialsAdsLoader или HlsInterstitialsAdsLoader.AdsMediaSourceFactory можно повторно использовать для нескольких экземпляров проигрывателя, которые создают несколько источников медиаконтента, для которых необходимо загрузить рекламу.

Экземпляр можно создать, например, в методе onCreate Activity , а затем повторно использовать для нескольких экземпляров плеера. Это работает до тех пор, пока он используется одним экземпляром плеера одновременно. Это полезно в распространенном случае, когда приложение переводится в фоновый режим, экземпляр плеера уничтожается, а затем новый экземпляр создается при повторном переводе приложения в активный режим.

Возобновление воспроизведения при наличии состояния воспроизведения рекламы.

Чтобы пользователям не приходилось пересматривать рекламу, состояние воспроизведения рекламы можно сохранить и восстановить при повторном создании плеера. Это делается путем вызова getAdsResumptionStates() перед завершением воспроизведения и сохранения возвращенных объектов AdsResumptionState . При повторном создании плеера состояние можно восстановить, вызвав addAdResumptionState() для экземпляра загрузчика рекламы. AdsResumptionState является пакетируемым, поэтому его можно сохранить в пакете onSaveInstanceState объекта Activity . Обратите внимание, что возобновление воспроизведения рекламы поддерживается только для видеопотоков по запросу (VOD).

Котлин

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);
    }
  }
}

Настройка воспроизведения

ExoPlayer предоставляет множество способов настроить воспроизведение в соответствии с потребностями вашего приложения. Примеры см. на странице «Настройка» .

Отключение подготовки без блоков

По умолчанию ExoPlayer использует подготовку без использования фрагментов. Это означает, что ExoPlayer будет использовать для подготовки потока только информацию из многовариантного плейлиста, что работает, если теги #EXT-X-STREAM-INF содержат атрибут CODECS .

Возможно, вам потребуется отключить эту функцию, если ваши медиасегменты содержат мультиплексированные дорожки субтитров, которые не указаны в многовариантном плейлисте с тегом #EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS . В противном случае эти дорожки субтитров не будут обнаружены и воспроизведены. Вы можете отключить подготовку без использования фрагментов в HlsMediaSource.Factory , как показано в следующем фрагменте кода. Обратите внимание, что это увеличит время запуска, поскольку ExoPlayer потребуется загрузить медиасегмент для обнаружения этих дополнительных дорожек, и предпочтительнее указывать дорожки субтитров в многовариантном плейлисте.

Котлин

val hlsMediaSource =
  HlsMediaSource.Factory(dataSourceFactory)
    .setAllowChunklessPreparation(false)
    .createMediaSource(MediaItem.fromUri(hlsUri))

Java

HlsMediaSource hlsMediaSource =
    new HlsMediaSource.Factory(dataSourceFactory)
        .setAllowChunklessPreparation(false)
        .createMediaSource(MediaItem.fromUri(hlsUri));

Создание высококачественного HLS-контента

Чтобы максимально эффективно использовать ExoPlayer, можно следовать определенным рекомендациям для улучшения качества HLS-контента. Подробное объяснение вы найдете в нашей статье на Medium о воспроизведении HLS в ExoPlayer . Основные моменты:

  • Используйте точную продолжительность сегментов.
  • Используйте непрерывный медиапоток; избегайте изменений в структуре медиаконтента между сегментами.
  • Используйте тег #EXT-X-INDEPENDENT-SEGMENTS .
  • Предпочтительнее использовать демультиплексированные потоки, а не файлы, содержащие как видео, так и аудио.
  • Включите в многовариантный плейлист всю доступную информацию.

Следующие правила применяются исключительно к прямым трансляциям:

  • Используйте тег #EXT-X-PROGRAM-DATE-TIME .
  • Используйте тег #EXT-X-DISCONTINUITY-SEQUENCE .
  • Предоставьте достаточно длительный временной интервал для трансляции. Одна минута или больше — отлично.