Search in sources :

Example 21 with SampleStream

use of com.google.android.exoplayer2.source.SampleStream in project ExoPlayer by google.

the class HlsSampleStreamWrapper method selectTracks.

public boolean selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, SampleStream[] streams, boolean[] streamResetFlags, boolean isFirstTrackSelection) {
    Assertions.checkState(prepared);
    // Disable old tracks.
    for (int i = 0; i < selections.length; i++) {
        if (streams[i] != null && (selections[i] == null || !mayRetainStreamFlags[i])) {
            int group = ((HlsSampleStream) streams[i]).group;
            setTrackGroupEnabledState(group, false);
            sampleQueues.valueAt(group).disable();
            streams[i] = null;
        }
    }
    // Enable new tracks.
    TrackSelection primaryTrackSelection = null;
    boolean selectedNewTracks = false;
    for (int i = 0; i < selections.length; i++) {
        if (streams[i] == null && selections[i] != null) {
            TrackSelection selection = selections[i];
            int group = trackGroups.indexOf(selection.getTrackGroup());
            setTrackGroupEnabledState(group, true);
            if (group == primaryTrackGroupIndex) {
                primaryTrackSelection = selection;
                chunkSource.selectTracks(selection);
            }
            streams[i] = new HlsSampleStream(this, group);
            streamResetFlags[i] = true;
            selectedNewTracks = true;
        }
    }
    if (isFirstTrackSelection) {
        // At the time of the first track selection all queues will be enabled, so we need to disable
        // any that are no longer required.
        int sampleQueueCount = sampleQueues.size();
        for (int i = 0; i < sampleQueueCount; i++) {
            if (!groupEnabledStates[i]) {
                sampleQueues.valueAt(i).disable();
            }
        }
        if (primaryTrackSelection != null && !mediaChunks.isEmpty()) {
            primaryTrackSelection.updateSelectedTrack(0);
            int chunkIndex = chunkSource.getTrackGroup().indexOf(mediaChunks.getLast().trackFormat);
            if (primaryTrackSelection.getSelectedIndexInTrackGroup() != chunkIndex) {
                // The loaded preparation chunk does match the selection. We discard it.
                seekTo(lastSeekPositionUs);
            }
        }
    }
    // Cancel requests if necessary.
    if (enabledTrackCount == 0) {
        chunkSource.reset();
        downstreamTrackFormat = null;
        mediaChunks.clear();
        if (loader.isLoading()) {
            loader.cancelLoading();
        }
    }
    return selectedNewTracks;
}
Also used : TrackSelection(com.google.android.exoplayer2.trackselection.TrackSelection)

Example 22 with SampleStream

use of com.google.android.exoplayer2.source.SampleStream in project ExoPlayer by google.

the class DashMediaPeriod method selectTracks.

