Search in sources :

Example 1 with ExoPlaybackException

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

the class ExoPlayerImplInternal method reselectTracksInternal.

private void reselectTracksInternal() throws ExoPlaybackException {
    if (playingPeriodHolder == null) {
        // We don't have tracks yet, so we don't care.
        return;
    }
    // Reselect tracks on each period in turn, until the selection changes.
    MediaPeriodHolder periodHolder = playingPeriodHolder;
    boolean selectionsChangedForReadPeriod = true;
    while (true) {
        if (periodHolder == null || !periodHolder.prepared) {
            // The reselection did not change any prepared periods.
            return;
        }
        if (periodHolder.selectTracks()) {
            // 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.next;
    }
    if (selectionsChangedForReadPeriod) {
        // Update streams and rebuffer for the new selection, recreating all streams if reading ahead.
        boolean recreateStreams = readingPeriodHolder != playingPeriodHolder;
        releasePeriodHoldersFrom(playingPeriodHolder.next);
        playingPeriodHolder.next = null;
        loadingPeriodHolder = playingPeriodHolder;
        readingPeriodHolder = playingPeriodHolder;
        boolean[] streamResetFlags = new boolean[renderers.length];
        long periodPositionUs = playingPeriodHolder.updatePeriodTrackSelection(playbackInfo.positionUs, recreateStreams, streamResetFlags);
        if (periodPositionUs != playbackInfo.positionUs) {
            playbackInfo.positionUs = periodPositionUs;
            resetRendererPosition(periodPositionUs);
        }
        int enabledRendererCount = 0;
        boolean[] rendererWasEnabledFlags = new boolean[renderers.length];
        for (int i = 0; i < renderers.length; i++) {
            Renderer renderer = renderers[i];
            rendererWasEnabledFlags[i] = renderer.getState() != Renderer.STATE_DISABLED;
            SampleStream sampleStream = playingPeriodHolder.sampleStreams[i];
            if (sampleStream != null) {
                enabledRendererCount++;
            }
            if (rendererWasEnabledFlags[i]) {
                if (sampleStream != renderer.getStream()) {
                    // We need to disable the renderer.
                    if (renderer == rendererMediaClockSource) {
                        // The renderer is providing the media clock.
                        if (sampleStream == null) {
                            // The renderer won't be re-enabled. Sync standaloneMediaClock so that it can take
                            // over timing responsibilities.
                            standaloneMediaClock.setPositionUs(rendererMediaClock.getPositionUs());
                        }
                        rendererMediaClock = null;
                        rendererMediaClockSource = null;
                    }
                    ensureStopped(renderer);
                    renderer.disable();
                } else if (streamResetFlags[i]) {
                    // The renderer will continue to consume from its current stream, but needs to be reset.
                    renderer.resetPosition(rendererPositionUs);
                }
            }
        }
        eventHandler.obtainMessage(MSG_TRACKS_CHANGED, periodHolder.trackSelectorResult).sendToTarget();
        enableRenderers(rendererWasEnabledFlags, enabledRendererCount);
    } else {
        // Release and re-prepare/buffer periods after the one whose selection changed.
        loadingPeriodHolder = periodHolder;
        periodHolder = loadingPeriodHolder.next;
        while (periodHolder != null) {
            periodHolder.release();
            periodHolder = periodHolder.next;
        }
        loadingPeriodHolder.next = null;
        if (loadingPeriodHolder.prepared) {
            long loadingPeriodPositionUs = Math.max(loadingPeriodHolder.startPositionUs, loadingPeriodHolder.toPeriodTime(rendererPositionUs));
            loadingPeriodHolder.updatePeriodTrackSelection(loadingPeriodPositionUs, false);
        }
    }
    maybeContinueLoading();
    updatePlaybackPositions();
    handler.sendEmptyMessage(MSG_DO_SOME_WORK);
}
Also used : SampleStream(com.google.android.exoplayer2.source.SampleStream)

Example 2 with ExoPlaybackException

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

the class SimpleDecoderAudioRenderer method drainOutputBuffer.

private boolean drainOutputBuffer() throws ExoPlaybackException, AudioDecoderException, AudioTrack.ConfigurationException, AudioTrack.InitializationException, AudioTrack.WriteException {
    if (outputBuffer == null) {
        outputBuffer = decoder.dequeueOutputBuffer();
        if (outputBuffer == null) {
            return false;
        }
        decoderCounters.skippedOutputBufferCount += outputBuffer.skippedOutputBufferCount;
    }
    if (outputBuffer.isEndOfStream()) {
        if (decoderReinitializationState == REINITIALIZATION_STATE_WAIT_END_OF_STREAM) {
            // We're waiting to re-initialize the decoder, and have now processed all final buffers.
            releaseDecoder();
            maybeInitDecoder();
            // The audio track may need to be recreated once the new output format is known.
            audioTrackNeedsConfigure = true;
        } else {
            outputBuffer.release();
            outputBuffer = null;
            processEndOfStream();
        }
        return false;
    }
    if (audioTrackNeedsConfigure) {
        Format outputFormat = getOutputFormat();
        audioTrack.configure(outputFormat.sampleMimeType, outputFormat.channelCount, outputFormat.sampleRate, outputFormat.pcmEncoding, 0);
        audioTrackNeedsConfigure = false;
    }
    if (audioTrack.handleBuffer(outputBuffer.data, outputBuffer.timeUs)) {
        decoderCounters.renderedOutputBufferCount++;
        outputBuffer.release();
        outputBuffer = null;
        return true;
    }
    return false;
}
Also used : Format(com.google.android.exoplayer2.Format)

Example 3 with ExoPlaybackException

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

the class ExoPlayerImplInternal method setPlayingPeriodHolder.

private void setPlayingPeriodHolder(MediaPeriodHolder periodHolder) throws ExoPlaybackException {
    if (playingPeriodHolder == periodHolder) {
        return;
    }
    int enabledRendererCount = 0;
    boolean[] rendererWasEnabledFlags = new boolean[renderers.length];
    for (int i = 0; i < renderers.length; i++) {
        Renderer renderer = renderers[i];
        rendererWasEnabledFlags[i] = renderer.getState() != Renderer.STATE_DISABLED;
        TrackSelection newSelection = periodHolder.trackSelectorResult.selections.get(i);
        if (newSelection != null) {
            enabledRendererCount++;
        }
        if (rendererWasEnabledFlags[i] && (newSelection == null || (renderer.isCurrentStreamFinal() && renderer.getStream() == playingPeriodHolder.sampleStreams[i]))) {
            // is final and it's not reading ahead.
            if (renderer == rendererMediaClockSource) {
                // Sync standaloneMediaClock so that it can take over timing responsibilities.
                standaloneMediaClock.setPositionUs(rendererMediaClock.getPositionUs());
                rendererMediaClock = null;
                rendererMediaClockSource = null;
            }
            ensureStopped(renderer);
            renderer.disable();
        }
    }
    playingPeriodHolder = periodHolder;
    eventHandler.obtainMessage(MSG_TRACKS_CHANGED, periodHolder.trackSelectorResult).sendToTarget();
    enableRenderers(rendererWasEnabledFlags, enabledRendererCount);
}
Also used : TrackSelection(com.google.android.exoplayer2.trackselection.TrackSelection)

Example 4 with ExoPlaybackException

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

the class ExoPlayerImplInternal method enableRenderers.

private void enableRenderers(boolean[] rendererWasEnabledFlags, int enabledRendererCount) throws ExoPlaybackException {
    enabledRenderers = new Renderer[enabledRendererCount];
    enabledRendererCount = 0;
    for (int i = 0; i < renderers.length; i++) {
        Renderer renderer = renderers[i];
        TrackSelection newSelection = playingPeriodHolder.trackSelectorResult.selections.get(i);
        if (newSelection != null) {
            enabledRenderers[enabledRendererCount++] = renderer;
            if (renderer.getState() == Renderer.STATE_DISABLED) {
                RendererConfiguration rendererConfiguration = playingPeriodHolder.trackSelectorResult.rendererConfigurations[i];
                // The renderer needs enabling with its new track selection.
                boolean playing = playWhenReady && state == ExoPlayer.STATE_READY;
                // Consider as joining only if the renderer was previously disabled.
                boolean joining = !rendererWasEnabledFlags[i] && playing;
                // Build an array of formats contained by the selection.
                Format[] formats = new Format[newSelection.length()];
                for (int j = 0; j < formats.length; j++) {
                    formats[j] = newSelection.getFormat(j);
                }
                // Enable the renderer.
                renderer.enable(rendererConfiguration, formats, playingPeriodHolder.sampleStreams[i], rendererPositionUs, joining, playingPeriodHolder.getRendererOffset());
                MediaClock mediaClock = renderer.getMediaClock();
                if (mediaClock != null) {
                    if (rendererMediaClock != null) {
                        throw ExoPlaybackException.createForUnexpected(new IllegalStateException("Multiple renderer media clocks enabled."));
                    }
                    rendererMediaClock = mediaClock;
                    rendererMediaClockSource = renderer;
                }
                // Start the renderer if playing.
                if (playing) {
                    renderer.start();
                }
            }
        }
    }
}
Also used : StandaloneMediaClock(com.google.android.exoplayer2.util.StandaloneMediaClock) MediaClock(com.google.android.exoplayer2.util.MediaClock) TrackSelection(com.google.android.exoplayer2.trackselection.TrackSelection)

Example 5 with ExoPlaybackException

use of com.google.android.exoplayer2.ExoPlaybackException 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)

