From b915b04594411ad5e71aeace1bc1670b97314040 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Mon, 22 Jan 2024 18:41:17 +0800 Subject: [PATCH 1/3] Fix HLS DTS Express bit-rate unknown issue. --- .../exoplayer/mediacodec/MediaCodecRenderer.java | 16 ++++++++++++++++ .../java/androidx/media3/extractor/DtsUtil.java | 3 +++ 2 files changed, 19 insertions(+) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java index b1f4734871..1dc5b8cffd 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java @@ -15,6 +15,7 @@ */ package androidx.media3.exoplayer.mediacodec; +import static androidx.media3.common.Format.NO_VALUE; import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkStateNotNull; @@ -79,6 +80,7 @@ import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.SampleStream; import androidx.media3.exoplayer.source.SampleStream.ReadDataResult; import androidx.media3.exoplayer.source.SampleStream.ReadFlags; +import androidx.media3.extractor.DtsUtil; import androidx.media3.extractor.OpusUtil; import java.lang.annotation.Documented; import java.lang.annotation.Retention; @@ -2400,6 +2402,20 @@ public abstract class MediaCodecRenderer extends BaseRenderer { .setEncoderDelay(numberPreSkipSamples) .build(); } + // For HLS-fMP4 and HLS-TS, the bit-rate of the DTS Express stream is not in the + // manifest file. The bit-rate has no value at the point of AudioTrack Initialisation. + // This will lead to a computed direct passthrough playback buffer size of 2250000 + // bytes. Some TVs (E.g. Xiaomi A Pro and Q2) do not support such a big buffer for + // direct passthrough playback. It will crash at the point of AudioTrack Initialisation. + // Here we set the unknown bit-rate to a known peak bit-rate for DTS Express streams. + if (Objects.equals(outputFormat.sampleMimeType, MimeTypes.AUDIO_DTS_EXPRESS) + && (outputFormat.bitrate == NO_VALUE)) { + outputFormat = + checkNotNull(outputFormat) + .buildUpon() + .setPeakBitrate(DtsUtil.DTS_EXPRESS_MAX_RATE_BITS_PER_SECOND) + .build(); + } onOutputFormatChanged(outputFormat, /* mediaFormat= */ null); waitingForFirstSampleInFormat = false; } diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java index faef2b9434..13f1391cae 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java @@ -143,6 +143,9 @@ public final class DtsUtil { /** Maximum rate for a DTS-HD audio stream, in bytes per second. */ public static final int DTS_HD_MAX_RATE_BYTES_PER_SECOND = 18000 * 1000 / 8; + /** Maximum bit-rate for a DTS Express audio stream, in bits per second. */ + public static final int DTS_EXPRESS_MAX_RATE_BITS_PER_SECOND = 768000; + /** * DTS Core Syncword (in different Endianness). See ETSI TS 102 114 V1.6.1 (2019-08), Section 5.3. */ From 460280556e678afeb8041987d5a5e7b8b8659d04 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Wed, 31 Jan 2024 10:59:57 +0800 Subject: [PATCH 2/3] Move DTS Express bit-rate change to DefaultAudioSink.java --- .../media3/exoplayer/audio/DefaultAudioSink.java | 16 +++++++++++++++- .../exoplayer/mediacodec/MediaCodecRenderer.java | 14 -------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java index 9fb053651f..2a733a13cb 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java @@ -76,6 +76,7 @@ import java.lang.annotation.Target; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayDeque; +import java.util.Objects; import java.util.concurrent.ExecutorService; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.RequiresNonNull; @@ -765,6 +766,19 @@ public final class DefaultAudioSink implements AudioSink { "Invalid output channel config (mode=" + outputMode + ") for: " + inputFormat, inputFormat); } + + // For HLS-fMP4 and HLS-TS, the bit-rate of the DTS Express stream is not in the + // manifest file. The bit-rate has no value at the point of AudioTrack Initialisation. + // This will lead to a computed direct passthrough playback buffer size of 2250000 + // bytes. Some TVs (E.g. Xiaomi A Pro and Q2) do not support such a big buffer for + // direct passthrough playback. It will crash at the point of AudioTrack Initialisation. + // Here we set the unknown bit-rate to a known peak bit-rate for DTS Express streams. + int bitRate = inputFormat.bitrate; + if (Objects.equals(inputFormat.sampleMimeType, MimeTypes.AUDIO_DTS_EXPRESS) + && (inputFormat.bitrate == Format.NO_VALUE)) { + bitRate = DtsUtil.DTS_EXPRESS_MAX_RATE_BITS_PER_SECOND; + } + int bufferSize = specifiedBufferSize != 0 ? specifiedBufferSize @@ -774,7 +788,7 @@ public final class DefaultAudioSink implements AudioSink { outputMode, outputPcmFrameSize != C.LENGTH_UNSET ? outputPcmFrameSize : 1, outputSampleRate, - inputFormat.bitrate, + bitRate, enableAudioTrackPlaybackParams ? MAX_PLAYBACK_SPEED : DEFAULT_PLAYBACK_SPEED); offloadDisabledUntilNextConfiguration = false; Configuration pendingConfiguration = diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java index 1dc5b8cffd..bd8a094ab4 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java @@ -2402,20 +2402,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { .setEncoderDelay(numberPreSkipSamples) .build(); } - // For HLS-fMP4 and HLS-TS, the bit-rate of the DTS Express stream is not in the - // manifest file. The bit-rate has no value at the point of AudioTrack Initialisation. - // This will lead to a computed direct passthrough playback buffer size of 2250000 - // bytes. Some TVs (E.g. Xiaomi A Pro and Q2) do not support such a big buffer for - // direct passthrough playback. It will crash at the point of AudioTrack Initialisation. - // Here we set the unknown bit-rate to a known peak bit-rate for DTS Express streams. - if (Objects.equals(outputFormat.sampleMimeType, MimeTypes.AUDIO_DTS_EXPRESS) - && (outputFormat.bitrate == NO_VALUE)) { - outputFormat = - checkNotNull(outputFormat) - .buildUpon() - .setPeakBitrate(DtsUtil.DTS_EXPRESS_MAX_RATE_BITS_PER_SECOND) - .build(); - } onOutputFormatChanged(outputFormat, /* mediaFormat= */ null); waitingForFirstSampleInFormat = false; } From 9ba93d386d771ea7760cccc6d56d4f7e6fe28ca9 Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 31 Jan 2024 12:32:20 +0000 Subject: [PATCH 3/3] Reworded comment and formatting fixes --- .../exoplayer/audio/DefaultAudioSink.java | 19 +++++++------------ .../mediacodec/MediaCodecRenderer.java | 2 -- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java index 2a733a13cb..7ba42ca870 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java @@ -76,7 +76,6 @@ import java.lang.annotation.Target; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayDeque; -import java.util.Objects; import java.util.concurrent.ExecutorService; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.RequiresNonNull; @@ -767,16 +766,12 @@ public final class DefaultAudioSink implements AudioSink { inputFormat); } - // For HLS-fMP4 and HLS-TS, the bit-rate of the DTS Express stream is not in the - // manifest file. The bit-rate has no value at the point of AudioTrack Initialisation. - // This will lead to a computed direct passthrough playback buffer size of 2250000 - // bytes. Some TVs (E.g. Xiaomi A Pro and Q2) do not support such a big buffer for - // direct passthrough playback. It will crash at the point of AudioTrack Initialisation. - // Here we set the unknown bit-rate to a known peak bit-rate for DTS Express streams. - int bitRate = inputFormat.bitrate; - if (Objects.equals(inputFormat.sampleMimeType, MimeTypes.AUDIO_DTS_EXPRESS) - && (inputFormat.bitrate == Format.NO_VALUE)) { - bitRate = DtsUtil.DTS_EXPRESS_MAX_RATE_BITS_PER_SECOND; + // Replace unknown bitrate by maximum allowed bitrate for DTS Express to avoid allocating an + // AudioTrack buffer for the much larger maximum bitrate of the underlying DTS-HD encoding. + int bitrate = inputFormat.bitrate; + if (MimeTypes.AUDIO_DTS_EXPRESS.equals(inputFormat.sampleMimeType) + && bitrate == Format.NO_VALUE) { + bitrate = DtsUtil.DTS_EXPRESS_MAX_RATE_BITS_PER_SECOND; } int bufferSize = @@ -788,7 +783,7 @@ public final class DefaultAudioSink implements AudioSink { outputMode, outputPcmFrameSize != C.LENGTH_UNSET ? outputPcmFrameSize : 1, outputSampleRate, - bitRate, + bitrate, enableAudioTrackPlaybackParams ? MAX_PLAYBACK_SPEED : DEFAULT_PLAYBACK_SPEED); offloadDisabledUntilNextConfiguration = false; Configuration pendingConfiguration = diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java index bd8a094ab4..b1f4734871 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java @@ -15,7 +15,6 @@ */ package androidx.media3.exoplayer.mediacodec; -import static androidx.media3.common.Format.NO_VALUE; import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkStateNotNull; @@ -80,7 +79,6 @@ import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.SampleStream; import androidx.media3.exoplayer.source.SampleStream.ReadDataResult; import androidx.media3.exoplayer.source.SampleStream.ReadFlags; -import androidx.media3.extractor.DtsUtil; import androidx.media3.extractor.OpusUtil; import java.lang.annotation.Documented; import java.lang.annotation.Retention;