Search in sources :

Example 36 with RendererCapabilities

use of com.google.android.exoplayer2.RendererCapabilities in project ExoPlayer by google.

the class MappingTrackSelector method findRenderer.

/**
   * Finds the renderer to which the provided {@link TrackGroup} should be associated.
   * <p>
   * A {@link TrackGroup} is associated to a renderer that reports
   * {@link RendererCapabilities#FORMAT_HANDLED} support for one or more of the tracks in the group,
   * or {@link RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES} if no such renderer exists, or
   * {@link RendererCapabilities#FORMAT_UNSUPPORTED_SUBTYPE} if again no such renderer exists. In
   * the case that two or more renderers report the same level of support, the renderer with the
   * lowest index is associated.
   * <p>
   * If all renderers report {@link RendererCapabilities#FORMAT_UNSUPPORTED_TYPE} for all of the
   * tracks in the group, then {@code renderers.length} is returned to indicate that no association
   * was made.
   *
   * @param rendererCapabilities The {@link RendererCapabilities} of the renderers.
   * @param group The {@link TrackGroup} whose associated renderer is to be found.
   * @return The index of the associated renderer, or {@code renderers.length} if no
   *     association was made.
   * @throws ExoPlaybackException If an error occurs finding a renderer.
   */
private static int findRenderer(RendererCapabilities[] rendererCapabilities, TrackGroup group) throws ExoPlaybackException {
    int bestRendererIndex = rendererCapabilities.length;
    int bestFormatSupportLevel = RendererCapabilities.FORMAT_UNSUPPORTED_TYPE;
    for (int rendererIndex = 0; rendererIndex < rendererCapabilities.length; rendererIndex++) {
        RendererCapabilities rendererCapability = rendererCapabilities[rendererIndex];
        for (int trackIndex = 0; trackIndex < group.length; trackIndex++) {
            int formatSupportLevel = rendererCapability.supportsFormat(group.getFormat(trackIndex)) & RendererCapabilities.FORMAT_SUPPORT_MASK;
            if (formatSupportLevel > bestFormatSupportLevel) {
                bestRendererIndex = rendererIndex;
                bestFormatSupportLevel = formatSupportLevel;
                if (bestFormatSupportLevel == RendererCapabilities.FORMAT_HANDLED) {
                    // We can't do better.
                    return bestRendererIndex;
                }
            }
        }
    }
    return bestRendererIndex;
}
Also used : RendererCapabilities(com.google.android.exoplayer2.RendererCapabilities)

Example 37 with RendererCapabilities

use of com.google.android.exoplayer2.RendererCapabilities in project ExoPlayer by google.

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(com.google.android.exoplayer2.source.TrackGroupArray) NullableType(org.checkerframework.checker.nullness.compatqual.NullableType) TracksInfo(com.google.android.exoplayer2.TracksInfo) TrackGroup(com.google.android.exoplayer2.source.TrackGroup) RendererCapabilities(com.google.android.exoplayer2.RendererCapabilities) Capabilities(com.google.android.exoplayer2.RendererCapabilities.Capabilities) AdaptiveSupport(com.google.android.exoplayer2.RendererCapabilities.AdaptiveSupport)

Example 38 with RendererCapabilities

use of com.google.android.exoplayer2.RendererCapabilities in project ExoPlayer by google.

the class ExoPlayerImplInternal method maybeUpdateReadingPeriod.

