ExoPlayer 中的播放列表(Playlists)
使用 ConcatenatingMediaSource 实现播放列表,该播放列表允许按顺序播放多个 MediaSource。以下示例表示由两个视频组成的播放列表。
MediaSource firstSource = new ProgressiveMediaSource.Factory(...).createMediaSource(firstVideoUri);
MediaSource secondSource = new ProgressiveMediaSource.Factory(...).createMediaSource(secondVideoUri);
// Plays the first video, then the second video.
ConcatenatingMediaSource concatenatedSource = new ConcatenatingMediaSource(firstSource, secondSource);
播放列表中项目之间的转换是无缝的。不需要它们具有相同的格式(例如,播放列表中可以同时包含H264和VP9视频)。它们甚至可能具有不同的类型(例如,播放列表同时包含视频和音频流都可以)。允许MediaSource在播放列表中多次使用相同的内容。
1、修改播放列表
ConcatenatingMediaSource 允许播放期间动态的添加和删除 MediaSource。可以在播放之前和播放期间通过调用对应的ConcatenatingMediaSource 方法来完成此操作。播放器会在播放过程中以正确的方式自动处理修改。例如,如果 MediaSource 移动了当前播放的文件,则播放不会中断,并且新的后继文件将在完成后播放。如果 MediaSource 删除了当前正在播放的播放器,则播放器将自动移动到播放剩余的第一个后继播放器,如果不存在此后继播放器,则过渡到结束状态。
2、识别播放列表项
为了简化播放列表项的标识,MediaSource 可以在工厂类中为每个项设置自定义标签。这可以是 uri,标题或任何其他自定义对象。可以使用 player.getCurrentTag() 查询当前播放项目的标签。调用 player.getCurrentTimeline() 返回的当前 Timeline 中也在 Timeline.Window 对象中包括了所有的标签 。
public void addItem() {
// Add mediaId (e.g. uri) as tag to the MediaSource.
MediaSource mediaSource =
new ProgressiveMediaSource.Factory(...)
.setTag(mediaId)
.createMediaSource(uri);
concatenatedSource.addMediaSource(mediaSource);
}
@Override
public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
// Load metadata for mediaId and update the UI.
CustomMetadata metadata = CustomMetadata.get(player.getCurrentTag());
titleView.setText(metadata.getTitle());
}
3、检测播放何时过渡到其他项目
当前播放项目更改时可能有三种类型的事件回调:
- EventListener.onPositionDiscontinuity中回调reason = Player.DISCONTINUITY_REASON_PERIOD_TRANSITION。当播放自动从一项过渡到另一项时,会触发此回调。
- EventListener.onPositionDiscontinuity中回调reason = Player.DISCONTINUITY_REASON_SEEK。当当前播放项作为定位操作的一部分而发生更改时(例如,在调用 Player.next时)。
- EventListener.onTimelineChanged中回调reason = Player.TIMELINE_CHANGE_REASON_DYNAMIC。当播放列表发生更改时(例如,添加,移动或删除项目)。
在任何情况下,当您的应用程序代码接收到该事件时,您可以查询播放器以确定正在播放播放列表中的哪个项目。例如,可以使用Player.getCurrentWindowIndex和Player.getCurrentTag。如果您只想检测播放列表项的更改,则有必要与最新的已知窗口索引或标签进行比较,因为这些事件可能由于其他原因而触发。