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 组件的 ExoPlayer
网络堆栈,还支持播放非 http(s) 内容。
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
HttpEngine 是 API 级别 34(或 Android S)在 Android 上建议的默认网络堆栈 扩展程序 7)。在大多数情况下,它在内部使用 Cronet 网络堆栈, 支持基于 QUIC 协议的 HTTP、HTTP/2 和 HTTP/3。
ExoPlayer 通过其 HttpEngineDataSource.Factory
支持 HttpEngine。您可以
按照配置 ExoPlayer 以使用
特定网络堆栈。
Cronet
Cronet 是 Chromium 网络堆栈以库的形式提供给 Android 应用。Cronet 通过 充分利用多种技术,缩短延迟时间并增加 您的应用需要工作所需的网络请求的吞吐量,包括那些 由 ExoPlayer 生成。它以原生方式支持基于 QUIC 的 HTTP、HTTP/2 和 HTTP/3 协议全球一些大型在线影音应用都在使用 Cronet, 包括 YouTube。
ExoPlayer 支持 Cronet,
Cronet 库。
如需详细了解如何使用,请参阅库的 README.md
。请注意,Cronet 库能够使用三个底层 Cronet
实现:
- Google Play 服务:我们建议在大多数情况下使用此实现,
以及回退到 Android 的内置网络堆栈
(
DefaultHttpDataSource
) 如果 Google Play 服务不可用。 - Cronet Embedded:如果您的大部分用户都使用这项服务,这是一个不错的选择 位于未广泛提供 Google Play 服务的市场,或者 想要控制正在使用的 Cronet 实现的确切版本。通过 Cronet Embedded 的主要缺点是,它会将大约 8MB 的内容 。
- Cronet 回退:Cronet 的回退实现会实现
Cronet 的 API,可用作 Android 内置网络堆栈的封装容器。它应该
不可用于 ExoPlayer,因为使用的是 Android 的内置网络堆栈
(使用
DefaultHttpDataSource
)的效率更高。
OkHttp
OkHttp 是另一种新型网络堆栈, 被许多热门的 Android 应用广泛使用。它支持 HTTP 和 HTTP/2,但尚不支持基于 QUIC 的 HTTP/3。
ExoPlayer 通过其 API 调用来支持 OkHttp,
OkHttp 库。
如需详细了解如何使用,请参阅库的 README.md
。使用 OkHttp 库时,网络堆栈会嵌入到
应用。与 Cronet Embedded 类似,但 OkHttp 显著
从而为应用增加不到 1MB 的大小。
Android 的内置网络堆栈
ExoPlayer 支持使用 Android 的内置网络堆栈
DefaultHttpDataSource
和 DefaultHttpDataSource.Factory
,属于
核心 ExoPlayer 库。
网络堆栈的确切实现取决于 底层设备大多数设备只支持 HTTP 不支持 HTTP/2 和 HTTP/3 over QUIC)。
其他网络堆栈
应用还可以将其他网络堆栈与 ExoPlayer 集成。
为此,请实现一个封装网络堆栈的 HttpDataSource
,
以及相应的 HttpDataSource.Factory
。ExoPlayer 的 Cronet 和
OkHttp 库就是关于如何执行此操作的范例。
与纯 Java 网络堆栈集成时,最好实现
DataSourceContractTest
,以检查您的 HttpDataSource
实现是否正常
正常运行。OkHttp 库中的 OkHttpDataSourceContractTest
是
这是一个不错的例子。
选择网络堆栈
下表概述了 Google Cloud 中 ExoPlayer。
网络堆栈 | 协议 | APK 大小影响 | 备注 |
---|---|---|---|
HttpEngine | HTTP HTTP/2 HTTP/3(基于 QUIC) |
无 | 仅适用于 API 34 或 S 扩展 7 |
Cronet(Google Play 服务) | HTTP HTTP/2 HTTP/3(基于 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 更高效地运行 因此,HttpEngine 和 Cronet 同时支持 HTTP/2 和 HTTP/3 与 QUIC(以及 OkHttp 对 HTTP/2 的支持)相比, 但前提是要用 Android 的内置网络堆栈 也支持这些协议。
在单独考虑媒体流式传输时,我们建议使用 HttpEngine 或
Google Play 服务提供的 Cronet 回退到 DefaultHttpDataSource
如果 Google Play 服务不可用。此建议不错
在大多数设备上通过 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();