Skip to content

Commit

Permalink
Decouple input format and codec format
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ojw28 committed Oct 31, 2018
1 parent 5de17b9 commit 4824f35
Showing 1 changed file with 52 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -290,13 +290,13 @@ private static String buildCustomDiagnosticInfo(int errorCode) {
private final List<Long> decodeOnlyPresentationTimestamps;
private final MediaCodec.BufferInfo outputBufferInfo;

private Format format;
private Format pendingFormat;
@Nullable private Format inputFormat;
private Format outputFormat;
private DrmSession<FrameworkMediaCrypto> drmSession;
private DrmSession<FrameworkMediaCrypto> pendingDrmSession;
private MediaCodec codec;
private float rendererOperatingRate;
@Nullable private MediaCodec codec;
@Nullable private Format codecFormat;
private float codecOperatingRate;
@Nullable private ArrayDeque<MediaCodecInfo> availableCodecInfos;
@Nullable private DecoderInitializationException preferredDecoderInitializationException;
Expand Down Expand Up @@ -328,7 +328,8 @@ private static String buildCustomDiagnosticInfo(int errorCode) {
private boolean inputStreamEnded;
private boolean outputStreamEnded;
private boolean waitingForKeys;
private boolean waitingForFirstSyncFrame;
private boolean waitingForFirstSyncSample;
private boolean waitingForFirstSampleInFormat;

protected DecoderCounters decoderCounters;

Expand Down Expand Up @@ -435,13 +436,13 @@ protected abstract void configureCodec(
throws DecoderQueryException;

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.
return;
}

drmSession = pendingDrmSession;
String mimeType = format.sampleMimeType;
String mimeType = inputFormat.sampleMimeType;
MediaCrypto wrappedMediaCrypto = null;
boolean drmSessionRequiresSecureDecoder = false;
if (drmSession != null) {
Expand Down Expand Up @@ -527,12 +528,14 @@ protected void onPositionReset(long positionUs, boolean joining) throws ExoPlayb
@Override
public final void setOperatingRate(float operatingRate) throws ExoPlaybackException {
rendererOperatingRate = operatingRate;
updateCodecOperatingRate();
if (codec != null && codecDrainAction != DRAIN_ACTION_REINITIALIZE) {
updateCodecOperatingRate();
}
}

@Override
protected void onDisabled() {
format = null;
inputFormat = null;
try {
releaseCodec();
} finally {
Expand Down Expand Up @@ -563,6 +566,7 @@ protected void releaseCodec() {
waitingForKeys = false;
decodeOnlyPresentationTimestamps.clear();
codecInfo = null;
codecFormat = null;
decoderCounters.decoderReleaseCount++;
try {
codec.stop();
Expand Down Expand Up @@ -599,7 +603,7 @@ public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackEx
renderToEndOfStream();
return;
}
if (format == null) {
if (inputFormat == null) {
// We don't have a format yet, so try and read one.
flagsOnlyBuffer.clear();
int result = readSource(formatHolder, flagsOnlyBuffer, true);
Expand Down Expand Up @@ -680,7 +684,7 @@ protected boolean flushOrReleaseCodec() {
codecHotswapDeadlineMs = C.TIME_UNSET;
codecReceivedEos = false;
codecReceivedBuffers = false;
waitingForFirstSyncFrame = true;
waitingForFirstSyncSample = true;
codecNeedsAdaptationWorkaroundBuffer = false;
shouldSkipAdaptationWorkaroundOutputBuffer = false;
shouldSkipOutputBuffer = false;
Expand All @@ -707,7 +711,7 @@ private void maybeInitCodecWithFallback(
preferredDecoderInitializationException = null;
} catch (DecoderQueryException e) {
throw new DecoderInitializationException(
format,
inputFormat,
e,
drmSessionRequiresSecureDecoder,
DecoderInitializationException.DECODER_QUERY_ERROR);
Expand All @@ -716,7 +720,7 @@ private void maybeInitCodecWithFallback(

if (availableCodecInfos.isEmpty()) {
throw new DecoderInitializationException(
format,
inputFormat,
/* cause= */ null,
drmSessionRequiresSecureDecoder,
DecoderInitializationException.NO_SUITABLE_DECODER_ERROR);
Expand All @@ -737,7 +741,7 @@ private void maybeInitCodecWithFallback(
availableCodecInfos.removeFirst();
DecoderInitializationException exception =
new DecoderInitializationException(
format, e, drmSessionRequiresSecureDecoder, codecInfo.name);
inputFormat, e, drmSessionRequiresSecureDecoder, codecInfo.name);
if (preferredDecoderInitializationException == null) {
preferredDecoderInitializationException = exception;
} else {
Expand All @@ -756,18 +760,19 @@ private void maybeInitCodecWithFallback(
private List<MediaCodecInfo> getAvailableCodecInfos(boolean drmSessionRequiresSecureDecoder)
throws DecoderQueryException {
List<MediaCodecInfo> codecInfos =
getDecoderInfos(mediaCodecSelector, format, drmSessionRequiresSecureDecoder);
getDecoderInfos(mediaCodecSelector, inputFormat, drmSessionRequiresSecureDecoder);
if (codecInfos.isEmpty() && drmSessionRequiresSecureDecoder) {
// 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
// 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.
codecInfos = getDecoderInfos(mediaCodecSelector, format, /* requiresSecureDecoder= */ false);
codecInfos =
getDecoderInfos(mediaCodecSelector, inputFormat, /* requiresSecureDecoder= */ false);
if (!codecInfos.isEmpty()) {
Log.w(
TAG,
"Drm session requires secure decoder for "
+ format.sampleMimeType
+ inputFormat.sampleMimeType
+ ", but no secure decoder available. Trying to proceed with "
+ codecInfos
+ ".");
Expand All @@ -785,7 +790,7 @@ private void initCodec(MediaCodecInfo codecInfo, MediaCrypto crypto) throws Exce
float codecOperatingRate =
Util.SDK_INT < 23
? CODEC_OPERATING_RATE_UNSET
: getCodecOperatingRateV23(rendererOperatingRate, format, getStreamFormats());
: getCodecOperatingRateV23(rendererOperatingRate, inputFormat, getStreamFormats());
if (codecOperatingRate <= assumedMinimumCodecOperatingRate) {
codecOperatingRate = CODEC_OPERATING_RATE_UNSET;
}
Expand All @@ -795,7 +800,7 @@ private void initCodec(MediaCodecInfo codecInfo, MediaCrypto crypto) throws Exce
codec = MediaCodec.createByCodecName(codecName);
TraceUtil.endSection();
TraceUtil.beginSection("configureCodec");
configureCodec(codecInfo, codec, format, crypto, codecOperatingRate);
configureCodec(codecInfo, codec, inputFormat, crypto, codecOperatingRate);
TraceUtil.endSection();
TraceUtil.beginSection("startCodec");
codec.start();
Expand All @@ -813,13 +818,15 @@ private void initCodec(MediaCodecInfo codecInfo, MediaCrypto crypto) throws Exce
this.codec = codec;
this.codecInfo = codecInfo;
this.codecOperatingRate = codecOperatingRate;
codecFormat = inputFormat;
codecAdaptationWorkaroundMode = codecAdaptationWorkaroundMode(codecName);
codecNeedsReconfigureWorkaround = codecNeedsReconfigureWorkaround(codecName);
codecNeedsDiscardToSpsWorkaround = codecNeedsDiscardToSpsWorkaround(codecName, format);
codecNeedsDiscardToSpsWorkaround = codecNeedsDiscardToSpsWorkaround(codecName, codecFormat);
codecNeedsFlushWorkaround = codecNeedsFlushWorkaround(codecName);
codecNeedsEosFlushWorkaround = codecNeedsEosFlushWorkaround(codecName);
codecNeedsEosOutputExceptionWorkaround = codecNeedsEosOutputExceptionWorkaround(codecName);
codecNeedsMonoChannelCountWorkaround = codecNeedsMonoChannelCountWorkaround(codecName, format);
codecNeedsMonoChannelCountWorkaround =
codecNeedsMonoChannelCountWorkaround(codecName, codecFormat);
codecNeedsEosPropagation =
codecNeedsEosPropagationWorkaround(codecInfo) || getCodecNeedsEosPropagation();

Expand All @@ -838,7 +845,7 @@ private void initCodec(MediaCodecInfo codecInfo, MediaCrypto crypto) throws Exce
codecNeedsAdaptationWorkaroundBuffer = false;
shouldSkipAdaptationWorkaroundOutputBuffer = false;
shouldSkipOutputBuffer = false;
waitingForFirstSyncFrame = true;
waitingForFirstSyncSample = true;

decoderCounters.decoderInitCount++;
long elapsed = codecInitializedTimestamp - codecInitializingTimestamp;
Expand Down Expand Up @@ -939,8 +946,8 @@ private boolean feedInputBuffer() throws ExoPlaybackException {
// 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.
if (codecReconfigurationState == RECONFIGURATION_STATE_WRITE_PENDING) {
for (int i = 0; i < format.initializationData.size(); i++) {
byte[] data = format.initializationData.get(i);
for (int i = 0; i < codecFormat.initializationData.size(); i++) {
byte[] data = codecFormat.initializationData.get(i);
buffer.data.put(data);
}
codecReconfigurationState = RECONFIGURATION_STATE_QUEUE_PENDING;
Expand Down Expand Up @@ -990,7 +997,7 @@ private boolean feedInputBuffer() throws ExoPlaybackException {
}
return false;
}
if (waitingForFirstSyncFrame && !buffer.isKeyFrame()) {
if (waitingForFirstSyncSample && !buffer.isKeyFrame()) {
buffer.clear();
if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) {
// The buffer we just cleared contained reconfiguration data. We need to re-write this
Expand All @@ -999,7 +1006,7 @@ private boolean feedInputBuffer() throws ExoPlaybackException {
}
return true;
}
waitingForFirstSyncFrame = false;
waitingForFirstSyncSample = false;
boolean bufferEncrypted = buffer.isEncrypted();
waitingForKeys = shouldWaitForKeys(bufferEncrypted);
if (waitingForKeys) {
Expand All @@ -1017,9 +1024,9 @@ private boolean feedInputBuffer() throws ExoPlaybackException {
if (buffer.isDecodeOnly()) {
decodeOnlyPresentationTimestamps.add(presentationTimeUs);
}
if (pendingFormat != null) {
formatQueue.add(presentationTimeUs, pendingFormat);
pendingFormat = null;
if (waitingForFirstSampleInFormat) {
formatQueue.add(presentationTimeUs, inputFormat);
waitingForFirstSampleInFormat = false;
}

buffer.flip();
Expand Down Expand Up @@ -1075,19 +1082,20 @@ protected void onCodecInitialized(String name, long initializedTimestampMs,
* @throws ExoPlaybackException If an error occurs re-initializing the {@link MediaCodec}.
*/
protected void onInputFormatChanged(Format newFormat) throws ExoPlaybackException {
Format oldFormat = format;
format = newFormat;
pendingFormat = newFormat;
Format oldFormat = inputFormat;
inputFormat = newFormat;
waitingForFirstSampleInFormat = true;

boolean drmInitDataChanged =
!Util.areEqual(format.drmInitData, oldFormat == null ? null : oldFormat.drmInitData);
!Util.areEqual(newFormat.drmInitData, oldFormat == null ? null : oldFormat.drmInitData);
if (drmInitDataChanged) {
if (format.drmInitData != null) {
if (newFormat.drmInitData != null) {
if (drmSessionManager == null) {
throw ExoPlaybackException.createForRenderer(
new IllegalStateException("Media requires a DrmSessionManager"), getIndex());
}
pendingDrmSession = drmSessionManager.acquireSession(Looper.myLooper(), format.drmInitData);
pendingDrmSession =
drmSessionManager.acquireSession(Looper.myLooper(), newFormat.drmInitData);
if (pendingDrmSession == drmSession) {
drmSessionManager.releaseSession(pendingDrmSession);
}
Expand All @@ -1106,12 +1114,13 @@ protected void onInputFormatChanged(Format newFormat) throws ExoPlaybackExceptio
if (pendingDrmSession != drmSession) {
drainAndReinitializeCodec();
} else {
switch (canKeepCodec(codec, codecInfo, oldFormat, format)) {
switch (canKeepCodec(codec, codecInfo, codecFormat, newFormat)) {
case KEEP_CODEC_RESULT_NO:
drainAndReinitializeCodec();
break;
case KEEP_CODEC_RESULT_YES_WITH_FLUSH:
drainAndFlushCodec();
codecFormat = newFormat;
updateCodecOperatingRate();
break;
case KEEP_CODEC_RESULT_YES_WITH_RECONFIGURATION:
Expand All @@ -1123,12 +1132,14 @@ protected void onInputFormatChanged(Format newFormat) throws ExoPlaybackExceptio
codecNeedsAdaptationWorkaroundBuffer =
codecAdaptationWorkaroundMode == ADAPTATION_WORKAROUND_MODE_ALWAYS
|| (codecAdaptationWorkaroundMode == ADAPTATION_WORKAROUND_MODE_SAME_RESOLUTION
&& format.width == oldFormat.width
&& format.height == oldFormat.height);
&& newFormat.width == codecFormat.width
&& newFormat.height == codecFormat.height);
codecFormat = newFormat;
updateCodecOperatingRate();
}
break;
case KEEP_CODEC_RESULT_YES_WITHOUT_RECONFIGURATION:
codecFormat = newFormat;
updateCodecOperatingRate();
break;
default:
Expand Down Expand Up @@ -1197,7 +1208,7 @@ public boolean isEnded() {

@Override
public boolean isReady() {
return format != null
return inputFormat != null
&& !waitingForKeys
&& (isSourceReady()
|| hasOutputBuffer()
Expand Down Expand Up @@ -1232,17 +1243,17 @@ protected float getCodecOperatingRateV23(
}

/**
* 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.
*/
private void updateCodecOperatingRate() throws ExoPlaybackException {
if (Util.SDK_INT < 23 || codec == null || codecDrainAction == DRAIN_ACTION_REINITIALIZE) {
if (Util.SDK_INT < 23) {
return;
}

float newCodecOperatingRate =
getCodecOperatingRateV23(rendererOperatingRate, format, getStreamFormats());
getCodecOperatingRateV23(rendererOperatingRate, codecFormat, getStreamFormats());
if (codecOperatingRate == newCodecOperatingRate) {
// No change.
} else if (newCodecOperatingRate == CODEC_OPERATING_RATE_UNSET) {
Expand Down

0 comments on commit 4824f35

Please sign in to comment.