@Override
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
    int adaptationSetCount = adaptationSets.size();
    HashMap<Integer, ChunkSampleStream<DashChunkSource>> primarySampleStreams = new HashMap<>();
    // First pass for primary tracks.
    for (int i = 0; i < selections.length; i++) {
        if (streams[i] instanceof ChunkSampleStream) {
            @SuppressWarnings("unchecked") ChunkSampleStream<DashChunkSource> stream = (ChunkSampleStream<DashChunkSource>) streams[i];
            if (selections[i] == null || !mayRetainStreamFlags[i]) {
                stream.release();
                streams[i] = null;
            } else {
                int adaptationSetIndex = trackGroups.indexOf(selections[i].getTrackGroup());
                primarySampleStreams.put(adaptationSetIndex, stream);
            }
        }
        if (streams[i] == null && selections[i] != null) {
            int trackGroupIndex = trackGroups.indexOf(selections[i].getTrackGroup());
            if (trackGroupIndex < adaptationSetCount) {
                ChunkSampleStream<DashChunkSource> stream = buildSampleStream(trackGroupIndex, selections[i], positionUs);
                primarySampleStreams.put(trackGroupIndex, stream);
                streams[i] = stream;
                streamResetFlags[i] = true;
            }
        }
    }
    // Second pass for embedded tracks.
    for (int i = 0; i < selections.length; i++) {
        if ((streams[i] instanceof EmbeddedSampleStream || streams[i] instanceof EmptySampleStream) && (selections[i] == null || !mayRetainStreamFlags[i])) {
            // The stream is for an embedded track and is either no longer selected or needs replacing.
            releaseIfEmbeddedSampleStream(streams[i]);
            streams[i] = null;
        }
        // may have been replaced, selected or deselected.
        if (selections[i] != null) {
            int trackGroupIndex = trackGroups.indexOf(selections[i].getTrackGroup());
            if (trackGroupIndex >= adaptationSetCount) {
                int embeddedTrackIndex = trackGroupIndex - adaptationSetCount;
                EmbeddedTrackInfo embeddedTrackInfo = embeddedTrackInfos[embeddedTrackIndex];
                int adaptationSetIndex = embeddedTrackInfo.adaptationSetIndex;
                ChunkSampleStream<?> primaryStream = primarySampleStreams.get(adaptationSetIndex);
                SampleStream stream = streams[i];
                boolean mayRetainStream = primaryStream == null ? stream instanceof EmptySampleStream : (stream instanceof EmbeddedSampleStream && ((EmbeddedSampleStream) stream).parent == primaryStream);
                if (!mayRetainStream) {
                    releaseIfEmbeddedSampleStream(stream);
                    streams[i] = primaryStream == null ? new EmptySampleStream() : primaryStream.selectEmbeddedTrack(positionUs, embeddedTrackInfo.trackType);
                    streamResetFlags[i] = true;
                }
            }
        }
    }
    sampleStreams = newSampleStreamArray(primarySampleStreams.size());
    primarySampleStreams.values().toArray(sampleStreams);
    sequenceableLoader = new CompositeSequenceableLoader(sampleStreams);
    return positionUs;
}
Also used : EmptySampleStream(com.google.android.exoplayer2.source.EmptySampleStream) ChunkSampleStream(com.google.android.exoplayer2.source.chunk.ChunkSampleStream) HashMap(java.util.HashMap) EmbeddedSampleStream(com.google.android.exoplayer2.source.chunk.ChunkSampleStream.EmbeddedSampleStream) ChunkSampleStream(com.google.android.exoplayer2.source.chunk.ChunkSampleStream) EmptySampleStream(com.google.android.exoplayer2.source.EmptySampleStream) SampleStream(com.google.android.exoplayer2.source.SampleStream) CompositeSequenceableLoader(com.google.android.exoplayer2.source.CompositeSequenceableLoader) EmbeddedSampleStream(com.google.android.exoplayer2.source.chunk.ChunkSampleStream.EmbeddedSampleStream)

Example 23 with SampleStream

use of com.google.android.exoplayer2.source.SampleStream in project ExoPlayer by google.

the class HlsMediaPeriod method selectTracks.

@Override
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
    // Map each selection and stream onto a child period index.
    int[] streamChildIndices = new int[selections.length];
    int[] selectionChildIndices = new int[selections.length];
    for (int i = 0; i < selections.length; i++) {
        streamChildIndices[i] = streams[i] == null ? C.INDEX_UNSET : streamWrapperIndices.get(streams[i]);
        selectionChildIndices[i] = C.INDEX_UNSET;
        if (selections[i] != null) {
            TrackGroup trackGroup = selections[i].getTrackGroup();
            for (int j = 0; j < sampleStreamWrappers.length; j++) {
                if (sampleStreamWrappers[j].getTrackGroups().indexOf(trackGroup) != C.INDEX_UNSET) {
                    selectionChildIndices[i] = j;
                    break;
                }
            }
        }
    }
    boolean selectedNewTracks = false;
    streamWrapperIndices.clear();
    // Select tracks for each child, copying the resulting streams back into a new streams array.
    SampleStream[] newStreams = new SampleStream[selections.length];
    SampleStream[] childStreams = new SampleStream[selections.length];
    TrackSelection[] childSelections = new TrackSelection[selections.length];
    ArrayList<HlsSampleStreamWrapper> enabledSampleStreamWrapperList = new ArrayList<>(sampleStreamWrappers.length);
    for (int i = 0; i < sampleStreamWrappers.length; i++) {
        for (int j = 0; j < selections.length; j++) {
            childStreams[j] = streamChildIndices[j] == i ? streams[j] : null;
            childSelections[j] = selectionChildIndices[j] == i ? selections[j] : null;
        }
        selectedNewTracks |= sampleStreamWrappers[i].selectTracks(childSelections, mayRetainStreamFlags, childStreams, streamResetFlags, !seenFirstTrackSelection);
        boolean wrapperEnabled = false;
        for (int j = 0; j < selections.length; j++) {
            if (selectionChildIndices[j] == i) {
                // Assert that the child provided a stream for the selection.
                Assertions.checkState(childStreams[j] != null);
                newStreams[j] = childStreams[j];
                wrapperEnabled = true;
                streamWrapperIndices.put(childStreams[j], i);
            } else if (streamChildIndices[j] == i) {
                // Assert that the child cleared any previous stream.
                Assertions.checkState(childStreams[j] == null);
            }
        }
        if (wrapperEnabled) {
            enabledSampleStreamWrapperList.add(sampleStreamWrappers[i]);
        }
    }
    // Copy the new streams back into the streams array.
    System.arraycopy(newStreams, 0, streams, 0, newStreams.length);
    // Update the local state.
    enabledSampleStreamWrappers = new HlsSampleStreamWrapper[enabledSampleStreamWrapperList.size()];
    enabledSampleStreamWrapperList.toArray(enabledSampleStreamWrappers);
    // initialization.
    if (enabledSampleStreamWrappers.length > 0) {
        enabledSampleStreamWrappers[0].setIsTimestampMaster(true);
        for (int i = 1; i < enabledSampleStreamWrappers.length; i++) {
            enabledSampleStreamWrappers[i].setIsTimestampMaster(false);
        }
    }
    sequenceableLoader = new CompositeSequenceableLoader(enabledSampleStreamWrappers);
    if (seenFirstTrackSelection && selectedNewTracks) {
        seekToUs(positionUs);
        // We'll need to reset renderers consuming from all streams due to the seek.
        for (int i = 0; i < selections.length; i++) {
            if (streams[i] != null) {
                streamResetFlags[i] = true;
            }
        }
    }
    seenFirstTrackSelection = true;
    return positionUs;
}
Also used : TrackGroup(com.google.android.exoplayer2.source.TrackGroup) ArrayList(java.util.ArrayList) TrackSelection(com.google.android.exoplayer2.trackselection.TrackSelection) SampleStream(com.google.android.exoplayer2.source.SampleStream) CompositeSequenceableLoader(com.google.android.exoplayer2.source.CompositeSequenceableLoader)

