Android ExoPlayer播放列表使用LoopingMediaSource引发IndexOutOfBoundsException
我必须播放一次视频A,播放完后,无限期地循环播放视频B。我正在尝试为此使用ConcatenatingMediaSource:Android ExoPlayer播放列表使用LoopingMediaSource引发IndexOutOfBoundsException,android,exoplayer,Android,Exoplayer,我必须播放一次视频A,播放完后,无限期地循环播放视频B。我正在尝试为此使用ConcatenatingMediaSource: private SimpleExoPlayer initPlayer(ViewGroup layout, int playerViewId, ExoPlayer.EventListener eventListener) { // 1. Create a default TrackSelector TrackSelector trackSelector =
private SimpleExoPlayer initPlayer(ViewGroup layout, int playerViewId, ExoPlayer.EventListener eventListener) {
// 1. Create a default TrackSelector
TrackSelector trackSelector = new DefaultTrackSelector();
// 2. Create a default LoadControl
LoadControl loadControl = new DefaultLoadControl();
// 3. Create the player
this.player = ExoPlayerFactory.newSimpleInstance(getContext(), trackSelector, loadControl);
SimpleExoPlayerView simpleExoPlayerView = (SimpleExoPlayerView) layout.findViewById(playerViewId);
// Bind the player to the view.
simpleExoPlayerView.setUseController(false);
simpleExoPlayerView.setPlayer(player);
if (eventListener != null)
player.addListener(eventListener);
// Prepare the player with the source.
player.setPlayWhenReady(true);
return player;
}
public void startPlayer(String firstURL, String loopingURL) {
initProxy();
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
MediaSource firstSource = getVideoPlayerMediaSource(bandwidthMeter, firstURL);
MediaSource secondSource = new LoopingMediaSource(getVideoPlayerMediaSource(bandwidthMeter, loopingURL));
ConcatenatingMediaSource concatenatedSource =
new ConcatenatingMediaSource(firstSource, secondSource);
player.setPlayWhenReady(true);
player.prepare(concatenatedSource);
player.setVideoScalingMode(C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
setPlayerPlaying(true);
}
private void initProxy() {
if (proxy == null)
proxy = VideoCache.getProxy(getContext());
}
@NonNull
private MediaSource getVideoPlayerMediaSource(DefaultBandwidthMeter bandwidthMeter, String videoUrl) {
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(getContext(),
Util.getUserAgent(getContext(), "com.myapp"), bandwidthMeter);
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
Uri url = Uri.parse(videoUrl);
MediaSource videoSource;
if (videoUrl.contains(".mp4")) {
url = Uri.parse(proxy.getProxyUrl(videoUrl));
videoSource = new ExtractorMediaSource(url,
dataSourceFactory, extractorsFactory, null, null);
} else {
videoSource = new HlsMediaSource(url, dataSourceFactory, null, null);
}
return videoSource;
}
但这会引发:
Internal runtime error.
java.lang.IndexOutOfBoundsException
at com.google.android.exoplayer2.util.Assertions.checkIndex(Assertions.java:66)
at com.google.android.exoplayer2.ExoPlayerImplInternal.getPeriodPosition(ExoPlayerImplInternal.java:1077)
at com.google.android.exoplayer2.ExoPlayerImplInternal.getPeriodPosition(ExoPlayerImplInternal.java:1059)
at com.google.android.exoplayer2.ExoPlayerImplInternal.getPeriodPosition(ExoPlayerImplInternal.java:1050)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleSourceInfoRefreshed(ExoPlayerImplInternal.java:872)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:320)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:148)
at android.os.HandlerThread.run(HandlerThread.java:61)
at com.google.android.exoplayer2.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)
只有当使用secondSource作为LoopingMediaSource
时,问题才会发生。它在没有它的情况下工作,但显然不会循环第二个视频
(ExoPlayer版本r2.3.1)尝试为LoopingMediaSource使用另一个构造函数,在该构造函数中指定循环计数并查看其是否有效:
public LoopingMediaSource(MediaSource childSource, int loopCount) {
Assertions.checkArgument(loopCount > 0);
this.childSource = childSource;
this.loopCount = loopCount;
}
看起来您正在收到一条HandleSourceInfoRefresh消息,该消息是从LoopingMediaSource prepareSource()方法发送的:
但这会创建一个新的LoopingTimeline对象,并将其传递给loopCount,在您的示例中为0。LoopingTimeline类重写getWindowCount():
如果loopCount为0,则返回0
如果这样做有效,那么您可以通过传递(Integer.MAX_VALUE-1)作为loopCount,让视频无限循环,因为LoopingTimeline无论如何都会限制循环计数。尝试为LoopingMediaSource使用另一个构造函数,在这里您指定一个循环计数,然后看看这是否有效:
public LoopingMediaSource(MediaSource childSource, int loopCount) {
Assertions.checkArgument(loopCount > 0);
this.childSource = childSource;
this.loopCount = loopCount;
}
看起来您正在收到一条HandleSourceInfoRefresh消息,该消息是从LoopingMediaSource prepareSource()方法发送的:
但这会创建一个新的LoopingTimeline对象,并将其传递给loopCount,在您的示例中为0。LoopingTimeline类重写getWindowCount():
如果loopCount为0,则返回0
如果这样做有效,那么您可以通过传递(Integer.MAX_值-1)作为loopCount使视频无限循环,因为LoopingTimeline无论如何都会限制循环计数。重要提示:使用
Integer.MAX_值-1
(他们指出了这一点)作为LoopingMediaSource
构造函数的第二个参数。非常感谢@罗米纳夫:好的。我编辑了答案以反映这一点。谢谢重要提示:使用Integer.MAX_VALUE-1
(他们指出了这一点)作为LoopingMediaSource
构造函数的第二个参数。非常感谢@罗米纳夫:好的。我编辑了答案以反映这一点。谢谢
@Override
public int getWindowCount() {
return childWindowCount * loopCount;
}