HLS

ExoPlayer mendukung HLS dengan beberapa format penampung. Format contoh audio dan video yang disertakan juga harus didukung (lihat bagian format contoh untuk mengetahui detailnya). Sebaiknya produsen konten HLS membuat streaming HLS berkualitas tinggi, seperti yang dijelaskan dalam postingan blog ini.

Fitur Didukung Komentar
Container
MPEG-TS YA
FMP4/CMAF YA
ADTS (AAC) YA
MP3 YA
Teks tertutup / subtitel
CEA-608 YA
CEA-708 YA
WebVTT YA
Metadata
ID3 YA
SCTE-35 TIDAK
Perlindungan konten
AES-128 YA
Contoh AES-128 TIDAK
Widevine YA API 19+ ("skema cenc") dan 25+ ("skema cbcs")
PlayReady SL2000 YA Khusus Android TV
Kontrol server
Update delta YA
Memblokir pemuatan ulang playlist YA
Memblokir pemuatan petunjuk pramuat YA Kecuali untuk byterange dengan panjang yang tidak ditentukan
Penyisipan iklan
Penyisipan iklan terpandu server (Interstisial) Sebagian Hanya VOD dengan X-ASSET-URI. Live stream dan X-ASSET-LIST akan ditambahkan nanti.
Iklan sisi server dan sisi klien IMA YA Panduan penyisipan iklan
Pemutaran live
Pemutaran live reguler YA
HLS latensi rendah (Apple) YA
HLS latensi rendah (Komunitas) TIDAK
Common Media Client Data CMCD YA Panduan integrasi CMCD

Menggunakan MediaItem

Untuk memutar streaming HLS, Anda harus bergantung pada modul HLS.

Kotlin

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

Groovy

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

Kemudian, Anda dapat membuat MediaItem untuk URI playlist HLS dan meneruskannya ke pemutar.

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

Jika URI tidak diakhiri dengan .m3u8, Anda dapat meneruskan MimeTypes.APPLICATION_M3U8 ke setMimeType dari MediaItem.Builder untuk secara eksplisit menunjukkan jenis konten.

URI item media dapat mengarah ke playlist media atau playlist multivarian. Jika URI mengarah ke playlist multivarian yang mendeklarasikan beberapa tag #EXT-X-STREAM-INF, ExoPlayer akan otomatis beradaptasi di antara varian, dengan mempertimbangkan bandwidth yang tersedia dan kemampuan perangkat.

Menggunakan HlsMediaSource

Untuk opsi penyesuaian lainnya, Anda dapat membuat HlsMediaSource dan meneruskannya langsung ke pemutar, bukan 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();

Mengakses manifes

Anda dapat mengambil manifes saat ini dengan memanggil Player.getCurrentManifest. Untuk HLS, Anda harus mentransmisikan objek yang ditampilkan ke HlsManifest. Callback onTimelineChanged dari Player.Listener juga dipanggil setiap kali manifes dimuat. Hal ini akan terjadi sekali untuk konten on demand dan mungkin berkali-kali untuk konten live. Cuplikan kode berikut menunjukkan cara aplikasi dapat melakukan sesuatu setiap kali manifes dimuat.

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

Memutar streaming HLS dengan interstisial

Spesifikasi HLS menentukan interstisial HLS yang dapat digunakan untuk menyertakan informasi interstisial dalam playlist media. ExoPlayer secara default mengabaikan interstisial ini. Dukungan dapat ditambahkan menggunakan HlsInterstitialsAdsLoader. Kami tidak mendukung semua fitur spesifikasi sejak awal. Jika Anda tidak mendapatkan dukungan untuk streaming, beri tahu kami dengan melaporkan masalah di GitHub dan kirimkan URI streaming Anda, sehingga kami dapat menambahkan dukungan untuk streaming Anda.

Menggunakan MediaItem dengan playlist API

Cara paling praktis untuk memutar streaming HLS dengan interstisial adalah dengan mem-build instance ExoPlayer dengan HlsInterstitialsAdsLoader.AdsMediaSourceFactory. Hal ini memungkinkan penggunaan playlist API berbasis MediaItem dari antarmuka Player untuk memutar interstisial HLS.

MediaSource.Factory dari ExoPlayer dapat dimasukkan ke builder saat mem-build instance pemutar:

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

Dengan penyiapan pemutar seperti itu, memutar interstisial HLS hanya dengan menetapkan item media dengan AdsConfiguration di pemutar:

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

Menggunakan API berbasis sumber media