Example 24 with SampleStream

use of com.google.android.exoplayer2.source.SampleStream in project ExoPlayer by google.

the class FakeMediaPeriod method selectTracks.

@Override
public long selectTracks(@NullableType ExoTrackSelection[] selections, boolean[] mayRetainStreamFlags, @NullableType SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
    assertThat(prepared).isTrue();
    int rendererCount = selections.length;
    for (int i = 0; i < rendererCount; i++) {
        if (streams[i] != null && (selections[i] == null || !mayRetainStreamFlags[i])) {
            ((FakeSampleStream) streams[i]).release();
            sampleStreams.remove(streams[i]);
            streams[i] = null;
        }
        if (streams[i] == null && selections[i] != null) {
            ExoTrackSelection selection = selections[i];
            assertThat(selection.length()).isAtLeast(1);
            TrackGroup trackGroup = selection.getTrackGroup();
            assertThat(trackGroupArray.indexOf(trackGroup) != C.INDEX_UNSET).isTrue();
            int indexInTrackGroup = selection.getIndexInTrackGroup(selection.getSelectedIndex());
            assertThat(indexInTrackGroup).isAtLeast(0);
            assertThat(indexInTrackGroup).isLessThan(trackGroup.length);
            List<FakeSampleStreamItem> sampleStreamItems = trackDataFactory.create(selection.getSelectedFormat(), checkNotNull(mediaSourceEventDispatcher.mediaPeriodId));
            FakeSampleStream sampleStream = createSampleStream(allocator, mediaSourceEventDispatcher, drmSessionManager, drmEventDispatcher, selection.getSelectedFormat(), sampleStreamItems);
            sampleStreams.add(sampleStream);
            streams[i] = sampleStream;
            streamResetFlags[i] = true;
        }
    }
    return seekToUs(positionUs);
}
Also used : FakeSampleStreamItem(com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem) ExoTrackSelection(com.google.android.exoplayer2.trackselection.ExoTrackSelection) TrackGroup(com.google.android.exoplayer2.source.TrackGroup)

Example 25 with SampleStream

use of com.google.android.exoplayer2.source.SampleStream in project ExoPlayer by google.

the class MergingMediaPeriodTest method selectTracks_withPeriodOffsets_selectTracksWithOffset_andCreatesSampleStreamsCorrectingOffset.

