Search in sources :

Example 1 with SampleStream

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

the class ExtractorMediaPeriod method selectTracks.

@Override
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
    Assertions.checkState(prepared);
    // Disable old tracks.
    for (int i = 0; i < selections.length; i++) {
        if (streams[i] != null && (selections[i] == null || !mayRetainStreamFlags[i])) {
            int track = ((SampleStreamImpl) streams[i]).track;
            Assertions.checkState(trackEnabledStates[track]);
            enabledTrackCount--;
            trackEnabledStates[track] = false;
            sampleQueues.valueAt(track).disable();
            streams[i] = null;
        }
    }
    // Enable new tracks.
    boolean selectedNewTracks = false;
    for (int i = 0; i < selections.length; i++) {
        if (streams[i] == null && selections[i] != null) {
            TrackSelection selection = selections[i];
            Assertions.checkState(selection.length() == 1);
            Assertions.checkState(selection.getIndexInTrackGroup(0) == 0);
            int track = tracks.indexOf(selection.getTrackGroup());
            Assertions.checkState(!trackEnabledStates[track]);
            enabledTrackCount++;
            trackEnabledStates[track] = true;
            streams[i] = new SampleStreamImpl(track);
            streamResetFlags[i] = true;
            selectedNewTracks = true;
        }
    }
    if (!seenFirstTrackSelection) {
        // 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 trackCount = sampleQueues.size();
        for (int i = 0; i < trackCount; i++) {
            if (!trackEnabledStates[i]) {
                sampleQueues.valueAt(i).disable();
            }
        }
    }
    if (enabledTrackCount == 0) {
        notifyReset = false;
        if (loader.isLoading()) {
            loader.cancelLoading();
        }
    } else if (seenFirstTrackSelection ? selectedNewTracks : positionUs != 0) {
        positionUs = seekToUs(positionUs);
        // We'll need to reset renderers consuming from all streams due to the seek.
        for (int i = 0; i < streams.length; i++) {
            if (streams[i] != null) {
                streamResetFlags[i] = true;
            }
        }
    }
    seenFirstTrackSelection = true;
    return positionUs;
}
Also used : TrackSelection(com.google.android.exoplayer2.trackselection.TrackSelection)

Example 2 with SampleStream

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

the class ExoPlayerImplInternal method updatePeriods.

private void updatePeriods() throws ExoPlaybackException, IOException {
    if (timeline == null) {
        // We're waiting to get information about periods.
        mediaSource.maybeThrowSourceInfoRefreshError();
        return;
    }
    // Update the loading period if required.
    maybeUpdateLoadingPeriod();
    if (loadingPeriodHolder == null || loadingPeriodHolder.isFullyBuffered()) {
        setIsLoading(false);
    } else if (loadingPeriodHolder != null && loadingPeriodHolder.needsContinueLoading) {
        maybeContinueLoading();
    }
    if (playingPeriodHolder == null) {
        // We're waiting for the first period to be prepared.
        return;
    }
    // Update the playing and reading periods.
    while (playingPeriodHolder != readingPeriodHolder && rendererPositionUs >= playingPeriodHolder.next.rendererPositionOffsetUs) {
        // All enabled renderers' streams have been read to the end, and the playback position reached
        // the end of the playing period, so advance playback to the next period.
        playingPeriodHolder.release();
        setPlayingPeriodHolder(playingPeriodHolder.next);
        playbackInfo = new PlaybackInfo(playingPeriodHolder.index, playingPeriodHolder.startPositionUs);
        updatePlaybackPositions();
        eventHandler.obtainMessage(MSG_POSITION_DISCONTINUITY, playbackInfo).sendToTarget();
    }
    if (readingPeriodHolder.isLast) {
        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()) {
                renderer.setCurrentStreamFinal();
            }
        }
        return;
    }
    for (int i = 0; i < renderers.length; i++) {
        Renderer renderer = renderers[i];
        SampleStream sampleStream = readingPeriodHolder.sampleStreams[i];
        if (renderer.getStream() != sampleStream || (sampleStream != null && !renderer.hasReadStreamToEnd())) {
            return;
        }
    }
    if (readingPeriodHolder.next != null && readingPeriodHolder.next.prepared) {
        TrackSelectorResult oldTrackSelectorResult = readingPeriodHolder.trackSelectorResult;
        readingPeriodHolder = readingPeriodHolder.next;
        TrackSelectorResult newTrackSelectorResult = readingPeriodHolder.trackSelectorResult;
        boolean initialDiscontinuity = readingPeriodHolder.mediaPeriod.readDiscontinuity() != C.TIME_UNSET;
        for (int i = 0; i < renderers.length; i++) {
            Renderer renderer = renderers[i];
            TrackSelection oldSelection = oldTrackSelectorResult.selections.get(i);
            if (oldSelection == null) {
            // The renderer has no current stream and will be enabled when we play the next period.
            } else if (initialDiscontinuity) {
                // The new period starts with a discontinuity, so the renderer will play out all data then
                // be disabled and re-enabled when it starts playing the next period.
                renderer.setCurrentStreamFinal();
            } else if (!renderer.isCurrentStreamFinal()) {
                TrackSelection newSelection = newTrackSelectorResult.selections.get(i);
                RendererConfiguration oldConfig = oldTrackSelectorResult.rendererConfigurations[i];
                RendererConfiguration newConfig = newTrackSelectorResult.rendererConfigurations[i];
                if (newSelection != null && newConfig.equals(oldConfig)) {
                    // Replace the renderer's SampleStream so the transition to playing the next period can
                    // be seamless.
                    Format[] formats = new Format[newSelection.length()];
                    for (int j = 0; j < formats.length; j++) {
                        formats[j] = newSelection.getFormat(j);
                    }
                    renderer.replaceStream(formats, readingPeriodHolder.sampleStreams[i], readingPeriodHolder.getRendererOffset());
                } else {
                    // The renderer will be disabled when transitioning to playing the next period, either
                    // because there's no new selection or because a configuration change is required. Mark
                    // the SampleStream as final to play out any remaining data.
                    renderer.setCurrentStreamFinal();
                }
            }
        }
    }
}
Also used : TrackSelectorResult(com.google.android.exoplayer2.trackselection.TrackSelectorResult) TrackSelection(com.google.android.exoplayer2.trackselection.TrackSelection) SampleStream(com.google.android.exoplayer2.source.SampleStream)

