优点和缺点

ExoPlayer具有很多优于Android内置的MediaPlayer的优势:

  • 支持基于Http的动态自适应的流和平滑的流,以及HLS(Http Live String 基于Http的直播流),FMP4,MP4,M4A,MKV,WebM,MP3,AAC,MPEG-TS,MPEG-PS,OGG,FLV,WAV
  • 支持高级HLS功能,例如:#EXT-X-DISCONTINUITY标签
  • 定制和扩展播放器,满足用户的使用情况。ExoPlayer是考虑到这一点而设计的,并允许许多组件与自定义组件的替换。

需要注意的是,也有一些缺点,这一点很重要:

  • ExoPlayer的标准音频和视频组件依赖于Android的API MediaCodec,这是在搭载Android 4.1(API级别16)公布。因此,他们不会在较早版本的Android的工作。

库概览

ExoPlayer库的核心是ExoPlayer类。这个类维护这Player的全局状态,播放时的特性,如何获取媒体数据,如何获取缓冲和格式。你可以通过给ExoPlayer的prepare()方法注入TrackRenderer对象来获取这些功能。

ExoPlayer使用Android Framework中的MediaCodec和AudioTrack类,来提供默认的音频和视频渲染器。这都需要注入SampleSource对象,从中获取媒体样本进行播放。

图1显示出了用于配置和播放MP4流的ExoPlayer高层对象模型。默认的音频和视频渲染器被注入到ExoPlayer实例中。一个ExtractorSampleSource的实例被注入到渲染器中以提供媒体样本。
DataSource和Extractor实例被注入到ExtractorSampleSource中,从被加载的数据中加载视频流和提取样本。在这种情况下DefaultUriDataSource和Mp4Extractor用于播放从他们的URI加载的MP4流。

综上所述,ExoPlayer实例被注入很多组件以提供开发者需要的功能。这种模式,很容易构建用户指定的功能和注入自定义组件。

TrackRenderer

一个TrackRenderer扮演着特定类型的媒体,诸如视频,音频或文本。ExoPlayer在一个单一的播放线程调用TrackRenderer实例的方法,通过这样做使每一类型的媒体呈现为全局播放位置。
在ExoPlayer库中提供MediaCodecVideoTrackRenderer作为视频渲染器的默认实现,提供MediaCodecAudioTRackRenderer作为音频渲染器的默认实现。
这两种实现使用Android的MediaCodec类的对媒体样本进行解码。支持大部分的音频和视频格式。ExoPlayer库也提供了文本渲染器的默认实现TextTrackRenderer。

下面的代码是实例化ExoPlayer使用标准TrackRenderer实现播放的视频和音频,所需的主要步骤的例子:

// 1. Instantiate the player.
player = ExoPlayer.Factory.newInstance(RENDERER_COUNT);
// 2. Construct renderers.
MediaCodecVideoTrackRenderer videoRenderer = ...
MediaCodecAudioTrackRenderer audioRenderer = ...
// 3. Inject the renderers through prepare.
player.prepare(videoRenderer, audioRenderer);
// 4. Pass the surface to the video renderer.
player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);
// 5. Start playback.
player.setPlayWhenReady(true);
...
player.release(); // Don’t forget to release when done!

SampleSource

一个标准的TrackRender实现,需要提供SampleSource的实例输入到其构造方法中。一个SampleSource对象提供了被渲染的格式信息和媒体样品。该ExoPlayer库提供了一些具体SampleSource实现:

  1. ExtractorSampleSource - FMP4 MP4 M4A MKV WebM MP3 AAC MPEG-TS MPEG-PS OGG FLV WAV 播放
  2. ChunkSampleSource - DASH(Dynamic Adaptive Streaming) SmoothStreaming 播放
  3. HlsSampleSource - HLS 播放

DataSource

一个标准的SampleSource实现需要提供DataSource的实例,用以加载媒体数据。各种实现可以在upstream包中找到。最常用的是:

  1. DefaultUriDataSource 可以播放本地或者是网络上的媒体。
  2. AssetDataSource 可以播放apk assets目录下的媒体。

Adaptive media playbacks (自适应媒体播放)

ExoPlayer支持自适应流,这使得播放期间媒体的播放质量是基于网络条件进行调整的。DASH,SmoothStreaming和HLS是自适应流技术的例子。
在这三个中,媒体被装载在小块(通常为2至10秒的播放时间),每当请求一个媒体块是,客户端都能从多个格式中选择。

