Search in sources :

Example 21 with ExoTrackSelection

use of com.google.android.exoplayer2.trackselection.ExoTrackSelection in project ExoPlayer by google.

the class HlsMediaPeriod method getStreamKeys.

// TODO: When the multivariant playlist does not de-duplicate variants by URL and allows
// Renditions with null URLs, this method must be updated to calculate stream keys that are
// compatible with those that may already be persisted for offline.
@Override
public List<StreamKey> getStreamKeys(List<ExoTrackSelection> trackSelections) {
    // See HlsMultivariantPlaylist.copy for interpretation of StreamKeys.
    HlsMultivariantPlaylist multivariantPlaylist = Assertions.checkNotNull(playlistTracker.getMultivariantPlaylist());
    boolean hasVariants = !multivariantPlaylist.variants.isEmpty();
    int audioWrapperOffset = hasVariants ? 1 : 0;
    // Subtitle sample stream wrappers are held last.
    int subtitleWrapperOffset = sampleStreamWrappers.length - multivariantPlaylist.subtitles.size();
    TrackGroupArray mainWrapperTrackGroups;
    int mainWrapperPrimaryGroupIndex;
    int[] mainWrapperVariantIndices;
    if (hasVariants) {
        HlsSampleStreamWrapper mainWrapper = sampleStreamWrappers[0];
        mainWrapperVariantIndices = manifestUrlIndicesPerWrapper[0];
        mainWrapperTrackGroups = mainWrapper.getTrackGroups();
        mainWrapperPrimaryGroupIndex = mainWrapper.getPrimaryTrackGroupIndex();
    } else {
        mainWrapperVariantIndices = new int[0];
        mainWrapperTrackGroups = TrackGroupArray.EMPTY;
        mainWrapperPrimaryGroupIndex = 0;
    }
    List<StreamKey> streamKeys = new ArrayList<>();
    boolean needsPrimaryTrackGroupSelection = false;
    boolean hasPrimaryTrackGroupSelection = false;
    for (ExoTrackSelection trackSelection : trackSelections) {
        TrackGroup trackSelectionGroup = trackSelection.getTrackGroup();
        int mainWrapperTrackGroupIndex = mainWrapperTrackGroups.indexOf(trackSelectionGroup);
        if (mainWrapperTrackGroupIndex != C.INDEX_UNSET) {
            if (mainWrapperTrackGroupIndex == mainWrapperPrimaryGroupIndex) {
                // Primary group in main wrapper.
                hasPrimaryTrackGroupSelection = true;
                for (int i = 0; i < trackSelection.length(); i++) {
                    int variantIndex = mainWrapperVariantIndices[trackSelection.getIndexInTrackGroup(i)];
                    streamKeys.add(new StreamKey(HlsMultivariantPlaylist.GROUP_INDEX_VARIANT, variantIndex));
                }
            } else {
                // Embedded group in main wrapper.
                needsPrimaryTrackGroupSelection = true;
            }
        } else {
            // Audio or subtitle group.
            for (int i = audioWrapperOffset; i < sampleStreamWrappers.length; i++) {
                TrackGroupArray wrapperTrackGroups = sampleStreamWrappers[i].getTrackGroups();
                int selectedTrackGroupIndex = wrapperTrackGroups.indexOf(trackSelectionGroup);
                if (selectedTrackGroupIndex != C.INDEX_UNSET) {
                    int groupIndexType = i < subtitleWrapperOffset ? HlsMultivariantPlaylist.GROUP_INDEX_AUDIO : HlsMultivariantPlaylist.GROUP_INDEX_SUBTITLE;
                    int[] selectedWrapperUrlIndices = manifestUrlIndicesPerWrapper[i];
                    for (int trackIndex = 0; trackIndex < trackSelection.length(); trackIndex++) {
                        int renditionIndex = selectedWrapperUrlIndices[trackSelection.getIndexInTrackGroup(trackIndex)];
                        streamKeys.add(new StreamKey(groupIndexType, renditionIndex));
                    }
                    break;
                }
            }
        }
    }
    if (needsPrimaryTrackGroupSelection && !hasPrimaryTrackGroupSelection) {
        // A track selection includes a variant-embedded track, but no variant is added yet. We use
        // the valid variant with the lowest bitrate to reduce overhead.
        int lowestBitrateIndex = mainWrapperVariantIndices[0];
        int lowestBitrate = multivariantPlaylist.variants.get(mainWrapperVariantIndices[0]).format.bitrate;
        for (int i = 1; i < mainWrapperVariantIndices.length; i++) {
            int variantBitrate = multivariantPlaylist.variants.get(mainWrapperVariantIndices[i]).format.bitrate;
            if (variantBitrate < lowestBitrate) {
                lowestBitrate = variantBitrate;
                lowestBitrateIndex = mainWrapperVariantIndices[i];
            }
        }
        streamKeys.add(new StreamKey(HlsMultivariantPlaylist.GROUP_INDEX_VARIANT, lowestBitrateIndex));
    }
    return streamKeys;
}
Also used : ExoTrackSelection(com.google.android.exoplayer2.trackselection.ExoTrackSelection) TrackGroup(com.google.android.exoplayer2.source.TrackGroup) TrackGroupArray(com.google.android.exoplayer2.source.TrackGroupArray) ArrayList(java.util.ArrayList) HlsMultivariantPlaylist(com.google.android.exoplayer2.source.hls.playlist.HlsMultivariantPlaylist) StreamKey(com.google.android.exoplayer2.offline.StreamKey)

