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`.
|
stays at its current behavior of `true`.
|
||||||
* Extractors:
|
* Extractors:
|
||||||
* Audio:
|
* Audio:
|
||||||
|
* Fix DTS Express audio buffer underflow issue
|
||||||
|
([#650](https://github.com/androidx/media/pull/650)).
|
||||||
* Video:
|
* Video:
|
||||||
* Text:
|
* Text:
|
||||||
* Remove `ExoplayerCuesDecoder`. Text tracks with `sampleMimeType =
|
* Remove `ExoplayerCuesDecoder`. Text tracks with `sampleMimeType =
|
||||||
|
@ -63,6 +63,11 @@ public class DefaultAudioTrackBufferSizeProvider
|
|||||||
*/
|
*/
|
||||||
private static final int AC3_BUFFER_MULTIPLICATION_FACTOR = 2;
|
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. */
|
/** A builder to create {@link DefaultAudioTrackBufferSizeProvider} instances. */
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
|
|
||||||
@ -72,6 +77,7 @@ public class DefaultAudioTrackBufferSizeProvider
|
|||||||
private int passthroughBufferDurationUs;
|
private int passthroughBufferDurationUs;
|
||||||
private int offloadBufferDurationUs;
|
private int offloadBufferDurationUs;
|
||||||
private int ac3BufferMultiplicationFactor;
|
private int ac3BufferMultiplicationFactor;
|
||||||
|
private int dtshdBufferMultiplicationFactor;
|
||||||
|
|
||||||
/** Creates a new builder. */
|
/** Creates a new builder. */
|
||||||
public Builder() {
|
public Builder() {
|
||||||
@ -81,6 +87,7 @@ public class DefaultAudioTrackBufferSizeProvider
|
|||||||
passthroughBufferDurationUs = PASSTHROUGH_BUFFER_DURATION_US;
|
passthroughBufferDurationUs = PASSTHROUGH_BUFFER_DURATION_US;
|
||||||
offloadBufferDurationUs = OFFLOAD_BUFFER_DURATION_US;
|
offloadBufferDurationUs = OFFLOAD_BUFFER_DURATION_US;
|
||||||
ac3BufferMultiplicationFactor = AC3_BUFFER_MULTIPLICATION_FACTOR;
|
ac3BufferMultiplicationFactor = AC3_BUFFER_MULTIPLICATION_FACTOR;
|
||||||
|
dtshdBufferMultiplicationFactor = DTSHD_BUFFER_MULTIPLICATION_FACTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -143,6 +150,16 @@ public class DefaultAudioTrackBufferSizeProvider
|
|||||||
return this;
|
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}. */
|
/** Build the {@link DefaultAudioTrackBufferSizeProvider}. */
|
||||||
public DefaultAudioTrackBufferSizeProvider build() {
|
public DefaultAudioTrackBufferSizeProvider build() {
|
||||||
return new DefaultAudioTrackBufferSizeProvider(this);
|
return new DefaultAudioTrackBufferSizeProvider(this);
|
||||||
@ -170,6 +187,12 @@ public class DefaultAudioTrackBufferSizeProvider
|
|||||||
*/
|
*/
|
||||||
public final int ac3BufferMultiplicationFactor;
|
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) {
|
protected DefaultAudioTrackBufferSizeProvider(Builder builder) {
|
||||||
minPcmBufferDurationUs = builder.minPcmBufferDurationUs;
|
minPcmBufferDurationUs = builder.minPcmBufferDurationUs;
|
||||||
maxPcmBufferDurationUs = builder.maxPcmBufferDurationUs;
|
maxPcmBufferDurationUs = builder.maxPcmBufferDurationUs;
|
||||||
@ -177,6 +200,7 @@ public class DefaultAudioTrackBufferSizeProvider
|
|||||||
passthroughBufferDurationUs = builder.passthroughBufferDurationUs;
|
passthroughBufferDurationUs = builder.passthroughBufferDurationUs;
|
||||||
offloadBufferDurationUs = builder.offloadBufferDurationUs;
|
offloadBufferDurationUs = builder.offloadBufferDurationUs;
|
||||||
ac3BufferMultiplicationFactor = builder.ac3BufferMultiplicationFactor;
|
ac3BufferMultiplicationFactor = builder.ac3BufferMultiplicationFactor;
|
||||||
|
dtshdBufferMultiplicationFactor = builder.dtshdBufferMultiplicationFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -232,7 +256,13 @@ public class DefaultAudioTrackBufferSizeProvider
|
|||||||
int bufferSizeUs = passthroughBufferDurationUs;
|
int bufferSizeUs = passthroughBufferDurationUs;
|
||||||
if (encoding == C.ENCODING_AC3) {
|
if (encoding == C.ENCODING_AC3) {
|
||||||
bufferSizeUs *= ac3BufferMultiplicationFactor;
|
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 =
|
int byteRate =
|
||||||
bitrate != Format.NO_VALUE
|
bitrate != Format.NO_VALUE
|
||||||
? divide(bitrate, 8, RoundingMode.CEILING)
|
? 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