Allow codec flushing without re-initialization

For decoder reuse, we want disable() to flush the decoder. However,
if the flush needs to release the decoder for some reason, it seems
non-ideal to immediately re-initialize it. Re-initialization can
also throw ExoPlaybackException, which we don't want for disabling.

This change allows a variant of flush that wont re-initialize the
decoder if it has to be released, which will be used from disable().

Issue: #2826

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=216834862
This commit is contained in:
olly 2018-10-12 02:57:28 -07:00 committed by Oliver Woodman
parent 42c3ff3934
commit 842f622d29
3 changed files with 45 additions and 16 deletions

View File

@ -546,9 +546,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
inputStreamEnded = false;
outputStreamEnded = false;
if (codec != null) {
flushCodec();
}
flushOrReinitCodec();
formatQueue.clear();
}
@ -687,10 +685,36 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
decoderCounters.ensureUpdated();
}
protected void flushCodec() throws ExoPlaybackException {
/**
* Flushes the codec. If flushing is not possible, the codec will be released and re-instantiated.
* This method is a no-op if the codec is {@code null}.
*
* <p>The implementation of this method calls {@link #flushOrReleaseCodec()}, and {@link
* #maybeInitCodec()} if the codec needs to be re-instantiated.
*
* @throws ExoPlaybackException If an error occurs re-instantiating the codec.
*/
protected final void flushOrReinitCodec() throws ExoPlaybackException {
if (flushOrReleaseCodec()) {
maybeInitCodec();
}
}
/**
* Flushes the codec. If flushing is not possible, the codec will be released. This method is a
* no-op if the codec is {@code null}.
*
* @return Whether the codec was released.
*/
protected boolean flushOrReleaseCodec() {
if (codec == null) {
// Nothing to do.
return false;
}
codecHotswapDeadlineMs = C.TIME_UNSET;
resetInputBuffer();
resetOutputBuffer();
codecReceivedBuffers = false;
waitingForFirstSyncFrame = true;
waitingForKeys = false;
shouldSkipOutputBuffer = false;
@ -699,28 +723,27 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
shouldSkipAdaptationWorkaroundOutputBuffer = false;
if (codecNeedsFlushWorkaround || (codecNeedsEosFlushWorkaround && codecReceivedEos)) {
releaseCodec();
maybeInitCodec();
return true;
} else if (codecReinitializationState != REINITIALIZATION_STATE_NONE) {
// We're already waiting to re-initialize the codec. Since we're now flushing, there's no need
// to wait any longer.
if (codecReinitializationIsRelease) {
releaseCodec();
maybeInitCodec();
return true;
} else {
codec.flush();
codecReceivedBuffers = false;
codecReinitializationState = REINITIALIZATION_STATE_NONE;
}
} else {
// We can flush and re-use the existing decoder.
codec.flush();
codecReceivedBuffers = false;
}
if (codecReconfigured && format != null) {
// Any reconfiguration data that we send shortly before the flush may be discarded. We
// avoid this issue by sending reconfiguration data following every flush.
codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
}
return false;
}
private boolean initCodecWithFallback(MediaCrypto crypto, boolean drmSessionRequiresSecureDecoder)
@ -1496,7 +1519,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
releaseCodec();
maybeInitCodec();
} else {
flushCodec();
flushOrReinitCodec();
}
} else {
outputStreamEnded = true;

View File

@ -520,9 +520,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
@CallSuper
@Override
protected void flushCodec() throws ExoPlaybackException {
super.flushCodec();
buffersInCodecCount = 0;
protected boolean flushOrReleaseCodec() {
try {
return super.flushOrReleaseCodec();
} finally {
buffersInCodecCount = 0;
}
}
@Override
@ -859,7 +862,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
// We dropped some buffers to catch up, so update the decoder counters and flush the codec,
// which releases all pending buffers buffers including the current output buffer.
updateDroppedBufferCounters(buffersInCodecCount + droppedSourceBufferCount);
flushCodec();
flushOrReinitCodec();
return true;
}

View File

@ -105,9 +105,12 @@ public class DebugRenderersFactory extends DefaultRenderersFactory {
}
@Override
protected void flushCodec() throws ExoPlaybackException {
super.flushCodec();
clearTimestamps();
protected boolean flushOrReleaseCodec() {
try {
return super.flushOrReleaseCodec();
} finally {
clearTimestamps();
}
}
@Override