@Test
public void selectTracks_withPeriodOffsets_selectTracksWithOffset_andCreatesSampleStreamsCorrectingOffset() throws Exception {
    MergingMediaPeriod mergingMediaPeriod = prepareMergingPeriod(new MergingPeriodDefinition(/* timeOffsetUs= */
    0, /* singleSampleTimeUs= */
    123_000, childFormat11, childFormat12), new MergingPeriodDefinition(/* timeOffsetUs= */
    -3000, /* singleSampleTimeUs= */
    456_000, childFormat21, childFormat22));
    ExoTrackSelection selectionForChild1 = new FixedTrackSelection(mergingMediaPeriod.getTrackGroups().get(0), /* track= */
    0);
    ExoTrackSelection selectionForChild2 = new FixedTrackSelection(mergingMediaPeriod.getTrackGroups().get(2), /* track= */
    0);
    SampleStream[] streams = new SampleStream[2];
    mergingMediaPeriod.selectTracks(/* selections= */
    new ExoTrackSelection[] { selectionForChild1, selectionForChild2 }, /* mayRetainStreamFlags= */
    new boolean[] { false, false }, streams, /* streamResetFlags= */
    new boolean[] { false, false }, /* positionUs= */
    0);
    mergingMediaPeriod.continueLoading(/* positionUs= */
    0);
    FormatHolder formatHolder = new FormatHolder();
    DecoderInputBuffer inputBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
    streams[0].readData(formatHolder, inputBuffer, FLAG_REQUIRE_FORMAT);
    streams[1].readData(formatHolder, inputBuffer, FLAG_REQUIRE_FORMAT);
    FakeMediaPeriodWithSelectTracksPosition childMediaPeriod1 = (FakeMediaPeriodWithSelectTracksPosition) mergingMediaPeriod.getChildPeriod(0);
    assertThat(childMediaPeriod1.selectTracksPositionUs).isEqualTo(0);
    assertThat(streams[0].readData(formatHolder, inputBuffer, /* readFlags= */
    0)).isEqualTo(C.RESULT_BUFFER_READ);
    assertThat(inputBuffer.timeUs).isEqualTo(123_000L);
    FakeMediaPeriodWithSelectTracksPosition childMediaPeriod2 = (FakeMediaPeriodWithSelectTracksPosition) mergingMediaPeriod.getChildPeriod(1);
    assertThat(childMediaPeriod2.selectTracksPositionUs).isEqualTo(3000L);
    assertThat(streams[1].readData(formatHolder, inputBuffer, /* readFlags= */
    0)).isEqualTo(C.RESULT_BUFFER_READ);
    assertThat(inputBuffer.timeUs).isEqualTo(456_000 - 3000);
}
Also used : ExoTrackSelection(com.google.android.exoplayer2.trackselection.ExoTrackSelection) DecoderInputBuffer(com.google.android.exoplayer2.decoder.DecoderInputBuffer) FormatHolder(com.google.android.exoplayer2.FormatHolder) FixedTrackSelection(com.google.android.exoplayer2.trackselection.FixedTrackSelection) Test(org.junit.Test)

Aggregations

EventStream (com.google.android.exoplayer2.source.dash.manifest.EventStream)15 Test (org.junit.Test)15 EventMessage (com.google.android.exoplayer2.metadata.emsg.EventMessage)10 ExoTrackSelection (com.google.android.exoplayer2.trackselection.ExoTrackSelection)10 SampleStream (com.google.android.exoplayer2.source.SampleStream)8 TrackGroup (com.google.android.exoplayer2.source.TrackGroup)6 CompositeSequenceableLoader (com.google.android.exoplayer2.source.CompositeSequenceableLoader)5 ChunkSampleStream (com.google.android.exoplayer2.source.chunk.ChunkSampleStream)5 TrackSelection (com.google.android.exoplayer2.trackselection.TrackSelection)5 ArrayList (java.util.ArrayList)5 Format (com.google.android.exoplayer2.Format)3 FormatHolder (com.google.android.exoplayer2.FormatHolder)3 EmptySampleStream (com.google.android.exoplayer2.source.EmptySampleStream)3 TextRenderer (com.google.android.exoplayer2.text.TextRenderer)3 TrackSelectorResult (com.google.android.exoplayer2.trackselection.TrackSelectorResult)3 DecoderInputBuffer (com.google.android.exoplayer2.decoder.DecoderInputBuffer)2 SampleQueue (com.google.android.exoplayer2.source.SampleQueue)2 EmbeddedSampleStream (com.google.android.exoplayer2.source.chunk.ChunkSampleStream.EmbeddedSampleStream)2 FixedTrackSelection (com.google.android.exoplayer2.trackselection.FixedTrackSelection)2 NullableType (org.checkerframework.checker.nullness.compatqual.NullableType)2