use of androidx.media3.exoplayer.trackselection.TrackSelectorResult in project media by androidx.
the class DownloadHelper method onMediaPrepared.
// Initialization of array of Lists.
@SuppressWarnings("unchecked")
private void onMediaPrepared() {
checkNotNull(mediaPreparer);
checkNotNull(mediaPreparer.mediaPeriods);
checkNotNull(mediaPreparer.timeline);
int periodCount = mediaPreparer.mediaPeriods.length;
int rendererCount = rendererCapabilities.length;
trackSelectionsByPeriodAndRenderer = (List<ExoTrackSelection>[][]) new List<?>[periodCount][rendererCount];
immutableTrackSelectionsByPeriodAndRenderer = (List<ExoTrackSelection>[][]) new List<?>[periodCount][rendererCount];
for (int i = 0; i < periodCount; i++) {
for (int j = 0; j < rendererCount; j++) {
trackSelectionsByPeriodAndRenderer[i][j] = new ArrayList<>();
immutableTrackSelectionsByPeriodAndRenderer[i][j] = Collections.unmodifiableList(trackSelectionsByPeriodAndRenderer[i][j]);
}
}
trackGroupArrays = new TrackGroupArray[periodCount];
mappedTrackInfos = new MappedTrackInfo[periodCount];
for (int i = 0; i < periodCount; i++) {
trackGroupArrays[i] = mediaPreparer.mediaPeriods[i].getTrackGroups();
TrackSelectorResult trackSelectorResult = runTrackSelection(/* periodIndex= */
i);
trackSelector.onSelectionActivated(trackSelectorResult.info);
mappedTrackInfos[i] = checkNotNull(trackSelector.getCurrentMappedTrackInfo());
}
setPreparedWithMedia();
checkNotNull(callbackHandler).post(() -> checkNotNull(callback).onPrepared(this));
}
use of androidx.media3.exoplayer.trackselection.TrackSelectorResult in project media by androidx.
the class ExoPlayerImplInternal method reselectTracksInternal.
private void reselectTracksInternal() throws ExoPlaybackException {
float playbackSpeed = mediaClock.getPlaybackParameters().speed;
// Reselect tracks on each period in turn, until the selection changes.
MediaPeriodHolder periodHolder = queue.getPlayingPeriod();
MediaPeriodHolder readingPeriodHolder = queue.getReadingPeriod();
boolean selectionsChangedForReadPeriod = true;
TrackSelectorResult newTrackSelectorResult;
while (true) {
if (periodHolder == null || !periodHolder.prepared) {
// The reselection did not change any prepared periods.
return;
}
newTrackSelectorResult = periodHolder.selectTracks(playbackSpeed, playbackInfo.timeline);
if (!newTrackSelectorResult.isEquivalent(periodHolder.getTrackSelectorResult())) {
// Selected tracks have changed for this period.
break;
}
if (periodHolder == readingPeriodHolder) {
// The track reselection didn't affect any period that has been read.
selectionsChangedForReadPeriod = false;
}
periodHolder = periodHolder.getNext();
}
if (selectionsChangedForReadPeriod) {
// Update streams and rebuffer for the new selection, recreating all streams if reading ahead.
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
boolean recreateStreams = queue.removeAfter(playingPeriodHolder);
boolean[] streamResetFlags = new boolean[renderers.length];
long periodPositionUs = playingPeriodHolder.applyTrackSelection(newTrackSelectorResult, playbackInfo.positionUs, recreateStreams, streamResetFlags);
boolean hasDiscontinuity = playbackInfo.playbackState != Player.STATE_ENDED && periodPositionUs != playbackInfo.positionUs;
playbackInfo = handlePositionDiscontinuity(playbackInfo.periodId, periodPositionUs, playbackInfo.requestedContentPositionUs, playbackInfo.discontinuityStartPositionUs, hasDiscontinuity, Player.DISCONTINUITY_REASON_INTERNAL);
if (hasDiscontinuity) {
resetRendererPosition(periodPositionUs);
}
boolean[] rendererWasEnabledFlags = new boolean[renderers.length];
for (int i = 0; i < renderers.length; i++) {
Renderer renderer = renderers[i];
rendererWasEnabledFlags[i] = isRendererEnabled(renderer);
SampleStream sampleStream = playingPeriodHolder.sampleStreams[i];
if (rendererWasEnabledFlags[i]) {
if (sampleStream != renderer.getStream()) {
// We need to disable the renderer.
disableRenderer(renderer);
} else if (streamResetFlags[i]) {
// The renderer will continue to consume from its current stream, but needs to be reset.
renderer.resetPosition(rendererPositionUs);
}
}
}
enableRenderers(rendererWasEnabledFlags);
} else {
// Release and re-prepare/buffer periods after the one whose selection changed.
queue.removeAfter(periodHolder);
if (periodHolder.prepared) {
long loadingPeriodPositionUs = max(periodHolder.info.startPositionUs, periodHolder.toPeriodTime(rendererPositionUs));
periodHolder.applyTrackSelection(newTrackSelectorResult, loadingPeriodPositionUs, false);
}
}
handleLoadingMediaPeriodChanged(/* loadingTrackSelectionChanged= */
true);
if (playbackInfo.playbackState != Player.STATE_ENDED) {
maybeContinueLoading();
updatePlaybackPositions();
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
}
}
use of androidx.media3.exoplayer.trackselection.TrackSelectorResult in project media by androidx.
the class MappingTrackSelector method selectTracks.
@Override
public final TrackSelectorResult selectTracks(RendererCapabilities[] rendererCapabilities, TrackGroupArray trackGroups, MediaPeriodId periodId, Timeline timeline) throws ExoPlaybackException {
// Structures into which data will be written during the selection. The extra item at the end
// of each array is to store data associated with track groups that cannot be associated with
// any renderer.
int[] rendererTrackGroupCounts = new int[rendererCapabilities.length + 1];
TrackGroup[][] rendererTrackGroups = new TrackGroup[rendererCapabilities.length + 1][];
@Capabilities int[][][] rendererFormatSupports = new int[rendererCapabilities.length + 1][][];
for (int i = 0; i < rendererTrackGroups.length; i++) {
rendererTrackGroups[i] = new TrackGroup[trackGroups.length];
rendererFormatSupports[i] = new int[trackGroups.length][];
}
// Determine the extent to which each renderer supports mixed mimeType adaptation.
@AdaptiveSupport int[] rendererMixedMimeTypeAdaptationSupports = getMixedMimeTypeAdaptationSupports(rendererCapabilities);
// renderer provides for each track in the group.
for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) {
TrackGroup group = trackGroups.get(groupIndex);
// Associate the group to a preferred renderer.
boolean preferUnassociatedRenderer = MimeTypes.getTrackType(group.getFormat(0).sampleMimeType) == C.TRACK_TYPE_METADATA;
int rendererIndex = findRenderer(rendererCapabilities, group, rendererTrackGroupCounts, preferUnassociatedRenderer);
// Evaluate the support that the renderer provides for each track in the group.
@Capabilities int[] rendererFormatSupport = rendererIndex == rendererCapabilities.length ? new int[group.length] : getFormatSupport(rendererCapabilities[rendererIndex], group);
// Stash the results.
int rendererTrackGroupCount = rendererTrackGroupCounts[rendererIndex];
rendererTrackGroups[rendererIndex][rendererTrackGroupCount] = group;
rendererFormatSupports[rendererIndex][rendererTrackGroupCount] = rendererFormatSupport;
rendererTrackGroupCounts[rendererIndex]++;
}
// Create a track group array for each renderer, and trim each rendererFormatSupports entry.
TrackGroupArray[] rendererTrackGroupArrays = new TrackGroupArray[rendererCapabilities.length];
String[] rendererNames = new String[rendererCapabilities.length];
int[] rendererTrackTypes = new int[rendererCapabilities.length];
for (int i = 0; i < rendererCapabilities.length; i++) {
int rendererTrackGroupCount = rendererTrackGroupCounts[i];
rendererTrackGroupArrays[i] = new TrackGroupArray(Util.nullSafeArrayCopy(rendererTrackGroups[i], rendererTrackGroupCount));
rendererFormatSupports[i] = Util.nullSafeArrayCopy(rendererFormatSupports[i], rendererTrackGroupCount);
rendererNames[i] = rendererCapabilities[i].getName();
rendererTrackTypes[i] = rendererCapabilities[i].getTrackType();
}
// Create a track group array for track groups not mapped to a renderer.
int unmappedTrackGroupCount = rendererTrackGroupCounts[rendererCapabilities.length];
TrackGroupArray unmappedTrackGroupArray = new TrackGroupArray(Util.nullSafeArrayCopy(rendererTrackGroups[rendererCapabilities.length], unmappedTrackGroupCount));
// Package up the track information and selections.
MappedTrackInfo mappedTrackInfo = new MappedTrackInfo(rendererNames, rendererTrackTypes, rendererTrackGroupArrays, rendererMixedMimeTypeAdaptationSupports, rendererFormatSupports, unmappedTrackGroupArray);
Pair<@NullableType RendererConfiguration[], @NullableType ExoTrackSelection[]> result = selectTracks(mappedTrackInfo, rendererFormatSupports, rendererMixedMimeTypeAdaptationSupports, periodId, timeline);
TracksInfo tracksInfo = buildTracksInfo(result.second, mappedTrackInfo);
return new TrackSelectorResult(result.first, result.second, tracksInfo, mappedTrackInfo);
}
use of androidx.media3.exoplayer.trackselection.TrackSelectorResult in project media by androidx.
the class DefaultTrackSelectorTest method selectTracksPreferHigherNumChannelBeforeSampleRate.
/**
* Tests that track selector will prefer audio tracks with higher channel count over tracks with
* higher sample rate when other factors are the same, and tracks are within renderer's
* capabilities.
*/
@Test
public void selectTracksPreferHigherNumChannelBeforeSampleRate() throws Exception {
Format.Builder formatBuilder = AUDIO_FORMAT.buildUpon();
Format higherChannelLowerSampleRateFormat = formatBuilder.setChannelCount(6).setSampleRate(22050).build();
Format lowerChannelHigherSampleRateFormat = formatBuilder.setChannelCount(2).setSampleRate(44100).build();
TrackGroupArray trackGroups = wrapFormats(higherChannelLowerSampleRateFormat, lowerChannelHigherSampleRateFormat);
TrackSelectorResult result = trackSelector.selectTracks(new RendererCapabilities[] { ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES }, trackGroups, periodId, TIMELINE);
assertFixedSelection(result.selections[0], trackGroups, higherChannelLowerSampleRateFormat);
}
use of androidx.media3.exoplayer.trackselection.TrackSelectorResult in project media by androidx.
the class DefaultTrackSelectorTest method selectTracksWithMultipleVideoTracks.
@Test
public void selectTracksWithMultipleVideoTracks() throws Exception {
Format.Builder formatBuilder = VIDEO_FORMAT.buildUpon();
TrackGroupArray trackGroups = singleTrackGroup(formatBuilder.setId("0").build(), formatBuilder.setId("1").build());
TrackSelectorResult result = trackSelector.selectTracks(new RendererCapabilities[] { VIDEO_CAPABILITIES }, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertAdaptiveSelection(result.selections[0], trackGroups.get(0), 0, 1);
}
Aggregations