Add tests to validate FLAC decoder output
PiperOrigin-RevId: 289091494
This commit is contained in:
parent
f4271f55bc
commit
ca11e56fe6
@ -0,0 +1,91 @@
|
||||
config:
|
||||
encoding = 2 (16 bit)
|
||||
channel count = 2
|
||||
sample rate = 48000
|
||||
buffer:
|
||||
time = 1000
|
||||
data = 1217833679
|
||||
buffer:
|
||||
time = 97000
|
||||
data = 558614672
|
||||
buffer:
|
||||
time = 193000
|
||||
data = -709714787
|
||||
buffer:
|
||||
time = 289000
|
||||
data = 1367870571
|
||||
buffer:
|
||||
time = 385000
|
||||
data = -141229457
|
||||
buffer:
|
||||
time = 481000
|
||||
data = 1287758361
|
||||
buffer:
|
||||
time = 577000
|
||||
data = 1125289147
|
||||
buffer:
|
||||
time = 673000
|
||||
data = -1677383475
|
||||
buffer:
|
||||
time = 769000
|
||||
data = 2130742861
|
||||
buffer:
|
||||
time = 865000
|
||||
data = -1292320253
|
||||
buffer:
|
||||
time = 961000
|
||||
data = -456587163
|
||||
buffer:
|
||||
time = 1057000
|
||||
data = 748981534
|
||||
buffer:
|
||||
time = 1153000
|
||||
data = 1550456016
|
||||
buffer:
|
||||
time = 1249000
|
||||
data = 1657906039
|
||||
buffer:
|
||||
time = 1345000
|
||||
data = -762677083
|
||||
buffer:
|
||||
time = 1441000
|
||||
data = -1343810763
|
||||
buffer:
|
||||
time = 1537000
|
||||
data = 1137318783
|
||||
buffer:
|
||||
time = 1633000
|
||||
data = -1891318229
|
||||
buffer:
|
||||
time = 1729000
|
||||
data = -472068495
|
||||
buffer:
|
||||
time = 1825000
|
||||
data = 832315001
|
||||
buffer:
|
||||
time = 1921000
|
||||
data = 2054935175
|
||||
buffer:
|
||||
time = 2017000
|
||||
data = 57921641
|
||||
buffer:
|
||||
time = 2113000
|
||||
data = 2132759067
|
||||
buffer:
|
||||
time = 2209000
|
||||
data = -1742540521
|
||||
buffer:
|
||||
time = 2305000
|
||||
data = 1657024301
|
||||
buffer:
|
||||
time = 2401000
|
||||
data = -585080145
|
||||
buffer:
|
||||
time = 2497000
|
||||
data = 427271397
|
||||
buffer:
|
||||
time = 2593000
|
||||
data = -364201340
|
||||
buffer:
|
||||
time = 2689000
|
||||
data = -627965287
|
BIN
extensions/flac/src/androidTest/assets/bear-flac-24bit.mka
Normal file
BIN
extensions/flac/src/androidTest/assets/bear-flac-24bit.mka
Normal file
Binary file not shown.
@ -0,0 +1,91 @@
|
||||
config:
|
||||
encoding = 536870912 (24 bit)
|
||||
channel count = 2
|
||||
sample rate = 48000
|
||||
buffer:
|
||||
time = 0
|
||||
data = 225023649
|
||||
buffer:
|
||||
time = 96000
|
||||
data = 455106306
|
||||
buffer:
|
||||
time = 192000
|
||||
data = 2025727297
|
||||
buffer:
|
||||
time = 288000
|
||||
data = 758514657
|
||||
buffer:
|
||||
time = 384000
|
||||
data = 1044986473
|
||||
buffer:
|
||||
time = 480000
|
||||
data = -2030029695
|
||||
buffer:
|
||||
time = 576000
|
||||
data = 1907053281
|
||||
buffer:
|
||||
time = 672000
|
||||
data = -1974954431
|
||||
buffer:
|
||||
time = 768000
|
||||
data = -206248383
|
||||
buffer:
|
||||
time = 864000
|
||||
data = 1484984417
|
||||
buffer:
|
||||
time = 960000
|
||||
data = -1306117439
|
||||
buffer:
|
||||
time = 1056000
|
||||
data = 692829792
|
||||
buffer:
|
||||
time = 1152000
|
||||
data = 1070563058
|
||||
buffer:
|
||||
time = 1248000
|
||||
data = -1444096479
|
||||
buffer:
|
||||
time = 1344000
|
||||
data = 1753016419
|
||||
buffer:
|
||||
time = 1440000
|
||||
data = 1947797953
|
||||
buffer:
|
||||
time = 1536000
|
||||
data = 266121411
|
||||
buffer:
|
||||
time = 1632000
|
||||
data = 1275494369
|
||||
buffer:
|
||||
time = 1728000
|
||||
data = 372077825
|
||||
buffer:
|
||||
time = 1824000
|
||||
data = -993079679
|
||||
buffer:
|
||||
time = 1920000
|
||||
data = 177307937
|
||||
buffer:
|
||||
time = 2016000
|
||||
data = 2037083009
|
||||
buffer:
|
||||
time = 2112000
|
||||
data = -435776287
|
||||
buffer:
|
||||
time = 2208000
|
||||
data = 1867447329
|
||||
buffer:
|
||||
time = 2304000
|
||||
data = 1884495937
|
||||
buffer:
|
||||
time = 2400000
|
||||
data = -804673375
|
||||
buffer:
|
||||
time = 2496000
|
||||
data = -588531007
|
||||
buffer:
|
||||
time = 2592000
|
||||
data = -1064642970
|
||||
buffer:
|
||||
time = 2688000
|
||||
data = -1771406207
|
@ -25,9 +25,13 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.audio.AudioProcessor;
|
||||
import com.google.android.exoplayer2.audio.AudioSink;
|
||||
import com.google.android.exoplayer2.audio.DefaultAudioSink;
|
||||
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.testutil.CapturingAudioSink;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -37,7 +41,8 @@ import org.junit.runner.RunWith;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class FlacPlaybackTest {
|
||||
|
||||
private static final String BEAR_FLAC_URI = "asset:///bear-flac.mka";
|
||||
private static final String BEAR_FLAC_16BIT = "bear-flac-16bit.mka";
|
||||
private static final String BEAR_FLAC_24BIT = "bear-flac-24bit.mka";
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@ -47,38 +52,56 @@ public class FlacPlaybackTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicPlayback() throws Exception {
|
||||
playUri(BEAR_FLAC_URI);
|
||||
public void test16BitPlayback() throws Exception {
|
||||
playAndAssertAudioSinkInput(BEAR_FLAC_16BIT);
|
||||
}
|
||||
|
||||
private void playUri(String uri) throws Exception {
|
||||
@Test
|
||||
public void test24BitPlayback() throws Exception {
|
||||
playAndAssertAudioSinkInput(BEAR_FLAC_24BIT);
|
||||
}
|
||||
|
||||
private static void playAndAssertAudioSinkInput(String fileName) throws Exception {
|
||||
CapturingAudioSink audioSink =
|
||||
new CapturingAudioSink(
|
||||
new DefaultAudioSink(/* audioCapabilities= */ null, new AudioProcessor[0]));
|
||||
|
||||
TestPlaybackRunnable testPlaybackRunnable =
|
||||
new TestPlaybackRunnable(Uri.parse(uri), ApplicationProvider.getApplicationContext());
|
||||
new TestPlaybackRunnable(
|
||||
Uri.parse("asset:///" + fileName),
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
audioSink);
|
||||
Thread thread = new Thread(testPlaybackRunnable);
|
||||
thread.start();
|
||||
thread.join();
|
||||
if (testPlaybackRunnable.playbackException != null) {
|
||||
throw testPlaybackRunnable.playbackException;
|
||||
}
|
||||
|
||||
audioSink.assertOutput(
|
||||
ApplicationProvider.getApplicationContext(), fileName + ".audiosink.dump");
|
||||
}
|
||||
|
||||
private static class TestPlaybackRunnable implements Player.EventListener, Runnable {
|
||||
|
||||
private final Context context;
|
||||
private final Uri uri;
|
||||
private final AudioSink audioSink;
|
||||
|
||||
private ExoPlayer player;
|
||||
private ExoPlaybackException playbackException;
|
||||
|
||||
public TestPlaybackRunnable(Uri uri, Context context) {
|
||||
public TestPlaybackRunnable(Uri uri, Context context, AudioSink audioSink) {
|
||||
this.uri = uri;
|
||||
this.context = context;
|
||||
this.audioSink = audioSink;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Looper.prepare();
|
||||
LibflacAudioRenderer audioRenderer = new LibflacAudioRenderer();
|
||||
LibflacAudioRenderer audioRenderer =
|
||||
new LibflacAudioRenderer(/* eventHandler= */ null, /* eventListener= */ null, audioSink);
|
||||
player = new ExoPlayer.Builder(context, audioRenderer).build();
|
||||
player.addListener(this);
|
||||
MediaSource mediaSource =
|
||||
@ -105,5 +128,4 @@ public class FlacPlaybackTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.audio.AudioProcessor;
|
||||
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
|
||||
import com.google.android.exoplayer2.audio.AudioSink;
|
||||
import com.google.android.exoplayer2.audio.SimpleDecoderAudioRenderer;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
@ -55,6 +56,24 @@ public final class LibflacAudioRenderer extends SimpleDecoderAudioRenderer {
|
||||
super(eventHandler, eventListener, audioProcessors);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
|
||||
* null if delivery of events is not required.
|
||||
* @param eventListener A listener of events. May be null if delivery of events is not required.
|
||||
* @param audioSink The sink to which audio will be output.
|
||||
*/
|
||||
public LibflacAudioRenderer(
|
||||
@Nullable Handler eventHandler,
|
||||
@Nullable AudioRendererEventListener eventListener,
|
||||
AudioSink audioSink) {
|
||||
super(
|
||||
eventHandler,
|
||||
eventListener,
|
||||
/* drmSessionManager= */ null,
|
||||
/* playClearSamplesWithoutKeys= */ false,
|
||||
audioSink);
|
||||
}
|
||||
|
||||
@Override
|
||||
@FormatSupport
|
||||
protected int supportsFormatInternal(
|
||||
@ -68,8 +87,8 @@ public final class LibflacAudioRenderer extends SimpleDecoderAudioRenderer {
|
||||
if (format.initializationData.isEmpty()) {
|
||||
// The initialization data might not be set if the format was obtained from a manifest (e.g.
|
||||
// for DASH playbacks) rather than directly from the media. In this case we assume
|
||||
// ENCODING_PCM_16BIT. If the actual encoding is different, playback will still succeed as
|
||||
// long as the AudioSink supports it (which will always be true when using DefaultAudioSink).
|
||||
// ENCODING_PCM_16BIT. If the actual encoding is different then playback will still succeed as
|
||||
// long as the AudioSink supports it, which will always be true when using DefaultAudioSink.
|
||||
pcmEncoding = C.ENCODING_PCM_16BIT;
|
||||
} else {
|
||||
int streamMetadataOffset =
|
||||
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 com.google.android.exoplayer2.audio;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/** An overridable {@link AudioSink} implementation forwarding all methods to another sink. */
|
||||
public class ForwardingAudioSink implements AudioSink {
|
||||
|
||||
private final AudioSink sink;
|
||||
|
||||
public ForwardingAudioSink(AudioSink sink) {
|
||||
this.sink = sink;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener(Listener listener) {
|
||||
sink.setListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsOutput(int channelCount, int encoding) {
|
||||
return sink.supportsOutput(channelCount, encoding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCurrentPositionUs(boolean sourceEnded) {
|
||||
return sink.getCurrentPositionUs(sourceEnded);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(
|
||||
int inputEncoding,
|
||||
int inputChannelCount,
|
||||
int inputSampleRate,
|
||||
int specifiedBufferSize,
|
||||
@Nullable int[] outputChannels,
|
||||
int trimStartFrames,
|
||||
int trimEndFrames)
|
||||
throws ConfigurationException {
|
||||
sink.configure(
|
||||
inputEncoding,
|
||||
inputChannelCount,
|
||||
inputSampleRate,
|
||||
specifiedBufferSize,
|
||||
outputChannels,
|
||||
trimStartFrames,
|
||||
trimEndFrames);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void play() {
|
||||
sink.play();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleDiscontinuity() {
|
||||
sink.handleDiscontinuity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleBuffer(ByteBuffer buffer, long presentationTimeUs)
|
||||
throws InitializationException, WriteException {
|
||||
return sink.handleBuffer(buffer, presentationTimeUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playToEndOfStream() throws WriteException {
|
||||
sink.playToEndOfStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnded() {
|
||||
return sink.isEnded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPendingData() {
|
||||
return sink.hasPendingData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlaybackParameters(PlaybackParameters playbackParameters) {
|
||||
sink.setPlaybackParameters(playbackParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlaybackParameters getPlaybackParameters() {
|
||||
return sink.getPlaybackParameters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAudioAttributes(AudioAttributes audioAttributes) {
|
||||
sink.setAudioAttributes(audioAttributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAudioSessionId(int audioSessionId) {
|
||||
sink.setAudioSessionId(audioSessionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuxEffectInfo(AuxEffectInfo auxEffectInfo) {
|
||||
sink.setAuxEffectInfo(auxEffectInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableTunnelingV21(int tunnelingAudioSessionId) {
|
||||
sink.enableTunnelingV21(tunnelingAudioSessionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableTunneling() {
|
||||
sink.disableTunneling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVolume(float volume) {
|
||||
sink.setVolume(volume);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
sink.pause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
sink.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
sink.reset();
|
||||
}
|
||||
}
|
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 com.google.android.exoplayer2.testutil;
|
||||
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.audio.AudioSink;
|
||||
import com.google.android.exoplayer2.audio.ForwardingAudioSink;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/** A {@link ForwardingAudioSink} that captures configuration, discontinuity and buffer events. */
|
||||
public final class CapturingAudioSink extends ForwardingAudioSink implements Dumper.Dumpable {
|
||||
|
||||
/**
|
||||
* If true, makes {@link #assertOutput(Context, String)} method write the output to a file, rather
|
||||
* than validating that the output matches the dump file.
|
||||
*
|
||||
* <p>The output file is written to the test apk's external storage directory, which is typically:
|
||||
* {@code /sdcard/Android/data/${package-under-test}.test/files/}.
|
||||
*/
|
||||
private static final boolean WRITE_DUMP = false;
|
||||
|
||||
private final List<Dumper.Dumpable> interceptedData;
|
||||
@Nullable private ByteBuffer currentBuffer;
|
||||
|
||||
public CapturingAudioSink(AudioSink sink) {
|
||||
super(sink);
|
||||
interceptedData = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(
|
||||
int inputEncoding,
|
||||
int inputChannelCount,
|
||||
int inputSampleRate,
|
||||
int specifiedBufferSize,
|
||||
@Nullable int[] outputChannels,
|
||||
int trimStartFrames,
|
||||
int trimEndFrames)
|
||||
throws ConfigurationException {
|
||||
interceptedData.add(
|
||||
new DumpableConfiguration(inputEncoding, inputChannelCount, inputSampleRate));
|
||||
super.configure(
|
||||
inputEncoding,
|
||||
inputChannelCount,
|
||||
inputSampleRate,
|
||||
specifiedBufferSize,
|
||||
outputChannels,
|
||||
trimStartFrames,
|
||||
trimEndFrames);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleDiscontinuity() {
|
||||
interceptedData.add(new DumpableDiscontinuity());
|
||||
super.handleDiscontinuity();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("ReferenceEquality")
|
||||
public boolean handleBuffer(ByteBuffer buffer, long presentationTimeUs)
|
||||
throws InitializationException, WriteException {
|
||||
// handleBuffer is called repeatedly with the same buffer until it's been fully consumed by the
|
||||
// sink. We only want to dump each buffer once, and we need to do so before the sink being
|
||||
// forwarded to has a chance to modify its position.
|
||||
if (buffer != currentBuffer) {
|
||||
interceptedData.add(new DumpableBuffer(buffer, presentationTimeUs));
|
||||
currentBuffer = buffer;
|
||||
}
|
||||
boolean fullyConsumed = super.handleBuffer(buffer, presentationTimeUs);
|
||||
if (fullyConsumed) {
|
||||
currentBuffer = null;
|
||||
}
|
||||
return fullyConsumed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
currentBuffer = null;
|
||||
super.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
currentBuffer = null;
|
||||
super.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that dump of this sink is equal to expected dump which is read from {@code dumpFile}.
|
||||
*
|
||||
* <p>If assertion fails because of an intended change in the output or a new dump file needs to
|
||||
* be created, set {@link #WRITE_DUMP} flag to true and run the test again. Instead of assertion,
|
||||
* actual dump will be written to {@code dumpFile}. This new dump file needs to be copied to the
|
||||
* project, {@code library/src/androidTest/assets} folder manually.
|
||||
*/
|
||||
public void assertOutput(Context context, String dumpFile) throws IOException {
|
||||
String actual = new Dumper().add(this).toString();
|
||||
|
||||
if (WRITE_DUMP) {
|
||||
File directory = context.getExternalFilesDir(null);
|
||||
File file = new File(directory, dumpFile);
|
||||
file.getParentFile().mkdirs();
|
||||
PrintWriter out = new PrintWriter(file);
|
||||
out.print(actual);
|
||||
out.close();
|
||||
} else {
|
||||
String expected = TestUtil.getString(context, dumpFile);
|
||||
assertWithMessage(dumpFile).that(actual).isEqualTo(expected);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Dumper dumper) {
|
||||
for (int i = 0; i < interceptedData.size(); i++) {
|
||||
interceptedData.get(i).dump(dumper);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DumpableConfiguration implements Dumper.Dumpable {
|
||||
|
||||
private final int inputEncoding;
|
||||
private final int inputChannelCount;
|
||||
private final int inputSampleRate;
|
||||
|
||||
public DumpableConfiguration(int inputEncoding, int inputChannelCount, int inputSampleRate) {
|
||||
this.inputEncoding = inputEncoding;
|
||||
this.inputChannelCount = inputChannelCount;
|
||||
this.inputSampleRate = inputSampleRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Dumper dumper) {
|
||||
int bitDepth = (Util.getPcmFrameSize(inputEncoding, /* channelCount= */ 1) * 8);
|
||||
dumper
|
||||
.startBlock("config")
|
||||
.add("encoding", inputEncoding + " (" + bitDepth + " bit)")
|
||||
.add("channel count", inputChannelCount)
|
||||
.add("sample rate", inputSampleRate)
|
||||
.endBlock();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DumpableBuffer implements Dumper.Dumpable {
|
||||
|
||||
private final long presentationTimeUs;
|
||||
private final int dataHashcode;
|
||||
|
||||
public DumpableBuffer(ByteBuffer buffer, long presentationTimeUs) {
|
||||
this.presentationTimeUs = presentationTimeUs;
|
||||
// Compute a hash of the buffer data without changing its position.
|
||||
int initialPosition = buffer.position();
|
||||
byte[] data = new byte[buffer.remaining()];
|
||||
buffer.get(data);
|
||||
buffer.position(initialPosition);
|
||||
this.dataHashcode = Arrays.hashCode(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Dumper dumper) {
|
||||
dumper
|
||||
.startBlock("buffer")
|
||||
.add("time", presentationTimeUs)
|
||||
.add("data", dataHashcode)
|
||||
.endBlock();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DumpableDiscontinuity implements Dumper.Dumpable {
|
||||
|
||||
@Override
|
||||
public void dump(Dumper dumper) {
|
||||
dumper.startBlock("discontinuity").endBlock();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user