mirror of
https://github.com/samsonjs/media.git
synced 2026-03-28 09:55:48 +00:00
Fix SampleQueue splicing when sampleOffsetUs != 0
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=212432661
This commit is contained in:
parent
ba8c22aba5
commit
6c3c71b554
2 changed files with 200 additions and 107 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue