ExoPlayer的缓存控制
对于视频播放类应用来说,流畅度是影响用户体验的第一因素,观看一段视频下来,先不谈视频内容怎么样,凭直觉就能感觉到播放是否流畅。缓存是和流畅度密切相关的一环,它给视频播放添加一个提前下载量,在网速比较慢的情况下减少卡顿次数,减少网速波动对观看体验的影响。
下面根据Googel ExoPlayer源码2.9.4版本,简单分析它的缓存控制。
ExoPlayer是面向接口编程的优秀示范,基本的方法几乎全部抽取成接口,可配置性强,灵活度高,跟缓存相关的方法定义在接口 LoadControl
里,并且提供了一个默认实现类 DefaultLoadControl
,DefaultLoadControl
在创建player的实例SimpleExoPlayer中用到,作为构造方法的参数传入ExoPlayerFactory.newSimpleInstance()
。
从DefaultLoadControl
定义的变量和方法名上能看出来,它控制着缓存相关的关键参数:
1 | |
2 | /** |
3 | * The default minimum duration of media that the player will attempt to ensure is buffered at all * times, in milliseconds. |
4 | 播放过程中player会默认保持的最小缓冲区视频片段长度,15s |
5 | */ |
6 | public static final int DEFAULT_MIN_BUFFER_MS = 15000; |
7 | |
8 | /** |
9 | * The default maximum duration of media that the player will attempt to buffer, in milliseconds. |
10 | 播放过程中player会默认保持的最大缓冲区视频片段长度,50s |
11 | */ |
12 | public static final int DEFAULT_MAX_BUFFER_MS = 50000; |
13 | |
14 | /** |
15 | * The default duration of media that must be buffered for playback to start or resume following a * user action such as a seek, in milliseconds. |
16 | 默认的开始播放或者继续播放前缓存的视频片段长度,2.5s,会在一些用户行为之后,例如用户调整播放进度 |
17 | */ |
18 | public static final int DEFAULT_BUFFER_FOR_PLAYBACK_MS = 2500; |
19 | |
20 | /** |
21 | * The default duration of media that must be buffered for playback to resume after a rebuffer, in * milliseconds. A rebuffer is defined to be caused by buffer depletion rather than a user action. |
22 | 重新缓冲后,缓存视频长度的默认值,5s |
23 | */ |
24 | public static final int DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS = 5000; |
创建DefaultLoadControl
实例时这些关键参数完全可以自定义,举个例子:
1 | final DefaultLoadControl.Builder builder = new DefaultLoadControl.Builder(); |
2 | builder.setBufferDurationsMs( |
3 | int minBufferMs, |
4 | int maxBufferMs, |
5 | int bufferForPlaybackMs, |
6 | int bufferForPlaybackAfterRebufferMs); |
7 | |
8 | final DefaultLoadControl defaultLoadControl = builder.createDefaultLoadControl(); |
有了这些变量,LoadControl
会进一步决定player是否应该继续缓存,或者缓存到一定量以后是否应该播放:
1 | |
2 | /** |
3 | * Called by the player to determine whether it should continue to load the source. * * @param bufferedDurationUs The duration of media that's currently buffered. |
4 | * @param playbackSpeed The current playback speed. |
5 | * @return Whether the loading should continue. |
6 | 根据已经缓存的视频长度和当前视频播放速度决定是否应该继续缓存 |
7 | */ |
8 | boolean shouldContinueLoading(long bufferedDurationUs, float playbackSpeed); |
9 | |
10 | |
11 | /** |
12 | * Called repeatedly by the player when it's loading the source, has yet to start playback, and * has the minimum amount of data necessary for playback to be started. The value returned * determines whether playback is actually started. The load control may opt to return {@code * false} until some condition has been met (e.g. a certain amount of media is buffered). * * @param bufferedDurationUs The duration of media that's currently buffered. |
13 | * @param playbackSpeed The current playback speed. |
14 | * @param rebuffering Whether the player is rebuffering. A rebuffer is defined to be caused by |
15 | * buffer depletion rather than a user action. Hence this parameter is false during initial * buffering and when buffering as a result of a seek operation. * @return Whether playback should be allowed to start or resume. |
16 | 根据已经缓存的视频长度,当前播放速度,是否是重新缓存决定是否应该开始播放 |
17 | */ |
18 | boolean shouldStartPlayback(long bufferedDurationUs, float playbackSpeed, boolean rebuffering); |
如果DefaultLoadControl
不能满足项目的使用需求,例如觉得默认缓存区间太小,创建一个类继承接口LoadControl
,添加自定义实现就可以了。