Example 22 with ExoTrackSelection

use of com.google.android.exoplayer2.trackselection.ExoTrackSelection 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 23 with ExoTrackSelection

use of com.google.android.exoplayer2.trackselection.ExoTrackSelection in project ExoPlayer by google.

the class DashMediaPeriod method getStreamKeys.

@Override
public List<StreamKey> getStreamKeys(List<ExoTrackSelection> trackSelections) {
    List<AdaptationSet> manifestAdaptationSets = manifest.getPeriod(periodIndex).adaptationSets;
    List<StreamKey> streamKeys = new ArrayList<>();
    for (ExoTrackSelection trackSelection : trackSelections) {
        int trackGroupIndex = trackGroups.indexOf(trackSelection.getTrackGroup());
        TrackGroupInfo trackGroupInfo = trackGroupInfos[trackGroupIndex];
        if (trackGroupInfo.trackGroupCategory != TrackGroupInfo.CATEGORY_PRIMARY) {
            // Ignore non-primary tracks.
            continue;
        }
        int[] adaptationSetIndices = trackGroupInfo.adaptationSetIndices;
        int[] trackIndices = new int[trackSelection.length()];
        for (int i = 0; i < trackSelection.length(); i++) {
            trackIndices[i] = trackSelection.getIndexInTrackGroup(i);
        }
        Arrays.sort(trackIndices);
        int currentAdaptationSetIndex = 0;
        int totalTracksInPreviousAdaptationSets = 0;
        int tracksInCurrentAdaptationSet = manifestAdaptationSets.get(adaptationSetIndices[0]).representations.size();
        for (int trackIndex : trackIndices) {
            while (trackIndex >= totalTracksInPreviousAdaptationSets + tracksInCurrentAdaptationSet) {
                currentAdaptationSetIndex++;
                totalTracksInPreviousAdaptationSets += tracksInCurrentAdaptationSet;
                tracksInCurrentAdaptationSet = manifestAdaptationSets.get(adaptationSetIndices[currentAdaptationSetIndex]).representations.size();
            }
            streamKeys.add(new StreamKey(periodIndex, adaptationSetIndices[currentAdaptationSetIndex], trackIndex - totalTracksInPreviousAdaptationSets));
        }
    }
    return streamKeys;
}
Also used : ExoTrackSelection(com.google.android.exoplayer2.trackselection.ExoTrackSelection) ArrayList(java.util.ArrayList) AdaptationSet(com.google.android.exoplayer2.source.dash.manifest.AdaptationSet) StreamKey(com.google.android.exoplayer2.offline.StreamKey)

Example 24 with ExoTrackSelection

use of com.google.android.exoplayer2.trackselection.ExoTrackSelection in project ExoPlayer by google.

the class DashMediaPeriod method selectTracks.

@Override
public long selectTracks(@NullableType ExoTrackSelection[] selections, boolean[] mayRetainStreamFlags, @NullableType SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
    int[] streamIndexToTrackGroupIndex = getStreamIndexToTrackGroupIndex(selections);
    releaseDisabledStreams(selections, mayRetainStreamFlags, streams);
    releaseOrphanEmbeddedStreams(selections, streams, streamIndexToTrackGroupIndex);
    selectNewStreams(selections, streams, streamResetFlags, positionUs, streamIndexToTrackGroupIndex);
    ArrayList<ChunkSampleStream<DashChunkSource>> sampleStreamList = new ArrayList<>();
    ArrayList<EventSampleStream> eventSampleStreamList = new ArrayList<>();
    for (SampleStream sampleStream : streams) {
        if (sampleStream instanceof ChunkSampleStream) {
            @SuppressWarnings("unchecked") ChunkSampleStream<DashChunkSource> stream = (ChunkSampleStream<DashChunkSource>) sampleStream;
            sampleStreamList.add(stream);
        } else if (sampleStream instanceof EventSampleStream) {
            eventSampleStreamList.add((EventSampleStream) sampleStream);
        }
    }
    sampleStreams = newSampleStreamArray(sampleStreamList.size());
    sampleStreamList.toArray(sampleStreams);
    eventSampleStreams = new EventSampleStream[eventSampleStreamList.size()];
    eventSampleStreamList.toArray(eventSampleStreams);
    compositeSequenceableLoader = compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(sampleStreams);
    return positionUs;
}
Also used : ChunkSampleStream(com.google.android.exoplayer2.source.chunk.ChunkSampleStream) ArrayList(java.util.ArrayList) EmptySampleStream(com.google.android.exoplayer2.source.EmptySampleStream) EmbeddedSampleStream(com.google.android.exoplayer2.source.chunk.ChunkSampleStream.EmbeddedSampleStream) ChunkSampleStream(com.google.android.exoplayer2.source.chunk.ChunkSampleStream) SampleStream(com.google.android.exoplayer2.source.SampleStream)

