Skip to content

Commit

Permalink
Merge pull request #650 from cedricxperi:dts-lbr-buffer-underflow-fix
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 572864175
  • Loading branch information
Copybara-Service committed Oct 12, 2023
2 parents a12bde4 + 492048c commit 2421ba4
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 0 deletions.
2 changes: 2 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand All @@ -72,6 +77,7 @@ public static class Builder {
private int passthroughBufferDurationUs;
private int offloadBufferDurationUs;
private int ac3BufferMultiplicationFactor;
private int dtshdBufferMultiplicationFactor;

/** Creates a new builder. */
public Builder() {
Expand All @@ -81,6 +87,7 @@ public Builder() {
passthroughBufferDurationUs = PASSTHROUGH_BUFFER_DURATION_US;
offloadBufferDurationUs = OFFLOAD_BUFFER_DURATION_US;
ac3BufferMultiplicationFactor = AC3_BUFFER_MULTIPLICATION_FACTOR;
dtshdBufferMultiplicationFactor = DTSHD_BUFFER_MULTIPLICATION_FACTOR;
}

/**
Expand Down Expand Up @@ -143,6 +150,16 @@ public Builder setAc3BufferMultiplicationFactor(int ac3BufferMultiplicationFacto
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);
Expand Down Expand Up @@ -170,13 +187,20 @@ public DefaultAudioTrackBufferSizeProvider build() {
*/
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;
pcmBufferMultiplicationFactor = builder.pcmBufferMultiplicationFactor;
passthroughBufferDurationUs = builder.passthroughBufferDurationUs;
offloadBufferDurationUs = builder.offloadBufferDurationUs;
ac3BufferMultiplicationFactor = builder.ac3BufferMultiplicationFactor;
dtshdBufferMultiplicationFactor = builder.dtshdBufferMultiplicationFactor;
}

@Override
Expand Down Expand Up @@ -232,7 +256,13 @@ protected int getPassthroughBufferSizeInBytes(@C.Encoding int encoding, int bitr
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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}

0 comments on commit 2421ba4

Please sign in to comment.