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
`DefaultPreloadManager` and `ExoPlayer` instances with consistently
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:
* Make setting the image duration using
`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.util.Assertions;
import androidx.media3.common.util.Log;
import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
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.DefaultAllocator;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.InlineMe;
import java.util.HashMap;
/** The default {@link LoadControl} implementation. */
@ -337,15 +339,12 @@ public class DefaultLoadControl implements LoadControl {
@Override
public void onTracksSelected(
PlayerId playerId,
Timeline timeline,
MediaPeriodId mediaPeriodId,
Renderer[] renderers,
LoadControl.Parameters parameters,
TrackGroupArray trackGroups,
ExoTrackSelection[] trackSelections) {
checkNotNull(loadingStates.get(playerId)).targetBufferBytes =
@NullableType ExoTrackSelection[] trackSelections) {
checkNotNull(loadingStates.get(parameters.playerId)).targetBufferBytes =
targetBufferBytesOverwrite == C.LENGTH_UNSET
? calculateTargetBufferBytes(renderers, trackSelections)
? calculateTargetBufferBytes(trackSelections)
: targetBufferBytesOverwrite;
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
* 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.
* @return The target buffer size in bytes.
*/
protected int calculateTargetBufferBytes(
Renderer[] renderers, ExoTrackSelection[] trackSelectionArray) {
protected int calculateTargetBufferBytes(@NullableType ExoTrackSelection[] trackSelectionArray) {
int targetBufferSize = 0;
for (int i = 0; i < renderers.length; i++) {
if (trackSelectionArray[i] != null) {
targetBufferSize += getDefaultBufferSize(renderers[i].getTrackType());
for (ExoTrackSelection exoTrackSelection : trackSelectionArray) {
if (exoTrackSelection != null) {
targetBufferSize += getDefaultBufferSize(exoTrackSelection.getTrackGroup().type);
}
}
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
/* package */ int calculateTotalTargetBufferBytes() {
int totalTargetBufferBytes = 0;
@ -503,6 +510,7 @@ public class DefaultLoadControl implements LoadControl {
case C.TRACK_TYPE_NONE:
return 0;
case C.TRACK_TYPE_UNKNOWN:
return DEFAULT_MIN_BUFFER_SIZE;
default:
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.
long bufferedDurationUs = getTotalBufferedDurationUs(loadingHolder.getBufferedPositionUs());
return loadControl.shouldStartPlayback(
new LoadControl.Parameters(
playerId,
@ -2907,11 +2908,29 @@ import java.util.concurrent.atomic.AtomicBoolean;
MediaPeriodId mediaPeriodId,
TrackGroupArray trackGroups,
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(
playerId,
playbackInfo.timeline,
mediaPeriodId,
renderers,
new LoadControl.Parameters(
playerId,
playbackInfo.timeline,
mediaPeriodId,
playbackPositionUs,
bufferedDurationUs,
mediaClock.getPlaybackParameters().speed,
playbackInfo.playWhenReady,
isRebuffering,
targetLiveOffsetUs),
trackGroups,
trackSelectorResult.selections);
}

View file

@ -20,6 +20,7 @@ import androidx.media3.common.Player;
import androidx.media3.common.Timeline;
import androidx.media3.common.TrackGroup;
import androidx.media3.common.util.Log;
import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.source.MediaPeriod;
@ -145,28 +146,40 @@ public interface LoadControl {
/**
* Called by the player when a track selection occurs.
*
* @param playerId The {@linkplain PlayerId ID of the player} that selected tracks.
* @param timeline The current {@link Timeline} in ExoPlayer.
* @param mediaPeriodId Identifies (in the current timeline) the {@link MediaPeriod} for which the
* selection was made. Will be {@link #EMPTY_MEDIA_PERIOD_ID} when {@code timeline} is empty.
* @param renderers The renderers.
* @param parameters containing the {@linkplain PlayerId ID of the player}, the current {@link
* Timeline} in ExoPlayer, and the {@link MediaPeriod} for which the selection was made. Will
* be {@link #EMPTY_MEDIA_PERIOD_ID} when {@code timeline} is empty.
* @param trackGroups The {@link TrackGroup}s from which the selection was 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.
@Deprecated
default void onTracksSelected(
PlayerId playerId,
Timeline timeline,
MediaPeriodId mediaPeriodId,
Renderer[] renderers,
TrackGroupArray trackGroups,
ExoTrackSelection[] trackSelections) {
@NullableType ExoTrackSelection[] trackSelections) {
onTracksSelected(timeline, mediaPeriodId, renderers, trackGroups, trackSelections);
}
/**
* @deprecated Implement {@link #onTracksSelected(PlayerId, Timeline, MediaPeriodId, Renderer[],
* TrackGroupArray, ExoTrackSelection[])} instead.
* @deprecated Implement {@link #onTracksSelected(Parameters, TrackGroupArray,
* ExoTrackSelection[])} instead.
*/
@SuppressWarnings("deprecation") // Calling deprecated version of this method.
@Deprecated
@ -175,18 +188,20 @@ public interface LoadControl {
MediaPeriodId mediaPeriodId,
Renderer[] renderers,
TrackGroupArray trackGroups,
ExoTrackSelection[] trackSelections) {
@NullableType ExoTrackSelection[] trackSelections) {
onTracksSelected(renderers, trackGroups, trackSelections);
}
/**
* @deprecated Implement {@link #onTracksSelected(PlayerId, Timeline, MediaPeriodId, Renderer[],
* TrackGroupArray, ExoTrackSelection[])} instead.
* @deprecated Implement {@link #onTracksSelected(Parameters, TrackGroupArray,
* ExoTrackSelection[])} instead.
*/
@SuppressWarnings("deprecation") // Calling deprecated version of this method.
@Deprecated
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
// implementation to please the compiler only.
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.FixedTrackSelection;
import androidx.media3.exoplayer.upstream.DefaultAllocator;
import androidx.media3.test.utils.FakeRenderer;
import androidx.media3.test.utils.FakeTimeline;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
@ -512,10 +511,16 @@ public class DefaultLoadControlTest {
loadControl = builder.build();
loadControl.onPrepared(playerId);
loadControl.onTracksSelected(
playerId,
timeline,
mediaPeriodId,
new Renderer[0],
new LoadControl.Parameters(
playerId,
timeline,
mediaPeriodId,
/* playbackPositionUs= */ 0L,
/* bufferedDurationUs= */ 0L,
/* playbackSpeed= */ 1f,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET),
TrackGroupArray.EMPTY,
new ExoTrackSelection[0]);
@ -747,24 +752,34 @@ public class DefaultLoadControlTest {
TrackGroup videoTrackGroup =
new TrackGroup(new Format.Builder().setSampleMimeType(MimeTypes.VIDEO_H264).build());
TrackGroupArray videoTrackGroupArray = new TrackGroupArray(videoTrackGroup);
Renderer[] videoRenderer = new Renderer[] {new FakeRenderer(C.TRACK_TYPE_VIDEO)};
TrackGroup audioTrackGroup =
new TrackGroup(new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).build());
TrackGroupArray audioTrackGroupArray = new TrackGroupArray(audioTrackGroup);
Renderer[] audioRenderer = new Renderer[] {new FakeRenderer(C.TRACK_TYPE_AUDIO)};
loadControl.onTracksSelected(
playerId,
timeline,
mediaPeriodId,
videoRenderer,
new LoadControl.Parameters(
playerId,
timeline,
mediaPeriodId,
/* playbackPositionUs= */ 0,
/* bufferedDurationUs= */ 0,
/* playbackSpeed= */ 1.0f,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET),
videoTrackGroupArray,
new ExoTrackSelection[] {new FixedTrackSelection(videoTrackGroup, /* track= */ 0)});
loadControl.onTracksSelected(
playerId2,
timeline2,
mediaPeriodId2,
audioRenderer,
new LoadControl.Parameters(
playerId2,
timeline2,
mediaPeriodId2,
/* playbackPositionUs= */ 0,
/* bufferedDurationUs= */ 0,
/* playbackSpeed= */ 1.0f,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET),
audioTrackGroupArray,
new ExoTrackSelection[] {new FixedTrackSelection(audioTrackGroup, /* track= */ 0)});
@ -796,10 +811,16 @@ public class DefaultLoadControlTest {
loadControl = builder.build();
loadControl.onPrepared(playerId);
loadControl.onTracksSelected(
playerId,
timeline,
mediaPeriodId,
new Renderer[0],
new LoadControl.Parameters(
playerId,
timeline,
mediaPeriodId,
/* playbackPositionUs= */ 0,
/* bufferedDurationUs= */ 0,
/* playbackSpeed= */ 1.0f,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET),
/* trackGroups= */ null,
/* trackSelections= */ null);
}