Commit 6c3c71b5 by olly Committed by Oliver Woodman

Fix SampleQueue splicing when sampleOffsetUs != 0

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