ExoPlayer备忘录

ExoPlayer是一个适用于Android 4.1+的开源媒体API,它提供了DASH,HLS,Smooth Stream等流媒体协议的支持,以及mp4,mp3,Webm等多种媒体格式的兼容。相比MediaPlayer,ExoPlayer具有更多的优点,如支持DRM,高清播放,自定义和拓展。其代码结构中,ExoPlayer接口通过ExoPlayerImpl和ExoPlayerImplInternal实现,使用MediaCodec进行硬件解码,ExtractorSampleSource负责数据源的解封装和加载。此外,ExoPlayer允许自定义渲染器和扩展使用场景。
摘要由CSDN通过智能技术生成

ExoPlayer


1.简述与应用范围

ExpPlayer是一个应用于Android系统4.1以上的,开源的,App等级的媒体API,它的开源项目包含了library和示例。它用Java实现了解封装,用MediaCodec实现硬件解码。

ExoPlayer相较于MediaPlayer有很多优点:

  1. 支持基于http的移动流媒体协议,包括DASH,HLS,Smooth Stream。同时也支持文件流和udp流等。(通过URI)

  2. 支持更多媒体封装格式,包括mp4,mp3,Webm,aac,mkv,mpeg-ts。

  3. 支持DRM(Digital Right Management 数字版权管理)。

  4. 支持HD高清播放。

  5. 支持自定义和拓展使用场景。

2.上层调用方式

(本节说明重点为demo。)

简单来说,上层调用方式基本为:

PlayerActivity -> DemoPlayer -> ExoPlayer 

PlayerActivity -> RendererBuilder -> ExtractorRendererBuilder 

类图为:
这里写图片描述

其中PlayerActivity面向UI层,一方面控制了播放器DemoPlayer,一方面选择了Renderer。

这里的Renderer指定了数据源格式、解码方式和缓冲区大小等。(说明,这里的缓冲区大小指RollingSampleBuffer的大小,不会影响进入播放的速度,只会影响缓存数据的最大值)

ExoPlayer则是媒体API接口。

DemoPlayer中直接封装了ExoPlayer和相关回调接口,负责播放器的逻辑控制和传入SurfaceView等操作,而非播放器的内部原理。

这里通过时序图来说明Demo中几个类的调用和封装方式。

3.代码结构

简单来说,代码结构是这样:

ExoPlayer ->ExoPlayerImpl -> ExoPlayerImplInternal -> TrackRenderer 

MediaCodecVideoTrackRenderer & MediaCodecAudioTrackRenderer ->  MediaCodecTrackRenderer -> SampleSourceTrackRenderer -> SampleSource,SampleSourceReader 

ExtractorSampleSource -> DataSource & Extractor & Loader 

这里,ExoPlayer为接口。ExoPlayerImpl为实现,实现的一些详细步骤在ExoPlayerImplInternal中。后者用Handler消息机制进行异步通信,必要时会阻塞。

TrackRenderer是渲染器接口。

MediaCodecTrackRenderer中加入了MediaCodec(Android硬解码)。这里能看出,ExoPlayer用的是硬解,并且要求4.1以上Android系统。

SampleSourceTrackRenderer中调用了SampleSource,SampleSourceReader接口。SampleSource在这里指的是解封装后的媒体数据。

ExtractorSampleSource相当于一个核心控制器,它实现了SampleSource和SampleSourceReader接口。它通过实际的控制线程Loader,把从某DataSource即数据源中传过来的原始数据,传递给某Extractor来解封装。原始数据解析成SampleSource后,储存在RollingSampleBuffer即环形缓冲区中。

MediaCodecTrackRenderer会间接通过ExtractorSampleSource间接从RollingSampleBuffer中读取数据并渲染成画面,显示到SurfaceView中。

最后的过程有些复杂,流程图如下所示:

这里写图片描述

从这张图我们也可以看出,ExoPlayer是如何支持自定义和拓展使用场景的。

4.代码原理

1.ExoPlayer -> ExoPlayerImpl -> ExoPlayerImplInternal

通过以下这段ExoPlayerImpl的构造方法代码,可以看出来ExoPlayerImpl中持有一个ExoPlayerImplInternal对象来控制播放器。创建ExoPlayerImplInternal对象时传入了一个eventHandler对象,把底层的错误信息和状态改变信息传递给上层处理。

ExoPlayerImpl类中构造方法:

eventHandler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
    ExoPlayerImpl.this.handleEvent(msg);
  }
};
internalPlayer = new ExoPlayerImplInternal(eventHandler, playWhenReady, selectedTrackIndices,
    minBufferMs, minRebufferMs);

具体的功能性代码块,都在ExoPlayerImplInternal中实现。

状态改变信息和错误信息会通过eventHandler传上来进行处理。

ExoPlayerImpl类:

// Not private so it can be called from an inner class without going through
// a thunk method.
/* package */ void handleEvent(Message msg) {
    switch (msg.what) {
    case ExoPlayerImplInternal.MSG_PREPARED: {
        System.arraycopy(msg.obj, 0, trackFormats, 0, trackFormats.length);
        playbackState = msg.arg1;
        for (Listener listener : listeners) {
            listener.onPlayerStateChanged(playWhenReady, playbackState);
        }
        break;
    }
    case ExoPlayerImplInternal.MSG_STATE_CHANGED: {
        playbackState = msg.arg1;
        for (Listener listener : listeners) {
            listener.onPlayerStateChanged(playWhenReady, playbackState);
        }
        break;
    }
    case ExoPlayerImplInternal.MSG_SET_PLAY_WHEN_READY_ACK: {
        pendingPlayWhenReadyAcks--;
        if (pendingPlayWhenReadyAcks == 0) {
            for (Listener listener : listeners) {
                listener.onPlayWhenReadyCommitted();
            }
        }
        break;
    }
    case ExoPlayerImplInternal.MSG_ERROR: {
        ExoPlaybackException exception = (ExoPlaybackException) msg.obj;
        for (Listener listener : listeners) {
            listener.onPlayerError(exception);
        }
        break;
    }
    }
}

这里的

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值