Atau, instance ExoPlayer dapat dibuat tanpa mengganti factory sumber media default. Untuk mendukung interstisial, aplikasi kemudian dapat menggunakan HlsInterstitialsAdsLoader.AdsMediaSourceFactory secara langsung untuk membuat MediaSource dan menyediakannya ke ExoPlayer menggunakan API playlist berbasis sumber media:

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

Memproses peristiwa iklan

Listener dapat ditambahkan ke HlsInterstitialsAdsLoader untuk memantau peristiwa terkait perubahan status terkait pemutaran interstisial HLS. Hal ini memungkinkan aplikasi atau SDK melacak iklan yang diputar, daftar aset yang dimuat, sumber media iklan yang disiapkan, atau mendeteksi pemuatan daftar aset dan error penyiapan iklan. Selain itu, metadata yang dipancarkan oleh sumber media iklan dapat diterima untuk verifikasi pemutaran iklan yang terperinci atau untuk melacak progres pemutaran iklan.

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 of HlsInterstitialsAdsLoader.Listener.

  @Override
  public void onStop(MediaItem mediaItem, Object adsId, AdPlaybackState adPlaybackState) {
    // Do something with the resulting ad playback state when stopped.
  }
}

Pemroses kemudian dapat ditambahkan ke loader iklan:

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

Siklus proses HlsInterstitialsAdsLoader

Instance HlsInterstitialsAdsLoader atau HlsInterstitialsAdsLoader.AdsMediaSourceFactory dapat digunakan kembali untuk beberapa instance pemutar yang membuat beberapa sumber media yang iklannya harus dimuat.

Instance dapat dibuat, misalnya dalam metode onCreate dari Activity, lalu digunakan kembali untuk beberapa instance pemain. Hal ini berfungsi selama digunakan oleh satu instance pemain secara bersamaan. Hal ini berguna untuk kasus penggunaan umum saat aplikasi dipindahkan ke latar belakang, instance pemain akan dihancurkan, lalu instance baru akan dibuat saat aplikasi kembali ke latar depan.

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

Umumnya, pastikan untuk merilis instance pemutar lama sebelum menetapkan instance pemutar berikutnya di loader iklan. Setelah loader iklan itu sendiri dirilis, loader iklan tidak dapat digunakan lagi.

Menyesuaikan pemutaran

ExoPlayer menyediakan beberapa cara bagi Anda untuk menyesuaikan pengalaman pemutaran dengan kebutuhan aplikasi. Lihat Halaman penyesuaian untuk mengetahui contohnya.

Menonaktifkan persiapan tanpa bagian

Secara default, ExoPlayer akan menggunakan persiapan tanpa potongan. Artinya, ExoPlayer hanya akan menggunakan informasi dalam playlist multivarian untuk menyiapkan streaming, yang berfungsi jika tag #EXT-X-STREAM-INF berisi atribut CODECS.

Anda mungkin perlu menonaktifkan fitur ini jika segmen media Anda berisi trek teks tertutup yang di-mux yang tidak dideklarasikan dalam playlist multivarian dengan tag #EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS. Jika tidak, trek teks tertutup ini tidak akan terdeteksi dan diputar. Anda dapat menonaktifkan persiapan tanpa bagian di HlsMediaSource.Factory seperti yang ditunjukkan dalam cuplikan berikut. Perhatikan bahwa hal ini akan meningkatkan waktu mulai karena ExoPlayer perlu mendownload segmen media untuk menemukan trek tambahan ini dan sebaiknya deklarasikan trek teks tertutup di playlist multivarian.

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

Membuat konten HLS berkualitas tinggi

Untuk mendapatkan hasil maksimal dari ExoPlayer, ada panduan tertentu yang dapat Anda ikuti untuk meningkatkan kualitas konten HLS. Baca postingan Medium tentang pemutaran HLS di ExoPlayer untuk mengetahui penjelasan selengkapnya. Poin utamanya adalah:

  • Gunakan durasi segmen yang tepat.
  • Gunakan streaming media berkelanjutan; hindari perubahan pada struktur media di seluruh segmen.
  • Gunakan tag #EXT-X-INDEPENDENT-SEGMENTS.
  • Pilih streaming yang telah didemux, bukan file yang menyertakan video dan audio.
  • Sertakan semua informasi yang dapat Anda sertakan dalam Playlist Multivarian.

Panduan berikut berlaku khusus untuk live stream:

  • Gunakan tag #EXT-X-PROGRAM-DATE-TIME.
  • Gunakan tag #EXT-X-DISCONTINUITY-SEQUENCE.
  • Berikan periode aktif yang lama. Satu menit atau lebih akan sangat bagus.