该文章翻译自这里,点击查看英文原文
本指南适用于ExoPlayer 2.x. 如果您仍然使用1.x,您可以在这里找到旧的开发者指南。
播放视频和音乐是Android设备上的热门活动。 Android框架提供了MediaPlayer,作为使用最少代码播放媒体的快速解决方案。 它还提供低级媒体API,如MediaCodec,AudioTrack和MediaDrm,可用于构建自定义媒体播放器解决方案。
ExoPlayer是一个开源的应用级媒体播放器,构建在Android的低级媒体API之上。 该开源项目包含ExoPlayer库和一个演示应用程序:
本指南介绍了ExoPlayer库及其用途。 它是指演示应用程序中的代码,以提供具体的示例。 本指南介绍了使用ExoPlayer的优缺点。 它显示了如何使用ExoPlayer播放DASH,SmoothStreaming和HLS自适应流,以及如MP4,M4A,FMP4,WebM,MKV,MP3,Ogg,WAV,MPEG-TS,MPEG-PS,FLV和ADTS AAC)。 它还讨论了ExoPlayer事件,消息,定制和DRM支持。
与Android内置的MediaPlayer相比,ExoPlayer具有许多优点:
请注意,还有一些缺点:
ExoPlayer的标准音频和视频组件依赖Android的MediaCodec API,这是在Android 4.1(API级别16)中发布的。 因此,它们不适用于早期版本的Android。 Widevine通用加密在Android 4.4(API级别19)及更高版本上可用。
ExoPlayer库的核心是ExoPlayer接口。 ExoPlayer公开了传统的高级媒体播放器功能,例如缓冲媒体,播放,暂停和寻找的功能。 实施旨在对播放的媒体类型,存储方式和位置及其渲染方式进行少量假设(因此对其进行限制)。 而不是直接实现媒体的加载和渲染,ExoPlayer实现将这项工作委托给创建播放器或播放准备时注入的组件。 所有ExoPlayer实现共同的组件有:
该库为常见用例提供了这些组件的默认实现,如下面更详细描述的。 ExoPlayer可以使用这些组件,但如果需要非标准行为,也可以使用自定义实现来构建。 例如,可以注入自定义的LoadControl来更改播放器的缓冲策略,或者可以注入自定义渲染器以使用Android本身不支持的视频编解码器。
在整个库中都存在着实现播放器功能的注入组件的概念。 上面列出的组件的默认实现委派工作到进一步注入的组件中。这使得许多子组件可以用自定义的实现单独替换。例如,默认的MediaSource实现需要通过其构造函数注入一个或多个DataSource工厂。 通过提供定制工厂,则可以从非标准源或不同的网络堆栈加载数据。
对于简单的用例,ExoPlayer入门包括实现以下步骤:
这些步骤在下面更详细地概述。 有关完整的示例,请参阅ExoPlayer演示程序中的PlayerActivity。
开始的第一步是确保您的项目根目录中的build.gradle文件中包含jcenter仓库。
repositories {
jcenter()
}
接下来,为ExoPlayer库添加一个gradle编译依赖关系到应用程序模块的build.gradle文件。
compile 'com.google.android.exoplayer:exoplayer:r2.X.X'
其中r2.X.X是您的首选版本。 有关最新版本,请参阅项目的版本。 有关更多详细信息,请参阅Bintray上的项目。
现在您可以使用ExoPlayerFactory创建一个ExoPlayer实例。 该工厂提供了一系列方法来创建具有不同级别的定制的ExoPlayer实例。 对于绝大多数用例,库中提供的默认Renderer实现就足够了。 对于这种情况,应该使用一个ExoPlayerFactory.newSimpleInstance方法。 这些方法返回SimpleExoPlayer,它扩展了ExoPlayer以添加额外的高级别播放器功能。 以下代码是创建SimpleExoPlayer的示例。
// 1. Create a default TrackSelector
Handler mainHandler = new Handler();
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector =
new DefaultTrackSelector(videoTrackSelectionFactory);
// 2. Create a default LoadControl
LoadControl loadControl = new DefaultLoadControl();
// 3. Create the player
SimpleExoPlayer player =
ExoPlayerFactory.newSimpleInstance(context, trackSelector, loadControl);
所述ExoPlayer库提供了SimpleExoPlayerView,其封装了PlaybackControlView和在其上的渲染视频的Surface。 SimpleExoPlayerView可以包含在应用程序的布局xml中。 将播放器绑定到视图如下面所示这样简单:
// Bind the player to the view.
simpleExoPlayerView.setPlayer(player);
如果您需要对播放器控件和渲染视频的Surface进行细粒度控制,则可以分别使用SimpleExoPlayer的setVideoSurfaceView
,setVideoTextureView
,setVideoSurfaceHolder
和setVideoSurface
方法直接设置播放器的目标SurfaceView,TextureView,SurfaceHolder或Surface。您可以使用PlaybackControlView作为独立组件,或实现与播放器直接交互的自己的播放控件。 setTextOutput
和setId3Output
可用于在播放过程中接收字幕和ID3元数据输出。
在ExoPlayer中,每一块媒体均由MediaSource表示。 要播放一块媒体,您必须先创建一个相应的MediaSource,然后将此对象传递给ExoPlayer.prepare。 该ExoPlayer库为DASH MediaSource(DashMediaSource),SmoothStreaming(SsMediaSource),HLS(HlsMediaSource)和常规的媒体文件(ExtractorMediaSource)提供了实现。这些实现将在本指南的后面更详细地描述。 以下代码显示如何使用适合播放MP4文件的MediaSource准备播放器。
// Measures bandwidth during playback. Can be null if not required.
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
// Produces DataSource instances through which media data is loaded.
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this,
Util.getUserAgent(this, "yourApplicationName"), bandwidthMeter);
// Produces Extractor instances for parsing the media data.
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
// This is the MediaSource representing the media to be played.
MediaSource videoSource = new ExtractorMediaSource(mp4VideoUri,
dataSourceFactory, extractorsFactory, null, null);
// Prepare the player with the source.
player.prepare(videoSource);
播放器准备好后,可以通过播放器上的方法来控制播放。 例如setPlayWhenReady
可用于启动和暂停播放,并且可以使用各种seekTo
方法在媒体内查找。 如果播放器被绑定到SimpleExoPlayerView或PlaybackControlView,则用户与这些组件的交互将导致播放器上的相应方法被调用。
在不再需要时释放播放器是很重要的,以释放有限的资源,如视频解码器供其他应用使用。 这可以通过调用ExoPlayer.release来完成。
在ExoPlayer中,每一块媒体均由MediaSource表示。 要播放一块媒体,您必须先创建一个相应的MediaSource,然后将此对象传递给ExoPlayer.prepare。 该ExoPlayer库为DASHMediaSource(DashMediaSource),SmoothStreaming(SsMediaSource),HLS(HlsMediaSource)和常规的媒体文件(ExtractorMediaSource)提供了实现,在ExoPlayer演示应用程序中,可以在PlayerActivity中找到实例化所有四个示例。
除了上述的MediaSource实现之外,ExoPlayer库还提供了MergingMediaSource,LoopingMediaSource和ConcatenatingMediaSource。 这些MediaSource实现通过组合实现更复杂的播放功能。 一些常见的用例如下所述。 注意,虽然在视频播放的上下文中描述了以下示例,但它们同样适用于仅音频播放,实际上也适用于任何支持的媒体类型的播放。
此处省略一部分
播放期间,您的应用程序可以监听由ExoPlayer生成的事件,指示播放器的整体状态。 这些事件可用作更新应用用户界面(如播放控件)的触发器。 许多ExoPlayer组件还报告自己的组件特定的低级别事件,这对于性能监视是很有用的。
ExoPlayer允许使用其addListener
和removeListener
方法添加和删除ExoPlayer.EventListener的实例。 注册的监听器在播放状态发生变化以及发生导致播放失败的错误时会得到通知。
实现自定义播放控件的开发人员应该注册一个监听器,并在播放器的状态发生变化时使用它来更新他们的控件。 如果播放失败,应用程序还应向用户显示适当的错误。
使用SimpleExoPlayer时,可以在播放器上设置其他监听器。 特别地,setVideoListener允许应用程序接收与视频呈现有关的事件,这些事件可能对于调整UI很有用(例如,用来渲染视频的Surface的宽高比)。 可以在SimpleExoPlayer上设置其他侦听器来接收调试信息,例如调用setVideoDebugListener和setAudioDebugListener。
除了高级别的监听器外,ExoPlayer库提供的许多单独的组件允许自己的事件监听器。 通常需要将Handler对象传递给这些组件,这些组件决定了调用监听器方法的线程。 在大多数情况下,您应该使用与应用程序主线程相关联的Handler。
一些ExoPlayer组件允许在播放过程中更改配置。 按照惯例,您可以通过使用sendMessages
或blockingSendMessages
方法将消息通过ExoPlayer传递到组件来进行这些更改。 这种方法既确保了线程安全性,又能让配置的更改与播放器上执行的任何其他操作一起有序执行。
ExoPlayer比Android MediaPlayer主要优点之一是可以自定义和扩展播放器,以更好地适应开发人员的需求。 ExoPlayer库专门设计了这一点,定义了许多接口和抽象基类,使应用程序开发人员可以轻松地替换库提供的默认实现。 以下是构建自定义组件的一些例子:
如果自定义组件需要将事件报告回应用程序,我们建议您使用与现有ExoPlayer组件相同的模型,其中将事件侦听器与Handler一起传递到组件的构造函数。
我们建议自定义组件使用与现有ExoPlayer组件相同的模型,如向组件发送消息中所述,以便在播放过程中由应用重新配置。 为此,您应该实现一个ExoPlayerComponent并在其handleMessage方法中接收配置的更改。 您的应用程序应通过调用ExoPlayer的sendMessages和blockingSendMessages方法来传递配置的更改。
在Android 4.4(API级别19)及更高版本上,ExoPlayer支持数字版权管理(DRM)保护的播放。为了使用ExoPlayer播放受DRM保护的内容,您的应用程序必须在实例化播放器时注入DrmSessionManager。ExoPlayerFactory提供工厂方法来满足这种做法。 DrmSessionManager对象负责提供DrmSession实例,该实例提供用于解密的MediaCrypto对象,并确保所需的解密密钥对所使用的底层DRM模块可用。
ExoPlayer库提供了一个名为DefaultDrmSessionManager的DrmSessionManager的默认实现,它使用MediaDrm。 会话管理器支持在设备上存在模块化DRM组件的任何DRM方案。 所有Android设备都需要支持Widevine模块化DRM(具有L3安全性,尽管许多设备也支持L1)。 某些设备可能支持其他方案,如PlayReady。 所有Android TV设备都支持PlayReady。
ExoPlayer演示应用程序中的PlayerActivity演示了如何在实例化播放器时创建和注入DrmSessionManager。