HLS

‫ExoPlayer از HLS با قالب‌های چندگانه محتوا پشتیبانی می‌کند. قالب‌های نمونه صوتی و ویدیویی موجود در آن نیز باید پشتیبانی شوند (برای جزئیات، به بخش قالب‌های نمونه مراجعه کنید). ما به‌شدت تولیدکنندگان محتوای HLS را تشویق می‌کنیم که جاری‌سازی‌های HLS با کیفیت بالا تولید کنند، همان‌طور که در این پست وبلاگ توضیح داده شده است.

ویژگی پشتیبانی می‌شود نظرات
محتوی‌ها
MPEG-TS بله
FMP4/CMAF بله
ADTS (AAC) بله
MP3 بله
زیرنویس ناشنوایان / زیرنویس
CEA-608 بله
CEA-708 بله
WebVTT بله
فراداده
ID3 بله
SCTE-35 نه
حفاظت از محتوا
اِی‌ای‌اس-۱۲۸ بله
نمونه AES-128 نه
Widevine بله ‫API 19+ (طرح «cenc») و ‫25+ (طرح «cbcs»)
PlayReady SL2000 بله فقط Android TV
کنترل سرور
به‌روزرسانی‌های دلتا بله
جلوگیری از بارگیری مجدد فهرست پخش بله
درحال مسدود کردن بار کردن اشاره‌های پیش‌بارگیری بله به‌جز برای محدوده‌های بایت با طول‌های تعریف‌نشده
درج آگهی
درج آگهی با هدایت سرور (بینابینی‌ها) تاحدودی فقط ویدیو به‌درخواست با X-ASSET-URI. جاری‌سازی‌های زنده و X-ASSET-LIST بعداً اضافه خواهند شد.
آگهی‌های سمت سرور و سمت مشتری IMA بله راهنمای درج آگهی
بازپخش زنده
بازپخش زنده معمولی بله
HLS با تأخیر کم (Apple) بله
‫HLS با تأخیر کم (انجمن) نه
داده‌های مشترک کارخواه رسانه CMCD بله راهنمای یکپارچه‌سازی CMCD

درحال استفاده از MediaItem

برای پخش جاری‌سازی HLS، باید به واحد HLS وابسته باشید.

کاتلین

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

شیک

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

سپس می‌توانید یک MediaItem برای نشانی وب فهرست پخش 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()

جاوا

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

اگر شناسه منبع یکنواخت شما با .m3u8 تمام نمی‌شود، می‌توانید MimeTypes.APPLICATION_M3U8 را به setMimeType از MediaItem.Builder منتقل کنید تا نوع محتوا را به‌طور صریح مشخص کنید.

نشانی وب عنصر رسانه‌ای ممکن است به فهرست پخش رسانه‌ای یا فهرست پخش چندمتغیره اشاره کند. اگر شناسه منبع یکنواخت به فهرست پخش چندمتغیره که چندین برچسب #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()

جاوا

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

جاوا

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 به ما اطلاع دهید و نشانی وب جاری‌سازی‌تان را برای ما ارسال کنید تا بتوانیم پشتیبانی از جاری‌سازی‌تان را اضافه کنیم.

استفاده از MediaItem با API فهرست پخش

راحت‌ترین راه برای پخش جاری‌سازی‌های HLS با میان‌آگهی‌ها، ساختن نمونه ExoPlayer با HlsInterstitialsAdsLoader.AdsMediaSourceFactory است. این امکان استفاده از MediaItem مبتنی بر API فهرست پخش از 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)

جاوا

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

جاوا

// 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 ارائه دهد:

کاتلین

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

جاوا

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

گوش دادن به رویدادهای آگهی

یک Listener می‌تواند به HlsInterstitialsAdsLoader اضافه شود تا رویدادهای مربوط به تغییرات وضعیت پخش میان‌آگهی‌های HLS را نظارت کند. این کار به برنامه یا کیت توسعه نرم‌افزار اجازه می‌دهد آگهی‌های پخش‌شده، فهرست‌های دارایی بارگیری‌شده، منابع رسانه‌ای آگهی درحال آماده‌سازی را ردیابی کند یا خطاهای آماده‌سازی آگهی و بارگیری فهرست دارایی را شناسایی کند. علاوه‌براین، فراداده منتشرشده توسط منابع رسانه‌ای آگهی می‌تواند برای تأیید دقیق پخش آگهی یا برای پیگیری پیشرفت پخش آگهی دریافت شود.

کاتلین

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

جاوا

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

جاوا

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 ذخیره شود. توجه داشته باشید که ازسرگیری آگهی فقط برای جاری‌سازی‌های «ویدیو به‌درخواست» پشتیبانی می‌شود

کاتلین

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

  @Suppress("DEPRECATION") // getParcelableArrayList without class type is deprecated in API 33+
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // Create the ads loader instance.
    hlsInterstitialsAdsLoader = HlsInterstitialsAdsLoader(this)
    // Restore ad resumption states.
    val bundles =
      if (Build.VERSION.SDK_INT >= 33) {
        savedInstanceState?.getParcelableArrayList(ADS_RESUMPTION_STATE_KEY, Bundle::class.java)
      } else {
        savedInstanceState?.getParcelableArrayList(ADS_RESUMPTION_STATE_KEY)
      }
    adsResumptionStates = bundles?.map(HlsInterstitialsAdsLoader.AdsResumptionState::fromBundle)
  }

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

جاوا

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

  @SuppressWarnings(
      "deprecation") // getParcelableArrayList without class type is deprecated in API 33+
  @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;
      if (Build.VERSION.SDK_INT >= 33) {
        bundles =
            savedInstanceState.getParcelableArrayList(ADS_RESUMPTION_STATE_KEY, Bundle.class);
      } else {
        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))

جاوا

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 استفاده کنید.
  • یک پنجره طولانی برای پخش زنده ارائه دهید. یک دقیقه یا بیشتر عالی است.