mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Merge pull request #5496 from szaboa:dev-v2-5040
PiperOrigin-RevId: 237412166
This commit is contained in:
commit
89908794e6
4 changed files with 150 additions and 102 deletions
|
|
@ -205,6 +205,7 @@ public class DefaultTimeBar extends View implements TimeBar {
|
||||||
private final CopyOnWriteArraySet<OnScrubListener> listeners;
|
private final CopyOnWriteArraySet<OnScrubListener> listeners;
|
||||||
private final int[] locationOnScreen;
|
private final int[] locationOnScreen;
|
||||||
private final Point touchPosition;
|
private final Point touchPosition;
|
||||||
|
private final float density;
|
||||||
|
|
||||||
private int keyCountIncrement;
|
private int keyCountIncrement;
|
||||||
private long keyTimeIncrement;
|
private long keyTimeIncrement;
|
||||||
|
|
@ -242,13 +243,14 @@ public class DefaultTimeBar extends View implements TimeBar {
|
||||||
// Calculate the dimensions and paints for drawn elements.
|
// Calculate the dimensions and paints for drawn elements.
|
||||||
Resources res = context.getResources();
|
Resources res = context.getResources();
|
||||||
DisplayMetrics displayMetrics = res.getDisplayMetrics();
|
DisplayMetrics displayMetrics = res.getDisplayMetrics();
|
||||||
fineScrubYThreshold = dpToPx(displayMetrics, FINE_SCRUB_Y_THRESHOLD_DP);
|
density = displayMetrics.density;
|
||||||
int defaultBarHeight = dpToPx(displayMetrics, DEFAULT_BAR_HEIGHT_DP);
|
fineScrubYThreshold = dpToPx(density, FINE_SCRUB_Y_THRESHOLD_DP);
|
||||||
int defaultTouchTargetHeight = dpToPx(displayMetrics, DEFAULT_TOUCH_TARGET_HEIGHT_DP);
|
int defaultBarHeight = dpToPx(density, DEFAULT_BAR_HEIGHT_DP);
|
||||||
int defaultAdMarkerWidth = dpToPx(displayMetrics, DEFAULT_AD_MARKER_WIDTH_DP);
|
int defaultTouchTargetHeight = dpToPx(density, DEFAULT_TOUCH_TARGET_HEIGHT_DP);
|
||||||
int defaultScrubberEnabledSize = dpToPx(displayMetrics, DEFAULT_SCRUBBER_ENABLED_SIZE_DP);
|
int defaultAdMarkerWidth = dpToPx(density, DEFAULT_AD_MARKER_WIDTH_DP);
|
||||||
int defaultScrubberDisabledSize = dpToPx(displayMetrics, DEFAULT_SCRUBBER_DISABLED_SIZE_DP);
|
int defaultScrubberEnabledSize = dpToPx(density, DEFAULT_SCRUBBER_ENABLED_SIZE_DP);
|
||||||
int defaultScrubberDraggedSize = dpToPx(displayMetrics, DEFAULT_SCRUBBER_DRAGGED_SIZE_DP);
|
int defaultScrubberDisabledSize = dpToPx(density, DEFAULT_SCRUBBER_DISABLED_SIZE_DP);
|
||||||
|
int defaultScrubberDraggedSize = dpToPx(density, DEFAULT_SCRUBBER_DRAGGED_SIZE_DP);
|
||||||
if (attrs != null) {
|
if (attrs != null) {
|
||||||
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DefaultTimeBar, 0,
|
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DefaultTimeBar, 0,
|
||||||
0);
|
0);
|
||||||
|
|
@ -436,6 +438,14 @@ public class DefaultTimeBar extends View implements TimeBar {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getPreferredUpdateDelay() {
|
||||||
|
int timeBarWidthDp = pxToDp(density, progressBar.width());
|
||||||
|
return timeBarWidthDp == 0 || duration == 0 || duration == C.TIME_UNSET
|
||||||
|
? Long.MAX_VALUE
|
||||||
|
: duration / timeBarWidthDp;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAdGroupTimesMs(@Nullable long[] adGroupTimesMs, @Nullable boolean[] playedAdGroups,
|
public void setAdGroupTimesMs(@Nullable long[] adGroupTimesMs, @Nullable boolean[] playedAdGroups,
|
||||||
int adGroupCount) {
|
int adGroupCount) {
|
||||||
|
|
@ -832,7 +842,11 @@ public class DefaultTimeBar extends View implements TimeBar {
|
||||||
return 0x33000000 | (adMarkerColor & 0x00FFFFFF);
|
return 0x33000000 | (adMarkerColor & 0x00FFFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int dpToPx(DisplayMetrics displayMetrics, int dps) {
|
private static int dpToPx(float density, int dps) {
|
||||||
return (int) (dps * displayMetrics.density + 0.5f);
|
return (int) (dps * density + 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int pxToDp(float density, int px) {
|
||||||
|
return (int) (px / density);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,12 @@ import java.util.Locale;
|
||||||
* <li>Corresponding method: {@link #setShowShuffleButton(boolean)}
|
* <li>Corresponding method: {@link #setShowShuffleButton(boolean)}
|
||||||
* <li>Default: false
|
* <li>Default: false
|
||||||
* </ul>
|
* </ul>
|
||||||
|
* <li><b>{@code time_bar_min_update_interval}</b> - Specifies the minimum interval between time
|
||||||
|
* bar position updates.
|
||||||
|
* <ul>
|
||||||
|
* <li>Corresponding method: {@link #setTimeBarMinUpdateInterval(int)}
|
||||||
|
* <li>Default: {@link #DEFAULT_TIME_BAR_MIN_UPDATE_INTERVAL_MS}
|
||||||
|
* </ul>
|
||||||
* <li><b>{@code controller_layout_id}</b> - Specifies the id of the layout to be inflated. See
|
* <li><b>{@code controller_layout_id}</b> - Specifies the id of the layout to be inflated. See
|
||||||
* below for more details.
|
* below for more details.
|
||||||
* <ul>
|
* <ul>
|
||||||
|
|
@ -191,11 +197,14 @@ public class PlayerControlView extends FrameLayout {
|
||||||
/** The default repeat toggle modes. */
|
/** The default repeat toggle modes. */
|
||||||
public static final @RepeatModeUtil.RepeatToggleModes int DEFAULT_REPEAT_TOGGLE_MODES =
|
public static final @RepeatModeUtil.RepeatToggleModes int DEFAULT_REPEAT_TOGGLE_MODES =
|
||||||
RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE;
|
RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE;
|
||||||
|
/** The default minimum interval between time bar position updates. */
|
||||||
|
public static final int DEFAULT_TIME_BAR_MIN_UPDATE_INTERVAL_MS = 200;
|
||||||
/** The maximum number of windows that can be shown in a multi-window time bar. */
|
/** The maximum number of windows that can be shown in a multi-window time bar. */
|
||||||
public static final int MAX_WINDOWS_FOR_MULTI_WINDOW_TIME_BAR = 100;
|
public static final int MAX_WINDOWS_FOR_MULTI_WINDOW_TIME_BAR = 100;
|
||||||
|
|
||||||
private static final long MAX_POSITION_FOR_SEEK_TO_PREVIOUS = 3000;
|
private static final long MAX_POSITION_FOR_SEEK_TO_PREVIOUS = 3000;
|
||||||
|
/** The maximum interval between time bar position updates. */
|
||||||
|
private static final int MAX_UPDATE_INTERVAL_MS = 1000;
|
||||||
|
|
||||||
private final ComponentListener componentListener;
|
private final ComponentListener componentListener;
|
||||||
private final View previousButton;
|
private final View previousButton;
|
||||||
|
|
@ -236,6 +245,7 @@ public class PlayerControlView extends FrameLayout {
|
||||||
private int rewindMs;
|
private int rewindMs;
|
||||||
private int fastForwardMs;
|
private int fastForwardMs;
|
||||||
private int showTimeoutMs;
|
private int showTimeoutMs;
|
||||||
|
private int timeBarMinUpdateIntervalMs;
|
||||||
private @RepeatModeUtil.RepeatToggleModes int repeatToggleModes;
|
private @RepeatModeUtil.RepeatToggleModes int repeatToggleModes;
|
||||||
private boolean showShuffleButton;
|
private boolean showShuffleButton;
|
||||||
private long hideAtMs;
|
private long hideAtMs;
|
||||||
|
|
@ -243,6 +253,7 @@ public class PlayerControlView extends FrameLayout {
|
||||||
private boolean[] playedAdGroups;
|
private boolean[] playedAdGroups;
|
||||||
private long[] extraAdGroupTimesMs;
|
private long[] extraAdGroupTimesMs;
|
||||||
private boolean[] extraPlayedAdGroups;
|
private boolean[] extraPlayedAdGroups;
|
||||||
|
private long currentWindowOffset;
|
||||||
|
|
||||||
public PlayerControlView(Context context) {
|
public PlayerControlView(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
|
|
@ -264,6 +275,7 @@ public class PlayerControlView extends FrameLayout {
|
||||||
fastForwardMs = DEFAULT_FAST_FORWARD_MS;
|
fastForwardMs = DEFAULT_FAST_FORWARD_MS;
|
||||||
showTimeoutMs = DEFAULT_SHOW_TIMEOUT_MS;
|
showTimeoutMs = DEFAULT_SHOW_TIMEOUT_MS;
|
||||||
repeatToggleModes = DEFAULT_REPEAT_TOGGLE_MODES;
|
repeatToggleModes = DEFAULT_REPEAT_TOGGLE_MODES;
|
||||||
|
timeBarMinUpdateIntervalMs = DEFAULT_TIME_BAR_MIN_UPDATE_INTERVAL_MS;
|
||||||
hideAtMs = C.TIME_UNSET;
|
hideAtMs = C.TIME_UNSET;
|
||||||
showShuffleButton = false;
|
showShuffleButton = false;
|
||||||
if (playbackAttrs != null) {
|
if (playbackAttrs != null) {
|
||||||
|
|
@ -402,7 +414,7 @@ public class PlayerControlView extends FrameLayout {
|
||||||
*/
|
*/
|
||||||
public void setShowMultiWindowTimeBar(boolean showMultiWindowTimeBar) {
|
public void setShowMultiWindowTimeBar(boolean showMultiWindowTimeBar) {
|
||||||
this.showMultiWindowTimeBar = showMultiWindowTimeBar;
|
this.showMultiWindowTimeBar = showMultiWindowTimeBar;
|
||||||
updateTimeBarMode();
|
updateTimeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -426,7 +438,7 @@ public class PlayerControlView extends FrameLayout {
|
||||||
this.extraAdGroupTimesMs = extraAdGroupTimesMs;
|
this.extraAdGroupTimesMs = extraAdGroupTimesMs;
|
||||||
this.extraPlayedAdGroups = extraPlayedAdGroups;
|
this.extraPlayedAdGroups = extraPlayedAdGroups;
|
||||||
}
|
}
|
||||||
updateProgress();
|
updateTimeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -583,6 +595,22 @@ public class PlayerControlView extends FrameLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the minimum interval between time bar position updates.
|
||||||
|
*
|
||||||
|
* <p>Note that smaller intervals, e.g. 33ms, will result in a smooth movement but will use more
|
||||||
|
* CPU resources while the time bar is visible, whereas larger intervals, e.g. 200ms, will result
|
||||||
|
* in a step-wise update with less CPU usage.
|
||||||
|
*
|
||||||
|
* @param minUpdateIntervalMs The minimum interval between time bar position updates, in
|
||||||
|
* milliseconds.
|
||||||
|
*/
|
||||||
|
public void setTimeBarMinUpdateInterval(int minUpdateIntervalMs) {
|
||||||
|
// Do not accept values below 16ms (60fps) and larger than the maximum update interval.
|
||||||
|
timeBarMinUpdateIntervalMs =
|
||||||
|
Util.constrainValue(minUpdateIntervalMs, 16, MAX_UPDATE_INTERVAL_MS);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the playback controls. If {@link #getShowTimeoutMs()} is positive then the controls will
|
* Shows the playback controls. If {@link #getShowTimeoutMs()} is positive then the controls will
|
||||||
* be automatically hidden after this duration of time has elapsed without user input.
|
* be automatically hidden after this duration of time has elapsed without user input.
|
||||||
|
|
@ -635,7 +663,7 @@ public class PlayerControlView extends FrameLayout {
|
||||||
updateNavigation();
|
updateNavigation();
|
||||||
updateRepeatModeButton();
|
updateRepeatModeButton();
|
||||||
updateShuffleButton();
|
updateShuffleButton();
|
||||||
updateProgress();
|
updateTimeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePlayPauseButton() {
|
private void updatePlayPauseButton() {
|
||||||
|
|
@ -735,12 +763,74 @@ public class PlayerControlView extends FrameLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTimeBarMode() {
|
private void updateTimeline() {
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
multiWindowTimeBar =
|
multiWindowTimeBar =
|
||||||
showMultiWindowTimeBar && canShowMultiWindowTimeBar(player.getCurrentTimeline(), window);
|
showMultiWindowTimeBar && canShowMultiWindowTimeBar(player.getCurrentTimeline(), window);
|
||||||
|
currentWindowOffset = 0;
|
||||||
|
long durationUs = 0;
|
||||||
|
int adGroupCount = 0;
|
||||||
|
Timeline timeline = player.getCurrentTimeline();
|
||||||
|
if (!timeline.isEmpty()) {
|
||||||
|
int currentWindowIndex = player.getCurrentWindowIndex();
|
||||||
|
int firstWindowIndex = multiWindowTimeBar ? 0 : currentWindowIndex;
|
||||||
|
int lastWindowIndex = multiWindowTimeBar ? timeline.getWindowCount() - 1 : currentWindowIndex;
|
||||||
|
for (int i = firstWindowIndex; i <= lastWindowIndex; i++) {
|
||||||
|
if (i == currentWindowIndex) {
|
||||||
|
currentWindowOffset = C.usToMs(durationUs);
|
||||||
|
}
|
||||||
|
timeline.getWindow(i, window);
|
||||||
|
if (window.durationUs == C.TIME_UNSET) {
|
||||||
|
Assertions.checkState(!multiWindowTimeBar);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (int j = window.firstPeriodIndex; j <= window.lastPeriodIndex; j++) {
|
||||||
|
timeline.getPeriod(j, period);
|
||||||
|
int periodAdGroupCount = period.getAdGroupCount();
|
||||||
|
for (int adGroupIndex = 0; adGroupIndex < periodAdGroupCount; adGroupIndex++) {
|
||||||
|
long adGroupTimeInPeriodUs = period.getAdGroupTimeUs(adGroupIndex);
|
||||||
|
if (adGroupTimeInPeriodUs == C.TIME_END_OF_SOURCE) {
|
||||||
|
if (period.durationUs == C.TIME_UNSET) {
|
||||||
|
// Don't show ad markers for postrolls in periods with unknown duration.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
adGroupTimeInPeriodUs = period.durationUs;
|
||||||
|
}
|
||||||
|
long adGroupTimeInWindowUs = adGroupTimeInPeriodUs + period.getPositionInWindowUs();
|
||||||
|
if (adGroupTimeInWindowUs >= 0 && adGroupTimeInWindowUs <= window.durationUs) {
|
||||||
|
if (adGroupCount == adGroupTimesMs.length) {
|
||||||
|
int newLength = adGroupTimesMs.length == 0 ? 1 : adGroupTimesMs.length * 2;
|
||||||
|
adGroupTimesMs = Arrays.copyOf(adGroupTimesMs, newLength);
|
||||||
|
playedAdGroups = Arrays.copyOf(playedAdGroups, newLength);
|
||||||
|
}
|
||||||
|
adGroupTimesMs[adGroupCount] = C.usToMs(durationUs + adGroupTimeInWindowUs);
|
||||||
|
playedAdGroups[adGroupCount] = period.hasPlayedAdGroup(adGroupIndex);
|
||||||
|
adGroupCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
durationUs += window.durationUs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long durationMs = C.usToMs(durationUs);
|
||||||
|
if (durationView != null) {
|
||||||
|
durationView.setText(Util.getStringForTime(formatBuilder, formatter, durationMs));
|
||||||
|
}
|
||||||
|
if (timeBar != null) {
|
||||||
|
timeBar.setDuration(durationMs);
|
||||||
|
int extraAdGroupCount = extraAdGroupTimesMs.length;
|
||||||
|
int totalAdGroupCount = adGroupCount + extraAdGroupCount;
|
||||||
|
if (totalAdGroupCount > adGroupTimesMs.length) {
|
||||||
|
adGroupTimesMs = Arrays.copyOf(adGroupTimesMs, totalAdGroupCount);
|
||||||
|
playedAdGroups = Arrays.copyOf(playedAdGroups, totalAdGroupCount);
|
||||||
|
}
|
||||||
|
System.arraycopy(extraAdGroupTimesMs, 0, adGroupTimesMs, adGroupCount, extraAdGroupCount);
|
||||||
|
System.arraycopy(extraPlayedAdGroups, 0, playedAdGroups, adGroupCount, extraAdGroupCount);
|
||||||
|
timeBar.setAdGroupTimesMs(adGroupTimesMs, playedAdGroups, totalAdGroupCount);
|
||||||
|
}
|
||||||
|
updateProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateProgress() {
|
private void updateProgress() {
|
||||||
|
|
@ -750,71 +840,9 @@ public class PlayerControlView extends FrameLayout {
|
||||||
|
|
||||||
long position = 0;
|
long position = 0;
|
||||||
long bufferedPosition = 0;
|
long bufferedPosition = 0;
|
||||||
long duration = 0;
|
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
long currentWindowTimeBarOffsetMs = 0;
|
position = currentWindowOffset + player.getContentPosition();
|
||||||
long durationUs = 0;
|
bufferedPosition = currentWindowOffset + player.getContentBufferedPosition();
|
||||||
int adGroupCount = 0;
|
|
||||||
Timeline timeline = player.getCurrentTimeline();
|
|
||||||
if (!timeline.isEmpty()) {
|
|
||||||
int currentWindowIndex = player.getCurrentWindowIndex();
|
|
||||||
int firstWindowIndex = multiWindowTimeBar ? 0 : currentWindowIndex;
|
|
||||||
int lastWindowIndex =
|
|
||||||
multiWindowTimeBar ? timeline.getWindowCount() - 1 : currentWindowIndex;
|
|
||||||
for (int i = firstWindowIndex; i <= lastWindowIndex; i++) {
|
|
||||||
if (i == currentWindowIndex) {
|
|
||||||
currentWindowTimeBarOffsetMs = C.usToMs(durationUs);
|
|
||||||
}
|
|
||||||
timeline.getWindow(i, window);
|
|
||||||
if (window.durationUs == C.TIME_UNSET) {
|
|
||||||
Assertions.checkState(!multiWindowTimeBar);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (int j = window.firstPeriodIndex; j <= window.lastPeriodIndex; j++) {
|
|
||||||
timeline.getPeriod(j, period);
|
|
||||||
int periodAdGroupCount = period.getAdGroupCount();
|
|
||||||
for (int adGroupIndex = 0; adGroupIndex < periodAdGroupCount; adGroupIndex++) {
|
|
||||||
long adGroupTimeInPeriodUs = period.getAdGroupTimeUs(adGroupIndex);
|
|
||||||
if (adGroupTimeInPeriodUs == C.TIME_END_OF_SOURCE) {
|
|
||||||
if (period.durationUs == C.TIME_UNSET) {
|
|
||||||
// Don't show ad markers for postrolls in periods with unknown duration.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
adGroupTimeInPeriodUs = period.durationUs;
|
|
||||||
}
|
|
||||||
long adGroupTimeInWindowUs = adGroupTimeInPeriodUs + period.getPositionInWindowUs();
|
|
||||||
if (adGroupTimeInWindowUs >= 0 && adGroupTimeInWindowUs <= window.durationUs) {
|
|
||||||
if (adGroupCount == adGroupTimesMs.length) {
|
|
||||||
int newLength = adGroupTimesMs.length == 0 ? 1 : adGroupTimesMs.length * 2;
|
|
||||||
adGroupTimesMs = Arrays.copyOf(adGroupTimesMs, newLength);
|
|
||||||
playedAdGroups = Arrays.copyOf(playedAdGroups, newLength);
|
|
||||||
}
|
|
||||||
adGroupTimesMs[adGroupCount] = C.usToMs(durationUs + adGroupTimeInWindowUs);
|
|
||||||
playedAdGroups[adGroupCount] = period.hasPlayedAdGroup(adGroupIndex);
|
|
||||||
adGroupCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
durationUs += window.durationUs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
duration = C.usToMs(durationUs);
|
|
||||||
position = currentWindowTimeBarOffsetMs + player.getContentPosition();
|
|
||||||
bufferedPosition = currentWindowTimeBarOffsetMs + player.getContentBufferedPosition();
|
|
||||||
if (timeBar != null) {
|
|
||||||
int extraAdGroupCount = extraAdGroupTimesMs.length;
|
|
||||||
int totalAdGroupCount = adGroupCount + extraAdGroupCount;
|
|
||||||
if (totalAdGroupCount > adGroupTimesMs.length) {
|
|
||||||
adGroupTimesMs = Arrays.copyOf(adGroupTimesMs, totalAdGroupCount);
|
|
||||||
playedAdGroups = Arrays.copyOf(playedAdGroups, totalAdGroupCount);
|
|
||||||
}
|
|
||||||
System.arraycopy(extraAdGroupTimesMs, 0, adGroupTimesMs, adGroupCount, extraAdGroupCount);
|
|
||||||
System.arraycopy(extraPlayedAdGroups, 0, playedAdGroups, adGroupCount, extraAdGroupCount);
|
|
||||||
timeBar.setAdGroupTimesMs(adGroupTimesMs, playedAdGroups, totalAdGroupCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (durationView != null) {
|
|
||||||
durationView.setText(Util.getStringForTime(formatBuilder, formatter, duration));
|
|
||||||
}
|
}
|
||||||
if (positionView != null && !scrubbing) {
|
if (positionView != null && !scrubbing) {
|
||||||
positionView.setText(Util.getStringForTime(formatBuilder, formatter, position));
|
positionView.setText(Util.getStringForTime(formatBuilder, formatter, position));
|
||||||
|
|
@ -822,33 +850,29 @@ public class PlayerControlView extends FrameLayout {
|
||||||
if (timeBar != null) {
|
if (timeBar != null) {
|
||||||
timeBar.setPosition(position);
|
timeBar.setPosition(position);
|
||||||
timeBar.setBufferedPosition(bufferedPosition);
|
timeBar.setBufferedPosition(bufferedPosition);
|
||||||
timeBar.setDuration(duration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancel any pending updates and schedule a new one if necessary.
|
// Cancel any pending updates and schedule a new one if necessary.
|
||||||
removeCallbacks(updateProgressAction);
|
removeCallbacks(updateProgressAction);
|
||||||
int playbackState = player == null ? Player.STATE_IDLE : player.getPlaybackState();
|
int playbackState = player == null ? Player.STATE_IDLE : player.getPlaybackState();
|
||||||
if (playbackState != Player.STATE_IDLE && playbackState != Player.STATE_ENDED) {
|
if (playbackState == Player.STATE_READY && player.getPlayWhenReady()) {
|
||||||
long delayMs;
|
long mediaTimeDelayMs =
|
||||||
if (player.getPlayWhenReady() && playbackState == Player.STATE_READY) {
|
timeBar != null ? timeBar.getPreferredUpdateDelay() : MAX_UPDATE_INTERVAL_MS;
|
||||||
float playbackSpeed = player.getPlaybackParameters().speed;
|
|
||||||
if (playbackSpeed <= 0.1f) {
|
// Limit delay to the start of the next full second to ensure position display is smooth.
|
||||||
delayMs = 1000;
|
long mediaTimeUntilNextFullSecondMs = 1000 - position % 1000;
|
||||||
} else if (playbackSpeed <= 5f) {
|
mediaTimeDelayMs = Math.min(mediaTimeDelayMs, mediaTimeUntilNextFullSecondMs);
|
||||||
long mediaTimeUpdatePeriodMs = 1000 / Math.max(1, Math.round(1 / playbackSpeed));
|
|
||||||
long mediaTimeDelayMs = mediaTimeUpdatePeriodMs - (position % mediaTimeUpdatePeriodMs);
|
// Calculate the delay until the next update in real time, taking playbackSpeed into account.
|
||||||
if (mediaTimeDelayMs < (mediaTimeUpdatePeriodMs / 5)) {
|
float playbackSpeed = player.getPlaybackParameters().speed;
|
||||||
mediaTimeDelayMs += mediaTimeUpdatePeriodMs;
|
long delayMs =
|
||||||
}
|
playbackSpeed > 0 ? (long) (mediaTimeDelayMs / playbackSpeed) : MAX_UPDATE_INTERVAL_MS;
|
||||||
delayMs =
|
|
||||||
playbackSpeed == 1 ? mediaTimeDelayMs : (long) (mediaTimeDelayMs / playbackSpeed);
|
// Constrain the delay to avoid too frequent / infrequent updates.
|
||||||
} else {
|
delayMs = Util.constrainValue(delayMs, timeBarMinUpdateIntervalMs, MAX_UPDATE_INTERVAL_MS);
|
||||||
delayMs = 200;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
delayMs = 1000;
|
|
||||||
}
|
|
||||||
postDelayed(updateProgressAction, delayMs);
|
postDelayed(updateProgressAction, delayMs);
|
||||||
|
} else if (playbackState != Player.STATE_ENDED && playbackState != Player.STATE_IDLE) {
|
||||||
|
postDelayed(updateProgressAction, MAX_UPDATE_INTERVAL_MS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1119,15 +1143,14 @@ public class PlayerControlView extends FrameLayout {
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
|
public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
|
||||||
updateNavigation();
|
updateNavigation();
|
||||||
updateProgress();
|
updateTimeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTimelineChanged(
|
public void onTimelineChanged(
|
||||||
Timeline timeline, @Nullable Object manifest, @Player.TimelineChangeReason int reason) {
|
Timeline timeline, @Nullable Object manifest, @Player.TimelineChangeReason int reason) {
|
||||||
updateNavigation();
|
updateNavigation();
|
||||||
updateTimeBarMode();
|
updateTimeline();
|
||||||
updateProgress();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,14 @@ public interface TimeBar {
|
||||||
*/
|
*/
|
||||||
void setDuration(long duration);
|
void setDuration(long duration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the preferred delay in milliseconds of media time after which the time bar position
|
||||||
|
* should be updated.
|
||||||
|
*
|
||||||
|
* @return Preferred delay, in milliseconds of media time.
|
||||||
|
*/
|
||||||
|
long getPreferredUpdateDelay();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the times of ad groups and whether each ad group has been played.
|
* Sets the times of ad groups and whether each ad group has been played.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
<flag name="all" value="2"/>
|
<flag name="all" value="2"/>
|
||||||
</attr>
|
</attr>
|
||||||
<attr name="show_shuffle_button" format="boolean"/>
|
<attr name="show_shuffle_button" format="boolean"/>
|
||||||
|
<attr name="time_bar_min_update_interval" format="integer"/>
|
||||||
|
|
||||||
<declare-styleable name="PlayerView">
|
<declare-styleable name="PlayerView">
|
||||||
<attr name="use_artwork" format="boolean"/>
|
<attr name="use_artwork" format="boolean"/>
|
||||||
|
|
@ -66,6 +67,7 @@
|
||||||
<attr name="fastforward_increment"/>
|
<attr name="fastforward_increment"/>
|
||||||
<attr name="repeat_toggle_modes"/>
|
<attr name="repeat_toggle_modes"/>
|
||||||
<attr name="show_shuffle_button"/>
|
<attr name="show_shuffle_button"/>
|
||||||
|
<attr name="time_bar_min_update_interval"/>
|
||||||
<attr name="controller_layout_id"/>
|
<attr name="controller_layout_id"/>
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
|
|
@ -79,6 +81,7 @@
|
||||||
<attr name="fastforward_increment"/>
|
<attr name="fastforward_increment"/>
|
||||||
<attr name="repeat_toggle_modes"/>
|
<attr name="repeat_toggle_modes"/>
|
||||||
<attr name="show_shuffle_button"/>
|
<attr name="show_shuffle_button"/>
|
||||||
|
<attr name="time_bar_min_update_interval"/>
|
||||||
<attr name="controller_layout_id"/>
|
<attr name="controller_layout_id"/>
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue