HLS

ExoPlayer は、複数のコンテナ形式の HLS をサポートしています。含まれる音声と動画のサンプル形式もサポートされている必要があります(詳しくは、サンプル形式のセクションをご覧ください)。HLS コンテンツの制作者には、こちらのブログ投稿で説明されているように、高品質の HLS ストリームを生成することを強くおすすめします。

機能 サポート対象 コメント
コンテナ
MPEG-TS
FMP4/CMAF
ADTS(AAC)
MP3
字幕 / クローズド キャプション
CEA-608
CEA-708
WebVTT
メタデータ
ID3
SCTE-35 いいえ
コンテンツの保護
AES-128
AES-128 のサンプル いいえ
Widevine API 19+(「cenc」スキーム)および 25+(「cbcs」スキーム)
PlayReady SL2000 Android TV のみ
サーバー制御
差分更新
再生リストの再読み込みをブロック
プリロード ヒントの読み込みをブロック 長さが未定義のバイト範囲を除く
広告挿入
サーバーガイド付き広告挿入 (インタースティシャル) 部分的 X-ASSET-URI の VOD のみ。ライブ配信と X-ASSET-LIST は後で追加されます。
IMA サーバーサイド広告とクライアントサイド広告 広告挿入ガイド
ライブ再生
通常のライブ再生
低遅延 HLS(Apple)
低レイテンシ HLS(コミュニティ) いいえ
共通メディア クライアント データ CMCD CMCD 統合ガイド

MediaItem の使用

HLS ストリームを再生するには、HLS モジュールに依存する必要があります。

Kotlin

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

Groovy

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

その後、HLS 再生リスト URI の MediaItem を作成して、プレーヤーに渡すことができます。

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

URI が .m3u8 で終わらない場合は、MediaItem.BuildersetMimeTypeMimeTypes.APPLICATION_M3U8 を渡して、コンテンツのタイプを明示的に示すことができます。

メディア アイテムの URI は、メディア プレイリストまたはマルチバリアント プレイリストのいずれかを指す場合があります。URI が複数の #EXT-X-STREAM-INF タグを宣言するマルチバリアント プレイリストを指している場合、ExoPlayer は利用可能な帯域幅とデバイスの機能の両方を考慮して、バリアント間で自動的に適応します。

HlsMediaSource を使用する

カスタマイズ オプションをさらに追加するには、MediaItem の代わりに HlsMediaSource を作成してプレーヤーに直接渡します。

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

マニフェストへのアクセス

現在のマニフェストを取得するには、Player.getCurrentManifest を呼び出します。HLS の場合は、返されたオブジェクトを HlsManifest にキャストする必要があります。また、マニフェストが読み込まれるたびに、Player.ListeneronTimelineChanged コールバックも呼び出されます。オンデマンド コンテンツの場合は 1 回、ライブ コンテンツの場合は複数回発生する可能性があります。次のコード スニペットは、マニフェストが読み込まれるたびにアプリが何らかの処理を行う方法を示しています。

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

インタースティシャルを含む HLS ストリームを再生する

HLS 仕様では、メディア再生リストにインタースティシャル情報を含めるために使用できる HLS インタースティシャルが定義されています。ExoPlayer はデフォルトでこれらのインタースティシャルを無視します。サポートは HlsInterstitialsAdsLoader を使用して追加できます。仕様のすべての機能が最初からサポートされるわけではありません。ストリームのサポートが不足している場合は、GitHub で問題を報告し、ストリーム URI をお送りください。ストリームのサポートを追加いたします。

プレイリスト API で MediaItem を使用する

インタースティシャルを含む HLS ストリームを再生する最も便利な方法は、HlsInterstitialsAdsLoader.AdsMediaSourceFactory を使用して ExoPlayer インスタンスをビルドすることです。これにより、Player インターフェースの MediaItem ベースのプレイリスト API を使用して HLS インタースティシャルを再生できます。

プレーヤー インスタンスのビルド時に、ExoPlayerMediaSource.Factory をビルダーに挿入できます。

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

このようなプレーヤーの設定では、HLS インタースティシャルを再生するには、プレーヤーで AdsConfiguration を使用してメディア アイテムを設定するだけです。

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

メディアソース ベースの API を使用する

