mirror of
https://github.com/androidx/media.git
synced 2025-05-05 06:30:24 +08:00
Add convenience methods to query current window
- Support querying whether the current window is dynamic and seekable. The new methods are similar to getDuration, which is also a convenience method for the current window. - Improve demo app to restore positions in VOD items within playlists where the last item is live. Also restore the position within the window for live items unless the player failed with BehindLiveWindowException. Issue: #2320 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=144443898
This commit is contained in:
parent
ca7febe442
commit
270f68a95e
@ -45,6 +45,7 @@ import com.google.android.exoplayer2.drm.UnsupportedDrmException;
|
|||||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
||||||
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException;
|
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException;
|
||||||
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
|
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
|
||||||
|
import com.google.android.exoplayer2.source.BehindLiveWindowException;
|
||||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
||||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
@ -100,7 +101,6 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Handler mainHandler;
|
private Handler mainHandler;
|
||||||
private Timeline.Window window;
|
|
||||||
private EventLogger eventLogger;
|
private EventLogger eventLogger;
|
||||||
private SimpleExoPlayerView simpleExoPlayerView;
|
private SimpleExoPlayerView simpleExoPlayerView;
|
||||||
private LinearLayout debugRootView;
|
private LinearLayout debugRootView;
|
||||||
@ -115,9 +115,8 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
|||||||
private boolean playerNeedsSource;
|
private boolean playerNeedsSource;
|
||||||
|
|
||||||
private boolean shouldAutoPlay;
|
private boolean shouldAutoPlay;
|
||||||
private boolean isTimelineStatic;
|
private int resumeWindow;
|
||||||
private int playerWindow;
|
private long resumePosition;
|
||||||
private long playerPosition;
|
|
||||||
|
|
||||||
// Activity lifecycle
|
// Activity lifecycle
|
||||||
|
|
||||||
@ -125,9 +124,9 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
|||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
shouldAutoPlay = true;
|
shouldAutoPlay = true;
|
||||||
|
clearResumePosition();
|
||||||
mediaDataSourceFactory = buildDataSourceFactory(true);
|
mediaDataSourceFactory = buildDataSourceFactory(true);
|
||||||
mainHandler = new Handler();
|
mainHandler = new Handler();
|
||||||
window = new Timeline.Window();
|
|
||||||
if (CookieHandler.getDefault() != DEFAULT_COOKIE_MANAGER) {
|
if (CookieHandler.getDefault() != DEFAULT_COOKIE_MANAGER) {
|
||||||
CookieHandler.setDefault(DEFAULT_COOKIE_MANAGER);
|
CookieHandler.setDefault(DEFAULT_COOKIE_MANAGER);
|
||||||
}
|
}
|
||||||
@ -148,7 +147,8 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
|||||||
@Override
|
@Override
|
||||||
public void onNewIntent(Intent intent) {
|
public void onNewIntent(Intent intent) {
|
||||||
releasePlayer();
|
releasePlayer();
|
||||||
isTimelineStatic = false;
|
shouldAutoPlay = true;
|
||||||
|
clearResumePosition();
|
||||||
setIntent(intent);
|
setIntent(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +264,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
|||||||
@SimpleExoPlayer.ExtensionRendererMode int extensionRendererMode =
|
@SimpleExoPlayer.ExtensionRendererMode int extensionRendererMode =
|
||||||
((DemoApplication) getApplication()).useExtensionRenderers()
|
((DemoApplication) getApplication()).useExtensionRenderers()
|
||||||
? (preferExtensionDecoders ? SimpleExoPlayer.EXTENSION_RENDERER_MODE_PREFER
|
? (preferExtensionDecoders ? SimpleExoPlayer.EXTENSION_RENDERER_MODE_PREFER
|
||||||
: SimpleExoPlayer.EXTENSION_RENDERER_MODE_ON)
|
: SimpleExoPlayer.EXTENSION_RENDERER_MODE_ON)
|
||||||
: SimpleExoPlayer.EXTENSION_RENDERER_MODE_OFF;
|
: SimpleExoPlayer.EXTENSION_RENDERER_MODE_OFF;
|
||||||
TrackSelection.Factory videoTrackSelectionFactory =
|
TrackSelection.Factory videoTrackSelectionFactory =
|
||||||
new AdaptiveVideoTrackSelection.Factory(BANDWIDTH_METER);
|
new AdaptiveVideoTrackSelection.Factory(BANDWIDTH_METER);
|
||||||
@ -281,13 +281,6 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
|||||||
player.setMetadataOutput(eventLogger);
|
player.setMetadataOutput(eventLogger);
|
||||||
|
|
||||||
simpleExoPlayerView.setPlayer(player);
|
simpleExoPlayerView.setPlayer(player);
|
||||||
if (isTimelineStatic) {
|
|
||||||
if (playerPosition == C.TIME_UNSET) {
|
|
||||||
player.seekToDefaultPosition(playerWindow);
|
|
||||||
} else {
|
|
||||||
player.seekTo(playerWindow, playerPosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
player.setPlayWhenReady(shouldAutoPlay);
|
player.setPlayWhenReady(shouldAutoPlay);
|
||||||
debugViewHelper = new DebugTextViewHelper(player, debugTextView);
|
debugViewHelper = new DebugTextViewHelper(player, debugTextView);
|
||||||
debugViewHelper.start();
|
debugViewHelper.start();
|
||||||
@ -324,7 +317,8 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
|||||||
}
|
}
|
||||||
MediaSource mediaSource = mediaSources.length == 1 ? mediaSources[0]
|
MediaSource mediaSource = mediaSources.length == 1 ? mediaSources[0]
|
||||||
: new ConcatenatingMediaSource(mediaSources);
|
: new ConcatenatingMediaSource(mediaSources);
|
||||||
player.prepare(mediaSource, !isTimelineStatic, !isTimelineStatic);
|
player.seekTo(resumeWindow, resumePosition);
|
||||||
|
player.prepare(mediaSource, false, false);
|
||||||
playerNeedsSource = false;
|
playerNeedsSource = false;
|
||||||
updateButtonVisibilities();
|
updateButtonVisibilities();
|
||||||
}
|
}
|
||||||
@ -367,12 +361,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
|||||||
debugViewHelper.stop();
|
debugViewHelper.stop();
|
||||||
debugViewHelper = null;
|
debugViewHelper = null;
|
||||||
shouldAutoPlay = player.getPlayWhenReady();
|
shouldAutoPlay = player.getPlayWhenReady();
|
||||||
playerWindow = player.getCurrentWindowIndex();
|
updateResumePosition();
|
||||||
playerPosition = C.TIME_UNSET;
|
|
||||||
Timeline timeline = player.getCurrentTimeline();
|
|
||||||
if (!timeline.isEmpty() && timeline.getWindow(playerWindow, window).isSeekable) {
|
|
||||||
playerPosition = player.getCurrentPosition();
|
|
||||||
}
|
|
||||||
player.release();
|
player.release();
|
||||||
player = null;
|
player = null;
|
||||||
trackSelector = null;
|
trackSelector = null;
|
||||||
@ -381,6 +370,17 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateResumePosition() {
|
||||||
|
resumeWindow = player.getCurrentWindowIndex();
|
||||||
|
resumePosition = player.isCurrentWindowSeekable() ? Math.max(0, player.getCurrentPosition())
|
||||||
|
: C.TIME_UNSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearResumePosition() {
|
||||||
|
resumeWindow = 0;
|
||||||
|
resumePosition = C.TIME_UNSET;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new DataSource factory.
|
* Returns a new DataSource factory.
|
||||||
*
|
*
|
||||||
@ -427,8 +427,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTimelineChanged(Timeline timeline, Object manifest) {
|
public void onTimelineChanged(Timeline timeline, Object manifest) {
|
||||||
isTimelineStatic = !timeline.isEmpty()
|
// Do nothing.
|
||||||
&& !timeline.getWindow(timeline.getWindowCount() - 1, window).isDynamic;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -460,6 +459,11 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
|||||||
showToast(errorString);
|
showToast(errorString);
|
||||||
}
|
}
|
||||||
playerNeedsSource = true;
|
playerNeedsSource = true;
|
||||||
|
if (isBehindLiveWindow(e)) {
|
||||||
|
clearResumePosition();
|
||||||
|
} else {
|
||||||
|
updateResumePosition();
|
||||||
|
}
|
||||||
updateButtonVisibilities();
|
updateButtonVisibilities();
|
||||||
showControls();
|
showControls();
|
||||||
}
|
}
|
||||||
@ -535,4 +539,18 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
|||||||
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
|
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isBehindLiveWindow(ExoPlaybackException e) {
|
||||||
|
if (e.type != ExoPlaybackException.TYPE_SOURCE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Throwable cause = e.getSourceException();
|
||||||
|
while (cause != null) {
|
||||||
|
if (cause instanceof BehindLiveWindowException) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
cause = cause.getCause();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -447,4 +447,20 @@ public interface ExoPlayer {
|
|||||||
*/
|
*/
|
||||||
int getBufferedPercentage();
|
int getBufferedPercentage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current window is dynamic, or {@code false} if the {@link Timeline} is
|
||||||
|
* empty.
|
||||||
|
*
|
||||||
|
* @see Timeline.Window#isDynamic
|
||||||
|
*/
|
||||||
|
boolean isCurrentWindowDynamic();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current window is seekable, or {@code false} if the {@link Timeline} is
|
||||||
|
* empty.
|
||||||
|
*
|
||||||
|
* @see Timeline.Window#isSeekable
|
||||||
|
*/
|
||||||
|
boolean isCurrentWindowSeekable();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -271,6 +271,22 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||||||
: (int) (duration == 0 ? 100 : (bufferedPosition * 100) / duration);
|
: (int) (duration == 0 ? 100 : (bufferedPosition * 100) / duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCurrentWindowDynamic() {
|
||||||
|
if (timeline.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return timeline.getWindow(getCurrentWindowIndex(), window).isDynamic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCurrentWindowSeekable() {
|
||||||
|
if (timeline.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return timeline.getWindow(getCurrentWindowIndex(), window).isSeekable;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRendererCount() {
|
public int getRendererCount() {
|
||||||
return renderers.length;
|
return renderers.length;
|
||||||
|
@ -545,6 +545,36 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||||||
player.blockingSendMessages(messages);
|
player.blockingSendMessages(messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRendererCount() {
|
||||||
|
return player.getRendererCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRendererType(int index) {
|
||||||
|
return player.getRendererType(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TrackGroupArray getCurrentTrackGroups() {
|
||||||
|
return player.getCurrentTrackGroups();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TrackSelectionArray getCurrentTrackSelections() {
|
||||||
|
return player.getCurrentTrackSelections();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Timeline getCurrentTimeline() {
|
||||||
|
return player.getCurrentTimeline();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getCurrentManifest() {
|
||||||
|
return player.getCurrentManifest();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCurrentPeriodIndex() {
|
public int getCurrentPeriodIndex() {
|
||||||
return player.getCurrentPeriodIndex();
|
return player.getCurrentPeriodIndex();
|
||||||
@ -576,33 +606,13 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRendererCount() {
|
public boolean isCurrentWindowDynamic() {
|
||||||
return player.getRendererCount();
|
return player.isCurrentWindowDynamic();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRendererType(int index) {
|
public boolean isCurrentWindowSeekable() {
|
||||||
return player.getRendererType(index);
|
return player.isCurrentWindowSeekable();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TrackGroupArray getCurrentTrackGroups() {
|
|
||||||
return player.getCurrentTrackGroups();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TrackSelectionArray getCurrentTrackSelections() {
|
|
||||||
return player.getCurrentTrackSelections();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Timeline getCurrentTimeline() {
|
|
||||||
return player.getCurrentTimeline();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getCurrentManifest() {
|
|
||||||
return player.getCurrentManifest();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renderer building.
|
// Renderer building.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user