举个例子,当网络条件好时客户端可能选择高质量的格式,网络条件不好时选择较低质量的格式。在这种技术中,视频和音频是分开处理的。

HLS Http Live Streaming

通过使用HlsSampleSource,ExoPlayer支持HLS自适应播放,从提取的样本中加载媒体块。一个HlsSampleSource需要一个HlsChunkSource实例注入到其构造函数中,它负责提供媒体块从中加载和读取样本。
一个HlsChunkSource需要一个DataSource实例注入到其构造方法中,通过其加载媒体数据。

Object model for HLS playbacks using ExoPlayer

下面的代码示例概述了视频和音频渲染器是如何构造的:

LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE));

DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();

PtsTimestampAdjusterProvider timestampAdjusterProvider = new PtsTimestampAdjusterProvider();

DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);

HlsChunkSource chunkSource = new HlsChunkSource(true /* isMaster */, dataSource, url, manifest,
    DefaultHlsTrackSelector.newDefaultInstance(context), bandwidthMeter, timestampAdjusterProvider,
    HlsChunkSource.ADAPTIVE_MODE_SPLICE);

HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, loadControl,
    MAIN_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE);

MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, sampleSource,
    MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT);

MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource,
    MediaCodecSelector.DEFAULT);

ExoPlayerDemo程序提供了这段代码HlsRendererBuilder的完整实现。该PlayerActivity类使用这个生成器来构建渲染器在演示应用程序播放HLS样品视频。

Player events

在播放过程中,您的应用程序可以监听由ExoPlayer生成的事件。这些事件经常用于更新用户界面。许多ExoPlayer组件还报告它们自己的组件的低级别的事件,其可用于性能监控。

High level events

ExoPlayer允许使用其的addListener()和的removeListener()方法来添加和删除ExoPlayer.Listener的实例。
注册的监听器通知播放状态的变化,以及当错误发生是的错误原因。有关有效播放状态以及它们之间的可能转变的更多信息,请参阅ExoPlayer源代码。

Low level events

ExoPlayer许多库也提供了自己的事件监听器。

例如,MediaCodecVideoTrackRenderer就需要一个MediaCodecVideoTrackRenderer.EventListener来构造.

在ExoPlayerDemoApp中,DemoPlayer实际上作为多个组件的监听器,将事件转发给PlayerActivity。其中一个就是根据当前宽高的比例来调整surface的大小。

Override
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
    float pixelWidthHeightRatio) {
  surfaceView.setVideoWidthHeightRatio(
      height == 0 ? 1 : (width * pixelWidthAspectRatio) / height);
}

Sending messages to components

一些ExoPlayer组件允许在播放期间改变配置。按照惯例,在ExoPlayer通过异步消息发送给组件,做出这些改变。

消息的最常见的用途是传递给surface MediaCodecVideoTrackRenderer。

player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);

请注意,如果需要调用销毁SurfaceHolder.Callback.surfaceDestroyed(),则必须发送阻塞消息。

player.blockingSendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, null);

你必须使用阻塞消息,surfaceDestroyed()要求在其返回之前不在处理surface。

Customization

一个ExoPlayer超过Android的MediaPlayer的一个主要好处是定制和扩展播放器以更好地满足开发者的能力。

ExoPlayer库是考虑到这一点而设计的,定义一些抽象基类和接口,使它们能够为应用程序开发人员能够轻松地更换库提供的缺省实现.

下面是一些用例为构建自定义组件:

  1. TrackRenderer - 实现自定义TrackRenderer处理比音频和视频等媒体类型。在ExoPlayer库中的TextTrackRenderer类是如何实现自定义渲染器的例子。
  2. Extractor -
  3. SampleSource - 如果想获取媒体的样本,通过继承SampleSource是一种合适的方式。
  4. FormatEvaluator - 对于DASH和SmoothStreaming播放,ExoPlayer提供了FormatEvaluator.AdaptiveEvaluator,可根据不同的带宽在不同的质量格式之间进行切换。
  5. DataSource - ExoPlayer的upstream包已经包含了一些DataSource的不同实现。你可能想用一种不同的方式加载数据,例如一个自定义的线程池,一个Http栈,或者是通过持久化缓存。1