Example 25 with ExoTrackSelection

use of com.google.android.exoplayer2.trackselection.ExoTrackSelection in project ExoPlayer by google.

the class DefaultTrackSelector method maybeConfigureRenderersForTunneling.

// Utility methods.
/**
 * Determines whether tunneling can be enabled, replacing {@link RendererConfiguration}s in {@code
 * rendererConfigurations} with configurations that enable tunneling on the appropriate renderers
 * if so.
 *
 * @param mappedTrackInfo Mapped track information.
 * @param renderererFormatSupports The {@link Capabilities} for each mapped track, indexed by
 *     renderer, track group and track (in that order).
 * @param rendererConfigurations The renderer configurations. Configurations may be replaced with
 *     ones that enable tunneling as a result of this call.
 * @param trackSelections The renderer track selections.
 */
private static void maybeConfigureRenderersForTunneling(MappedTrackInfo mappedTrackInfo, @Capabilities int[][][] renderererFormatSupports, @NullableType RendererConfiguration[] rendererConfigurations, @NullableType ExoTrackSelection[] trackSelections) {
    // Check whether we can enable tunneling. To enable tunneling we require exactly one audio and
    // one video renderer to support tunneling and have a selection.
    int tunnelingAudioRendererIndex = -1;
    int tunnelingVideoRendererIndex = -1;
    boolean enableTunneling = true;
    for (int i = 0; i < mappedTrackInfo.getRendererCount(); i++) {
        int rendererType = mappedTrackInfo.getRendererType(i);
        ExoTrackSelection trackSelection = trackSelections[i];
        if ((rendererType == C.TRACK_TYPE_AUDIO || rendererType == C.TRACK_TYPE_VIDEO) && trackSelection != null) {
            if (rendererSupportsTunneling(renderererFormatSupports[i], mappedTrackInfo.getTrackGroups(i), trackSelection)) {
                if (rendererType == C.TRACK_TYPE_AUDIO) {
                    if (tunnelingAudioRendererIndex != -1) {
                        enableTunneling = false;
                        break;
                    } else {
                        tunnelingAudioRendererIndex = i;
                    }
                } else {
                    if (tunnelingVideoRendererIndex != -1) {
                        enableTunneling = false;
                        break;
                    } else {
                        tunnelingVideoRendererIndex = i;
                    }
                }
            }
        }
    }
    enableTunneling &= tunnelingAudioRendererIndex != -1 && tunnelingVideoRendererIndex != -1;
    if (enableTunneling) {
        RendererConfiguration tunnelingRendererConfiguration = new RendererConfiguration(/* tunneling= */
        true);
        rendererConfigurations[tunnelingAudioRendererIndex] = tunnelingRendererConfiguration;
        rendererConfigurations[tunnelingVideoRendererIndex] = tunnelingRendererConfiguration;
    }
}
Also used : RendererConfiguration(com.google.android.exoplayer2.RendererConfiguration) SuppressLint(android.annotation.SuppressLint) Point(android.graphics.Point)

Aggregations

ExoTrackSelection (com.google.android.exoplayer2.trackselection.ExoTrackSelection)21 TrackGroup (com.google.android.exoplayer2.source.TrackGroup)9 ArrayList (java.util.ArrayList)8 TrackGroupArray (com.google.android.exoplayer2.source.TrackGroupArray)6 Format (com.google.android.exoplayer2.Format)5 NullableType (org.checkerframework.checker.nullness.compatqual.NullableType)5 StreamKey (com.google.android.exoplayer2.offline.StreamKey)4 ChunkSampleStream (com.google.android.exoplayer2.source.chunk.ChunkSampleStream)4 SuppressLint (android.annotation.SuppressLint)3 Point (android.graphics.Point)3 Nullable (androidx.annotation.Nullable)3 TrackSelectorResult (com.google.android.exoplayer2.trackselection.TrackSelectorResult)3 FormatHolder (com.google.android.exoplayer2.FormatHolder)2 RendererCapabilities (com.google.android.exoplayer2.RendererCapabilities)2 Capabilities (com.google.android.exoplayer2.RendererCapabilities.Capabilities)2 RendererConfiguration (com.google.android.exoplayer2.RendererConfiguration)2 DecoderInputBuffer (com.google.android.exoplayer2.decoder.DecoderInputBuffer)2 EmptySampleStream (com.google.android.exoplayer2.source.EmptySampleStream)2 SampleStream (com.google.android.exoplayer2.source.SampleStream)2 FixedTrackSelection (com.google.android.exoplayer2.trackselection.FixedTrackSelection)2