Search in sources :

Example 1 with TrackSelectorResult

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));
}
Also used : TrackSelectorResult(androidx.media3.exoplayer.trackselection.TrackSelectorResult) ExoTrackSelection(androidx.media3.exoplayer.trackselection.ExoTrackSelection) List(java.util.List) ArrayList(java.util.ArrayList)

Example 2 with TrackSelectorResult

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);
    }
}
Also used : TrackSelectorResult(androidx.media3.exoplayer.trackselection.TrackSelectorResult) TextRenderer(androidx.media3.exoplayer.text.TextRenderer) MetadataRenderer(androidx.media3.exoplayer.metadata.MetadataRenderer) SampleStream(androidx.media3.exoplayer.source.SampleStream)

Example 3 with TrackSelectorResult

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);
}
Also used : TrackGroupArray(androidx.media3.common.TrackGroupArray) NullableType(org.checkerframework.checker.nullness.compatqual.NullableType) TracksInfo(androidx.media3.common.TracksInfo) TrackGroup(androidx.media3.common.TrackGroup) RendererCapabilities(androidx.media3.exoplayer.RendererCapabilities) Capabilities(androidx.media3.exoplayer.RendererCapabilities.Capabilities) AdaptiveSupport(androidx.media3.exoplayer.RendererCapabilities.AdaptiveSupport)

Example 4 with TrackSelectorResult

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);
}
Also used : Format(androidx.media3.common.Format) TrackGroupArray(androidx.media3.common.TrackGroupArray) Test(org.junit.Test)

Example 5 with TrackSelectorResult

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);
}
Also used : Format(androidx.media3.common.Format) TrackGroupArray(androidx.media3.common.TrackGroupArray) Test(org.junit.Test)

Aggregations

TrackGroupArray (androidx.media3.common.TrackGroupArray)60 Test (org.junit.Test)58 Format (androidx.media3.common.Format)49 RendererCapabilities (androidx.media3.exoplayer.RendererCapabilities)29 TrackGroup (androidx.media3.common.TrackGroup)10 TrackSelectorResult (androidx.media3.exoplayer.trackselection.TrackSelectorResult)9 HashMap (java.util.HashMap)8 ParametersBuilder (androidx.media3.exoplayer.trackselection.DefaultTrackSelector.ParametersBuilder)7 TrackSelectionOverride (androidx.media3.common.TrackSelectionOverrides.TrackSelectionOverride)6 MetadataRenderer (androidx.media3.exoplayer.metadata.MetadataRenderer)4 TextRenderer (androidx.media3.exoplayer.text.TextRenderer)4 Nullable (androidx.annotation.Nullable)3 Capabilities (androidx.media3.exoplayer.RendererCapabilities.Capabilities)3 ExoTrackSelection (androidx.media3.exoplayer.trackselection.ExoTrackSelection)3 SampleStream (androidx.media3.exoplayer.source.SampleStream)2 SelectionOverride (androidx.media3.exoplayer.trackselection.DefaultTrackSelector.SelectionOverride)2 CheckResult (androidx.annotation.CheckResult)1 Metadata (androidx.media3.common.Metadata)1 Timeline (androidx.media3.common.Timeline)1 TracksInfo (androidx.media3.common.TracksInfo)1