private void maybeUpdateReadingPeriod() {
    @Nullable MediaPeriodHolder readingPeriodHolder = queue.getReadingPeriod();
    if (readingPeriodHolder == null) {
        return;
    }
    if (readingPeriodHolder.getNext() == null || pendingPauseAtEndOfPeriod) {
        // intentionally to pause at the end of the period.
        if (readingPeriodHolder.info.isFinal || pendingPauseAtEndOfPeriod) {
            for (int i = 0; i < renderers.length; i++) {
                Renderer renderer = renderers[i];
                SampleStream sampleStream = readingPeriodHolder.sampleStreams[i];
                // stream in case of playlist changes that cause the stream to be no longer final.
                if (sampleStream != null && renderer.getStream() == sampleStream && renderer.hasReadStreamToEnd()) {
                    long streamEndPositionUs = readingPeriodHolder.info.durationUs != C.TIME_UNSET && readingPeriodHolder.info.durationUs != C.TIME_END_OF_SOURCE ? readingPeriodHolder.getRendererOffset() + readingPeriodHolder.info.durationUs : C.TIME_UNSET;
                    setCurrentStreamFinal(renderer, streamEndPositionUs);
                }
            }
        }
        return;
    }
    if (!hasReadingPeriodFinishedReading()) {
        return;
    }
    if (!readingPeriodHolder.getNext().prepared && rendererPositionUs < readingPeriodHolder.getNext().getStartPositionRendererTime()) {
        // The successor is not prepared yet and playback hasn't reached the transition point.
        return;
    }
    MediaPeriodHolder oldReadingPeriodHolder = readingPeriodHolder;
    TrackSelectorResult oldTrackSelectorResult = readingPeriodHolder.getTrackSelectorResult();
    readingPeriodHolder = queue.advanceReadingPeriod();
    TrackSelectorResult newTrackSelectorResult = readingPeriodHolder.getTrackSelectorResult();
    updatePlaybackSpeedSettingsForNewPeriod(/* newTimeline= */
    playbackInfo.timeline, /* newPeriodId= */
    readingPeriodHolder.info.id, /* oldTimeline= */
    playbackInfo.timeline, /* oldPeriodId= */
    oldReadingPeriodHolder.info.id, /* positionForTargetOffsetOverrideUs= */
    C.TIME_UNSET);
    if (readingPeriodHolder.prepared && readingPeriodHolder.mediaPeriod.readDiscontinuity() != C.TIME_UNSET) {
        // The new period starts with a discontinuity, so the renderers will play out all data, then
        // be disabled and re-enabled when they start playing the next period.
        setAllRendererStreamsFinal(/* streamEndPositionUs= */
        readingPeriodHolder.getStartPositionRendererTime());
        return;
    }
    for (int i = 0; i < renderers.length; i++) {
        boolean oldRendererEnabled = oldTrackSelectorResult.isRendererEnabled(i);
        boolean newRendererEnabled = newTrackSelectorResult.isRendererEnabled(i);
        if (oldRendererEnabled && !renderers[i].isCurrentStreamFinal()) {
            boolean isNoSampleRenderer = rendererCapabilities[i].getTrackType() == C.TRACK_TYPE_NONE;
            RendererConfiguration oldConfig = oldTrackSelectorResult.rendererConfigurations[i];
            RendererConfiguration newConfig = newTrackSelectorResult.rendererConfigurations[i];
            if (!newRendererEnabled || !newConfig.equals(oldConfig) || isNoSampleRenderer) {
                // The renderer will be disabled when transitioning to playing the next period, because
                // there's no new selection, or because a configuration change is required, or because
                // it's a no-sample renderer for which rendererOffsetUs should be updated only when
                // starting to play the next period. Mark the SampleStream as final to play out any
                // remaining data.
                setCurrentStreamFinal(renderers[i], /* streamEndPositionUs= */
                readingPeriodHolder.getStartPositionRendererTime());
            }
        }
    }
}
Also used : TrackSelectorResult(com.google.android.exoplayer2.trackselection.TrackSelectorResult) TextRenderer(com.google.android.exoplayer2.text.TextRenderer) Nullable(androidx.annotation.Nullable) SampleStream(com.google.android.exoplayer2.source.SampleStream)

Example 39 with RendererCapabilities

use of com.google.android.exoplayer2.RendererCapabilities in project ExoPlayer by google.

the class DefaultTrackSelectorTest method selectTracksWithMultipleAudioTracksOverrideReturnsAdaptiveTrackSelection.

