关联博客:
ExoPlayer播放器剖析(一)进入ExoPlayer的世界
ExoPlayer播放器剖析(二)编写exoplayer的demo
ExoPlayer播放器剖析(三)流程分析—从build到prepare看ExoPlayer的创建流程
ExoPlayer播放器剖析(四)从renderer.render函数分析至MediaCodec
ExoPlayer播放器剖析(五)ExoPlayer对AudioTrack的操作
ExoPlayer播放器剖析(六)ExoPlayer同步机制分析
ExoPlayer播放器剖析(七)ExoPlayer对音频时间戳的处理
ExoPlayer播放器扩展(一)DASH流与HLS流简介
一、前言:
上一篇博客介绍了exoplayer的简单demo,对流程有了一个大致的了解,我们都知道exoplayer的本质是调用Android原生的MediaCodec接口,这篇博客将着重分析其内部实现逻辑,看exoplayer是如何完成创建的。
二、流程分析:
先贴出上篇博客中讲exoplayer初始化的五步曲:
private fun initPlayer(playUri: String?) {
if (playUri == null){
Log.d("ExoTest", "playUri is null!")
return
}
/* 1.创建SimpleExoPlayer实例 */
mPlayer = SimpleExoPlayer.Builder(this).build()
/* 2.创建播放菜单并添加到播放器 */
val firstLocalMediaItem = MediaItem.fromUri(playUri)
mPlayer!!.addMediaItem(firstLocalMediaItem)
/* 3.设置播放方式为自动播放 */
mPlayer!!.playWhenReady = true
/* 4.将SimpleExoPlayer实例设置到StyledPlayerView中 */
mPlayerView!!.player = mPlayer
/* 5,设置播放器状态为prepare */
mPlayer!!.prepare()
}
实际上,我们可以看到,真正跟播放器相关的只有1、3和5三步,我们就从这三步入手看看exoplayer内部到底是如何实现的。
1.分析SimpleExoPlayer.Builder(this).build():
看build实现如下:
/**
* Builds a {@link SimpleExoPlayer} instance.
*
* @throws IllegalStateException If this method has already been called.
*/
public SimpleExoPlayer build() {
Assertions.checkState(!buildCalled);
buildCalled = true;
return new SimpleExoPlayer(/* builder= */ this);
}
}
看build方式实际上是实例了一个SimpleExoPlayer对象,继续跟进到SimpleExoPlayer的构造函数:
protected SimpleExoPlayer(Builder builder) {
...
/* 构建render */
renderers =
builder.renderersFactory.createRenderers(
eventHandler,
componentListener,
componentListener,
componentListener,
componentListener);
...
// Build the player and associated objects.
player =
new ExoPlayerImpl(
renderers,
builder.trackSelector,
builder.mediaSourceFactory,
builder.loadControl,
builder.bandwidthMeter,
analyticsCollector,
builder.useLazyPreparation,
builder.seekParameters,
builder.pauseAtEndOfMediaItems,
builder.clock,
builder.looper);
player.addListener(componentListener);
videoDebugListeners.add(analyticsCollector);
videoListeners.add(analyticsCollector);
audioDebugListeners.add(analyticsCollector);
audioListeners.add(analyticsCollector);
addMetadataOutput(analyticsCollector);
...
}
可以看到,SimpleExoPlayer的构造里面继续去实例化了一个ExoPlayerImpl的对象,再往下跟进:
public ExoPlayerImpl(
Renderer[] renderers,
TrackSelector trackSelector,
MediaSourceFactory mediaSourceFactory,
LoadControl loadControl,
BandwidthMeter bandwidthMeter,
@Nullable AnalyticsCollector analyticsCollector,
boolean useLazyPreparation,
SeekParameters seekParameters,
boolean pauseAtEndOfMediaItems,
Clock clock,
Looper applicationLooper) {
...
internalPlayer =
new ExoPlayerImplInternal(
renderers,
trackSelector,
emptyTrackSelectorResult,
loadControl,
bandwidthMeter,
repeatMode,
shuffleModeEnabled,
analyticsCollector,
seekParameters,
pauseAtEndOfMediaItems,
applicationLooper,
clock,
playbackInfoUpdateListener);
internalPlayerHandler = new Handler(internalPlayer.