@Awille
2022-09-08T15:56:16.000000Z
字数 1907
阅读 481
Android Exoplayer 缓存
首先看下视频存储文件:
红框部分为具体的视频文件,蓝框部分为存储的uid,只作为标记用途。
缓存文件命名格式为:
"视频id_文件所代表的视频开始byte位置_创建时间戳.v3.exo”
后缀中的.v3.exo为写死的后缀,如果后续exoPlayer缓存文件组织结构变更,可以根据该后缀加以区分。
可以看到数据库为exoplayer_internal.db
该数据库下的信息存储为:
下面两个表与exoplayer版本信息相关,可以主要关注上面两张表
先看1.1中文件对应在数据库中的存储信息:
存储的信息为文件名、文件大小、最后一次读取或修改的时间戳。
其中文件名就包含了 视频id、文件对应视频起始位置。
同一个视频,id是一致,并且存在多个缓存文件,他们是由下面这张表来组织的
该表存储了视频id, 视频key(我们项目中未对key做自定义处理,默认使用url作为key),以及一个byte数据。
byte数组中对应的信息为:
"exo_len":Key for content length in bytes (type: long).
"exo_redir":Key for redirected uri (type: String).
"custom_":自定义信息
每一个存储的缓存文件,对应的java对象数据结构为:
而一个视频对应的所有存储文件信息为:

可以看到,这两个数据结构与 数据库的信息是意义对应的,CacheContent中用一个TreeSet的结构持有了SimpleCacheSpan列表。
并且ExoPlayer内部会在CacheContentIndex对象中归集所有视频的缓存文件信息:
CacheContentIndex中keyToContent : HashMap 存储了缓存文件的所有信息。
CacheContentIndex被ExoPlayer的SimpleCache所持有,我们在new SimpleCache时,内部流程会加载数据库的所有信息并装填到CacheContentIndex当中。
com.google.android.exoplayer2.upstream.cache.SimpleCache#SimpleCache(java.io.File,
com.google.android.exoplayer2.upstream.cache.CacheEvictor,
com.google.android.exoplayer2.upstream.cache.CachedContentIndex,
com.google.android.exoplayer2.upstream.cache.CacheFileMetadataIndex)

后续我们查询缓存大小时都是在内存中进行的不会有文件IO操作。 但是后续对缓存文件读取会更新数据库表中的last_touch_timestamp字段。
可以看看simpleCache中获取缓存的逻辑:
可以看到,已缓存文件读是允许多个播放器来读取的,对于写操作,是独占的。
播放器内部提供了block_on_cache的标志位,当有一个播放器在写缓存文件时,其他播放器尝试读或写该文件,当block_on_cache为true时,阻塞等待,当block_on_cache为false时,可不等待该文件直接网络拉取视频进行播放,但是该case下,第二个播放器不会边播边缓存。
Exoplayer提供了一些开放接口做了支持
* 在DataSourceFactory传入自定义的CacheKeyFactory
public interface CacheKeyFactory {
/**
* Returns a cache key for the given {@link DataSpec}.
*
* @param dataSpec The data being cached.
*/
String buildCacheKey(DataSpec dataSpec);
}
public Factory setCustomCacheKey(String customCacheKey) { Assertions.checkState(!isCreateCalled); this.customCacheKey = customCacheKey; return this; }