Remove Renderer[] from LoadControl.onTracksSelected

The `DefaultLoadControl` implementation of onTracksSelected only utilizes the `Renderer[]` parameter for use in stream type, of which it can collect from the `ExoTrackSelection[]` parameter.

PiperOrigin-RevId: 685677726
This commit is contained in:
michaelkatz 2024-10-14 05:53:39 -07:00 committed by Copybara-Service
parent 17c0ff8ba8
commit 1c4ee06ad6
5 changed files with 119 additions and 48 deletions

View file

@ -51,6 +51,14 @@
* Add `DefaultPreloadManager.Builder` that builds the * Add `DefaultPreloadManager.Builder` that builds the
`DefaultPreloadManager` and `ExoPlayer` instances with consistently `DefaultPreloadManager` and `ExoPlayer` instances with consistently
shared configurations. shared configurations.
* Remove `Renderer[]` parameter from `LoadControl.onTracksSelected()` as
`DefaultLoadControl` implementation can retrieve the stream types from
`ExoTrackSelection[]`.
* Deprecated `DefaultLoadControl.calculateTargetBufferBytes(Renderer[],
ExoTrackSelection[])` and marked method as final to prevent overrides.
The new
`DefaultLoadControl.calculateTargetBufferBytes(ExoTrackSelection[])`
should be used instead.
* Transformer: * Transformer:
* Make setting the image duration using * Make setting the image duration using
`MediaItem.Builder.setImageDurationMs` mandatory for image export. `MediaItem.Builder.setImageDurationMs` mandatory for image export.

View file

