Exoplayer 介绍
本文记录了一些关于 ExoPlayer 库的一些入门知识。
我们的 Android 项目中可能要使用到视频播放功能。于是提前进行预研,在此记录。
WebView- 性能较差,用于H5页面的视频尚能接受,但作为原生播放组件体验差VideoView- 性能尚可,但它无缓存,无缓冲动画。要自行实现这些功能有较大工作量
官方推荐使用 ExoPlayer 库用于音视频播放。
ExoPlayer
ExoPlayer 提供目前 MediaPlayer API 接口不支持的功能,例如 DASH 和 SmoothStreaming 自适应播放。相比 MediaPlayer,ExoPlayer 易于自定义扩展。
库概览
整个 ExoPlayer 库的核心是 ExoPlayer 接口。一个 ExoPlayer 实例对外暴露传统上常见的高级媒体播放器功能,比如媒体缓冲、播放、暂停及seek。ExoPlayer 的实现被设计成对媒体类型,如何存储,在哪里存储,如何渲染等问题有很少的假定和限制。ExoPlayer 并不是直接实现媒体加载和渲染功能,而是将这些工作代理给专门的组件。这些组件在播放器被创建时或准备播放时被注入进来。ExoPlayer 的常用组件包括:
MediaSource- 用于定义将被播放的媒体,用于加载媒体,用于指定可以从哪里读取媒体。在开始播放媒体时通过ExoPlayer.prepare()方法将MediaSource注入进来Renderers- 用于渲染 media 中的单个组件。创建 player 时注入进来TrackSelector- 用于选择MediaSource中的 tracks 给每个可用的Renderer来消费。创建 player 时注入进来LoadControl- 用于控制MediaSource何时缓冲更多媒体数据,以及如何缓冲。创建 player 时注入进来
ExoPlayer 提供了各种缺省的实现。如果仍然不能满足使用需求,也可以进行自定义。比如,自定义 LoadControl 来修改 player 的缓冲策略。或者自定义 Renderer 来使用 Android 并不能原生支持的视频解码器。
优缺点
ExoPlayer 对比 Android MediaPlayer API 的优缺点:
- DASH(Dynamic Adaptive Streaming over HTTP) 和 SmoothStreaming 支持
- 支持更多的媒体格式
- 设备和 Android 版本兼容性更好
- 自定义和扩展能力更好
- 使用官方扩展跟第三方库交互的能力更好
配置
简单介绍 ExoPlayer 的用法。先保证在 build.gradle 中包含 Google 和 JCenter 库:
1 | repositories { |
然后在 build.gradle 中添加依赖:
1 | implementation 'com.google.android.exoplayer:exoplayer:2.9.0' |
另外注意 ExoPlayer 使用 Java 8 编译,所以你的 app 也必须使用 Java 8 编译。
1 | compileOptions { |
也可以按需要添加对特定 ExoPlayer API 的依赖,而不是整个 ExoPlayer 库。比如,只依赖 Core,DASH 和 UI:
1 | implementation 'com.google.android.exoplayer:exoplayer-core:2.X.X' |
ExoPlayer 可用的模块如下:
exoplayer-core- 核心功能(必须)exoplayer-dash- 支持 DASHexoplayer-hls- 支持 HLSexoplayer-smoothstreaming- 支持 SmoothStreamingexoplayer-ui- 提供 ExoPlayer 使用的 UI 组件及资源
除了以上库模块,ExoPlayer 还提供若干依赖外部库的扩展模块用于额外功能。具体见扩展库列表。
用法
对于简单场景,按照以下几个步骤使用 ExoPlayer:
- 添加
ExoPlayer依赖 - 创建
SimpleExoPlayer实例 - 将 player 跟 view 关联(用于视频输出和用户输入)
- 使用完毕后释放 player
创建 ExoPlayer
- 使用
ExoPlayerFactory创建SimpleExoPlayer ExoPlayerFactory中有不同的方法用于创建SimpleExoPlayer- 最常用的创建方法是
ExoPlayerFactory.newSimpleInstance
1 | SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(context); |
关于线程安全问题:
- 必须从同一个线程来访问
ExoPlayer实例(通常来说就是主线程) - 访问
ExoPlayer的线程必须要有Looper
关联 view
ExoPlayer 库提供 PlayerView,它封装了 PlayerControlView 和用于渲染 video 的 Surface。可以在布局中使用 PlayerView,然后像下面这样进行绑定:
1 | // Bind the player to the view. |
SimpleExoPlayer 提供接口用于设置自定义的组件以便更精细地控制 player controls 以及 Surface。
setVideoSurfaceViewsetVideoTextureViewsetVideoSurfaceHoldersetVideoSurface
准备播放
ExoPlayer 库中 每个媒体片断由 MediaSource 表示。首先创建媒体片断 MediaSource,然后将其传给 ExoPlayer.prepare() 方法。ExoPlayer 库提供不同的 MediaSource 实现:
DashMediaSource- DASHSsMediaSource- SmoothStreamingHlsMediaSource- HLSExtractorMediaSource- regular media files
这段代码用于播放 MP4 文件:
1 | // Produces DataSource instances through which media data is loaded. |
播放控制
有两种途径进行播放控制:
- 直接调用 player 相应的方法。例如:
setPlayWhenReady- 播放或暂停seekTo- seeksetRepeatMode- 控制是否循环以及如何循环setShuffleModeEnabled- 控制是否乱序播放setPlaybackParameters- 调整播放速度
- player 绑定到 view 的情况下,用户操作也会导致调用 player 相应的方法
事件监听
使用 Player.EventListener 监听播放状态及可能出现的错误。
1 | // Add a listener to receive events from the player. |
SimpleExoPlayer 还提供一些额外的监听器:
addVideoListener- 监听视频渲染相关事件,可以用于调整 UIaddAnalyticsListener- 监听详细事件,可以用于问题诊断分析
释放
使用 ExoPlayer.release 释放资源。
ExoPlayer demo
demo展示了 ExoPlayer 的基本用法。
从 [github](git clone https://github.com/google/ExoPlayer.git) 下载代码后导入 Android Studio 编译成功后如下图所示。

demo 可能在模拟器上无法运行。我在 Genemotion 上的现象是卡在播放状态,不报错也不 crash,原因是某些模拟器并没有正确地实现 Android media stack。不过官方模拟器是支持 ExoPlayer 的(SDK level 23及以上)。
建议在真机上运行 demo。
demo 最终都是通过 PlayerActivity 来播放视频。使用如下命令在 logcat 中查看日志:
1 | adb logcat EventLogger:V *:E |
可以调整 demo 的 build variants 为 withExtensions 以使用各种扩展库。

编辑 assets/media.exolist.json 文件可以向 demo 中添加自己的视频 sample。
关于代码混淆问题:不用特殊配置,直接混淆即可。
ExoPlayer tutorial
这里提供了不错的入门指导。