Example 3 with SampleStream

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

the class SsMediaPeriod method selectTracks.

@Override
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
    ArrayList<ChunkSampleStream<SsChunkSource>> sampleStreamsList = new ArrayList<>();
    for (int i = 0; i < selections.length; i++) {
        if (streams[i] != null) {
            @SuppressWarnings("unchecked") ChunkSampleStream<SsChunkSource> stream = (ChunkSampleStream<SsChunkSource>) streams[i];
            if (selections[i] == null || !mayRetainStreamFlags[i]) {
                stream.release();
                streams[i] = null;
            } else {
                sampleStreamsList.add(stream);
            }
        }
        if (streams[i] == null && selections[i] != null) {
            ChunkSampleStream<SsChunkSource> stream = buildSampleStream(selections[i], positionUs);
            sampleStreamsList.add(stream);
            streams[i] = stream;
            streamResetFlags[i] = true;
        }
    }
    sampleStreams = newSampleStreamArray(sampleStreamsList.size());
    sampleStreamsList.toArray(sampleStreams);
    sequenceableLoader = new CompositeSequenceableLoader(sampleStreams);
    return positionUs;
}
Also used : ChunkSampleStream(com.google.android.exoplayer2.source.chunk.ChunkSampleStream) ArrayList(java.util.ArrayList) CompositeSequenceableLoader(com.google.android.exoplayer2.source.CompositeSequenceableLoader)

Example 4 with SampleStream

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

the class MediaCodecRenderer method readSourceOmittingSampleData.

/**
 * Reads from the source when sample data is not required. If a format or an end of stream buffer
 * is read, it will be handled before the call returns.
 *
 * @param readFlags Additional {@link ReadFlags}. {@link SampleStream#FLAG_OMIT_SAMPLE_DATA} is
 *     added internally, and so does not need to be passed.
 * @return Whether a format was read and processed.
 */
private boolean readSourceOmittingSampleData(@SampleStream.ReadFlags int readFlags) throws ExoPlaybackException {
    FormatHolder formatHolder = getFormatHolder();
    noDataBuffer.clear();
    @ReadDataResult int result = readSource(formatHolder, noDataBuffer, readFlags | FLAG_OMIT_SAMPLE_DATA);
    if (result == C.RESULT_FORMAT_READ) {
        onInputFormatChanged(formatHolder);
        return true;
    } else if (result == C.RESULT_BUFFER_READ && noDataBuffer.isEndOfStream()) {
        inputStreamEnded = true;
        processEndOfStream();
    }
    return false;
}
Also used : ReadDataResult(com.google.android.exoplayer2.source.SampleStream.ReadDataResult) FormatHolder(com.google.android.exoplayer2.FormatHolder)

Example 5 with SampleStream

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

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(com.google.android.exoplayer2.trackselection.TrackSelectorResult) TextRenderer(com.google.android.exoplayer2.text.TextRenderer) SampleStream(com.google.android.exoplayer2.source.SampleStream)

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