Aggregations

Format (com.google.android.exoplayer2.Format)4 ExoPlaybackException (com.google.android.exoplayer2.ExoPlaybackException)3 TrackSelection (com.google.android.exoplayer2.trackselection.TrackSelection)3 DecoderCounters (com.google.android.exoplayer2.decoder.DecoderCounters)2 ExoMediaCrypto (com.google.android.exoplayer2.drm.ExoMediaCrypto)2 DecoderQueryException (com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException)2 SampleStream (com.google.android.exoplayer2.source.SampleStream)2 TrackGroup (com.google.android.exoplayer2.source.TrackGroup)2 Point (android.graphics.Point)1 CodecException (android.media.MediaCodec.CodecException)1 CryptoException (android.media.MediaCodec.CryptoException)1 MediaCrypto (android.media.MediaCrypto)1 MediaFormat (android.media.MediaFormat)1 ExoPlayerMessage (com.google.android.exoplayer2.ExoPlayer.ExoPlayerMessage)1 RendererCapabilities (com.google.android.exoplayer2.RendererCapabilities)1 RendererConfiguration (com.google.android.exoplayer2.RendererConfiguration)1 FrameworkMediaCrypto (com.google.android.exoplayer2.drm.FrameworkMediaCrypto)1 UnsupportedDrmException (com.google.android.exoplayer2.drm.UnsupportedDrmException)1 MediaCodecRenderer (com.google.android.exoplayer2.mediacodec.MediaCodecRenderer)1 DecoderInitializationException (com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException)1