HLS

ExoPlayer 支持采用多种容器格式的 HLS。所包含的音频和视频示例格式也必须受支持(详情请参阅示例格式部分)。我们强烈建议 HLS 内容制作者生成高品质 HLS 流,如此处所述。

功能 支持 评论
容器
MPEG-TS
FMP4/CMAF
ADTS (AAC)
MP3
字幕
CEA-608
CEA-708
WebVTT
Metadata
ID3
SCTE-35
内容保护
AES-128
AES-128 示例
Widevine API 19+(“cenc”架构)和 25+(“cbcs”架构)
PlayReady SL2000 仅分发至 Android TV
服务器控制
增量更新
禁止重新加载播放列表
阻止预加载提示的加载 长度未定义的 byterange 除外
实时播放
定期直播
低延迟 HLS (Apple)
低延迟 HLS(社区)
通用媒体客户端数据 (CMCD) 集成指南

使用 MediaItem

若要播放 HLS 视频流,您需要依赖于 HLS 模块。

Kotlin

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

Groovy

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

然后,您可以为 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 结尾,您可以将 MimeTypes.APPLICATION_M3U8 传递给 MediaItem.BuildersetMimeType,以明确指明内容的类型。

媒体项的 URI 可以指向媒体播放列表或多变体播放列表。如果 URI 指向声明了多个 #EXT-X-STREAM-INF 标记的多变体播放列表,ExoPlayer 会在考虑可用带宽和设备能力的前提下自动适应变体。

使用 HlsMediaSource

如需使用更多自定义选项,您可以创建 HlsMediaSource 并将其直接传递给播放器,而不是 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();

访问清单

您可以通过调用 Player.getCurrentManifest 来检索当前清单。对于 HLS,您应将返回的对象转换为 HlsManifest。每当加载清单时,系统也会调用 Player.ListeneronTimelineChanged 回调。对于点播内容,这种情况将发生一次,对于直播内容,可能也会发生多次。以下代码段展示了应用在清单加载时如何执行某项操作。

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

自定义播放

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 标记。
  • 提供一个长实时窗口。一分钟或更长时间比较好。