Trim CodecDelay/PreSkip In New OpusDecoder Instances By Default

PiperOrigin-RevId: 427819209
This commit is contained in:
olly 2022-02-10 20:37:25 +00:00 committed by Ian Baker
parent 1af8d57032
commit 8d09da4abf
2 changed files with 62 additions and 0 deletions

View File

@ -99,6 +99,7 @@ public final class OpusDecoder
}
preSkipSamples = getPreSkipSamples(initializationData);
seekPreRollSamples = getSeekPreRollSamples(initializationData);
skipSamples = preSkipSamples;
byte[] headerBytes = initializationData.get(0);
if (headerBytes.length < 19) {

View File

@ -17,11 +17,16 @@ package androidx.media3.decoder.opus;
import static com.google.common.truth.Truth.assertThat;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.util.LibraryLoader;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.decoder.SimpleDecoderOutputBuffer;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.collect.ImmutableList;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -29,9 +34,14 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public final class OpusDecoderTest {
private static final LibraryLoader LOADER = new LibraryLoader("opusV2JNI");
private static final byte[] HEADER =
new byte[] {79, 112, 117, 115, 72, 101, 97, 100, 0, 2, 1, 56, 0, 0, -69, -128, 0, 0, 0};
private static final byte[] ENCODED_DATA = new byte[] {-4};
private static final int DECODED_DATA_SIZE = 3840;
private static final int HEADER_PRE_SKIP_SAMPLES = 14337;
private static final int DEFAULT_SEEK_PRE_ROLL_SAMPLES = 3840;
@ -39,6 +49,7 @@ public final class OpusDecoderTest {
private static final ImmutableList<byte[]> HEADER_ONLY_INITIALIZATION_DATA =
ImmutableList.of(HEADER);
private static final long PRE_SKIP_NANOS = 6_500_000;
private static final long CUSTOM_PRE_SKIP_SAMPLES = 28674;
private static final byte[] CUSTOM_PRE_SKIP_BYTES =
buildNativeOrderByteArray(sampleCountToNanoseconds(CUSTOM_PRE_SKIP_SAMPLES));
@ -50,6 +61,11 @@ public final class OpusDecoderTest {
private static final ImmutableList<byte[]> FULL_INITIALIZATION_DATA =
ImmutableList.of(HEADER, CUSTOM_PRE_SKIP_BYTES, CUSTOM_SEEK_PRE_ROLL_BYTES);
@Before
public void setUp() {
assertThat(LOADER.isAvailable()).isTrue();
}
@Test
public void getChannelCount() {
int channelCount = OpusDecoder.getChannelCount(HEADER);
@ -80,11 +96,56 @@ public final class OpusDecoderTest {
assertThat(seekPreRollSamples).isEqualTo(DEFAULT_SEEK_PRE_ROLL_SAMPLES);
}
@Test
public void decode_removesPreSkipFromOutput() throws OpusDecoderException {
OpusDecoder decoder =
new OpusDecoder(
/* numInputBuffers= */ 0,
/* numOutputBuffers= */ 0,
/* initialInputBufferSize= */ 0,
createInitializationData(/* preSkipNanos= */ PRE_SKIP_NANOS),
/* cryptoConfig= */ null,
/* outputFloat= */ false);
DecoderInputBuffer input =
createInputBuffer(decoder, ENCODED_DATA, /* supplementalData= */ null);
SimpleDecoderOutputBuffer output = decoder.createOutputBuffer();
assertThat(decoder.decode(input, output, false)).isNull();
assertThat(output.data.remaining())
.isEqualTo(DECODED_DATA_SIZE - nanosecondsToBytes(PRE_SKIP_NANOS));
}
private static long sampleCountToNanoseconds(long sampleCount) {
return (sampleCount * C.NANOS_PER_SECOND) / OpusDecoder.SAMPLE_RATE;
}
private static long nanosecondsToSampleCount(long nanoseconds) {
return (nanoseconds * OpusDecoder.SAMPLE_RATE) / C.NANOS_PER_SECOND;
}
private static long nanosecondsToBytes(long nanoseconds) {
return nanosecondsToSampleCount(nanoseconds) * 4;
}
private static byte[] buildNativeOrderByteArray(long value) {
return ByteBuffer.allocate(8).order(ByteOrder.nativeOrder()).putLong(value).array();
}
private static ImmutableList<byte[]> createInitializationData(long preSkipNanos) {
byte[] preSkip = buildNativeOrderByteArray(preSkipNanos);
return ImmutableList.of(HEADER, preSkip, CUSTOM_SEEK_PRE_ROLL_BYTES);
}
private static DecoderInputBuffer createInputBuffer(
OpusDecoder decoder, byte[] data, @Nullable byte[] supplementalData) {
DecoderInputBuffer input = decoder.createInputBuffer();
input.ensureSpaceForWrite(data.length);
input.data.put(data);
input.data.position(0).limit(data.length);
if (supplementalData != null) {
input.resetSupplementalData(supplementalData.length);
input.supplementalData.put(supplementalData).rewind();
input.addFlag(C.BUFFER_FLAG_HAS_SUPPLEMENTAL_DATA);
}
return input;
}
}