系列文章目录
ExoPlayer架构详解与源码分析(1)——前言
ExoPlayer架构详解与源码分析(2)——Player
ExoPlayer架构详解与源码分析(3)——Timeline
ExoPlayer架构详解与源码分析(4)——整体架构
ExoPlayer架构详解与源码分析(5)——MediaSource
ExoPlayer架构详解与源码分析(6)——MediaPeriod
ExoPlayer架构详解与源码分析(7)——SampleQueue
ExoPlayer架构详解与源码分析(8)——Loader
ExoPlayer架构详解与源码分析(9)——TsExtractor
ExoPlayer架构详解与源码分析(10)——H264Reader
ExoPlayer架构详解与源码分析(11)——DataSource
ExoPlayer架构详解与源码分析(12)——Cache
ExoPlayer架构详解与源码分析(13)——TeeDataSource和CacheDataSource
ExoPlayer架构详解与源码分析(14)——ProgressiveMediaPeriod
ExoPlayer架构详解与源码分析(15)——Renderer
ExoPlayer架构详解与源码分析(16)——LoadControl
ExoPlayer架构详解与源码分析(17)——TrackSelector
文章目录
前言
ProgressiveMediaPeriod的左半部分SampleQueue已经在上篇讲完,相对今天说的这部分还算简单,ProgressiveMediaPeriod右半部分主要为Loader,而Loader中及包含数据的获取也包含数据的解析,本篇主要分析Loader的整体机构和数据解析部分结构。
ProgressiveMediaPeriod
还是先预习下上篇的整体结构,本篇主要分析右半半部分的Loader:
图中Loader数据的加载主要靠DataSource,而解析部分主要为Executor
Loader
Loader本质上就是就是一个线程池,初始化时就创建了一个ExecutorService,启动时实例化出一个LoadTask放入线程池中执行。
private final ExecutorService downloadExecutorService;
public Loader(String threadNameSuffix) {
this.downloadExecutorService =
Util.newSingleThreadExecutor(THREAD_NAME_PREFIX + threadNameSuffix);
}
public <T extends Loadable> long startLoading(
T loadable, Callback<T> callback, int defaultMinRetryCount) {
Looper looper = Assertions.checkStateNotNull(Looper.myLooper());//获取当前启动线程的looper
fatalError = null;
long startTimeMs = SystemClock.elapsedRealtime();
new LoadTask<>(looper, loadable, callback, defaultMinRetryCount, startTimeMs).start(0);
return startTimeMs;
}
LoadTask初始化时会传入当前线程的looper和callback,通过looper将后台线程的信息传递到启动线程的callback中执行,所以startLoading的线程必须要包含一个looper,callback也将在启动现场上调用。通常情况下启动线程就是内部播放线程,具体参照之前将的线程模型。
//@LoadTask.java
@Override
public void run() {
try {
boolean shouldLoad;
synchronized (this) {
shouldLoad = !canceled;
executorThread = Thread.currentThread();
}
if (shouldLoad) {
TraceUtil.beginSection("load:" + loadable.getClass().getSimpleName());
try {
loadable.load();//执行loadable
} finally {
TraceUtil.endSection();
}
}
synchronized (this) {
executorThread = null;
// Clear the interrupted flag if set, to avoid it leaking into a subsequent task.
Thread.interrupted();
}
if (!released) {
sendEmptyMessage(MSG_FINISH);//将执行结果通过handler发给启动线程looper
}
...
}
@Override
public void handleMessage(Message msg) {
if (released) {
return