网络堆栈

ExoPlayer 通常用于通过互联网流式传输媒体内容。它支持使用多个网络堆栈发出底层网络请求。具体选择哪种方式,完全由你决定 可能会对流式传输性能产生重大影响。

本页概述了如何配置 ExoPlayer 以使用 列出了可用的选项,并提供了一些有关如何 并说明如何为流式播放启用缓存 媒体。

配置 ExoPlayer 以使用特定的网络堆栈

ExoPlayer 通过 DataSource 组件加载数据,该组件会从 从应用代码注入的 DataSource.Factory 实例。

如果您的应用只需播放 http(s) 内容,请选择一个网络 就像更新任意 DataSource.Factory 实例一样简单, 应用注入为 HttpDataSource.Factory 的实例 与您要使用的网络堆栈相对应如果您的应用还 需要播放非 http(s) 内容(如本地文件)、 DefaultDataSource.Factory

Kotlin

DefaultDataSource.Factory(
  ...
  /* baseDataSourceFactory= */ PreferredHttpDataSource.Factory(...))

Java

new DefaultDataSource.Factory(
    ...
    /* baseDataSourceFactory= */ new PreferredHttpDataSource.Factory(...));

在此示例中,PreferredHttpDataSource.Factory 是与您的 首选网络堆栈DefaultDataSource.Factory 层添加了支持 用于非 http(s) 来源,例如本地文件。

以下示例展示了如何构建将使用 Cronet 网络堆栈并支持播放非 http(s) 内容的 ExoPlayer

Kotlin

// Given a CronetEngine and Executor, build a CronetDataSource.Factory.
val cronetDataSourceFactory = CronetDataSource.Factory(cronetEngine, executor)

// Wrap the CronetDataSource.Factory in a DefaultDataSource.Factory, which adds
// in support for requesting data from other sources (such as files, resources,
// etc).
val dataSourceFactory =
  DefaultDataSource.Factory(context, /* baseDataSourceFactory= */ cronetDataSourceFactory)

// Inject the DefaultDataSource.Factory when creating the player.
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(
      DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory)
    )
    .build()

Java

// Given a CronetEngine and Executor, build a CronetDataSource.Factory.
CronetDataSource.Factory cronetDataSourceFactory =
    new CronetDataSource.Factory(cronetEngine, executor);

// Wrap the CronetDataSource.Factory in a DefaultDataSource.Factory, which adds
// in support for requesting data from other sources (such as files, resources,
// etc).
DefaultDataSource.Factory dataSourceFactory =
    new DefaultDataSource.Factory(
        context, /* baseDataSourceFactory= */ cronetDataSourceFactory);

// Inject the DefaultDataSource.Factory when creating the player.
ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory))
        .build();

支持的网络堆栈

ExoPlayer 直接支持 HttpEngine、Cronet、OkHttp 和 Android 的 内置默认网络堆栈ExoPlayer 还可以经过扩展,以支持 其他网络堆栈

HttpEngine

从 API 34(或 S 扩展程序 7)开始,Android 上推荐的默认网络堆栈是 HttpEngine。在大多数情况下,它在内部使用 Cronet 网络堆栈, 支持基于 QUIC 协议的 HTTP、HTTP/2 和 HTTP/3。

ExoPlayer 通过其 HttpEngineDataSource.Factory 支持 HttpEngine。您可以 按照配置 ExoPlayer 以使用 特定网络堆栈

Cronet

Cronet 是以库的形式提供给 Android 应用使用的 Chromium 网络堆栈。Cronet 利用多种技术来减少延迟和提高网络请求吞吐量,以满足您的应用的运行需要,包括 ExoPlayer 发出的请求。它以原生方式支持基于 QUIC 的 HTTP、HTTP/2 和 HTTP/3 协议一些全球最大的在线媒体应用(包括 YouTube)都使用 Cronet。

ExoPlayer 支持 Cronet, Cronet 库。 如需详细了解如何使用,请参阅库的 README.md 。请注意,Cronet 库能够使用三个底层 Cronet 实现:

  1. Google Play 服务:我们建议在大多数情况下使用此实现, 以及回退到 Android 的内置网络堆栈 (DefaultHttpDataSource) 如果 Google Play 服务不可用。
  2. Cronet Embedded:如果您的大部分用户都使用这项服务,这会是个不错的选择 位于未广泛提供 Google Play 服务的市场,或者 想要控制正在使用的 Cronet 实现的确切版本。Cronet 嵌入的主要缺点是会使应用增加大约 8MB。
  3. Cronet 回退:Cronet 的回退实现会将 Cronet 的 API 作为 Android 内置网络堆栈的封装容器来实现。不应将其与 ExoPlayer 搭配使用,因为直接使用 Android 的内置网络堆栈(通过使用 DefaultHttpDataSource)更高效。

OkHttp

OkHttp 是另一种新型网络堆栈, 被许多热门的 Android 应用广泛使用。它支持 HTTP 和 HTTP/2,但尚不支持通过 QUIC 使用 HTTP/3。

ExoPlayer 支持 OkHttp,只需为其提供 OkHttp 库。 如需详细了解如何使用该库,请参阅该库的 README.md。使用 OkHttp 库时,网络堆栈会嵌入到应用中。这与 Cronet 嵌入式类似,但 OkHttp 的大小要小得多,只会为应用增加不到 1MB 的大小。