@Test
public void selectTracksWithMultipleAudioTracksOverrideReturnsAdaptiveTrackSelection() throws Exception {
    Format.Builder formatBuilder = AUDIO_FORMAT.buildUpon();
    TrackGroupArray trackGroups = singleTrackGroup(formatBuilder.setId("0").build(), formatBuilder.setId("1").build(), formatBuilder.setId("2").build());
    trackSelector.setParameters(trackSelector.buildUponParameters().setSelectionOverride(/* rendererIndex= */
    0, trackGroups, new SelectionOverride(/* groupIndex= */
    0, /* tracks=... */
    1, 2)));
    TrackSelectorResult result = trackSelector.selectTracks(new RendererCapabilities[] { AUDIO_CAPABILITIES }, trackGroups, periodId, TIMELINE);
    assertThat(result.length).isEqualTo(1);
    assertAdaptiveSelection(result.selections[0], trackGroups.get(0), 1, 2);
}
Also used : SelectionOverride(com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride) TrackSelectionOverride(com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride) Format(com.google.android.exoplayer2.Format) TrackGroupArray(com.google.android.exoplayer2.source.TrackGroupArray) Test(org.junit.Test)

Example 40 with RendererCapabilities

use of com.google.android.exoplayer2.RendererCapabilities in project ExoPlayer by google.

the class DefaultTrackSelectorTest method selectTracksExceedingCapabilitiesSelectLowerNumChannel.

/**
 * Tests that track selector will select audio tracks with lower num channel when other factors
 * are the same, and tracks exceed renderer's capabilities.
 */
@Test
public void selectTracksExceedingCapabilitiesSelectLowerNumChannel() throws Exception {
    Format.Builder formatBuilder = AUDIO_FORMAT.buildUpon();
    Format higherChannelFormat = formatBuilder.setChannelCount(6).build();
    Format lowerChannelFormat = formatBuilder.setChannelCount(2).build();
    TrackGroupArray trackGroups = wrapFormats(higherChannelFormat, lowerChannelFormat);
    TrackSelectorResult result = trackSelector.selectTracks(new RendererCapabilities[] { ALL_AUDIO_FORMAT_EXCEEDED_RENDERER_CAPABILITIES }, trackGroups, periodId, TIMELINE);
    assertFixedSelection(result.selections[0], trackGroups, lowerChannelFormat);
}
Also used : Format(com.google.android.exoplayer2.Format) TrackGroupArray(com.google.android.exoplayer2.source.TrackGroupArray) Test(org.junit.Test)

Aggregations

TrackGroupArray (com.google.android.exoplayer2.source.TrackGroupArray)59 Test (org.junit.Test)57 Format (com.google.android.exoplayer2.Format)47 RendererCapabilities (com.google.android.exoplayer2.RendererCapabilities)36 TrackGroup (com.google.android.exoplayer2.source.TrackGroup)11 HashMap (java.util.HashMap)8 ParametersBuilder (com.google.android.exoplayer2.trackselection.DefaultTrackSelector.ParametersBuilder)5 TrackSelectionOverride (com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride)4 Capabilities (com.google.android.exoplayer2.RendererCapabilities.Capabilities)3 Nullable (androidx.annotation.Nullable)2 RendererConfiguration (com.google.android.exoplayer2.RendererConfiguration)2 SelectionOverride (com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride)2 TrackSelectorResult (com.google.android.exoplayer2.trackselection.TrackSelectorResult)2 Point (android.graphics.Point)1 Handler (android.os.Handler)1 FormatSupport (com.google.android.exoplayer2.C.FormatSupport)1 ExoPlaybackException (com.google.android.exoplayer2.ExoPlaybackException)1 Renderer (com.google.android.exoplayer2.Renderer)1 AdaptiveSupport (com.google.android.exoplayer2.RendererCapabilities.AdaptiveSupport)1 TracksInfo (com.google.android.exoplayer2.TracksInfo)1