Commit 4824f352 by olly Committed by Oliver Woodman

Decouple input format and codec format

This paves the way to cleanly fix the first two issues
listed in [] onDisabled will null inputFormat,
but nulling of codecFormat will remain tied to the codec
being released.

Issue: #2826

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=219125458
parent 5de17b9a
...@@ -290,13 +290,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -290,13 +290,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private final List<Long> decodeOnlyPresentationTimestamps; private final List<Long> decodeOnlyPresentationTimestamps;
private final MediaCodec.BufferInfo outputBufferInfo; private final MediaCodec.BufferInfo outputBufferInfo;
private Format format; @Nullable private Format inputFormat;
private Format pendingFormat;
private Format outputFormat; private Format outputFormat;
private DrmSession<FrameworkMediaCrypto> drmSession; private DrmSession<FrameworkMediaCrypto> drmSession;
private DrmSession<FrameworkMediaCrypto> pendingDrmSession; private DrmSession<FrameworkMediaCrypto> pendingDrmSession;
private MediaCodec codec;
private float rendererOperatingRate; private float rendererOperatingRate;
@Nullable private MediaCodec codec;
@Nullable private Format codecFormat;
private float codecOperatingRate; private float codecOperatingRate;
@Nullable private ArrayDeque<MediaCodecInfo> availableCodecInfos; @Nullable private ArrayDeque<MediaCodecInfo> availableCodecInfos;
@Nullable private DecoderInitializationException preferredDecoderInitializationException; @Nullable private DecoderInitializationException preferredDecoderInitializationException;
...@@ -328,7 +328,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -328,7 +328,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private boolean inputStreamEnded; private boolean inputStreamEnded;
private boolean outputStreamEnded; private boolean outputStreamEnded;
private boolean waitingForKeys; private boolean waitingForKeys;
private boolean waitingForFirstSyncFrame; private boolean waitingForFirstSyncSample;
private boolean waitingForFirstSampleInFormat;
protected DecoderCounters decoderCounters; protected DecoderCounters decoderCounters;
...@@ -435,13 +436,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -435,13 +436,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
throws DecoderQueryException; throws DecoderQueryException;
protected final void maybeInitCodec() throws ExoPlaybackException { protected final void maybeInitCodec() throws ExoPlaybackException {
if (codec != null || format == null) { if (codec != null || inputFormat == null) {
// We have a codec already, or we don't have a format with which to instantiate one. // We have a codec already, or we don't have a format with which to instantiate one.
return; return;
} }
drmSession = pendingDrmSession; drmSession = pendingDrmSession;
String mimeType = format.sampleMimeType; String mimeType = inputFormat.sampleMimeType;
MediaCrypto wrappedMediaCrypto = null; MediaCrypto wrappedMediaCrypto = null;
boolean drmSessionRequiresSecureDecoder = false; boolean drmSessionRequiresSecureDecoder = false;
if (drmSession != null) { if (drmSession != null) {
...@@ -527,12 +528,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -527,12 +528,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
@Override @Override
public final void setOperatingRate(float operatingRate) throws ExoPlaybackException { public final void setOperatingRate(float operatingRate) throws ExoPlaybackException {
rendererOperatingRate = operatingRate; rendererOperatingRate = operatingRate;
if (codec != null && codecDrainAction != DRAIN_ACTION_REINITIALIZE) {
updateCodecOperatingRate(); updateCodecOperatingRate();
} }
}
@Override @Override
protected void onDisabled() { protected void onDisabled() {
format = null; inputFormat = null;
try { try {
releaseCodec(); releaseCodec();
} finally { } finally {
...@@ -563,6 +566,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -563,6 +566,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
waitingForKeys = false; waitingForKeys = false;
decodeOnlyPresentationTimestamps.clear(); decodeOnlyPresentationTimestamps.clear();
codecInfo = null; codecInfo = null;
codecFormat = null;
decoderCounters.decoderReleaseCount++; decoderCounters.decoderReleaseCount++;
try { try {
codec.stop(); codec.stop();
...@@ -599,7 +603,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -599,7 +603,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
renderToEndOfStream(); renderToEndOfStream();
return; return;
} }
if (format == null) { if (inputFormat == null) {
// We don't have a format yet, so try and read one. // We don't have a format yet, so try and read one.
flagsOnlyBuffer.clear(); flagsOnlyBuffer.clear();
int result = readSource(formatHolder, flagsOnlyBuffer, true); int result = readSource(formatHolder, flagsOnlyBuffer, true);
...@@ -680,7 +684,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -680,7 +684,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codecHotswapDeadlineMs = C.TIME_UNSET; codecHotswapDeadlineMs = C.TIME_UNSET;
codecReceivedEos = false; codecReceivedEos = false;
codecReceivedBuffers = false; codecReceivedBuffers = false;
waitingForFirstSyncFrame = true; waitingForFirstSyncSample = true;
codecNeedsAdaptationWorkaroundBuffer = false; codecNeedsAdaptationWorkaroundBuffer = false;
shouldSkipAdaptationWorkaroundOutputBuffer = false; shouldSkipAdaptationWorkaroundOutputBuffer = false;
shouldSkipOutputBuffer = false; shouldSkipOutputBuffer = false;
...@@ -707,7 +711,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -707,7 +711,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
preferredDecoderInitializationException = null; preferredDecoderInitializationException = null;
} catch (DecoderQueryException e) { } catch (DecoderQueryException e) {
throw new DecoderInitializationException( throw new DecoderInitializationException(
format, inputFormat,
e, e,
drmSessionRequiresSecureDecoder, drmSessionRequiresSecureDecoder,
DecoderInitializationException.DECODER_QUERY_ERROR); DecoderInitializationException.DECODER_QUERY_ERROR);
...@@ -716,7 +720,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -716,7 +720,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (availableCodecInfos.isEmpty()) { if (availableCodecInfos.isEmpty()) {
throw new DecoderInitializationException( throw new DecoderInitializationException(
format, inputFormat,
/* cause= */ null, /* cause= */ null,
drmSessionRequiresSecureDecoder, drmSessionRequiresSecureDecoder,
DecoderInitializationException.NO_SUITABLE_DECODER_ERROR); DecoderInitializationException.NO_SUITABLE_DECODER_ERROR);
...@@ -737,7 +741,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -737,7 +741,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
availableCodecInfos.removeFirst(); availableCodecInfos.removeFirst();
DecoderInitializationException exception = DecoderInitializationException exception =
new DecoderInitializationException( new DecoderInitializationException(
format, e, drmSessionRequiresSecureDecoder, codecInfo.name); inputFormat, e, drmSessionRequiresSecureDecoder, codecInfo.name);
if (preferredDecoderInitializationException == null) { if (preferredDecoderInitializationException == null) {
preferredDecoderInitializationException = exception; preferredDecoderInitializationException = exception;
} else { } else {
...@@ -756,18 +760,19 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -756,18 +760,19 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private List<MediaCodecInfo> getAvailableCodecInfos(boolean drmSessionRequiresSecureDecoder) private List<MediaCodecInfo> getAvailableCodecInfos(boolean drmSessionRequiresSecureDecoder)
throws DecoderQueryException { throws DecoderQueryException {
List<MediaCodecInfo> codecInfos = List<MediaCodecInfo> codecInfos =
getDecoderInfos(mediaCodecSelector, format, drmSessionRequiresSecureDecoder); getDecoderInfos(mediaCodecSelector, inputFormat, drmSessionRequiresSecureDecoder);
if (codecInfos.isEmpty() && drmSessionRequiresSecureDecoder) { if (codecInfos.isEmpty() && drmSessionRequiresSecureDecoder) {
// The drm session indicates that a secure decoder is required, but the device does not // The drm session indicates that a secure decoder is required, but the device does not
// have one. Assuming that supportsFormat indicated support for the media being played, we // have one. Assuming that supportsFormat indicated support for the media being played, we
// know that it does not require a secure output path. Most CDM implementations allow // know that it does not require a secure output path. Most CDM implementations allow
// playback to proceed with a non-secure decoder in this case, so we try our luck. // playback to proceed with a non-secure decoder in this case, so we try our luck.
codecInfos = getDecoderInfos(mediaCodecSelector, format, /* requiresSecureDecoder= */ false); codecInfos =
getDecoderInfos(mediaCodecSelector, inputFormat, /* requiresSecureDecoder= */ false);
if (!codecInfos.isEmpty()) { if (!codecInfos.isEmpty()) {
Log.w( Log.w(
TAG, TAG,
"Drm session requires secure decoder for " "Drm session requires secure decoder for "
+ format.sampleMimeType + inputFormat.sampleMimeType
+ ", but no secure decoder available. Trying to proceed with " + ", but no secure decoder available. Trying to proceed with "
+ codecInfos + codecInfos
+ "."); + ".");
...@@ -785,7 +790,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -785,7 +790,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
float codecOperatingRate = float codecOperatingRate =
Util.SDK_INT < 23 Util.SDK_INT < 23
? CODEC_OPERATING_RATE_UNSET ? CODEC_OPERATING_RATE_UNSET
: getCodecOperatingRateV23(rendererOperatingRate, format, getStreamFormats()); : getCodecOperatingRateV23(rendererOperatingRate, inputFormat, getStreamFormats());
if (codecOperatingRate <= assumedMinimumCodecOperatingRate) { if (codecOperatingRate <= assumedMinimumCodecOperatingRate) {
codecOperatingRate = CODEC_OPERATING_RATE_UNSET; codecOperatingRate = CODEC_OPERATING_RATE_UNSET;
} }
...@@ -795,7 +800,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -795,7 +800,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codec = MediaCodec.createByCodecName(codecName); codec = MediaCodec.createByCodecName(codecName);
TraceUtil.endSection(); TraceUtil.endSection();
TraceUtil.beginSection("configureCodec"); TraceUtil.beginSection("configureCodec");
configureCodec(codecInfo, codec, format, crypto, codecOperatingRate); configureCodec(codecInfo, codec, inputFormat, crypto, codecOperatingRate);
TraceUtil.endSection(); TraceUtil.endSection();
TraceUtil.beginSection("startCodec"); TraceUtil.beginSection("startCodec");
codec.start(); codec.start();
...@@ -813,13 +818,15 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -813,13 +818,15 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
this.codec = codec; this.codec = codec;
this.codecInfo = codecInfo; this.codecInfo = codecInfo;
this.codecOperatingRate = codecOperatingRate; this.codecOperatingRate = codecOperatingRate;
codecFormat = inputFormat;
codecAdaptationWorkaroundMode = codecAdaptationWorkaroundMode(codecName); codecAdaptationWorkaroundMode = codecAdaptationWorkaroundMode(codecName);
codecNeedsReconfigureWorkaround = codecNeedsReconfigureWorkaround(codecName); codecNeedsReconfigureWorkaround = codecNeedsReconfigureWorkaround(codecName);
codecNeedsDiscardToSpsWorkaround = codecNeedsDiscardToSpsWorkaround(codecName, format); codecNeedsDiscardToSpsWorkaround = codecNeedsDiscardToSpsWorkaround(codecName, codecFormat);
codecNeedsFlushWorkaround = codecNeedsFlushWorkaround(codecName); codecNeedsFlushWorkaround = codecNeedsFlushWorkaround(codecName);
codecNeedsEosFlushWorkaround = codecNeedsEosFlushWorkaround(codecName); codecNeedsEosFlushWorkaround = codecNeedsEosFlushWorkaround(codecName);
codecNeedsEosOutputExceptionWorkaround = codecNeedsEosOutputExceptionWorkaround(codecName); codecNeedsEosOutputExceptionWorkaround = codecNeedsEosOutputExceptionWorkaround(codecName);
codecNeedsMonoChannelCountWorkaround = codecNeedsMonoChannelCountWorkaround(codecName, format); codecNeedsMonoChannelCountWorkaround =
codecNeedsMonoChannelCountWorkaround(codecName, codecFormat);
codecNeedsEosPropagation = codecNeedsEosPropagation =
codecNeedsEosPropagationWorkaround(codecInfo) || getCodecNeedsEosPropagation(); codecNeedsEosPropagationWorkaround(codecInfo) || getCodecNeedsEosPropagation();
...@@ -838,7 +845,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -838,7 +845,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codecNeedsAdaptationWorkaroundBuffer = false; codecNeedsAdaptationWorkaroundBuffer = false;
shouldSkipAdaptationWorkaroundOutputBuffer = false; shouldSkipAdaptationWorkaroundOutputBuffer = false;
shouldSkipOutputBuffer = false; shouldSkipOutputBuffer = false;
waitingForFirstSyncFrame = true; waitingForFirstSyncSample = true;
decoderCounters.decoderInitCount++; decoderCounters.decoderInitCount++;
long elapsed = codecInitializedTimestamp - codecInitializingTimestamp; long elapsed = codecInitializedTimestamp - codecInitializingTimestamp;
...@@ -939,8 +946,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -939,8 +946,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
// For adaptive reconfiguration OMX decoders expect all reconfiguration data to be supplied // For adaptive reconfiguration OMX decoders expect all reconfiguration data to be supplied
// at the start of the buffer that also contains the first frame in the new format. // at the start of the buffer that also contains the first frame in the new format.
if (codecReconfigurationState == RECONFIGURATION_STATE_WRITE_PENDING) { if (codecReconfigurationState == RECONFIGURATION_STATE_WRITE_PENDING) {
for (int i = 0; i < format.initializationData.size(); i++) { for (int i = 0; i < codecFormat.initializationData.size(); i++) {
byte[] data = format.initializationData.get(i); byte[] data = codecFormat.initializationData.get(i);
buffer.data.put(data); buffer.data.put(data);
} }
codecReconfigurationState = RECONFIGURATION_STATE_QUEUE_PENDING; codecReconfigurationState = RECONFIGURATION_STATE_QUEUE_PENDING;
...@@ -990,7 +997,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -990,7 +997,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} }
return false; return false;
} }
if (waitingForFirstSyncFrame && !buffer.isKeyFrame()) { if (waitingForFirstSyncSample && !buffer.isKeyFrame()) {
buffer.clear(); buffer.clear();
if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) { if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) {
// The buffer we just cleared contained reconfiguration data. We need to re-write this // The buffer we just cleared contained reconfiguration data. We need to re-write this
...@@ -999,7 +1006,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -999,7 +1006,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} }
return true; return true;
} }
waitingForFirstSyncFrame = false; waitingForFirstSyncSample = false;
boolean bufferEncrypted = buffer.isEncrypted(); boolean bufferEncrypted = buffer.isEncrypted();
waitingForKeys = shouldWaitForKeys(bufferEncrypted); waitingForKeys = shouldWaitForKeys(bufferEncrypted);
if (waitingForKeys) { if (waitingForKeys) {
...@@ -1017,9 +1024,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1017,9 +1024,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (buffer.isDecodeOnly()) { if (buffer.isDecodeOnly()) {
decodeOnlyPresentationTimestamps.add(presentationTimeUs); decodeOnlyPresentationTimestamps.add(presentationTimeUs);
} }
if (pendingFormat != null) { if (waitingForFirstSampleInFormat) {
formatQueue.add(presentationTimeUs, pendingFormat); formatQueue.add(presentationTimeUs, inputFormat);
pendingFormat = null; waitingForFirstSampleInFormat = false;
} }
buffer.flip(); buffer.flip();
...@@ -1075,19 +1082,20 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1075,19 +1082,20 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
* @throws ExoPlaybackException If an error occurs re-initializing the {@link MediaCodec}. * @throws ExoPlaybackException If an error occurs re-initializing the {@link MediaCodec}.
*/ */
protected void onInputFormatChanged(Format newFormat) throws ExoPlaybackException { protected void onInputFormatChanged(Format newFormat) throws ExoPlaybackException {
Format oldFormat = format; Format oldFormat = inputFormat;
format = newFormat; inputFormat = newFormat;
pendingFormat = newFormat; waitingForFirstSampleInFormat = true;
boolean drmInitDataChanged = boolean drmInitDataChanged =
!Util.areEqual(format.drmInitData, oldFormat == null ? null : oldFormat.drmInitData); !Util.areEqual(newFormat.drmInitData, oldFormat == null ? null : oldFormat.drmInitData);
if (drmInitDataChanged) { if (drmInitDataChanged) {
if (format.drmInitData != null) { if (newFormat.drmInitData != null) {
if (drmSessionManager == null) { if (drmSessionManager == null) {
throw ExoPlaybackException.createForRenderer( throw ExoPlaybackException.createForRenderer(
new IllegalStateException("Media requires a DrmSessionManager"), getIndex()); new IllegalStateException("Media requires a DrmSessionManager"), getIndex());
} }
pendingDrmSession = drmSessionManager.acquireSession(Looper.myLooper(), format.drmInitData); pendingDrmSession =
drmSessionManager.acquireSession(Looper.myLooper(), newFormat.drmInitData);
if (pendingDrmSession == drmSession) { if (pendingDrmSession == drmSession) {
drmSessionManager.releaseSession(pendingDrmSession); drmSessionManager.releaseSession(pendingDrmSession);
} }
...@@ -1106,12 +1114,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1106,12 +1114,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (pendingDrmSession != drmSession) { if (pendingDrmSession != drmSession) {
drainAndReinitializeCodec(); drainAndReinitializeCodec();
} else { } else {
switch (canKeepCodec(codec, codecInfo, oldFormat, format)) { switch (canKeepCodec(codec, codecInfo, codecFormat, newFormat)) {
case KEEP_CODEC_RESULT_NO: case KEEP_CODEC_RESULT_NO:
drainAndReinitializeCodec(); drainAndReinitializeCodec();
break; break;
case KEEP_CODEC_RESULT_YES_WITH_FLUSH: case KEEP_CODEC_RESULT_YES_WITH_FLUSH:
drainAndFlushCodec(); drainAndFlushCodec();
codecFormat = newFormat;
updateCodecOperatingRate(); updateCodecOperatingRate();
break; break;
case KEEP_CODEC_RESULT_YES_WITH_RECONFIGURATION: case KEEP_CODEC_RESULT_YES_WITH_RECONFIGURATION:
...@@ -1123,12 +1132,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1123,12 +1132,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codecNeedsAdaptationWorkaroundBuffer = codecNeedsAdaptationWorkaroundBuffer =
codecAdaptationWorkaroundMode == ADAPTATION_WORKAROUND_MODE_ALWAYS codecAdaptationWorkaroundMode == ADAPTATION_WORKAROUND_MODE_ALWAYS
|| (codecAdaptationWorkaroundMode == ADAPTATION_WORKAROUND_MODE_SAME_RESOLUTION || (codecAdaptationWorkaroundMode == ADAPTATION_WORKAROUND_MODE_SAME_RESOLUTION
&& format.width == oldFormat.width && newFormat.width == codecFormat.width
&& format.height == oldFormat.height); && newFormat.height == codecFormat.height);
codecFormat = newFormat;
updateCodecOperatingRate(); updateCodecOperatingRate();
} }
break; break;
case KEEP_CODEC_RESULT_YES_WITHOUT_RECONFIGURATION: case KEEP_CODEC_RESULT_YES_WITHOUT_RECONFIGURATION:
codecFormat = newFormat;
updateCodecOperatingRate(); updateCodecOperatingRate();
break; break;
default: default:
...@@ -1197,7 +1208,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1197,7 +1208,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
@Override @Override
public boolean isReady() { public boolean isReady() {
return format != null return inputFormat != null
&& !waitingForKeys && !waitingForKeys
&& (isSourceReady() && (isSourceReady()
|| hasOutputBuffer() || hasOutputBuffer()
...@@ -1232,17 +1243,17 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1232,17 +1243,17 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} }
/** /**
* Updates the codec operating rate, and the codec itself if necessary. * Updates the codec operating rate.
* *
* @throws ExoPlaybackException If an error occurs releasing or initializing a codec. * @throws ExoPlaybackException If an error occurs releasing or initializing a codec.
*/ */
private void updateCodecOperatingRate() throws ExoPlaybackException { private void updateCodecOperatingRate() throws ExoPlaybackException {
if (Util.SDK_INT < 23 || codec == null || codecDrainAction == DRAIN_ACTION_REINITIALIZE) { if (Util.SDK_INT < 23) {
return; return;
} }
float newCodecOperatingRate = float newCodecOperatingRate =
getCodecOperatingRateV23(rendererOperatingRate, format, getStreamFormats()); getCodecOperatingRateV23(rendererOperatingRate, codecFormat, getStreamFormats());
if (codecOperatingRate == newCodecOperatingRate) { if (codecOperatingRate == newCodecOperatingRate) {
// No change. // No change.
} else if (newCodecOperatingRate == CODEC_OPERATING_RATE_UNSET) { } else if (newCodecOperatingRate == CODEC_OPERATING_RATE_UNSET) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment