diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index 4055173739..c4dfaed7fe 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -94,7 +94,6 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media private int codecMaxInputSize; private boolean codecNeedsDiscardChannelsWorkaround; - private boolean codecNeedsEosBufferTimestampWorkaround; /** Codec used for DRM decryption only in passthrough and offload. */ @Nullable private Format decryptOnlyCodecFormat; @@ -318,7 +317,6 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media float codecOperatingRate) { codecMaxInputSize = getCodecMaxInputSize(codecInfo, format, getStreamFormats()); codecNeedsDiscardChannelsWorkaround = codecNeedsDiscardChannelsWorkaround(codecInfo.name); - codecNeedsEosBufferTimestampWorkaround = codecNeedsEosBufferTimestampWorkaround(codecInfo.name); MediaFormat mediaFormat = getMediaFormat(format, codecInfo.codecMimeType, codecMaxInputSize, codecOperatingRate); codecAdapter.configure(mediaFormat, /* surface= */ null, crypto, /* flags= */ 0); @@ -571,13 +569,6 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media Format format) throws ExoPlaybackException { checkNotNull(buffer); - if (codec != null - && codecNeedsEosBufferTimestampWorkaround - && bufferPresentationTimeUs == 0 - && (bufferFlags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0 - && getLargestQueuedPresentationTimeUs() != C.TIME_UNSET) { - bufferPresentationTimeUs = getLargestQueuedPresentationTimeUs(); - } if (decryptOnlyCodecFormat != null && (bufferFlags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) { @@ -782,24 +773,6 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media || Util.DEVICE.startsWith("heroqlte")); } - /** - * Returns whether the decoder may output a non-empty buffer with timestamp 0 as the end of stream - * buffer. - * - *
See GitHub issue #5045. - */ - private static boolean codecNeedsEosBufferTimestampWorkaround(String codecName) { - return Util.SDK_INT < 21 - && "OMX.SEC.mp3.dec".equals(codecName) - && "samsung".equals(Util.MANUFACTURER) - && (Util.DEVICE.startsWith("baffin") - || Util.DEVICE.startsWith("grand") - || Util.DEVICE.startsWith("fortuna") - || Util.DEVICE.startsWith("gprimelte") - || Util.DEVICE.startsWith("j2y18lte") - || Util.DEVICE.startsWith("ms01")); - } - private final class AudioSinkListener implements AudioSink.Listener { @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index 49bb5c35c1..4e7bd67eec 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -321,6 +321,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { private boolean codecNeedsSosFlushWorkaround; private boolean codecNeedsEosFlushWorkaround; private boolean codecNeedsEosOutputExceptionWorkaround; + private boolean codecNeedsEosBufferTimestampWorkaround; private boolean codecNeedsMonoChannelCountWorkaround; private boolean codecNeedsAdaptationWorkaroundBuffer; private boolean shouldSkipAdaptationWorkaroundOutputBuffer; @@ -898,6 +899,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { codecNeedsSosFlushWorkaround = false; codecNeedsEosFlushWorkaround = false; codecNeedsEosOutputExceptionWorkaround = false; + codecNeedsEosBufferTimestampWorkaround = false; codecNeedsMonoChannelCountWorkaround = false; codecNeedsEosPropagation = false; codecReconfigured = false; @@ -1089,6 +1091,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { codecNeedsSosFlushWorkaround = codecNeedsSosFlushWorkaround(codecName); codecNeedsEosFlushWorkaround = codecNeedsEosFlushWorkaround(codecName); codecNeedsEosOutputExceptionWorkaround = codecNeedsEosOutputExceptionWorkaround(codecName); + codecNeedsEosBufferTimestampWorkaround = codecNeedsEosBufferTimestampWorkaround(codecName); codecNeedsMonoChannelCountWorkaround = codecNeedsMonoChannelCountWorkaround(codecName, codecInputFormat); codecNeedsEosPropagation = @@ -1746,6 +1749,12 @@ public abstract class MediaCodecRenderer extends BaseRenderer { outputBuffer.position(outputBufferInfo.offset); outputBuffer.limit(outputBufferInfo.offset + outputBufferInfo.size); } + if (codecNeedsEosBufferTimestampWorkaround + && outputBufferInfo.presentationTimeUs == 0 + && (outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0 + && largestQueuedPresentationTimeUs != C.TIME_UNSET) { + outputBufferInfo.presentationTimeUs = largestQueuedPresentationTimeUs; + } isDecodeOnlyOutputBuffer = isDecodeOnlyBuffer(outputBufferInfo.presentationTimeUs); isLastOutputBuffer = lastBufferInStreamPresentationTimeUs == outputBufferInfo.presentationTimeUs; @@ -1928,18 +1937,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { pendingOutputEndOfStream = true; } - /** Returns the largest queued input presentation time, in microseconds. */ - protected final long getLargestQueuedPresentationTimeUs() { - return largestQueuedPresentationTimeUs; - } - - /** - * Returns the start position of the output {@link SampleStream}, in renderer time microseconds. - */ - protected final long getOutputStreamStartPositionUs() { - return outputStreamStartPositionUs; - } - /** * Returns the offset that should be subtracted from {@code bufferPresentationTimeUs} in {@link * #processOutputBuffer(long, long, MediaCodec, ByteBuffer, int, int, int, long, boolean, boolean, @@ -2272,6 +2269,23 @@ public abstract class MediaCodecRenderer extends BaseRenderer { && "OMX.MTK.VIDEO.DECODER.AVC".equals(name); } + /** + * Returns whether the decoder is known to behave incorrectly if flushed prior to having output a + * {@link MediaFormat}. + * + *
If true is returned, the renderer will work around the issue by instantiating a new decoder + * when this case occurs. + * + *
See [Internal: b/141097367]. + * + * @param name The name of the decoder. + * @return True if the decoder is known to behave incorrectly if flushed prior to having output a + * {@link MediaFormat}. False otherwise. + */ + private static boolean codecNeedsSosFlushWorkaround(String name) { + return Util.SDK_INT == 29 && "c2.android.aac.decoder".equals(name); + } + /** * Returns whether the decoder is known to handle the propagation of the {@link * MediaCodec#BUFFER_FLAG_END_OF_STREAM} flag incorrectly on the host device. @@ -2316,12 +2330,30 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } /** - * Returns whether the decoder may throw an {@link IllegalStateException} from - * {@link MediaCodec#dequeueOutputBuffer(MediaCodec.BufferInfo, long)} or - * {@link MediaCodec#releaseOutputBuffer(int, boolean)} after receiving an input - * buffer with {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM} set. - *
- * See [Internal: b/17933838]. + * Returns whether the decoder may output a non-empty buffer with timestamp 0 as the end of stream + * buffer. + * + *
See GitHub issue #5045. + */ + private static boolean codecNeedsEosBufferTimestampWorkaround(String codecName) { + return Util.SDK_INT < 21 + && "OMX.SEC.mp3.dec".equals(codecName) + && "samsung".equals(Util.MANUFACTURER) + && (Util.DEVICE.startsWith("baffin") + || Util.DEVICE.startsWith("grand") + || Util.DEVICE.startsWith("fortuna") + || Util.DEVICE.startsWith("gprimelte") + || Util.DEVICE.startsWith("j2y18lte") + || Util.DEVICE.startsWith("ms01")); + } + + /** + * Returns whether the decoder may throw an {@link IllegalStateException} from {@link + * MediaCodec#dequeueOutputBuffer(MediaCodec.BufferInfo, long)} or {@link + * MediaCodec#releaseOutputBuffer(int, boolean)} after receiving an input buffer with {@link + * MediaCodec#BUFFER_FLAG_END_OF_STREAM} set. + * + *
See [Internal: b/17933838]. * * @param name The name of the decoder. * @return True if the decoder may throw an exception after receiving an end-of-stream buffer. @@ -2348,21 +2380,4 @@ public abstract class MediaCodecRenderer extends BaseRenderer { return Util.SDK_INT <= 18 && format.channelCount == 1 && "OMX.MTK.AUDIO.DECODER.MP3".equals(name); } - - /** - * Returns whether the decoder is known to behave incorrectly if flushed prior to having output a - * {@link MediaFormat}. - * - *
If true is returned, the renderer will work around the issue by instantiating a new decoder - * when this case occurs. - * - *
See [Internal: b/141097367]. - * - * @param name The name of the decoder. - * @return True if the decoder is known to behave incorrectly if flushed prior to having output a - * {@link MediaFormat}. False otherwise. - */ - private static boolean codecNeedsSosFlushWorkaround(String name) { - return Util.SDK_INT == 29 && "c2.android.aac.decoder".equals(name); - } }