@ -26,6 +26,7 @@ import androidx.media3.common.C;
import androidx.media3.common.Timeline; import androidx.media3.common.Timeline;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.analytics.PlayerId; import androidx.media3.exoplayer.analytics.PlayerId;
@ -35,6 +36,7 @@ import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
import androidx.media3.exoplayer.upstream.Allocator; import androidx.media3.exoplayer.upstream.Allocator;
import androidx.media3.exoplayer.upstream.DefaultAllocator; import androidx.media3.exoplayer.upstream.DefaultAllocator;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.InlineMe;
import java.util.HashMap; import java.util.HashMap;
/** The default {@link LoadControl} implementation. */ /** The default {@link LoadControl} implementation. */
@ -337,15 +339,12 @@ public class DefaultLoadControl implements LoadControl {
@Override @Override
public void onTracksSelected( public void onTracksSelected(
PlayerId playerId, LoadControl.Parameters parameters,
Timeline timeline,
MediaPeriodId mediaPeriodId,
Renderer[] renderers,
TrackGroupArray trackGroups, TrackGroupArray trackGroups,
ExoTrackSelection[] trackSelections) { @NullableType ExoTrackSelection[] trackSelections) {
checkNotNull(loadingStates.get(playerId)).targetBufferBytes = checkNotNull(loadingStates.get(parameters.playerId)).targetBufferBytes =
targetBufferBytesOverwrite == C.LENGTH_UNSET targetBufferBytesOverwrite == C.LENGTH_UNSET
? calculateTargetBufferBytes(renderers, trackSelections) ? calculateTargetBufferBytes(trackSelections)
: targetBufferBytesOverwrite; : targetBufferBytesOverwrite;
updateAllocator(); updateAllocator();
} }
@ -437,21 +436,29 @@ public class DefaultLoadControl implements LoadControl {
* Calculate target buffer size in bytes based on the selected tracks. The player will try not to * Calculate target buffer size in bytes based on the selected tracks. The player will try not to
* exceed this target buffer. Only used when {@code targetBufferBytes} is {@link C#LENGTH_UNSET}. * exceed this target buffer. Only used when {@code targetBufferBytes} is {@link C#LENGTH_UNSET}.
* *
* @param renderers The renderers for which the track were selected.
* @param trackSelectionArray The selected tracks. * @param trackSelectionArray The selected tracks.
* @return The target buffer size in bytes. * @return The target buffer size in bytes.
*/ */
protected int calculateTargetBufferBytes( protected int calculateTargetBufferBytes(@NullableType ExoTrackSelection[] trackSelectionArray) {
Renderer[] renderers, ExoTrackSelection[] trackSelectionArray) {
int targetBufferSize = 0; int targetBufferSize = 0;
for (int i = 0; i < renderers.length; i++) { for (ExoTrackSelection exoTrackSelection : trackSelectionArray) {
if (trackSelectionArray[i] != null) { if (exoTrackSelection != null) {
targetBufferSize += getDefaultBufferSize(renderers[i].getTrackType()); targetBufferSize += getDefaultBufferSize(exoTrackSelection.getTrackGroup().type);
} }
} }
return max(DEFAULT_MIN_BUFFER_SIZE, targetBufferSize); return max(DEFAULT_MIN_BUFFER_SIZE, targetBufferSize);
} }
/**
* @deprecated Use {@link #calculateTargetBufferBytes(ExoTrackSelection[])} instead.
*/
@InlineMe(replacement = "this.calculateTargetBufferBytes(trackSelectionArray)")
@Deprecated
protected final int calculateTargetBufferBytes(
Renderer[] renderers, ExoTrackSelection[] trackSelectionArray) {
return calculateTargetBufferBytes(trackSelectionArray);
}
@VisibleForTesting @VisibleForTesting
/* package */ int calculateTotalTargetBufferBytes() { /* package */ int calculateTotalTargetBufferBytes() {
int totalTargetBufferBytes = 0; int totalTargetBufferBytes = 0;
@ -503,6 +510,7 @@ public class DefaultLoadControl implements LoadControl {
case C.TRACK_TYPE_NONE: case C.TRACK_TYPE_NONE:
return 0; return 0;
case C.TRACK_TYPE_UNKNOWN: case C.TRACK_TYPE_UNKNOWN:
return DEFAULT_MIN_BUFFER_SIZE;
default: default:
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }

View file

@ -2008,6 +2008,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
} }
// Get updated buffered duration as it may have changed since the start of the renderer loop. // Get updated buffered duration as it may have changed since the start of the renderer loop.
long bufferedDurationUs = getTotalBufferedDurationUs(loadingHolder.getBufferedPositionUs()); long bufferedDurationUs = getTotalBufferedDurationUs(loadingHolder.getBufferedPositionUs());
return loadControl.shouldStartPlayback( return loadControl.shouldStartPlayback(
new LoadControl.Parameters( new LoadControl.Parameters(
playerId, playerId,
@ -2907,11 +2908,29 @@ import java.util.concurrent.atomic.AtomicBoolean;
MediaPeriodId mediaPeriodId, MediaPeriodId mediaPeriodId,
TrackGroupArray trackGroups, TrackGroupArray trackGroups,
TrackSelectorResult trackSelectorResult) { TrackSelectorResult trackSelectorResult) {
MediaPeriodHolder loadingPeriodHolder = checkNotNull(queue.getLoadingPeriod());
long playbackPositionUs =
loadingPeriodHolder == queue.getPlayingPeriod()
? loadingPeriodHolder.toPeriodTime(rendererPositionUs)
: loadingPeriodHolder.toPeriodTime(rendererPositionUs)
- loadingPeriodHolder.info.startPositionUs;
long bufferedDurationUs =
getTotalBufferedDurationUs(loadingPeriodHolder.getBufferedPositionUs());
long targetLiveOffsetUs =
shouldUseLivePlaybackSpeedControl(playbackInfo.timeline, loadingPeriodHolder.info.id)
? livePlaybackSpeedControl.getTargetLiveOffsetUs()
: C.TIME_UNSET;
loadControl.onTracksSelected( loadControl.onTracksSelected(
playerId, new LoadControl.Parameters(
playbackInfo.timeline, playerId,
mediaPeriodId, playbackInfo.timeline,
renderers, mediaPeriodId,
playbackPositionUs,
bufferedDurationUs,
mediaClock.getPlaybackParameters().speed,
playbackInfo.playWhenReady,
isRebuffering,
targetLiveOffsetUs),
trackGroups, trackGroups,
trackSelectorResult.selections); trackSelectorResult.selections);
} }

View file

@ -20,6 +20,7 @@ import androidx.media3.common.Player;
import androidx.media3.common.Timeline; import androidx.media3.common.Timeline;
import androidx.media3.common.TrackGroup; import androidx.media3.common.TrackGroup;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.exoplayer.analytics.PlayerId; import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.source.MediaPeriod; import androidx.media3.exoplayer.source.MediaPeriod;
@ -145,28 +146,40 @@ public interface LoadControl {
/** /**
* Called by the player when a track selection occurs. * Called by the player when a track selection occurs.
* *
* @param playerId The {@linkplain PlayerId ID of the player} that selected tracks. * @param parameters containing the {@linkplain PlayerId ID of the player}, the current {@link
* @param timeline The current {@link Timeline} in ExoPlayer. * Timeline} in ExoPlayer, and the {@link MediaPeriod} for which the selection was made. Will
* @param mediaPeriodId Identifies (in the current timeline) the {@link MediaPeriod} for which the * be {@link #EMPTY_MEDIA_PERIOD_ID} when {@code timeline} is empty.
* selection was made. Will be {@link #EMPTY_MEDIA_PERIOD_ID} when {@code timeline} is empty.
* @param renderers The renderers.
* @param trackGroups The {@link TrackGroup}s from which the selection was made. * @param trackGroups The {@link TrackGroup}s from which the selection was made.
* @param trackSelections The track selections that were made. * @param trackSelections The track selections that were made.
*/ */
default void onTracksSelected(
Parameters parameters,
TrackGroupArray trackGroups,
@NullableType ExoTrackSelection[] trackSelections) {
// Media3 ExoPlayer will never call this method. This default implementation provides an
// implementation to please the compiler only.
throw new IllegalStateException("onTracksSelected not implemented");
}
/**
* @deprecated Implement {@link #onTracksSelected(Parameters, TrackGroupArray,
* ExoTrackSelection[])} instead.
*/
@SuppressWarnings("deprecation") // Calling deprecated version of this method. @SuppressWarnings("deprecation") // Calling deprecated version of this method.
@Deprecated
default void onTracksSelected( default void onTracksSelected(
PlayerId playerId, PlayerId playerId,
Timeline timeline, Timeline timeline,
MediaPeriodId mediaPeriodId, MediaPeriodId mediaPeriodId,
Renderer[] renderers, Renderer[] renderers,
TrackGroupArray trackGroups, TrackGroupArray trackGroups,
ExoTrackSelection[] trackSelections) { @NullableType ExoTrackSelection[] trackSelections) {
onTracksSelected(timeline, mediaPeriodId, renderers, trackGroups, trackSelections); onTracksSelected(timeline, mediaPeriodId, renderers, trackGroups, trackSelections);
} }
/** /**
* @deprecated Implement {@link #onTracksSelected(PlayerId, Timeline, MediaPeriodId, Renderer[], * @deprecated Implement {@link #onTracksSelected(Parameters, TrackGroupArray,
* TrackGroupArray, ExoTrackSelection[])} instead. * ExoTrackSelection[])} instead.
*/ */
@SuppressWarnings("deprecation") // Calling deprecated version of this method. @SuppressWarnings("deprecation") // Calling deprecated version of this method.
@Deprecated @Deprecated
@ -175,18 +188,20 @@ public interface LoadControl {
MediaPeriodId mediaPeriodId, MediaPeriodId mediaPeriodId,
Renderer[] renderers, Renderer[] renderers,
TrackGroupArray trackGroups, TrackGroupArray trackGroups,
ExoTrackSelection[] trackSelections) { @NullableType ExoTrackSelection[] trackSelections) {
onTracksSelected(renderers, trackGroups, trackSelections); onTracksSelected(renderers, trackGroups, trackSelections);
} }
/** /**
* @deprecated Implement {@link #onTracksSelected(PlayerId, Timeline, MediaPeriodId, Renderer[], * @deprecated Implement {@link #onTracksSelected(Parameters, TrackGroupArray,
* TrackGroupArray, ExoTrackSelection[])} instead. * ExoTrackSelection[])} instead.
*/ */
@SuppressWarnings("deprecation") // Calling deprecated version of this method. @SuppressWarnings("deprecation") // Calling deprecated version of this method.
@Deprecated @Deprecated
default void onTracksSelected( default void onTracksSelected(
Renderer[] renderers, TrackGroupArray trackGroups, ExoTrackSelection[] trackSelections) { Renderer[] renderers,
TrackGroupArray trackGroups,
@NullableType ExoTrackSelection[] trackSelections) {
// Media3 ExoPlayer will never call this method. This default implementation provides an // Media3 ExoPlayer will never call this method. This default implementation provides an
// implementation to please the compiler only. // implementation to please the compiler only.
throw new IllegalStateException("onTracksSelected not implemented"); throw new IllegalStateException("onTracksSelected not implemented");

View file

@ -32,7 +32,6 @@ import androidx.media3.exoplayer.source.TrackGroupArray;
import androidx.media3.exoplayer.trackselection.ExoTrackSelection; import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
import androidx.media3.exoplayer.trackselection.FixedTrackSelection; import androidx.media3.exoplayer.trackselection.FixedTrackSelection;
import androidx.media3.exoplayer.upstream.DefaultAllocator; import androidx.media3.exoplayer.upstream.DefaultAllocator;
import androidx.media3.test.utils.FakeRenderer;
import androidx.media3.test.utils.FakeTimeline; import androidx.media3.test.utils.FakeTimeline;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before; import org.junit.Before;
@ -512,10 +511,16 @@ public class DefaultLoadControlTest {
loadControl = builder.build(); loadControl = builder.build();
loadControl.onPrepared(playerId); loadControl.onPrepared(playerId);
loadControl.onTracksSelected( loadControl.onTracksSelected(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
new Renderer[0], mediaPeriodId,
/* playbackPositionUs= */ 0L,
/* bufferedDurationUs= */ 0L,
/* playbackSpeed= */ 1f,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET),
TrackGroupArray.EMPTY, TrackGroupArray.EMPTY,
new ExoTrackSelection[0]); new ExoTrackSelection[0]);
@ -747,24 +752,34 @@ public class DefaultLoadControlTest {
TrackGroup videoTrackGroup = TrackGroup videoTrackGroup =
new TrackGroup(new Format.Builder().setSampleMimeType(MimeTypes.VIDEO_H264).build()); new TrackGroup(new Format.Builder().setSampleMimeType(MimeTypes.VIDEO_H264).build());
TrackGroupArray videoTrackGroupArray = new TrackGroupArray(videoTrackGroup); TrackGroupArray videoTrackGroupArray = new TrackGroupArray(videoTrackGroup);
Renderer[] videoRenderer = new Renderer[] {new FakeRenderer(C.TRACK_TYPE_VIDEO)};
TrackGroup audioTrackGroup = TrackGroup audioTrackGroup =
new TrackGroup(new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).build()); new TrackGroup(new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).build());
TrackGroupArray audioTrackGroupArray = new TrackGroupArray(audioTrackGroup); TrackGroupArray audioTrackGroupArray = new TrackGroupArray(audioTrackGroup);
Renderer[] audioRenderer = new Renderer[] {new FakeRenderer(C.TRACK_TYPE_AUDIO)};
loadControl.onTracksSelected( loadControl.onTracksSelected(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
videoRenderer, mediaPeriodId,
/* playbackPositionUs= */ 0,
/* bufferedDurationUs= */ 0,
/* playbackSpeed= */ 1.0f,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET),
videoTrackGroupArray, videoTrackGroupArray,
new ExoTrackSelection[] {new FixedTrackSelection(videoTrackGroup, /* track= */ 0)}); new ExoTrackSelection[] {new FixedTrackSelection(videoTrackGroup, /* track= */ 0)});
loadControl.onTracksSelected( loadControl.onTracksSelected(
playerId2, new LoadControl.Parameters(
timeline2, playerId2,
mediaPeriodId2, timeline2,
audioRenderer, mediaPeriodId2,
/* playbackPositionUs= */ 0,
/* bufferedDurationUs= */ 0,
/* playbackSpeed= */ 1.0f,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET),
audioTrackGroupArray, audioTrackGroupArray,
new ExoTrackSelection[] {new FixedTrackSelection(audioTrackGroup, /* track= */ 0)}); new ExoTrackSelection[] {new FixedTrackSelection(audioTrackGroup, /* track= */ 0)});
@ -796,10 +811,16 @@ public class DefaultLoadControlTest {
loadControl = builder.build(); loadControl = builder.build();
loadControl.onPrepared(playerId); loadControl.onPrepared(playerId);
loadControl.onTracksSelected( loadControl.onTracksSelected(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
new Renderer[0], mediaPeriodId,
/* playbackPositionUs= */ 0,
/* bufferedDurationUs= */ 0,
/* playbackSpeed= */ 1.0f,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET),
/* trackGroups= */ null, /* trackGroups= */ null,
/* trackSelections= */ null); /* trackSelections= */ null);
} }