Merge pull request #650 from cedricxperi:dts-lbr-buffer-underflow-fix
PiperOrigin-RevId: 572864175
This commit is contained in:
commit
2421ba4d8f
@ -11,6 +11,8 @@
|
||||
stays at its current behavior of `true`.
|
||||
* Extractors:
|
||||
* Audio:
|
||||
* Fix DTS Express audio buffer underflow issue
|
||||
([#650](https://github.com/androidx/media/pull/650)).
|
||||
* Video:
|
||||
* Text:
|
||||
* Remove `ExoplayerCuesDecoder`. Text tracks with `sampleMimeType =
|
||||
|
@ -63,6 +63,11 @@ public class DefaultAudioTrackBufferSizeProvider
|
||||
*/
|
||||
private static final int AC3_BUFFER_MULTIPLICATION_FACTOR = 2;
|
||||
|
||||
/**
|
||||
* Default multiplication factor to apply to DTS Express passthrough buffer to avoid underruns.
|
||||
*/
|
||||
private static final int DTSHD_BUFFER_MULTIPLICATION_FACTOR = 4;
|
||||
|
||||
/** A builder to create {@link DefaultAudioTrackBufferSizeProvider} instances. */
|
||||
public static class Builder {
|
||||
|
||||
@ -72,6 +77,7 @@ public class DefaultAudioTrackBufferSizeProvider
|
||||
private int passthroughBufferDurationUs;
|
||||
private int offloadBufferDurationUs;
|
||||
private int ac3BufferMultiplicationFactor;
|
||||
private int dtshdBufferMultiplicationFactor;
|
||||
|
||||
/** Creates a new builder. */
|
||||
public Builder() {
|
||||
@ -81,6 +87,7 @@ public class DefaultAudioTrackBufferSizeProvider
|
||||
passthroughBufferDurationUs = PASSTHROUGH_BUFFER_DURATION_US;
|
||||
offloadBufferDurationUs = OFFLOAD_BUFFER_DURATION_US;
|
||||
ac3BufferMultiplicationFactor = AC3_BUFFER_MULTIPLICATION_FACTOR;
|
||||
dtshdBufferMultiplicationFactor = DTSHD_BUFFER_MULTIPLICATION_FACTOR;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -143,6 +150,16 @@ public class DefaultAudioTrackBufferSizeProvider
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the multiplication factor to apply to the passthrough buffer for DTS-HD (DTS Express) to
|
||||
* avoid underruns. Default is {@link #DTSHD_BUFFER_MULTIPLICATION_FACTOR}.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setDtshdBufferMultiplicationFactor(int dtshdBufferMultiplicationFactor) {
|
||||
this.dtshdBufferMultiplicationFactor = dtshdBufferMultiplicationFactor;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Build the {@link DefaultAudioTrackBufferSizeProvider}. */
|
||||
public DefaultAudioTrackBufferSizeProvider build() {
|
||||
return new DefaultAudioTrackBufferSizeProvider(this);
|
||||
@ -170,6 +187,12 @@ public class DefaultAudioTrackBufferSizeProvider
|
||||
*/
|
||||
public final int ac3BufferMultiplicationFactor;
|
||||
|
||||
/**
|
||||
* The multiplication factor to apply to DTS-HD (DTS Express) passthrough buffer to avoid
|
||||
* underruns.
|
||||
*/
|
||||
public final int dtshdBufferMultiplicationFactor;
|
||||
|
||||
protected DefaultAudioTrackBufferSizeProvider(Builder builder) {
|
||||
minPcmBufferDurationUs = builder.minPcmBufferDurationUs;
|
||||
maxPcmBufferDurationUs = builder.maxPcmBufferDurationUs;
|
||||
@ -177,6 +200,7 @@ public class DefaultAudioTrackBufferSizeProvider
|
||||
passthroughBufferDurationUs = builder.passthroughBufferDurationUs;
|
||||
offloadBufferDurationUs = builder.offloadBufferDurationUs;
|
||||
ac3BufferMultiplicationFactor = builder.ac3BufferMultiplicationFactor;
|
||||
dtshdBufferMultiplicationFactor = builder.dtshdBufferMultiplicationFactor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -232,7 +256,13 @@ public class DefaultAudioTrackBufferSizeProvider
|
||||
int bufferSizeUs = passthroughBufferDurationUs;
|
||||
if (encoding == C.ENCODING_AC3) {
|
||||
bufferSizeUs *= ac3BufferMultiplicationFactor;
|
||||
} else if (encoding == C.ENCODING_DTS_HD) {
|
||||
// DTS-HD (DTS Express) for streaming uses a frame size (number of audio samples per channel
|
||||
// per frame) of 4096. This requires a higher multiple for the buffersize computation.
|
||||
// Otherwise, there will be buffer underflow during DASH playback.
|
||||
bufferSizeUs *= dtshdBufferMultiplicationFactor;
|
||||
}
|
||||
|
||||
int byteRate =
|
||||
bitrate != Format.NO_VALUE
|
||||
? divide(bitrate, 8, RoundingMode.CEILING)
|
||||
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package androidx.media3.exoplayer.audio;
|
||||
|
||||
import static androidx.media3.common.C.MICROS_PER_SECOND;
|
||||
import static androidx.media3.exoplayer.audio.DefaultAudioSink.OUTPUT_MODE_PASSTHROUGH;
|
||||
import static androidx.media3.exoplayer.audio.DefaultAudioTrackBufferSizeProvider.getMaximumEncodedRateBytesPerSecond;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/** Tests for {@link DefaultAudioTrackBufferSizeProvider} DTS-HD (DTS Express) audio. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DefaultAudioTrackBufferSizeProviderDTSHDTest {
|
||||
|
||||
private static final DefaultAudioTrackBufferSizeProvider DEFAULT =
|
||||
new DefaultAudioTrackBufferSizeProvider.Builder().build();
|
||||
|
||||
@Test
|
||||
public void
|
||||
getBufferSizeInBytes_passthroughDtshdAndNoBitrate_assumesMaxByteRateTimesMultiplicationFactor() {
|
||||
int bufferSize =
|
||||
DEFAULT.getBufferSizeInBytes(
|
||||
/* minBufferSizeInBytes= */ 0,
|
||||
/* encoding= */ C.ENCODING_DTS_HD,
|
||||
/* outputMode= */ OUTPUT_MODE_PASSTHROUGH,
|
||||
/* pcmFrameSize= */ 1,
|
||||
/* sampleRate= */ 0,
|
||||
/* bitrate= */ Format.NO_VALUE,
|
||||
/* maxAudioTrackPlaybackSpeed= */ 1);
|
||||
|
||||
assertThat(bufferSize)
|
||||
.isEqualTo(
|
||||
durationUsToDtshdMaxBytes(DEFAULT.passthroughBufferDurationUs)
|
||||
* DEFAULT.dtshdBufferMultiplicationFactor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
getBufferSizeInBytes_passthroughDtshdAt384Kbits_isPassthroughBufferSizeTimesMultiplicationFactor() {
|
||||
int bufferSize =
|
||||
DEFAULT.getBufferSizeInBytes(
|
||||
/* minBufferSizeInBytes= */ 0,
|
||||
/* encoding= */ C.ENCODING_DTS_HD,
|
||||
/* outputMode= */ OUTPUT_MODE_PASSTHROUGH,
|
||||
/* pcmFrameSize= */ 1,
|
||||
/* sampleRate= */ 0,
|
||||
/* bitrate= */ 384_000,
|
||||
/* maxAudioTrackPlaybackSpeed= */ 1);
|
||||
|
||||
// Default buffer duration 0.25s => 0.25 * 384000 / 8 = 12000
|
||||
assertThat(bufferSize).isEqualTo(12000 * DEFAULT.dtshdBufferMultiplicationFactor);
|
||||
}
|
||||
|
||||
private static int durationUsToDtshdMaxBytes(long durationUs) {
|
||||
return (int)
|
||||
(durationUs * getMaximumEncodedRateBytesPerSecond(C.ENCODING_DTS_HD) / MICROS_PER_SECOND);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user