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
。
setVideoSurfaceView
setVideoTextureView
setVideoSurfaceHolder
setVideoSurface
准备播放
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
这里提供了不错的入门指导。