ExoPlayer播放列表使用LoopingMediaSource抛出IndexOutOfBoundsException

时间:2017-04-13 01:27:22

标签: android exoplayer

我必须播放视频A一次,完成后,无限循环播放视频B.我正在尝试使用ConcatenatingMediaSource:

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)

1 个答案:

答案 0 :(得分:0)

尝试使用LoopingMediaSource的其他构造函数,在其中指定循环计数并查看是否有效:

public LoopingMediaSource(MediaSource childSource, int loopCount) {
    Assertions.checkArgument(loopCount > 0);
    this.childSource = childSource;
    this.loopCount = loopCount;
}

看起来您正在获取一个handleSourceInfoRefreshed消息,该消息是从LoopingMediaSource prepareSource()方法发送的:

@Override
public void prepareSource(ExoPlayer player, boolean isTopLevelSource, final Listener listener) {
    childSource.prepareSource(player, false, new Listener() {
      @Override
      public void onSourceInfoRefreshed(Timeline timeline, Object manifest) {
        childPeriodCount = timeline.getPeriodCount();
        listener.onSourceInfoRefreshed(new LoopingTimeline(timeline, loopCount), manifest);
      }
    });
}

但是这会创建一个新的LoopingTimeline对象并传递给它loopCount,在你的情况下为0。 LoopingTimeline类重写getWindowCount():

@Override
public int getWindowCount() {
  return childWindowCount * loopCount;
}

如果loopCount为0,则返回0。

如果可以,那么你可以通过传递(Integer.MAX_VALUE - 1)作为loopCount来无限循环你的视频,因为LoopingTimeline无论如何都会限制循环计数。