Fix incorrect decoder non-reuse when operating rate needs clearing

This fixes a case where updateCodecOperatingRate would configure
the decoder to be drained and then released, only for
onInputFormatChanged to override the drain action with something
else.

We've not seen any reports of this issue, which suggests that either
it's OK to not release the decoder in such cases, or that the
case doesn't happen very often. I suspect that it's both, but let's
restore the intended behaviour for now.

PiperOrigin-RevId: 340909132
This commit is contained in:
olly 2020-11-05 20:45:38 +00:00 committed by Andrew Lewis
parent 702e5cfb3e
commit 477eae3c57

View File

@ -683,7 +683,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (codec != null if (codec != null
&& codecDrainAction != DRAIN_ACTION_REINITIALIZE && codecDrainAction != DRAIN_ACTION_REINITIALIZE
&& getState() != STATE_DISABLED) { && getState() != STATE_DISABLED) {
updateCodecOperatingRate(); updateOperatingRateOrReinitializeCodec(codecInputFormat);
} }
} }
@ -1416,15 +1416,21 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
drainAndReinitializeCodec(); drainAndReinitializeCodec();
break; break;
case KEEP_CODEC_RESULT_YES_WITH_FLUSH: case KEEP_CODEC_RESULT_YES_WITH_FLUSH:
if (updateOperatingRateOrReinitializeCodec(newFormat)) {
// Codec re-initialization triggered.
} else {
codecInputFormat = newFormat; codecInputFormat = newFormat;
updateCodecOperatingRate();
if (drainAndUpdateCodecDrmSession) { if (drainAndUpdateCodecDrmSession) {
drainAndUpdateCodecDrmSessionV23(); drainAndUpdateCodecDrmSessionV23();
} else { } else {
drainAndFlushCodec(); drainAndFlushCodec();
} }
}
break; break;
case KEEP_CODEC_RESULT_YES_WITH_RECONFIGURATION: case KEEP_CODEC_RESULT_YES_WITH_RECONFIGURATION:
if (updateOperatingRateOrReinitializeCodec(newFormat)) {
// Codec re-initialization triggered.
} else {
codecReconfigured = true; codecReconfigured = true;
codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING; codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
codecNeedsAdaptationWorkaroundBuffer = codecNeedsAdaptationWorkaroundBuffer =
@ -1433,17 +1439,20 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
&& newFormat.width == codecInputFormat.width && newFormat.width == codecInputFormat.width
&& newFormat.height == codecInputFormat.height); && newFormat.height == codecInputFormat.height);
codecInputFormat = newFormat; codecInputFormat = newFormat;
updateCodecOperatingRate();
if (drainAndUpdateCodecDrmSession) { if (drainAndUpdateCodecDrmSession) {
drainAndUpdateCodecDrmSessionV23(); drainAndUpdateCodecDrmSessionV23();
} }
}
break; break;
case KEEP_CODEC_RESULT_YES_WITHOUT_RECONFIGURATION: case KEEP_CODEC_RESULT_YES_WITHOUT_RECONFIGURATION:
if (updateOperatingRateOrReinitializeCodec(newFormat)) {
// Codec re-initialization triggered.
} else {
codecInputFormat = newFormat; codecInputFormat = newFormat;
updateCodecOperatingRate();
if (drainAndUpdateCodecDrmSession) { if (drainAndUpdateCodecDrmSession) {
drainAndUpdateCodecDrmSessionV23(); drainAndUpdateCodecDrmSessionV23();
} }
}
break; break;
default: default:
throw new IllegalStateException(); // Never happens. throw new IllegalStateException(); // Never happens.
@ -1598,23 +1607,30 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} }
/** /**
* Updates the codec operating rate. * Updates the codec operating rate, or triggers codec release and re-initialization if a
* previously set operating rate needs to be cleared.
* *
* @param format The {@link Format} for which the operating rate should be configured.
* @throws ExoPlaybackException If an error occurs releasing or initializing a codec. * @throws ExoPlaybackException If an error occurs releasing or initializing a codec.
* @return Whether codec release and re-initialization was triggered, rather than the existing
* codec being updated.
*/ */
private void updateCodecOperatingRate() throws ExoPlaybackException { private boolean updateOperatingRateOrReinitializeCodec(Format format)
throws ExoPlaybackException {
if (Util.SDK_INT < 23) { if (Util.SDK_INT < 23) {
return; return false;
} }
float newCodecOperatingRate = float newCodecOperatingRate =
getCodecOperatingRateV23(playbackSpeed, codecInputFormat, getStreamFormats()); getCodecOperatingRateV23(playbackSpeed, format, getStreamFormats());
if (codecOperatingRate == newCodecOperatingRate) { if (codecOperatingRate == newCodecOperatingRate) {
// No change. // No change.
return false;
} else if (newCodecOperatingRate == CODEC_OPERATING_RATE_UNSET) { } else if (newCodecOperatingRate == CODEC_OPERATING_RATE_UNSET) {
// The only way to clear the operating rate is to instantiate a new codec instance. See // The only way to clear the operating rate is to instantiate a new codec instance. See
// [Internal ref: b/111543954]. // [Internal ref: b/111543954].
drainAndReinitializeCodec(); drainAndReinitializeCodec();
return true;
} else if (codecOperatingRate != CODEC_OPERATING_RATE_UNSET } else if (codecOperatingRate != CODEC_OPERATING_RATE_UNSET
|| newCodecOperatingRate > assumedMinimumCodecOperatingRate) { || newCodecOperatingRate > assumedMinimumCodecOperatingRate) {
// We need to set the operating rate, either because we've set it previously or because it's // We need to set the operating rate, either because we've set it previously or because it's
@ -1623,7 +1639,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codecParameters.putFloat(MediaFormat.KEY_OPERATING_RATE, newCodecOperatingRate); codecParameters.putFloat(MediaFormat.KEY_OPERATING_RATE, newCodecOperatingRate);
codec.setParameters(codecParameters); codec.setParameters(codecParameters);
codecOperatingRate = newCodecOperatingRate; codecOperatingRate = newCodecOperatingRate;
return false;
} }
return false;
} }
/** Starts draining the codec for flush. */ /** Starts draining the codec for flush. */