Fix SampleQueue splicing when sampleOffsetUs != 0

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=212432661
This commit is contained in:
olly 2018-09-11 04:54:00 -07:00 committed by Oliver Woodman
parent ba8c22aba5
commit 6c3c71b554
2 changed files with 200 additions and 107 deletions

View file

@ -577,13 +577,13 @@ public final class SampleQueue implements TrackOutput {
if (pendingFormatAdjustment) {
format(lastUnadjustedFormat);
}
timeUs += sampleOffsetUs;
if (pendingSplice) {
if ((flags & C.BUFFER_FLAG_KEY_FRAME) == 0 || !metadataQueue.attemptSplice(timeUs)) {
return;
}
pendingSplice = false;
}
timeUs += sampleOffsetUs;
long absoluteOffset = totalBytesWritten - size - offset;
metadataQueue.commitSample(timeUs, flags, absoluteOffset, size, cryptoData);
}

View file

@ -23,6 +23,7 @@ import static com.google.common.truth.Truth.assertThat;
import static java.lang.Long.MIN_VALUE;
import static java.util.Arrays.copyOfRange;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder;
@ -45,41 +46,51 @@ public final class SampleQueueTest {
private static final int ALLOCATION_SIZE = 16;
private static final Format TEST_FORMAT_1 = Format.createSampleFormat("1", "mimeType", 0);
private static final Format TEST_FORMAT_2 = Format.createSampleFormat("2", "mimeType", 0);
private static final Format TEST_FORMAT_1_COPY = Format.createSampleFormat("1", "mimeType", 0);
private static final byte[] TEST_DATA = TestUtil.buildTestData(ALLOCATION_SIZE * 10);
private static final Format FORMAT_1 = Format.createSampleFormat("1", "mimeType", 0);
private static final Format FORMAT_2 = Format.createSampleFormat("2", "mimeType", 0);
private static final Format FORMAT_1_COPY = Format.createSampleFormat("1", "mimeType", 0);
private static final Format FORMAT_SPLICED = Format.createSampleFormat("spliced", "mimeType", 0);
private static final byte[] DATA = TestUtil.buildTestData(ALLOCATION_SIZE * 10);
/*
* TEST_SAMPLE_SIZES and TEST_SAMPLE_OFFSETS are intended to test various boundary cases (with
* respect to the allocation size). TEST_SAMPLE_OFFSETS values are defined as the backward offsets
* (as expected by SampleQueue.sampleMetadata) assuming that TEST_DATA has been written to the
* SAMPLE_SIZES and SAMPLE_OFFSETS are intended to test various boundary cases (with
* respect to the allocation size). SAMPLE_OFFSETS values are defined as the backward offsets
* (as expected by SampleQueue.sampleMetadata) assuming that DATA has been written to the
* sampleQueue in full. The allocations are filled as follows, where | indicates a boundary
* between allocations and x indicates a byte that doesn't belong to a sample:
*
* x<s1>|x<s2>x|x<s3>|<s4>x|<s5>|<s6|s6>|x<s7|s7>x|<s8>
*/
private static final int[] TEST_SAMPLE_SIZES = new int[] {
ALLOCATION_SIZE - 1, ALLOCATION_SIZE - 2, ALLOCATION_SIZE - 1, ALLOCATION_SIZE - 1,
ALLOCATION_SIZE, ALLOCATION_SIZE * 2, ALLOCATION_SIZE * 2 - 2, ALLOCATION_SIZE
};
private static final int[] TEST_SAMPLE_OFFSETS = new int[] {
ALLOCATION_SIZE * 9, ALLOCATION_SIZE * 8 + 1, ALLOCATION_SIZE * 7, ALLOCATION_SIZE * 6 + 1,
ALLOCATION_SIZE * 5, ALLOCATION_SIZE * 3, ALLOCATION_SIZE + 1, 0
};
private static final long[] TEST_SAMPLE_TIMESTAMPS = new long[] {
0, 1000, 2000, 3000, 4000, 5000, 6000, 7000
};
private static final long LAST_SAMPLE_TIMESTAMP =
TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1];
private static final int[] TEST_SAMPLE_FLAGS = new int[] {
C.BUFFER_FLAG_KEY_FRAME, 0, 0, 0, C.BUFFER_FLAG_KEY_FRAME, 0, 0, 0
};
private static final Format[] TEST_SAMPLE_FORMATS = new Format[] {
TEST_FORMAT_1, TEST_FORMAT_1, TEST_FORMAT_1, TEST_FORMAT_1, TEST_FORMAT_2, TEST_FORMAT_2,
TEST_FORMAT_2, TEST_FORMAT_2
};
private static final int TEST_DATA_SECOND_KEYFRAME_INDEX = 4;
private static final int[] SAMPLE_SIZES =
new int[] {
ALLOCATION_SIZE - 1,
ALLOCATION_SIZE - 2,
ALLOCATION_SIZE - 1,
ALLOCATION_SIZE - 1,
ALLOCATION_SIZE,
ALLOCATION_SIZE * 2,
ALLOCATION_SIZE * 2 - 2,
ALLOCATION_SIZE
};
private static final int[] SAMPLE_OFFSETS =
new int[] {
ALLOCATION_SIZE * 9,
ALLOCATION_SIZE * 8 + 1,
ALLOCATION_SIZE * 7,
ALLOCATION_SIZE * 6 + 1,
ALLOCATION_SIZE * 5,
ALLOCATION_SIZE * 3,
ALLOCATION_SIZE + 1,
0
};
private static final long[] SAMPLE_TIMESTAMPS =
new long[] {0, 1000, 2000, 3000, 4000, 5000, 6000, 7000};
private static final long LAST_SAMPLE_TIMESTAMP = SAMPLE_TIMESTAMPS[SAMPLE_TIMESTAMPS.length - 1];
private static final int[] SAMPLE_FLAGS =
new int[] {C.BUFFER_FLAG_KEY_FRAME, 0, 0, 0, C.BUFFER_FLAG_KEY_FRAME, 0, 0, 0};
private static final Format[] SAMPLE_FORMATS =
new Format[] {FORMAT_1, FORMAT_1, FORMAT_1, FORMAT_1, FORMAT_2, FORMAT_2, FORMAT_2, FORMAT_2};
private static final int DATA_SECOND_KEYFRAME_INDEX = 4;
private Allocator allocator;
private SampleQueue sampleQueue;
@ -117,37 +128,37 @@ public final class SampleQueueTest {
@Test
public void testReadFormatDeduplicated() {
sampleQueue.format(TEST_FORMAT_1);
assertReadFormat(false, TEST_FORMAT_1);
sampleQueue.format(FORMAT_1);
assertReadFormat(false, FORMAT_1);
// If the same format is input then it should be de-duplicated (i.e. not output again).
sampleQueue.format(TEST_FORMAT_1);
assertNoSamplesToRead(TEST_FORMAT_1);
sampleQueue.format(FORMAT_1);
assertNoSamplesToRead(FORMAT_1);
// The same applies for a format that's equal (but a different object).
sampleQueue.format(TEST_FORMAT_1_COPY);
assertNoSamplesToRead(TEST_FORMAT_1);
sampleQueue.format(FORMAT_1_COPY);
assertNoSamplesToRead(FORMAT_1);
}
@Test
public void testReadSingleSamples() {
sampleQueue.sampleData(new ParsableByteArray(TEST_DATA), ALLOCATION_SIZE);
sampleQueue.sampleData(new ParsableByteArray(DATA), ALLOCATION_SIZE);
assertAllocationCount(1);
// Nothing to read.
assertNoSamplesToRead(null);
sampleQueue.format(TEST_FORMAT_1);
sampleQueue.format(FORMAT_1);
// Read the format.
assertReadFormat(false, TEST_FORMAT_1);
assertReadFormat(false, FORMAT_1);
// Nothing to read.
assertNoSamplesToRead(TEST_FORMAT_1);
assertNoSamplesToRead(FORMAT_1);
sampleQueue.sampleMetadata(1000, C.BUFFER_FLAG_KEY_FRAME, ALLOCATION_SIZE, 0, null);
// If formatRequired, should read the format rather than the sample.
assertReadFormat(true, TEST_FORMAT_1);
assertReadFormat(true, FORMAT_1);
// Otherwise should read the sample.
assertSampleRead(1000, true, TEST_DATA, 0, ALLOCATION_SIZE);
assertReadSample(1000, true, DATA, 0, ALLOCATION_SIZE);
// Allocation should still be held.
assertAllocationCount(1);
sampleQueue.discardToRead();
@ -155,16 +166,16 @@ public final class SampleQueueTest {
assertAllocationCount(0);
// Nothing to read.
assertNoSamplesToRead(TEST_FORMAT_1);
assertNoSamplesToRead(FORMAT_1);
// Write a second sample followed by one byte that does not belong to it.
sampleQueue.sampleData(new ParsableByteArray(TEST_DATA), ALLOCATION_SIZE);
sampleQueue.sampleData(new ParsableByteArray(DATA), ALLOCATION_SIZE);
sampleQueue.sampleMetadata(2000, 0, ALLOCATION_SIZE - 1, 1, null);
// If formatRequired, should read the format rather than the sample.
assertReadFormat(true, TEST_FORMAT_1);
assertReadFormat(true, FORMAT_1);
// Read the sample.
assertSampleRead(2000, false, TEST_DATA, 0, ALLOCATION_SIZE - 1);
assertReadSample(2000, false, DATA, 0, ALLOCATION_SIZE - 1);
// Allocation should still be held.
assertAllocationCount(1);
sampleQueue.discardToRead();
@ -176,9 +187,9 @@ public final class SampleQueueTest {
sampleQueue.sampleMetadata(3000, 0, 1, 0, null);
// If formatRequired, should read the format rather than the sample.
assertReadFormat(true, TEST_FORMAT_1);
assertReadFormat(true, FORMAT_1);
// Read the sample.
assertSampleRead(3000, false, TEST_DATA, ALLOCATION_SIZE - 1, 1);
assertReadSample(3000, false, DATA, ALLOCATION_SIZE - 1, 1);
// Allocation should still be held.
assertAllocationCount(1);
sampleQueue.discardToRead();
@ -202,8 +213,8 @@ public final class SampleQueueTest {
writeTestData();
writeTestData();
assertAllocationCount(20);
assertReadTestData(TEST_FORMAT_2);
assertReadTestData(TEST_FORMAT_2);
assertReadTestData(FORMAT_2);
assertReadTestData(FORMAT_2);
assertAllocationCount(20);
sampleQueue.discardToRead();
assertAllocationCount(0);
@ -251,15 +262,15 @@ public final class SampleQueueTest {
assertAllocationCount(0);
// Despite skipping all samples, we should still read the last format, since this is the
// expected format for a subsequent sample.
assertReadFormat(false, TEST_FORMAT_2);
assertReadFormat(false, FORMAT_2);
// Once the format has been read, there's nothing else to read.
assertNoSamplesToRead(TEST_FORMAT_2);
assertNoSamplesToRead(FORMAT_2);
}
@Test
public void testAdvanceToEndRetainsUnassignedData() {
sampleQueue.format(TEST_FORMAT_1);
sampleQueue.sampleData(new ParsableByteArray(TEST_DATA), ALLOCATION_SIZE);
sampleQueue.format(FORMAT_1);
sampleQueue.sampleData(new ParsableByteArray(DATA), ALLOCATION_SIZE);
sampleQueue.advanceToEnd();
assertAllocationCount(1);
sampleQueue.discardToRead();
@ -267,14 +278,14 @@ public final class SampleQueueTest {
// written.
assertAllocationCount(1);
// We should be able to read the format.
assertReadFormat(false, TEST_FORMAT_1);
assertReadFormat(false, FORMAT_1);
// Once the format has been read, there's nothing else to read.
assertNoSamplesToRead(TEST_FORMAT_1);
assertNoSamplesToRead(FORMAT_1);
sampleQueue.sampleMetadata(0, C.BUFFER_FLAG_KEY_FRAME, ALLOCATION_SIZE, 0, null);
// Once the metadata has been written, check the sample can be read as expected.
assertSampleRead(0, true, TEST_DATA, 0, ALLOCATION_SIZE);
assertNoSamplesToRead(TEST_FORMAT_1);
assertReadSample(0, true, DATA, 0, ALLOCATION_SIZE);
assertNoSamplesToRead(FORMAT_1);
assertAllocationCount(1);
sampleQueue.discardToRead();
assertAllocationCount(0);
@ -283,21 +294,21 @@ public final class SampleQueueTest {
@Test
public void testAdvanceToBeforeBuffer() {
writeTestData();
int skipCount = sampleQueue.advanceTo(TEST_SAMPLE_TIMESTAMPS[0] - 1, true, false);
int skipCount = sampleQueue.advanceTo(SAMPLE_TIMESTAMPS[0] - 1, true, false);
// Should fail and have no effect.
assertThat(skipCount).isEqualTo(ADVANCE_FAILED);
assertReadTestData();
assertNoSamplesToRead(TEST_FORMAT_2);
assertNoSamplesToRead(FORMAT_2);
}
@Test
public void testAdvanceToStartOfBuffer() {
writeTestData();
int skipCount = sampleQueue.advanceTo(TEST_SAMPLE_TIMESTAMPS[0], true, false);
int skipCount = sampleQueue.advanceTo(SAMPLE_TIMESTAMPS[0], true, false);
// Should succeed but have no effect (we're already at the first frame).
assertThat(skipCount).isEqualTo(0);
assertReadTestData();
assertNoSamplesToRead(TEST_FORMAT_2);
assertNoSamplesToRead(FORMAT_2);
}
@Test
@ -306,8 +317,8 @@ public final class SampleQueueTest {
int skipCount = sampleQueue.advanceTo(LAST_SAMPLE_TIMESTAMP, true, false);
// Should succeed and skip to 2nd keyframe (the 4th frame).
assertThat(skipCount).isEqualTo(4);
assertReadTestData(null, TEST_DATA_SECOND_KEYFRAME_INDEX);
assertNoSamplesToRead(TEST_FORMAT_2);
assertReadTestData(null, DATA_SECOND_KEYFRAME_INDEX);
assertNoSamplesToRead(FORMAT_2);
}
@Test
@ -317,7 +328,7 @@ public final class SampleQueueTest {
// Should fail and have no effect.
assertThat(skipCount).isEqualTo(ADVANCE_FAILED);
assertReadTestData();
assertNoSamplesToRead(TEST_FORMAT_2);
assertNoSamplesToRead(FORMAT_2);
}
@Test
@ -326,8 +337,8 @@ public final class SampleQueueTest {
int skipCount = sampleQueue.advanceTo(LAST_SAMPLE_TIMESTAMP + 1, true, true);
// Should succeed and skip to 2nd keyframe (the 4th frame).
assertThat(skipCount).isEqualTo(4);
assertReadTestData(null, TEST_DATA_SECOND_KEYFRAME_INDEX);
assertNoSamplesToRead(TEST_FORMAT_2);
assertReadTestData(null, DATA_SECOND_KEYFRAME_INDEX);
assertNoSamplesToRead(FORMAT_2);
}
@Test
@ -339,10 +350,10 @@ public final class SampleQueueTest {
assertThat(sampleQueue.getReadIndex()).isEqualTo(8);
assertAllocationCount(0);
// We should still be able to read the upstream format.
assertReadFormat(false, TEST_FORMAT_2);
assertReadFormat(false, FORMAT_2);
// We should be able to write and read subsequent samples.
writeTestData();
assertReadTestData(TEST_FORMAT_2);
assertReadTestData(FORMAT_2);
}
@Test
@ -356,12 +367,12 @@ public final class SampleQueueTest {
// Read the first sample.
assertReadTestData(null, 0, 1);
// Shouldn't discard anything.
sampleQueue.discardTo(TEST_SAMPLE_TIMESTAMPS[1] - 1, false, true);
sampleQueue.discardTo(SAMPLE_TIMESTAMPS[1] - 1, false, true);
assertThat(sampleQueue.getFirstIndex()).isEqualTo(0);
assertThat(sampleQueue.getReadIndex()).isEqualTo(1);
assertAllocationCount(10);
// Should discard the read sample.
sampleQueue.discardTo(TEST_SAMPLE_TIMESTAMPS[1], false, true);
sampleQueue.discardTo(SAMPLE_TIMESTAMPS[1], false, true);
assertThat(sampleQueue.getFirstIndex()).isEqualTo(1);
assertThat(sampleQueue.getReadIndex()).isEqualTo(1);
assertAllocationCount(9);
@ -371,7 +382,7 @@ public final class SampleQueueTest {
assertThat(sampleQueue.getReadIndex()).isEqualTo(1);
assertAllocationCount(9);
// Should be able to read the remaining samples.
assertReadTestData(TEST_FORMAT_1, 1, 7);
assertReadTestData(FORMAT_1, 1, 7);
assertThat(sampleQueue.getFirstIndex()).isEqualTo(1);
assertThat(sampleQueue.getReadIndex()).isEqualTo(8);
// Should discard up to the second last sample
@ -390,17 +401,17 @@ public final class SampleQueueTest {
public void testDiscardToDontStopAtReadPosition() {
writeTestData();
// Shouldn't discard anything.
sampleQueue.discardTo(TEST_SAMPLE_TIMESTAMPS[1] - 1, false, false);
sampleQueue.discardTo(SAMPLE_TIMESTAMPS[1] - 1, false, false);
assertThat(sampleQueue.getFirstIndex()).isEqualTo(0);
assertThat(sampleQueue.getReadIndex()).isEqualTo(0);
assertAllocationCount(10);
// Should discard the first sample.
sampleQueue.discardTo(TEST_SAMPLE_TIMESTAMPS[1], false, false);
sampleQueue.discardTo(SAMPLE_TIMESTAMPS[1], false, false);
assertThat(sampleQueue.getFirstIndex()).isEqualTo(1);
assertThat(sampleQueue.getReadIndex()).isEqualTo(1);
assertAllocationCount(9);
// Should be able to read the remaining samples.
assertReadTestData(TEST_FORMAT_1, 1, 7);
assertReadTestData(FORMAT_1, 1, 7);
}
@Test
@ -424,8 +435,8 @@ public final class SampleQueueTest {
assertAllocationCount(1);
sampleQueue.discardUpstreamSamples(0);
assertAllocationCount(0);
assertReadFormat(false, TEST_FORMAT_2);
assertNoSamplesToRead(TEST_FORMAT_2);
assertReadFormat(false, FORMAT_2);
assertNoSamplesToRead(FORMAT_2);
}
@Test
@ -435,8 +446,8 @@ public final class SampleQueueTest {
assertAllocationCount(4);
sampleQueue.discardUpstreamSamples(0);
assertAllocationCount(0);
assertReadFormat(false, TEST_FORMAT_2);
assertNoSamplesToRead(TEST_FORMAT_2);
assertReadFormat(false, FORMAT_2);
assertNoSamplesToRead(FORMAT_2);
}
@Test
@ -445,8 +456,8 @@ public final class SampleQueueTest {
sampleQueue.discardUpstreamSamples(4);
assertAllocationCount(4);
assertReadTestData(null, 0, 4);
assertReadFormat(false, TEST_FORMAT_2);
assertNoSamplesToRead(TEST_FORMAT_2);
assertReadFormat(false, FORMAT_2);
assertNoSamplesToRead(FORMAT_2);
}
@Test
@ -467,18 +478,18 @@ public final class SampleQueueTest {
assertAllocationCount(1);
sampleQueue.discardUpstreamSamples(3);
assertAllocationCount(0);
assertReadFormat(false, TEST_FORMAT_2);
assertNoSamplesToRead(TEST_FORMAT_2);
assertReadFormat(false, FORMAT_2);
assertNoSamplesToRead(FORMAT_2);
}
@Test
public void testLargestQueuedTimestampWithDiscardUpstream() {
writeTestData();
assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(LAST_SAMPLE_TIMESTAMP);
sampleQueue.discardUpstreamSamples(TEST_SAMPLE_TIMESTAMPS.length - 1);
sampleQueue.discardUpstreamSamples(SAMPLE_TIMESTAMPS.length - 1);
// Discarding from upstream should reduce the largest timestamp.
assertThat(sampleQueue.getLargestQueuedTimestampUs())
.isEqualTo(TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 2]);
.isEqualTo(SAMPLE_TIMESTAMPS[SAMPLE_TIMESTAMPS.length - 2]);
sampleQueue.discardUpstreamSamples(0);
// Discarding everything from upstream without reading should unset the largest timestamp.
assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(MIN_VALUE);
@ -487,14 +498,14 @@ public final class SampleQueueTest {
@Test
public void testLargestQueuedTimestampWithDiscardUpstreamDecodeOrder() {
long[] decodeOrderTimestamps = new long[] {0, 3000, 2000, 1000, 4000, 7000, 6000, 5000};
writeTestData(TEST_DATA, TEST_SAMPLE_SIZES, TEST_SAMPLE_OFFSETS, decodeOrderTimestamps,
TEST_SAMPLE_FORMATS, TEST_SAMPLE_FLAGS);
writeTestData(
DATA, SAMPLE_SIZES, SAMPLE_OFFSETS, decodeOrderTimestamps, SAMPLE_FORMATS, SAMPLE_FLAGS);
assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(7000);
sampleQueue.discardUpstreamSamples(TEST_SAMPLE_TIMESTAMPS.length - 2);
sampleQueue.discardUpstreamSamples(SAMPLE_TIMESTAMPS.length - 2);
// Discarding the last two samples should not change the largest timestamp, due to the decode
// ordering of the timestamps.
assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(7000);
sampleQueue.discardUpstreamSamples(TEST_SAMPLE_TIMESTAMPS.length - 3);
sampleQueue.discardUpstreamSamples(SAMPLE_TIMESTAMPS.length - 3);
// Once a third sample is discarded, the largest timestamp should have changed.
assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(4000);
sampleQueue.discardUpstreamSamples(0);
@ -511,21 +522,77 @@ public final class SampleQueueTest {
assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(LAST_SAMPLE_TIMESTAMP);
}
@Test
public void testSetSampleOffset() {
long sampleOffsetUs = 1000;
sampleQueue.setSampleOffsetUs(sampleOffsetUs);
writeTestData();
assertReadTestData(null, 0, 8, sampleOffsetUs);
assertReadEndOfStream(false);
}
@Test
public void testSplice() {
writeTestData();
sampleQueue.splice();
// Splice should succeed, replacing the last 4 samples with the sample being written.
long spliceSampleTimeUs = SAMPLE_TIMESTAMPS[4];
writeSample(DATA, spliceSampleTimeUs, FORMAT_SPLICED, C.BUFFER_FLAG_KEY_FRAME);
assertReadTestData(null, 0, 4);
assertReadFormat(false, FORMAT_SPLICED);
assertReadSample(spliceSampleTimeUs, true, DATA, 0, DATA.length);
assertReadEndOfStream(false);
}
@Test
public void testSpliceAfterRead() {
writeTestData();
assertReadTestData(null, 0, 4);
sampleQueue.splice();
// Splice should fail, leaving the last 4 samples unchanged.
long spliceSampleTimeUs = SAMPLE_TIMESTAMPS[3];
writeSample(DATA, spliceSampleTimeUs, FORMAT_SPLICED, C.BUFFER_FLAG_KEY_FRAME);
assertReadTestData(SAMPLE_FORMATS[3], 4, 4);
assertReadEndOfStream(false);
sampleQueue.rewind();
assertReadTestData(null, 0, 4);
sampleQueue.splice();
// Splice should succeed, replacing the last 4 samples with the sample being written
spliceSampleTimeUs = SAMPLE_TIMESTAMPS[3] + 1;
writeSample(DATA, spliceSampleTimeUs, FORMAT_SPLICED, C.BUFFER_FLAG_KEY_FRAME);
assertReadFormat(false, FORMAT_SPLICED);
assertReadSample(spliceSampleTimeUs, true, DATA, 0, DATA.length);
assertReadEndOfStream(false);
}
@Test
public void testSpliceWithSampleOffset() {
long sampleOffsetUs = 30000;
sampleQueue.setSampleOffsetUs(sampleOffsetUs);
writeTestData();
sampleQueue.splice();
// Splice should succeed, replacing the last 4 samples with the sample being written.
long spliceSampleTimeUs = SAMPLE_TIMESTAMPS[4];
writeSample(DATA, spliceSampleTimeUs, FORMAT_SPLICED, C.BUFFER_FLAG_KEY_FRAME);
assertReadTestData(null, 0, 4, sampleOffsetUs);
assertReadFormat(false, FORMAT_SPLICED.copyWithSubsampleOffsetUs(sampleOffsetUs));
assertReadSample(spliceSampleTimeUs + sampleOffsetUs, true, DATA, 0, DATA.length);
assertReadEndOfStream(false);
}
// Internal methods.
/**
* Writes standard test data to {@code sampleQueue}.
*/
@SuppressWarnings("ReferenceEquality")
private void writeTestData() {
writeTestData(TEST_DATA, TEST_SAMPLE_SIZES, TEST_SAMPLE_OFFSETS, TEST_SAMPLE_TIMESTAMPS,
TEST_SAMPLE_FORMATS, TEST_SAMPLE_FLAGS);
writeTestData(
DATA, SAMPLE_SIZES, SAMPLE_OFFSETS, SAMPLE_TIMESTAMPS, SAMPLE_FORMATS, SAMPLE_FLAGS);
}
/**
* Writes the specified test data to {@code sampleQueue}.
*
*
*/
@SuppressWarnings("ReferenceEquality")
private void writeTestData(byte[] data, int[] sampleSizes, int[] sampleOffsets,
@ -542,6 +609,13 @@ public final class SampleQueueTest {
}
}
/** Writes a single sample to {@code sampleQueue}. */
private void writeSample(byte[] data, long timestampUs, Format format, int sampleFlags) {
sampleQueue.format(format);
sampleQueue.sampleData(new ParsableByteArray(data), data.length);
sampleQueue.sampleMetadata(timestampUs, sampleFlags, data.length, 0, null);
}
/**
* Asserts correct reading of standard test data from {@code sampleQueue}.
*/
@ -565,8 +639,7 @@ public final class SampleQueueTest {
* @param firstSampleIndex The index of the first sample that's expected to be read.
*/
private void assertReadTestData(Format startFormat, int firstSampleIndex) {
assertReadTestData(startFormat, firstSampleIndex,
TEST_SAMPLE_TIMESTAMPS.length - firstSampleIndex);
assertReadTestData(startFormat, firstSampleIndex, SAMPLE_TIMESTAMPS.length - firstSampleIndex);
}
/**
@ -577,23 +650,38 @@ public final class SampleQueueTest {
* @param sampleCount The number of samples to read.
*/
private void assertReadTestData(Format startFormat, int firstSampleIndex, int sampleCount) {
Format format = startFormat;
assertReadTestData(startFormat, firstSampleIndex, sampleCount, 0);
}
/**
* Asserts correct reading of standard test data from {@code sampleQueue}.
*
* @param startFormat The format of the last sample previously read from {@code sampleQueue}.
* @param firstSampleIndex The index of the first sample that's expected to be read.
* @param sampleCount The number of samples to read.
* @param sampleOffsetUs The expected sample offset.
*/
private void assertReadTestData(
Format startFormat, int firstSampleIndex, int sampleCount, long sampleOffsetUs) {
Format format = adjustFormat(startFormat, sampleOffsetUs);
for (int i = firstSampleIndex; i < firstSampleIndex + sampleCount; i++) {
// Use equals() on the read side despite using referential equality on the write side, since
// sampleQueue de-duplicates written formats using equals().
if (!TEST_SAMPLE_FORMATS[i].equals(format)) {
Format testSampleFormat = adjustFormat(SAMPLE_FORMATS[i], sampleOffsetUs);
if (!testSampleFormat.equals(format)) {
// If the format has changed, we should read it.
assertReadFormat(false, TEST_SAMPLE_FORMATS[i]);
format = TEST_SAMPLE_FORMATS[i];
assertReadFormat(false, testSampleFormat);
format = testSampleFormat;
}
// If we require the format, we should always read it.
assertReadFormat(true, TEST_SAMPLE_FORMATS[i]);
assertReadFormat(true, testSampleFormat);
// Assert the sample is as expected.
assertSampleRead(TEST_SAMPLE_TIMESTAMPS[i],
(TEST_SAMPLE_FLAGS[i] & C.BUFFER_FLAG_KEY_FRAME) != 0,
TEST_DATA,
TEST_DATA.length - TEST_SAMPLE_OFFSETS[i] - TEST_SAMPLE_SIZES[i],
TEST_SAMPLE_SIZES[i]);
assertReadSample(
SAMPLE_TIMESTAMPS[i] + sampleOffsetUs,
(SAMPLE_FLAGS[i] & C.BUFFER_FLAG_KEY_FRAME) != 0,
DATA,
DATA.length - SAMPLE_OFFSETS[i] - SAMPLE_SIZES[i],
SAMPLE_SIZES[i]);
}
}
@ -688,8 +776,8 @@ public final class SampleQueueTest {
* @param offset The offset in {@code sampleData} of the expected sample data.
* @param length The length of the expected sample data.
*/
private void assertSampleRead(long timeUs, boolean isKeyframe, byte[] sampleData, int offset,
int length) {
private void assertReadSample(
long timeUs, boolean isKeyframe, byte[] sampleData, int offset, int length) {
clearFormatHolderAndInputBuffer();
int result = sampleQueue.read(formatHolder, inputBuffer, false, false, 0);
assertThat(result).isEqualTo(RESULT_BUFFER_READ);
@ -738,4 +826,9 @@ public final class SampleQueueTest {
inputBuffer.clear();
}
private static Format adjustFormat(@Nullable Format format, long sampleOffsetUs) {
return format == null || sampleOffsetUs == 0
? format
: format.copyWithSubsampleOffsetUs(sampleOffsetUs);
}
}