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);
}
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;
}
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);
}
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();
}
}
}
}
}
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();
}
}
}
}
}
Aggregations