0

While playing videos from a ConcatenatingMediaSource playlist, I would like the player to pause automatically at the start of a new item eg. not automatically playing it.

Using the demo application, I modified onPositionDiscontinuity function to detect current item change:

int currentPosition = 0;
@Override
public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
    if (inErrorState) {
        // This will only occur if the user has performed a seek whilst in the error state. Update
        // the resume position so that if the user then retries, playback will resume from the
        // position to which they seeked.
        updateResumePosition();
    }
    if (player.getCurrentWindowIndex() != currentPosition) {
        currentPosition = player.getCurrentWindowIndex();
        player.setPlayWhenReady(false);
    }
}

While this code pauses the player, it does not clear the surface view used by the player hence we are still seeing the last frame of the previous video. I suppose this callback is invoked too soon, but that's the only callback I found which was always invoked on playlist item change (onPlayerStateChanged might not be invoked).

How can I have the first frame of the newly current item displayed instead of the previous item last frame?

My weak workaround is to delay invocation of 200ms with Handler().postDelayed({ mPlayer?.playWhenReady = false }, 200).

bagage
  • 1,094
  • 1
  • 21
  • 44
  • I don't know a better event handler. When the above works you can maybe seek to the default position of the current window? player.seekTo(0, player.getCurrentWindowIndex()) ? However, I'm not sure at what point in time onPlayerDiscontinuity is called excactly. So this might cause some kind of rebuffering. Maybe wort a try. – marcbaechinger Feb 16 '18 at 11:48

1 Answers1

0

This is not supported yet:

The problem with using the event listener is that there is no way to ensure the request to pause in your event listener is handled while the first frame of the new playlist item is showing.

If stopping at approximately the right frame is fine, your solution of pausing the player on position discontinuity looks fine, but I think there's no guarantee that the video renderer will have kept up with the player position which is why you still see a frame from the previous source at the point of pausing the player. For what it's worth, in my testing the video renderer did advance to the first frame of the next playlist item before the request to pause was handled.

A couple of other suggestions:

  • You could try customizing your MediaSource to insert a position discontinuity at the start of each period. I think then you'd get onRenderedFirstFrame at the start of each item. If you pause the player there you can guarantee to pause the player at a frame in the new playlist item.
  • To get this to work perfectly, in the sense that the first frame of the new playlist item is shown and the player pauses before any other frame is shown, it will be necessary to coordinate showing a frame and blocking further rendering (on the playback thread) with pausing the player (on the thread your app is using to interact with the payer). This will require a bit of code, but I think it is probably possible roughly as follows: subclass MediaCodecVideoRenderer and override onStreamChanged to get the time offset of the new playlist item. Then override processOutputBuffer. In this method you can detect when the first frame of the new stream has been rendered (based on the time offset) and then prevent processing any output frames until you've paused the player on your app's thread. After the request to pause has been handled and the renderer is stopped (onStopped) you can unblock processOutputBuffer.

We could also look at supporting this directly in the player, but it will likely be a low priority at least for the moment.

bagage
  • 1,094
  • 1
  • 21
  • 44