HLS

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

ویژگی پشتیبانی می‌شود نظرات
محفظه‌ها
MPEG-TS بله
FMP4/CMAF بله
ADTS (AAC)‎ بله
MP3 بله
زیرنویس ناشنوایان / زیرنویس
CEA-608 بله
CEA-708 بله
WebVTT بله
فراداده
ID3 بله
SCTE-35 نه
حفاظت از محتوا
اِی‌ای‌اس-۱۲۸ بله
نمونه اِی‌ای‌اس-۱۲۸ نه
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 را برای 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()

جاوا

// 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 منتقل کنید تا نوع محتوا را به‌طور صریح نشان دهید.

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

جاوا

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

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

جاوا

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

استفاده از میانای برنامه‌سازی کاربردی مبتنی بر منبع رسانه

یا اینکه نمونه 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";

  private @Nullable HlsInterstitialsAdsLoader hlsInterstitialsAdsLoader;
  private @Nullable PlayerView playerView;
  private @Nullable 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 استفاده کنید.
  • بازه فعال بودن طولانی ارائه دهید. یک دقیقه یا بیشتر عالی است.