または、デフォルトのメディアソース ファクトリをオーバーライドせずに ExoPlayer インスタンスをビルドすることもできます。インタースティシャルをサポートするために、アプリは HlsInterstitialsAdsLoader.AdsMediaSourceFactory を直接使用して MediaSource を作成し、メディアソース ベースのプレイリスト API を使用して ExoPlayer に提供できます。

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

広告イベントをリッスンする

ListenerHlsInterstitialsAdsLoader に追加して、HLS インタースティシャル再生に関するステータス変更のイベントをモニタリングできます。これにより、アプリや SDK は、再生された広告、読み込まれているアセット リスト、準備中の広告メディア ソースをトラッキングしたり、アセット リストの読み込みエラーや広告の準備エラーを検出したりできます。また、広告メディア ソースから出力されたメタデータを受信して、広告再生のきめ細かい検証や広告再生の進行状況のトラッキングを行うことができます。

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

使用可能なすべてのコールバックの詳細なドキュメントについては、HlsInterstitialsAdsLoader.Listener の JavaDoc をご覧ください。

リスナーを広告ローダーに追加できます。

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

HlsInterstitialsAdsLoader ライフサイクル

HlsInterstitialsAdsLoader または HlsInterstitialsAdsLoader.AdsMediaSourceFactory のインスタンスは、広告を読み込む必要がある複数のメディアソースを作成する複数のプレーヤー インスタンスで再利用できます。

たとえば、ActivityonCreate メソッドでインスタンスを作成し、複数のプレーヤー インスタンスで再利用できます。これは、同時に 1 つのプレーヤー インスタンスで使用されている場合に機能します。これは、アプリがバックグラウンドに移行し、プレーヤー インスタンスが破棄されてから、アプリが再びフォアグラウンドに移行したときに新しいインスタンスが作成されるという一般的なユースケースで役立ちます。

広告の再生状態を使用した再生の再開

ユーザーが広告を再度視聴する必要がないように、プレーヤーが再作成されたときに広告の再生状態を保存して復元できます。これは、プレーヤーが解放される直前に getAdsResumptionStates() を呼び出し、返された AdsResumptionState オブジェクトを保存することで行われます。プレーヤーが再作成されると、広告ローダー インスタンスで addAdResumptionState() を呼び出すことで状態を復元できます。AdsResumptionState はバンドル可能であるため、ActivityonSaveInstanceState バンドルに保存できます。広告の再開は 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);
    }
  }
}

再生をカスタマイズする

ExoPlayer には、アプリのニーズに合わせて再生エクスペリエンスを調整するための複数の方法が用意されています。例については、カスタマイズ ページをご覧ください。

チャンクレス準備を無効にする

デフォルトでは、ExoPlayer はチャンクレス準備を使用します。つまり、ExoPlayer はマルチバリアント プレイリストの情報のみを使用してストリームを準備します。これは、#EXT-X-STREAM-INF タグに CODECS 属性が含まれている場合に機能します。

メディア セグメントに、#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS タグを使用してマルチバリアント再生リストで宣言されていない多重化されたクローズド キャプション トラックが含まれている場合は、この機能を無効にする必要があります。そうしないと、これらの字幕トラックは検出されず、再生されません。次のスニペットに示すように、HlsMediaSource.Factory でチャンクなしの準備を無効にできます。ExoPlayer はこれらの追加トラックを検出するためにメディア セグメントをダウンロードする必要があるため、起動時間が長くなります。そのため、代わりにマルチバリアント プレイリストでクローズド キャプション トラックを宣言することをおすすめします。

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

高品質な HLS コンテンツを作成する

ExoPlayer を最大限に活用するには、HLS コンテンツを改善するためのガイドラインに沿って対応する必要があります。詳細については、ExoPlayer での HLS 再生に関する Medium の投稿をご覧ください。主なポイントは次のとおりです。

  • 正確なセグメントの長さを使用します。
  • 連続したメディア ストリームを使用します。セグメント間でメディア構造を変更しないでください。
  • #EXT-X-INDEPENDENT-SEGMENTS タグを使用します。
  • 動画と音声の両方を含むファイルではなく、デマルチプレックスされたストリームを優先します。
  • マルチバリエーション再生リストに、可能な限りすべての情報を含めます。

ライブ ストリームには、次のガイドラインが適用されます。

  • #EXT-X-PROGRAM-DATE-TIME タグを使用します。
  • #EXT-X-DISCONTINUITY-SEQUENCE タグを使用します。
  • ライブ ウィンドウを長くします。1 分以上が理想的です。