Add option to skip samples too big for MediaCodec input buffers

PiperOrigin-RevId: 363480412
This commit is contained in:
olly 2021-03-17 19:29:24 +00:00 committed by Ian Baker
parent 2d9177b7c2
commit 8b5090048d

View File

@ -51,6 +51,7 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.FormatHolder;
import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer.InsufficientCapacityException;
import com.google.android.exoplayer2.decoder.DecoderReuseEvaluation; import com.google.android.exoplayer2.decoder.DecoderReuseEvaluation;
import com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.DecoderDiscardReasons; import com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.DecoderDiscardReasons;
import com.google.android.exoplayer2.drm.DrmSession; import com.google.android.exoplayer2.drm.DrmSession;
@ -365,6 +366,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private boolean forceAsyncQueueingSynchronizationWorkaround; private boolean forceAsyncQueueingSynchronizationWorkaround;
private boolean enableSynchronizeCodecInteractionsWithQueueing; private boolean enableSynchronizeCodecInteractionsWithQueueing;
private boolean enableRecoverableCodecExceptionRetries; private boolean enableRecoverableCodecExceptionRetries;
private boolean enableSkipAndContinueIfSampleTooLarge;
@Nullable private ExoPlaybackException pendingPlaybackException; @Nullable private ExoPlaybackException pendingPlaybackException;
protected DecoderCounters decoderCounters; protected DecoderCounters decoderCounters;
private long outputStreamStartPositionUs; private long outputStreamStartPositionUs;
@ -432,7 +434,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} }
/** /**
* Enable asynchronous input buffer queueing. * Enables asynchronous input buffer queueing.
* *
* <p>Operates the underlying {@link MediaCodec} in asynchronous mode and submits input buffers * <p>Operates the underlying {@link MediaCodec} in asynchronous mode and submits input buffers
* from a separate thread to unblock the playback thread. * from a separate thread to unblock the playback thread.
@ -445,7 +447,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} }
/** /**
* Enable the asynchronous queueing synchronization workaround. * Enables the asynchronous queueing synchronization workaround.
* *
* <p>When enabled, the queueing threads for {@link MediaCodec} instance will synchronize on a * <p>When enabled, the queueing threads for {@link MediaCodec} instance will synchronize on a
* shared lock when submitting buffers to the respective {@link MediaCodec}. * shared lock when submitting buffers to the respective {@link MediaCodec}.
@ -458,7 +460,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} }
/** /**
* Enable synchronizing codec interactions with asynchronous buffer queueing. * Enables synchronizing codec interactions with asynchronous buffer queueing.
* *
* <p>When enabled, codec interactions will wait until all input buffers pending for asynchronous * <p>When enabled, codec interactions will wait until all input buffers pending for asynchronous
* queueing are submitted to the {@link MediaCodec} first. This method is effective only if {@link * queueing are submitted to the {@link MediaCodec} first. This method is effective only if {@link
@ -472,7 +474,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} }
/** /**
* Enable internal player retries for codec exceptions if the underlying platform indicates that * Enables internal player retries for codec exceptions if the underlying platform indicates that
* they are recoverable. * they are recoverable.
* *
* <p>This method is experimental, and will be renamed or removed in a future release. It should * <p>This method is experimental, and will be renamed or removed in a future release. It should
@ -482,6 +484,18 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
enableRecoverableCodecExceptionRetries = enabled; enableRecoverableCodecExceptionRetries = enabled;
} }
/**
* Enables skipping and continuing playback from the next key frame if a sample is encountered
* that's too large to fit into one of the decoder's input buffers. When not enabled, playback
* will fail in this case.
*
* <p>This method is experimental, and will be renamed or removed in a future release. It should
* only be called before the renderer is used.
*/
public void experimentalSetSkipAndContinueIfSampleTooLarge(boolean enabled) {
enableSkipAndContinueIfSampleTooLarge = enabled;
}
@Override @Override
@AdaptiveSupport @AdaptiveSupport
public final int supportsMixedMimeTypeAdaptation() { public final int supportsMixedMimeTypeAdaptation() {
@ -1261,7 +1275,23 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
int adaptiveReconfigurationBytes = buffer.data.position(); int adaptiveReconfigurationBytes = buffer.data.position();
FormatHolder formatHolder = getFormatHolder(); FormatHolder formatHolder = getFormatHolder();
@ReadDataResult int result = readSource(formatHolder, buffer, /* readFlags= */ 0);
@SampleStream.ReadDataResult int result;
try {
result = readSource(formatHolder, buffer, /* readFlags= */ 0);
} catch (InsufficientCapacityException e) {
onCodecError(e);
if (enableSkipAndContinueIfSampleTooLarge) {
// Skip the sample that's too large by reading it without its data. Then flush the codec so
// that rendering will resume from the next key frame.
readSourceOmittingSampleData(/* readFlags= */ 0);
flushCodec();
return true;
} else {
throw createRendererException(
createDecoderException(e, getCodecInfo()), inputFormat, /* isRecoverable= */ false);
}
}
if (hasReadStreamToEnd()) { if (hasReadStreamToEnd()) {
// Notify output queue of the last buffer's timestamp. // Notify output queue of the last buffer's timestamp.
@ -1319,7 +1349,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
// during normal consumption of samples from the source (i.e., without a corresponding // during normal consumption of samples from the source (i.e., without a corresponding
// Renderer.enable or Renderer.resetPosition call). This is necessary for certain legacy and // Renderer.enable or Renderer.resetPosition call). This is necessary for certain legacy and
// workaround behaviors, for example when switching the output Surface on API levels prior to // workaround behaviors, for example when switching the output Surface on API levels prior to
// the introduction of MediaCodec.setOutputSurface. // the introduction of MediaCodec.setOutputSurface, and when it's necessary to skip past a
// sample that's too large to be held in one of the decoder's input buffers.
if (!codecReceivedBuffers && !buffer.isKeyFrame()) { if (!codecReceivedBuffers && !buffer.isKeyFrame()) {
buffer.clear(); buffer.clear();
if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) { if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) {