Android 的内置网络堆栈

ExoPlayer 支持将 Android 的内置网络堆栈与 DefaultHttpDataSourceDefaultHttpDataSource.Factory 搭配使用,这两者是核心 ExoPlayer 库的一部分。

确切的网络堆栈实现取决于底层设备上运行的软件。大多数设备仅支持 HTTP(即不支持通过 QUIC 的 HTTP/2 和 HTTP/3)。

其他网络栈

应用还可以将其他网络堆栈与 ExoPlayer 集成。 为此,请实现封装网络堆栈的 HttpDataSource 以及相应的 HttpDataSource.Factory。ExoPlayer 的 Cronet 和 OkHttp 库就是很好的示例。

与纯 Java 网络堆栈集成时,最好实现 DataSourceContractTest 以检查 HttpDataSource 实现是否正常运行。OkHttp 库中的 OkHttpDataSourceContractTest 是 这是一个不错的例子。

选择网络堆栈

下表概述了 ExoPlayer 支持的网络堆栈的优缺点。

网络堆栈 协议 APK 大小影响 备注
HttpEngine HTTP
HTTP/2
HTTP/3 over QUIC
仅适用于 API 34 或 S 扩展 7
Cronet(Google Play 服务) HTTP
HTTP/2
HTTP/3 over QUIC

(小于 100KB)
需要 Google Play 服务。Cronet 版本已自动更新
Cronet(嵌入式) HTTP
HTTP/2
HTTP/3(基于 QUIC)

(约 8MB)
由应用开发者控制的 Cronet 版本
Cronet(后备) HTTP
(因设备而异)

(<100KB)
不推荐用于 ExoPlayer
OkHttp HTTP
HTTP/2

(小于 1MB)
内置网络堆栈 HTTP
(因设备而异)
实现因设备而异

通过 QUIC 协议实现的 HTTP/2 和 HTTP/3 可以显著提升媒体在线播放性能。特别是,当流式传输 使用内容分发网络 (CDN) 分发,则在某些情况下, 使用这些协议可让 CDN 更高效地运行 因此,与使用 Android 的内置网络堆栈相比,HttpEngine 和 Cronet 通过 QUIC 同时支持 HTTP/2 和 HTTP/3(以及 OkHttp 支持 HTTP/2)是一项重大优势,前提是托管内容的服务器也支持这些协议。

单独考虑媒体流式传输时,我们建议使用 Google Play 服务提供的 HttpEngine 或 Cronet,并在 Google Play 服务不可用时回退到 DefaultHttpDataSource。此建议在支持在大多数设备上通过 QUIC 使用 HTTP/2 和 HTTP/3 与避免 APK 大小大幅增加之间取得了良好的平衡。不过,也有例外情况 建议。针对可能无法使用 Google Play 服务的情况 在很大一部分设备上运行您的应用时 使用 Cronet Embedded 或 OkHttp 可能更加合适。使用内置 如果 APK 大小非常关键,或者如果媒体 流式传输只是应用功能的一小部分。

除了媒体之外,通常最好选择单个网络堆栈 为您的应用执行的所有网络配置数据。这样,资源便可 (例如套接字)在 ExoPlayer 和其他 应用组件。

因为您的应用很可能需要执行与网络无关的连接 到媒体播放,您对网络堆栈的选择最终应考虑我们的 单独进行媒体流式传输时,所有媒体流的 执行网络连接的其他组件,以及它们对您的应用的 应用。

缓存媒体

ExoPlayer 支持将加载的字节缓存到磁盘,以防止重复加载 来自网络的相同字节当在当前媒体中快退或重复同一项时,此功能非常有用。

缓存需要指向专用缓存的 SimpleCache 实例 目录和 CacheDataSource.Factory

Kotlin

// Note: This should be a singleton in your app.
val databaseProvider = StandaloneDatabaseProvider(context)

// An on-the-fly cache should evict media when reaching a maximum disk space limit.
val cache =
    SimpleCache(
        downloadDirectory, LeastRecentlyUsedCacheEvictor(maxBytes), databaseProvider)

// Configure the DataSource.Factory with the cache and factory for the desired HTTP stack.
val cacheDataSourceFactory =
    CacheDataSource.Factory()
        .setCache(cache)
        .setUpstreamDataSourceFactory(httpDataSourceFactory)

// Inject the DefaultDataSource.Factory when creating the player.
val player =
    ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory))
        .build()

Java

// Note: This should be a singleton in your app.
DatabaseProvider databaseProvider = new StandaloneDatabaseProvider(context);

// An on-the-fly cache should evict media when reaching a maximum disk space limit.
Cache cache =
    new SimpleCache(
        downloadDirectory, new LeastRecentlyUsedCacheEvictor(maxBytes), databaseProvider);

// Configure the DataSource.Factory with the cache and factory for the desired HTTP stack.
DataSource.Factory cacheDataSourceFactory =
    new CacheDataSource.Factory()
        .setCache(cache)
        .setUpstreamDataSourceFactory(httpDataSourceFactory);

// Inject the DefaultDataSource.Factory when creating the player.
ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory))
        .build();