diff options
Diffstat (limited to 'tree/library/core/src/test/java/com/google/android/exoplayer2/source/SampleQueueTest.java')
-rw-r--r-- | tree/library/core/src/test/java/com/google/android/exoplayer2/source/SampleQueueTest.java | 1385 |
1 files changed, 0 insertions, 1385 deletions
diff --git a/tree/library/core/src/test/java/com/google/android/exoplayer2/source/SampleQueueTest.java b/tree/library/core/src/test/java/com/google/android/exoplayer2/source/SampleQueueTest.java deleted file mode 100644 index 41b953a0..00000000 --- a/tree/library/core/src/test/java/com/google/android/exoplayer2/source/SampleQueueTest.java +++ /dev/null @@ -1,1385 +0,0 @@ -/* - * Copyright (C) 2017 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.source; - -import static com.google.android.exoplayer2.C.BUFFER_FLAG_ENCRYPTED; -import static com.google.android.exoplayer2.C.BUFFER_FLAG_KEY_FRAME; -import static com.google.android.exoplayer2.C.RESULT_BUFFER_READ; -import static com.google.android.exoplayer2.C.RESULT_FORMAT_READ; -import static com.google.android.exoplayer2.C.RESULT_NOTHING_READ; -import static com.google.common.truth.Truth.assertThat; -import static java.lang.Long.MIN_VALUE; -import static java.util.Arrays.copyOfRange; -import static org.junit.Assert.assertArrayEquals; -import static org.mockito.Mockito.when; - -import android.os.Looper; -import androidx.annotation.Nullable; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.Format; -import com.google.android.exoplayer2.FormatHolder; -import com.google.android.exoplayer2.decoder.DecoderInputBuffer; -import com.google.android.exoplayer2.drm.DrmInitData; -import com.google.android.exoplayer2.drm.DrmSession; -import com.google.android.exoplayer2.drm.DrmSessionManager; -import com.google.android.exoplayer2.extractor.TrackOutput; -import com.google.android.exoplayer2.testutil.TestUtil; -import com.google.android.exoplayer2.upstream.Allocator; -import com.google.android.exoplayer2.upstream.DefaultAllocator; -import com.google.android.exoplayer2.util.Assertions; -import com.google.android.exoplayer2.util.MediaSourceEventDispatcher; -import com.google.android.exoplayer2.util.ParsableByteArray; -import java.io.IOException; -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicReference; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; -import org.mockito.Mockito; - -/** Test for {@link SampleQueue}. */ -@RunWith(AndroidJUnit4.class) -public final class SampleQueueTest { - - private static final int ALLOCATION_SIZE = 16; - - private static final Format FORMAT_1 = buildFormat(/* id= */ "1"); - private static final Format FORMAT_2 = buildFormat(/* id= */ "2"); - private static final Format FORMAT_1_COPY = buildFormat(/* id= */ "1"); - private static final Format FORMAT_SPLICED = buildFormat(/* id= */ "spliced"); - private static final Format FORMAT_ENCRYPTED = - new Format.Builder().setId(/* id= */ "encrypted").setDrmInitData(new DrmInitData()).build(); - private static final byte[] DATA = TestUtil.buildTestData(ALLOCATION_SIZE * 10); - - /* - * 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[] 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 static final int[] ENCRYPTED_SAMPLES_FLAGS = - new int[] { - C.BUFFER_FLAG_KEY_FRAME, C.BUFFER_FLAG_ENCRYPTED, 0, C.BUFFER_FLAG_ENCRYPTED, - }; - private static final long[] ENCRYPTED_SAMPLE_TIMESTAMPS = new long[] {0, 1000, 2000, 3000}; - private static final Format[] ENCRYPTED_SAMPLE_FORMATS = - new Format[] {FORMAT_ENCRYPTED, FORMAT_ENCRYPTED, FORMAT_1, FORMAT_ENCRYPTED}; - /** Encrypted samples require the encryption preamble. */ - private static final int[] ENCRYPTED_SAMPLE_SIZES = new int[] {1, 3, 1, 3}; - - private static final int[] ENCRYPTED_SAMPLE_OFFSETS = new int[] {7, 4, 3, 0}; - private static final byte[] ENCRYPTED_SAMPLE_DATA = new byte[] {1, 1, 1, 1, 1, 1, 1, 1}; - - private static final TrackOutput.CryptoData DUMMY_CRYPTO_DATA = - new TrackOutput.CryptoData(C.CRYPTO_MODE_AES_CTR, new byte[16], 0, 0); - - private Allocator allocator; - private DrmSessionManager mockDrmSessionManager; - private DrmSession mockDrmSession; - private MediaSourceEventDispatcher eventDispatcher; - private SampleQueue sampleQueue; - private FormatHolder formatHolder; - private DecoderInputBuffer inputBuffer; - - @Before - public void setUp() { - allocator = new DefaultAllocator(false, ALLOCATION_SIZE); - mockDrmSessionManager = Mockito.mock(DrmSessionManager.class); - mockDrmSession = Mockito.mock(DrmSession.class); - when(mockDrmSessionManager.acquireSession( - ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.any())) - .thenReturn(mockDrmSession); - eventDispatcher = new MediaSourceEventDispatcher(); - sampleQueue = - new SampleQueue( - allocator, - /* playbackLooper= */ Assertions.checkNotNull(Looper.myLooper()), - mockDrmSessionManager, - eventDispatcher); - formatHolder = new FormatHolder(); - inputBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL); - } - - @After - public void tearDown() { - allocator = null; - sampleQueue = null; - formatHolder = null; - inputBuffer = null; - } - - @Test - public void capacityIncreases() { - int numberOfSamplesToInput = 3 * SampleQueue.SAMPLE_CAPACITY_INCREMENT + 1; - sampleQueue.format(FORMAT_1); - sampleQueue.sampleData( - new ParsableByteArray(numberOfSamplesToInput), /* length= */ numberOfSamplesToInput); - for (int i = 0; i < numberOfSamplesToInput; i++) { - sampleQueue.sampleMetadata( - /* timeUs= */ i * 1000, - /* flags= */ C.BUFFER_FLAG_KEY_FRAME, - /* size= */ 1, - /* offset= */ numberOfSamplesToInput - i - 1, - /* cryptoData= */ null); - } - - assertReadFormat(/* formatRequired= */ false, FORMAT_1); - for (int i = 0; i < numberOfSamplesToInput; i++) { - assertReadSample( - /* timeUs= */ i * 1000, - /* isKeyFrame= */ true, - /* isEncrypted= */ false, - /* sampleData= */ new byte[1], - /* offset= */ 0, - /* length= */ 1); - } - assertReadNothing(/* formatRequired= */ false); - } - - @Test - public void resetReleasesAllocations() { - writeTestData(); - assertAllocationCount(10); - sampleQueue.reset(); - assertAllocationCount(0); - } - - @Test - public void readWithoutWrite() { - assertNoSamplesToRead(null); - } - - @Test - public void equalFormatsDeduplicated() { - sampleQueue.format(FORMAT_1); - assertReadFormat(false, FORMAT_1); - // If the same format is written then it should not cause a format change on the read side. - sampleQueue.format(FORMAT_1); - assertNoSamplesToRead(FORMAT_1); - // The same applies for a format that's equal (but a different object). - sampleQueue.format(FORMAT_1_COPY); - assertNoSamplesToRead(FORMAT_1); - } - - @Test - public void multipleFormatsDeduplicated() { - sampleQueue.format(FORMAT_1); - sampleQueue.sampleData(new ParsableByteArray(DATA), ALLOCATION_SIZE); - sampleQueue.sampleMetadata(0, C.BUFFER_FLAG_KEY_FRAME, ALLOCATION_SIZE, 0, null); - // Writing multiple formats should not cause a format change on the read side, provided the last - // format to be written is equal to the format of the previous sample. - sampleQueue.format(FORMAT_2); - sampleQueue.format(FORMAT_1_COPY); - sampleQueue.sampleData(new ParsableByteArray(DATA), ALLOCATION_SIZE); - sampleQueue.sampleMetadata(1000, C.BUFFER_FLAG_KEY_FRAME, ALLOCATION_SIZE, 0, null); - - assertReadFormat(false, FORMAT_1); - assertReadSample(0, true, /* isEncrypted= */ false, DATA, 0, ALLOCATION_SIZE); - // Assert the second sample is read without a format change. - assertReadSample(1000, true, /* isEncrypted= */ false, DATA, 0, ALLOCATION_SIZE); - - // The same applies if the queue is empty when the formats are written. - sampleQueue.format(FORMAT_2); - sampleQueue.format(FORMAT_1); - sampleQueue.sampleData(new ParsableByteArray(DATA), ALLOCATION_SIZE); - sampleQueue.sampleMetadata(2000, C.BUFFER_FLAG_KEY_FRAME, ALLOCATION_SIZE, 0, null); - - // Assert the third sample is read without a format change. - assertReadSample(2000, true, /* isEncrypted= */ false, DATA, 0, ALLOCATION_SIZE); - } - - @Test - public void readSingleSamples() { - sampleQueue.sampleData(new ParsableByteArray(DATA), ALLOCATION_SIZE); - - assertAllocationCount(1); - // Nothing to read. - assertNoSamplesToRead(null); - - sampleQueue.format(FORMAT_1); - - // Read the format. - assertReadFormat(false, FORMAT_1); - // Nothing to read. - 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, FORMAT_1); - // Otherwise should read the sample. - assertReadSample(1000, true, /* isEncrypted= */ false, DATA, 0, ALLOCATION_SIZE); - // Allocation should still be held. - assertAllocationCount(1); - sampleQueue.discardToRead(); - // The allocation should have been released. - assertAllocationCount(0); - - // Nothing to read. - assertNoSamplesToRead(FORMAT_1); - - // Write a second sample followed by one byte that does not belong to it. - 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, FORMAT_1); - // Read the sample. - assertReadSample(2000, false, /* isEncrypted= */ false, DATA, 0, ALLOCATION_SIZE - 1); - // Allocation should still be held. - assertAllocationCount(1); - sampleQueue.discardToRead(); - // The last byte written to the sample queue may belong to a sample whose metadata has yet to be - // written, so an allocation should still be held. - assertAllocationCount(1); - - // Write metadata for a third sample containing the remaining byte. - sampleQueue.sampleMetadata(3000, 0, 1, 0, null); - - // If formatRequired, should read the format rather than the sample. - assertReadFormat(true, FORMAT_1); - // Read the sample. - assertReadSample(3000, false, /* isEncrypted= */ false, DATA, ALLOCATION_SIZE - 1, 1); - // Allocation should still be held. - assertAllocationCount(1); - sampleQueue.discardToRead(); - // The allocation should have been released. - assertAllocationCount(0); - } - - @Test - public void readMultiSamples() { - writeTestData(); - assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(LAST_SAMPLE_TIMESTAMP); - assertAllocationCount(10); - assertReadTestData(); - assertAllocationCount(10); - sampleQueue.discardToRead(); - assertAllocationCount(0); - } - - @Test - public void readMultiSamplesTwice() { - writeTestData(); - writeTestData(); - assertAllocationCount(20); - assertReadTestData(FORMAT_2); - assertReadTestData(FORMAT_2); - assertAllocationCount(20); - sampleQueue.discardToRead(); - assertAllocationCount(0); - } - - @Test - public void readMultiWithSeek() { - writeTestData(); - assertReadTestData(); - assertThat(sampleQueue.getFirstIndex()).isEqualTo(0); - assertThat(sampleQueue.getReadIndex()).isEqualTo(8); - assertAllocationCount(10); - - sampleQueue.seekTo(0); - assertAllocationCount(10); - // Read again. - assertThat(sampleQueue.getFirstIndex()).isEqualTo(0); - assertThat(sampleQueue.getReadIndex()).isEqualTo(0); - assertReadTestData(); - } - - @Test - public void emptyQueueReturnsLoadingFinished() { - sampleQueue.sampleData(new ParsableByteArray(DATA), DATA.length); - assertThat(sampleQueue.isReady(/* loadingFinished= */ false)).isFalse(); - assertThat(sampleQueue.isReady(/* loadingFinished= */ true)).isTrue(); - } - - @Test - public void isReadyWithUpstreamFormatOnlyReturnsTrue() { - sampleQueue.format(FORMAT_ENCRYPTED); - assertThat(sampleQueue.isReady(/* loadingFinished= */ false)).isTrue(); - } - - @Test - public void isReadyReturnsTrueForValidDrmSession() { - writeTestDataWithEncryptedSections(); - assertReadFormat(/* formatRequired= */ false, FORMAT_ENCRYPTED); - assertThat(sampleQueue.isReady(/* loadingFinished= */ false)).isFalse(); - when(mockDrmSession.getState()).thenReturn(DrmSession.STATE_OPENED_WITH_KEYS); - assertThat(sampleQueue.isReady(/* loadingFinished= */ false)).isTrue(); - } - - @Test - public void isReadyReturnsTrueForClearSampleAndPlayClearSamplesWithoutKeysIsTrue() { - when(mockDrmSession.playClearSamplesWithoutKeys()).thenReturn(true); - // We recreate the queue to ensure the mock DRM session manager flags are taken into account. - sampleQueue = - new SampleQueue( - allocator, - /* playbackLooper= */ Assertions.checkNotNull(Looper.myLooper()), - mockDrmSessionManager, - eventDispatcher); - writeTestDataWithEncryptedSections(); - assertThat(sampleQueue.isReady(/* loadingFinished= */ false)).isTrue(); - } - - @Test - public void readEncryptedSectionsWaitsForKeys() { - when(mockDrmSession.getState()).thenReturn(DrmSession.STATE_OPENED); - writeTestDataWithEncryptedSections(); - - assertReadFormat(/* formatRequired= */ false, FORMAT_ENCRYPTED); - assertReadNothing(/* formatRequired= */ false); - assertThat(inputBuffer.waitingForKeys).isTrue(); - when(mockDrmSession.getState()).thenReturn(DrmSession.STATE_OPENED_WITH_KEYS); - assertReadEncryptedSample(/* sampleIndex= */ 0); - assertThat(inputBuffer.waitingForKeys).isFalse(); - } - - @Test - public void readEncryptedSectionsPopulatesDrmSession() { - when(mockDrmSession.getState()).thenReturn(DrmSession.STATE_OPENED_WITH_KEYS); - writeTestDataWithEncryptedSections(); - - int result = - sampleQueue.read( - formatHolder, - inputBuffer, - /* formatRequired= */ false, - /* loadingFinished= */ false, - /* decodeOnlyUntilUs= */ 0); - assertThat(result).isEqualTo(RESULT_FORMAT_READ); - assertThat(formatHolder.drmSession).isSameInstanceAs(mockDrmSession); - assertReadEncryptedSample(/* sampleIndex= */ 0); - assertReadEncryptedSample(/* sampleIndex= */ 1); - formatHolder.clear(); - assertThat(formatHolder.drmSession).isNull(); - result = - sampleQueue.read( - formatHolder, - inputBuffer, - /* formatRequired= */ false, - /* loadingFinished= */ false, - /* decodeOnlyUntilUs= */ 0); - assertThat(result).isEqualTo(RESULT_FORMAT_READ); - assertThat(formatHolder.drmSession).isNull(); - assertReadEncryptedSample(/* sampleIndex= */ 2); - result = - sampleQueue.read( - formatHolder, - inputBuffer, - /* formatRequired= */ false, - /* loadingFinished= */ false, - /* decodeOnlyUntilUs= */ 0); - assertThat(result).isEqualTo(RESULT_FORMAT_READ); - assertThat(formatHolder.drmSession).isSameInstanceAs(mockDrmSession); - } - - @Test - public void allowPlaceholderSessionPopulatesDrmSession() { - when(mockDrmSession.getState()).thenReturn(DrmSession.STATE_OPENED_WITH_KEYS); - DrmSession mockPlaceholderDrmSession = Mockito.mock(DrmSession.class); - when(mockPlaceholderDrmSession.getState()).thenReturn(DrmSession.STATE_OPENED_WITH_KEYS); - when(mockDrmSessionManager.acquirePlaceholderSession( - ArgumentMatchers.any(), ArgumentMatchers.anyInt())) - .thenReturn(mockPlaceholderDrmSession); - writeTestDataWithEncryptedSections(); - - int result = - sampleQueue.read( - formatHolder, - inputBuffer, - /* formatRequired= */ false, - /* loadingFinished= */ false, - /* decodeOnlyUntilUs= */ 0); - assertThat(result).isEqualTo(RESULT_FORMAT_READ); - assertThat(formatHolder.drmSession).isSameInstanceAs(mockDrmSession); - assertReadEncryptedSample(/* sampleIndex= */ 0); - assertReadEncryptedSample(/* sampleIndex= */ 1); - formatHolder.clear(); - assertThat(formatHolder.drmSession).isNull(); - result = - sampleQueue.read( - formatHolder, - inputBuffer, - /* formatRequired= */ false, - /* loadingFinished= */ false, - /* decodeOnlyUntilUs= */ 0); - assertThat(result).isEqualTo(RESULT_FORMAT_READ); - assertThat(formatHolder.drmSession).isSameInstanceAs(mockPlaceholderDrmSession); - assertReadEncryptedSample(/* sampleIndex= */ 2); - result = - sampleQueue.read( - formatHolder, - inputBuffer, - /* formatRequired= */ false, - /* loadingFinished= */ false, - /* decodeOnlyUntilUs= */ 0); - assertThat(result).isEqualTo(RESULT_FORMAT_READ); - assertThat(formatHolder.drmSession).isSameInstanceAs(mockDrmSession); - assertReadEncryptedSample(/* sampleIndex= */ 3); - } - - @Test - public void trailingCryptoInfoInitializationVectorBytesZeroed() { - when(mockDrmSession.getState()).thenReturn(DrmSession.STATE_OPENED_WITH_KEYS); - DrmSession mockPlaceholderDrmSession = Mockito.mock(DrmSession.class); - when(mockPlaceholderDrmSession.getState()).thenReturn(DrmSession.STATE_OPENED_WITH_KEYS); - when(mockDrmSessionManager.acquirePlaceholderSession( - ArgumentMatchers.any(), ArgumentMatchers.anyInt())) - .thenReturn(mockPlaceholderDrmSession); - - writeFormat(ENCRYPTED_SAMPLE_FORMATS[0]); - byte[] sampleData = new byte[] {0, 1, 2}; - byte[] initializationVector = new byte[] {7, 6, 5, 4, 3, 2, 1, 0}; - byte[] encryptedSampleData = - TestUtil.joinByteArrays( - new byte[] { - 0x08, // subsampleEncryption = false (1 bit), ivSize = 8 (7 bits). - }, - initializationVector, - sampleData); - writeSample( - encryptedSampleData, /* timestampUs= */ 0, BUFFER_FLAG_KEY_FRAME | BUFFER_FLAG_ENCRYPTED); - - int result = - sampleQueue.read( - formatHolder, - inputBuffer, - /* formatRequired= */ false, - /* loadingFinished= */ false, - /* decodeOnlyUntilUs= */ 0); - assertThat(result).isEqualTo(RESULT_FORMAT_READ); - - // Fill cryptoInfo.iv with non-zero data. When the 8 byte initialization vector is written into - // it, we expect the trailing 8 bytes to be zeroed. - inputBuffer.cryptoInfo.iv = new byte[16]; - Arrays.fill(inputBuffer.cryptoInfo.iv, (byte) 1); - - result = - sampleQueue.read( - formatHolder, - inputBuffer, - /* formatRequired= */ false, - /* loadingFinished= */ false, - /* decodeOnlyUntilUs= */ 0); - assertThat(result).isEqualTo(RESULT_BUFFER_READ); - - // Assert cryptoInfo.iv contains the 8-byte initialization vector and that the trailing 8 bytes - // have been zeroed. - byte[] expectedInitializationVector = Arrays.copyOf(initializationVector, 16); - assertArrayEquals(expectedInitializationVector, inputBuffer.cryptoInfo.iv); - } - - @Test - public void readWithErrorSessionReadsNothingAndThrows() throws IOException { - when(mockDrmSession.getState()).thenReturn(DrmSession.STATE_OPENED); - writeTestDataWithEncryptedSections(); - - assertReadFormat(/* formatRequired= */ false, FORMAT_ENCRYPTED); - assertReadNothing(/* formatRequired= */ false); - sampleQueue.maybeThrowError(); - when(mockDrmSession.getState()).thenReturn(DrmSession.STATE_ERROR); - when(mockDrmSession.getError()).thenReturn(new DrmSession.DrmSessionException(new Exception())); - assertReadNothing(/* formatRequired= */ false); - try { - sampleQueue.maybeThrowError(); - Assert.fail(); - } catch (IOException e) { - // Expected. - } - when(mockDrmSession.getState()).thenReturn(DrmSession.STATE_OPENED_WITH_KEYS); - assertReadEncryptedSample(/* sampleIndex= */ 0); - } - - @Test - public void allowPlayClearSamplesWithoutKeysReadsClearSamples() { - when(mockDrmSession.playClearSamplesWithoutKeys()).thenReturn(true); - // We recreate the queue to ensure the mock DRM session manager flags are taken into account. - sampleQueue = - new SampleQueue( - allocator, - /* playbackLooper= */ Assertions.checkNotNull(Looper.myLooper()), - mockDrmSessionManager, - eventDispatcher); - when(mockDrmSession.getState()).thenReturn(DrmSession.STATE_OPENED); - writeTestDataWithEncryptedSections(); - - assertReadFormat(/* formatRequired= */ false, FORMAT_ENCRYPTED); - assertReadEncryptedSample(/* sampleIndex= */ 0); - } - - @Test - public void seekAfterDiscard() { - writeTestData(); - assertReadTestData(); - sampleQueue.discardToRead(); - assertThat(sampleQueue.getFirstIndex()).isEqualTo(8); - assertThat(sampleQueue.getReadIndex()).isEqualTo(8); - assertAllocationCount(0); - - sampleQueue.seekTo(0); - assertAllocationCount(0); - // Can't read again. - assertThat(sampleQueue.getFirstIndex()).isEqualTo(8); - assertThat(sampleQueue.getReadIndex()).isEqualTo(8); - assertReadEndOfStream(false); - } - - @Test - public void advanceToEnd() { - writeTestData(); - sampleQueue.advanceToEnd(); - assertAllocationCount(10); - sampleQueue.discardToRead(); - 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, FORMAT_2); - // Once the format has been read, there's nothing else to read. - assertNoSamplesToRead(FORMAT_2); - } - - @Test - public void advanceToEndRetainsUnassignedData() { - sampleQueue.format(FORMAT_1); - sampleQueue.sampleData(new ParsableByteArray(DATA), ALLOCATION_SIZE); - sampleQueue.advanceToEnd(); - assertAllocationCount(1); - sampleQueue.discardToRead(); - // Skipping shouldn't discard data that may belong to a sample whose metadata has yet to be - // written. - assertAllocationCount(1); - // We should be able to read the format. - assertReadFormat(false, FORMAT_1); - // Once the format has been read, there's nothing else to read. - 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. - assertReadSample(0, true, /* isEncrypted= */ false, DATA, 0, ALLOCATION_SIZE); - assertNoSamplesToRead(FORMAT_1); - assertAllocationCount(1); - sampleQueue.discardToRead(); - assertAllocationCount(0); - } - - @Test - public void advanceToBeforeBuffer() { - writeTestData(); - int skipCount = sampleQueue.advanceTo(SAMPLE_TIMESTAMPS[0] - 1); - // Should have no effect (we're already at the first frame). - assertThat(skipCount).isEqualTo(0); - assertReadTestData(); - assertNoSamplesToRead(FORMAT_2); - } - - @Test - public void advanceToStartOfBuffer() { - writeTestData(); - int skipCount = sampleQueue.advanceTo(SAMPLE_TIMESTAMPS[0]); - // Should have no effect (we're already at the first frame). - assertThat(skipCount).isEqualTo(0); - assertReadTestData(); - assertNoSamplesToRead(FORMAT_2); - } - - @Test - public void advanceToEndOfBuffer() { - writeTestData(); - int skipCount = sampleQueue.advanceTo(LAST_SAMPLE_TIMESTAMP); - // Should advance to 2nd keyframe (the 4th frame). - assertThat(skipCount).isEqualTo(4); - assertReadTestData(null, DATA_SECOND_KEYFRAME_INDEX); - assertNoSamplesToRead(FORMAT_2); - } - - @Test - public void advanceToAfterBuffer() { - writeTestData(); - int skipCount = sampleQueue.advanceTo(LAST_SAMPLE_TIMESTAMP + 1); - // Should advance to 2nd keyframe (the 4th frame). - assertThat(skipCount).isEqualTo(4); - assertReadTestData(null, DATA_SECOND_KEYFRAME_INDEX); - assertNoSamplesToRead(FORMAT_2); - } - - @Test - public void seekToBeforeBuffer() { - writeTestData(); - boolean success = sampleQueue.seekTo(SAMPLE_TIMESTAMPS[0] - 1, false); - assertThat(success).isFalse(); - assertThat(sampleQueue.getReadIndex()).isEqualTo(0); - assertReadTestData(); - assertNoSamplesToRead(FORMAT_2); - } - - @Test - public void seekToStartOfBuffer() { - writeTestData(); - boolean success = sampleQueue.seekTo(SAMPLE_TIMESTAMPS[0], false); - assertThat(success).isTrue(); - assertThat(sampleQueue.getReadIndex()).isEqualTo(0); - assertReadTestData(); - assertNoSamplesToRead(FORMAT_2); - } - - @Test - public void seekToEndOfBuffer() { - writeTestData(); - boolean success = sampleQueue.seekTo(LAST_SAMPLE_TIMESTAMP, false); - assertThat(success).isTrue(); - assertThat(sampleQueue.getReadIndex()).isEqualTo(4); - assertReadTestData(null, DATA_SECOND_KEYFRAME_INDEX); - assertNoSamplesToRead(FORMAT_2); - } - - @Test - public void seekToAfterBuffer() { - writeTestData(); - boolean success = sampleQueue.seekTo(LAST_SAMPLE_TIMESTAMP + 1, false); - assertThat(success).isFalse(); - assertThat(sampleQueue.getReadIndex()).isEqualTo(0); - assertReadTestData(); - assertNoSamplesToRead(FORMAT_2); - } - - @Test - public void seekToAfterBufferAllowed() { - writeTestData(); - boolean success = sampleQueue.seekTo(LAST_SAMPLE_TIMESTAMP + 1, true); - assertThat(success).isTrue(); - assertThat(sampleQueue.getReadIndex()).isEqualTo(4); - assertReadTestData(null, DATA_SECOND_KEYFRAME_INDEX); - assertNoSamplesToRead(FORMAT_2); - } - - @Test - public void seekToEndAndBackToStart() { - writeTestData(); - boolean success = sampleQueue.seekTo(LAST_SAMPLE_TIMESTAMP, false); - assertThat(success).isTrue(); - assertThat(sampleQueue.getReadIndex()).isEqualTo(4); - assertReadTestData(null, DATA_SECOND_KEYFRAME_INDEX); - assertNoSamplesToRead(FORMAT_2); - // Seek back to the start. - success = sampleQueue.seekTo(SAMPLE_TIMESTAMPS[0], false); - assertThat(success).isTrue(); - assertThat(sampleQueue.getReadIndex()).isEqualTo(0); - assertReadTestData(); - assertNoSamplesToRead(FORMAT_2); - } - - @Test - public void discardToEnd() { - writeTestData(); - // Should discard everything. - sampleQueue.discardToEnd(); - assertThat(sampleQueue.getFirstIndex()).isEqualTo(8); - assertThat(sampleQueue.getReadIndex()).isEqualTo(8); - assertAllocationCount(0); - // We should still be able to read the upstream format. - assertReadFormat(false, FORMAT_2); - // We should be able to write and read subsequent samples. - writeTestData(); - assertReadTestData(FORMAT_2); - } - - @Test - public void discardToStopAtReadPosition() { - writeTestData(); - // Shouldn't discard anything. - sampleQueue.discardTo(LAST_SAMPLE_TIMESTAMP, false, true); - assertThat(sampleQueue.getFirstIndex()).isEqualTo(0); - assertThat(sampleQueue.getReadIndex()).isEqualTo(0); - assertAllocationCount(10); - // Read the first sample. - assertReadTestData(null, 0, 1); - // Shouldn't discard anything. - 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(SAMPLE_TIMESTAMPS[1], false, true); - assertThat(sampleQueue.getFirstIndex()).isEqualTo(1); - assertThat(sampleQueue.getReadIndex()).isEqualTo(1); - assertAllocationCount(9); - // Shouldn't discard anything. - sampleQueue.discardTo(LAST_SAMPLE_TIMESTAMP, false, true); - assertThat(sampleQueue.getFirstIndex()).isEqualTo(1); - assertThat(sampleQueue.getReadIndex()).isEqualTo(1); - assertAllocationCount(9); - // Should be able to read the remaining samples. - assertReadTestData(FORMAT_1, 1, 7); - assertThat(sampleQueue.getFirstIndex()).isEqualTo(1); - assertThat(sampleQueue.getReadIndex()).isEqualTo(8); - // Should discard up to the second last sample - sampleQueue.discardTo(LAST_SAMPLE_TIMESTAMP - 1, false, true); - assertThat(sampleQueue.getFirstIndex()).isEqualTo(6); - assertThat(sampleQueue.getReadIndex()).isEqualTo(8); - assertAllocationCount(3); - // Should discard up the last sample - sampleQueue.discardTo(LAST_SAMPLE_TIMESTAMP, false, true); - assertThat(sampleQueue.getFirstIndex()).isEqualTo(7); - assertThat(sampleQueue.getReadIndex()).isEqualTo(8); - assertAllocationCount(1); - } - - @Test - public void discardToDontStopAtReadPosition() { - writeTestData(); - // Shouldn't discard anything. - 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(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(FORMAT_1, 1, 7); - } - - @Test - public void discardUpstream() { - writeTestData(); - sampleQueue.discardUpstreamSamples(8); - assertAllocationCount(10); - sampleQueue.discardUpstreamSamples(7); - assertAllocationCount(9); - sampleQueue.discardUpstreamSamples(6); - assertAllocationCount(7); - sampleQueue.discardUpstreamSamples(5); - assertAllocationCount(5); - sampleQueue.discardUpstreamSamples(4); - assertAllocationCount(4); - sampleQueue.discardUpstreamSamples(3); - assertAllocationCount(3); - sampleQueue.discardUpstreamSamples(2); - assertAllocationCount(2); - sampleQueue.discardUpstreamSamples(1); - assertAllocationCount(1); - sampleQueue.discardUpstreamSamples(0); - assertAllocationCount(0); - assertReadFormat(false, FORMAT_2); - assertNoSamplesToRead(FORMAT_2); - } - - @Test - public void discardUpstreamMulti() { - writeTestData(); - sampleQueue.discardUpstreamSamples(4); - assertAllocationCount(4); - sampleQueue.discardUpstreamSamples(0); - assertAllocationCount(0); - assertReadFormat(false, FORMAT_2); - assertNoSamplesToRead(FORMAT_2); - } - - @Test - public void discardUpstreamBeforeRead() { - writeTestData(); - sampleQueue.discardUpstreamSamples(4); - assertAllocationCount(4); - assertReadTestData(null, 0, 4); - assertReadFormat(false, FORMAT_2); - assertNoSamplesToRead(FORMAT_2); - } - - @Test - public void discardUpstreamAfterRead() { - writeTestData(); - assertReadTestData(null, 0, 3); - sampleQueue.discardUpstreamSamples(8); - assertAllocationCount(10); - sampleQueue.discardToRead(); - assertAllocationCount(7); - sampleQueue.discardUpstreamSamples(7); - assertAllocationCount(6); - sampleQueue.discardUpstreamSamples(6); - assertAllocationCount(4); - sampleQueue.discardUpstreamSamples(5); - assertAllocationCount(2); - sampleQueue.discardUpstreamSamples(4); - assertAllocationCount(1); - sampleQueue.discardUpstreamSamples(3); - assertAllocationCount(0); - assertReadFormat(false, FORMAT_2); - assertNoSamplesToRead(FORMAT_2); - } - - @Test - public void largestQueuedTimestampWithDiscardUpstream() { - writeTestData(); - assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(LAST_SAMPLE_TIMESTAMP); - sampleQueue.discardUpstreamSamples(SAMPLE_TIMESTAMPS.length - 1); - // Discarding from upstream should reduce the largest timestamp. - assertThat(sampleQueue.getLargestQueuedTimestampUs()) - .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); - } - - @Test - public void largestQueuedTimestampWithDiscardUpstreamDecodeOrder() { - long[] decodeOrderTimestamps = new long[] {0, 3000, 2000, 1000, 4000, 7000, 6000, 5000}; - writeTestData( - DATA, SAMPLE_SIZES, SAMPLE_OFFSETS, decodeOrderTimestamps, SAMPLE_FORMATS, SAMPLE_FLAGS); - assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(7000); - 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(SAMPLE_TIMESTAMPS.length - 3); - // Once a third sample is discarded, the largest timestamp should have changed. - assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(4000); - sampleQueue.discardUpstreamSamples(0); - // Discarding everything from upstream without reading should unset the largest timestamp. - assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(MIN_VALUE); - } - - @Test - public void largestQueuedTimestampWithRead() { - writeTestData(); - assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(LAST_SAMPLE_TIMESTAMP); - assertReadTestData(); - // Reading everything should not reduce the largest timestamp. - assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(LAST_SAMPLE_TIMESTAMP); - } - - @Test - public void setSampleOffsetBeforeData() { - long sampleOffsetUs = 1000; - sampleQueue.setSampleOffsetUs(sampleOffsetUs); - writeTestData(); - assertReadTestData( - /* startFormat= */ null, /* firstSampleIndex= */ 0, /* sampleCount= */ 8, sampleOffsetUs); - assertReadEndOfStream(/* formatRequired= */ false); - } - - @Test - public void setSampleOffsetBetweenSamples() { - writeTestData(); - long sampleOffsetUs = 1000; - sampleQueue.setSampleOffsetUs(sampleOffsetUs); - - // Write a final sample now the offset is set. - long unadjustedTimestampUs = LAST_SAMPLE_TIMESTAMP + 1234; - writeSample(DATA, unadjustedTimestampUs, /* sampleFlags= */ 0); - - assertReadTestData(); - // We expect to read the format adjusted to account for the sample offset, followed by the final - // sample and then the end of stream. - assertReadFormat( - /* formatRequired= */ false, - FORMAT_2.buildUpon().setSubsampleOffsetUs(sampleOffsetUs).build()); - assertReadSample( - unadjustedTimestampUs + sampleOffsetUs, - /* isKeyFrame= */ false, - /* isEncrypted= */ false, - DATA, - /* offset= */ 0, - DATA.length); - assertReadEndOfStream(/* formatRequired= */ false); - } - - @Test - public void adjustUpstreamFormat() { - String label = "label"; - sampleQueue = - new SampleQueue( - allocator, - /* playbackLooper= */ Assertions.checkNotNull(Looper.myLooper()), - mockDrmSessionManager, - eventDispatcher) { - @Override - public Format getAdjustedUpstreamFormat(Format format) { - return super.getAdjustedUpstreamFormat(copyWithLabel(format, label)); - } - }; - - writeFormat(FORMAT_1); - assertReadFormat(/* formatRequired= */ false, copyWithLabel(FORMAT_1, label)); - assertReadEndOfStream(/* formatRequired= */ false); - } - - @Test - public void invalidateUpstreamFormatAdjustment() { - AtomicReference<String> label = new AtomicReference<>("label1"); - sampleQueue = - new SampleQueue( - allocator, - /* playbackLooper= */ Assertions.checkNotNull(Looper.myLooper()), - mockDrmSessionManager, - eventDispatcher) { - @Override - public Format getAdjustedUpstreamFormat(Format format) { - return super.getAdjustedUpstreamFormat(copyWithLabel(format, label.get())); - } - }; - - writeFormat(FORMAT_1); - writeSample(DATA, /* timestampUs= */ 0, BUFFER_FLAG_KEY_FRAME); - - // Make a change that'll affect the SampleQueue's format adjustment, and invalidate it. - label.set("label2"); - sampleQueue.invalidateUpstreamFormatAdjustment(); - - writeSample(DATA, /* timestampUs= */ 1, /* sampleFlags= */ 0); - - assertReadFormat(/* formatRequired= */ false, copyWithLabel(FORMAT_1, "label1")); - assertReadSample( - /* timeUs= */ 0, - /* isKeyFrame= */ true, - /* isEncrypted= */ false, - DATA, - /* offset= */ 0, - DATA.length); - assertReadFormat(/* formatRequired= */ false, copyWithLabel(FORMAT_1, "label2")); - assertReadSample( - /* timeUs= */ 1, - /* isKeyFrame= */ false, - /* isEncrypted= */ false, - DATA, - /* offset= */ 0, - DATA.length); - assertReadEndOfStream(/* formatRequired= */ false); - } - - @Test - public void splice() { - writeTestData(); - sampleQueue.splice(); - // Splice should succeed, replacing the last 4 samples with the sample being written. - long spliceSampleTimeUs = SAMPLE_TIMESTAMPS[4]; - writeFormat(FORMAT_SPLICED); - writeSample(DATA, spliceSampleTimeUs, C.BUFFER_FLAG_KEY_FRAME); - assertReadTestData(null, 0, 4); - assertReadFormat(false, FORMAT_SPLICED); - assertReadSample(spliceSampleTimeUs, true, /* isEncrypted= */ false, DATA, 0, DATA.length); - assertReadEndOfStream(false); - } - - @Test - public void spliceAfterRead() { - writeTestData(); - assertReadTestData(null, 0, 4); - sampleQueue.splice(); - // Splice should fail, leaving the last 4 samples unchanged. - long spliceSampleTimeUs = SAMPLE_TIMESTAMPS[3]; - writeFormat(FORMAT_SPLICED); - writeSample(DATA, spliceSampleTimeUs, C.BUFFER_FLAG_KEY_FRAME); - assertReadTestData(SAMPLE_FORMATS[3], 4, 4); - assertReadEndOfStream(false); - - sampleQueue.seekTo(0); - assertReadTestData(null, 0, 4); - sampleQueue.splice(); - // Splice should succeed, replacing the last 4 samples with the sample being written - spliceSampleTimeUs = SAMPLE_TIMESTAMPS[3] + 1; - writeFormat(FORMAT_SPLICED); - writeSample(DATA, spliceSampleTimeUs, C.BUFFER_FLAG_KEY_FRAME); - assertReadFormat(false, FORMAT_SPLICED); - assertReadSample(spliceSampleTimeUs, true, /* isEncrypted= */ false, DATA, 0, DATA.length); - assertReadEndOfStream(false); - } - - @Test - public void spliceWithSampleOffset() { - 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]; - writeFormat(FORMAT_SPLICED); - writeSample(DATA, spliceSampleTimeUs, C.BUFFER_FLAG_KEY_FRAME); - assertReadTestData(null, 0, 4, sampleOffsetUs); - assertReadFormat( - false, FORMAT_SPLICED.buildUpon().setSubsampleOffsetUs(sampleOffsetUs).build()); - assertReadSample( - spliceSampleTimeUs + sampleOffsetUs, true, /* isEncrypted= */ false, DATA, 0, DATA.length); - assertReadEndOfStream(false); - } - - // Internal methods. - - /** - * Writes standard test data to {@code sampleQueue}. - */ - private void writeTestData() { - writeTestData( - DATA, SAMPLE_SIZES, SAMPLE_OFFSETS, SAMPLE_TIMESTAMPS, SAMPLE_FORMATS, SAMPLE_FLAGS); - } - - private void writeTestDataWithEncryptedSections() { - writeTestData( - ENCRYPTED_SAMPLE_DATA, - ENCRYPTED_SAMPLE_SIZES, - ENCRYPTED_SAMPLE_OFFSETS, - ENCRYPTED_SAMPLE_TIMESTAMPS, - ENCRYPTED_SAMPLE_FORMATS, - ENCRYPTED_SAMPLES_FLAGS); - } - - /** - * Writes the specified test data to {@code sampleQueue}. - */ - @SuppressWarnings("ReferenceEquality") - private void writeTestData(byte[] data, int[] sampleSizes, int[] sampleOffsets, - long[] sampleTimestamps, Format[] sampleFormats, int[] sampleFlags) { - sampleQueue.sampleData(new ParsableByteArray(data), data.length); - Format format = null; - for (int i = 0; i < sampleTimestamps.length; i++) { - if (sampleFormats[i] != format) { - sampleQueue.format(sampleFormats[i]); - format = sampleFormats[i]; - } - sampleQueue.sampleMetadata( - sampleTimestamps[i], - sampleFlags[i], - sampleSizes[i], - sampleOffsets[i], - (sampleFlags[i] & C.BUFFER_FLAG_ENCRYPTED) != 0 ? DUMMY_CRYPTO_DATA : null); - } - } - - /** Writes a {@link Format} to the {@code sampleQueue}. */ - private void writeFormat(Format format) { - sampleQueue.format(format); - } - - /** Writes a single sample to {@code sampleQueue}. */ - private void writeSample(byte[] data, long timestampUs, int sampleFlags) { - sampleQueue.sampleData(new ParsableByteArray(data), data.length); - sampleQueue.sampleMetadata( - timestampUs, - sampleFlags, - data.length, - /* offset= */ 0, - (sampleFlags & C.BUFFER_FLAG_ENCRYPTED) != 0 ? DUMMY_CRYPTO_DATA : null); - } - - /** - * Asserts correct reading of standard test data from {@code sampleQueue}. - */ - private void assertReadTestData() { - assertReadTestData(null, 0); - } - - /** - * Asserts correct reading of standard test data from {@code sampleQueue}. - * - * @param startFormat The format of the last sample previously read from {@code sampleQueue}. - */ - private void assertReadTestData(Format startFormat) { - assertReadTestData(startFormat, 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. - */ - private void assertReadTestData(Format startFormat, int firstSampleIndex) { - assertReadTestData(startFormat, firstSampleIndex, SAMPLE_TIMESTAMPS.length - firstSampleIndex); - } - - /** - * 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. - */ - private void assertReadTestData(Format startFormat, int firstSampleIndex, int sampleCount) { - 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(). - Format testSampleFormat = adjustFormat(SAMPLE_FORMATS[i], sampleOffsetUs); - if (!testSampleFormat.equals(format)) { - // If the format has changed, we should read it. - assertReadFormat(false, testSampleFormat); - format = testSampleFormat; - } - // If we require the format, we should always read it. - assertReadFormat(true, testSampleFormat); - // Assert the sample is as expected. - assertReadSample( - SAMPLE_TIMESTAMPS[i] + sampleOffsetUs, - (SAMPLE_FLAGS[i] & C.BUFFER_FLAG_KEY_FRAME) != 0, - /* isEncrypted= */ false, - DATA, - DATA.length - SAMPLE_OFFSETS[i] - SAMPLE_SIZES[i], - SAMPLE_SIZES[i]); - } - } - - /** - * Asserts {@link SampleQueue#read} is behaving correctly, given there are no samples to read and - * the last format to be written to the sample queue is {@code endFormat}. - * - * @param endFormat The last format to be written to the sample queue, or null of no format has - * been written. - */ - private void assertNoSamplesToRead(Format endFormat) { - // If not formatRequired or loadingFinished, should read nothing. - assertReadNothing(false); - // If formatRequired, should read the end format if set, else read nothing. - if (endFormat == null) { - assertReadNothing(true); - } else { - assertReadFormat(true, endFormat); - } - // If loadingFinished, should read end of stream. - assertReadEndOfStream(false); - assertReadEndOfStream(true); - // Having read end of stream should not affect other cases. - assertReadNothing(false); - if (endFormat == null) { - assertReadNothing(true); - } else { - assertReadFormat(true, endFormat); - } - } - - /** - * Asserts {@link SampleQueue#read} returns {@link C#RESULT_NOTHING_READ}. - * - * @param formatRequired The value of {@code formatRequired} passed to {@link SampleQueue#read}. - */ - private void assertReadNothing(boolean formatRequired) { - clearFormatHolderAndInputBuffer(); - int result = - sampleQueue.read( - formatHolder, - inputBuffer, - formatRequired, - /* loadingFinished= */ false, - /* decodeOnlyUntilUs= */ 0); - assertThat(result).isEqualTo(RESULT_NOTHING_READ); - // formatHolder should not be populated. - assertThat(formatHolder.format).isNull(); - // inputBuffer should not be populated. - assertInputBufferContainsNoSampleData(); - assertInputBufferHasNoDefaultFlagsSet(); - } - - /** - * Asserts {@link SampleQueue#read} returns {@link C#RESULT_BUFFER_READ} and that the {@link - * DecoderInputBuffer#isEndOfStream()} is set. - * - * @param formatRequired The value of {@code formatRequired} passed to {@link SampleQueue#read}. - */ - private void assertReadEndOfStream(boolean formatRequired) { - clearFormatHolderAndInputBuffer(); - int result = - sampleQueue.read( - formatHolder, - inputBuffer, - formatRequired, - /* loadingFinished= */ true, - /* decodeOnlyUntilUs= */ 0); - assertThat(result).isEqualTo(RESULT_BUFFER_READ); - // formatHolder should not be populated. - assertThat(formatHolder.format).isNull(); - // inputBuffer should not contain sample data, but end of stream flag should be set. - assertInputBufferContainsNoSampleData(); - assertThat(inputBuffer.isEndOfStream()).isTrue(); - assertThat(inputBuffer.isDecodeOnly()).isFalse(); - assertThat(inputBuffer.isEncrypted()).isFalse(); - } - - /** - * Asserts {@link SampleQueue#read} returns {@link C#RESULT_FORMAT_READ} and that the format - * holder is filled with a {@link Format} that equals {@code format}. - * - * @param formatRequired The value of {@code formatRequired} passed to {@link SampleQueue#read}. - * @param format The expected format. - */ - private void assertReadFormat(boolean formatRequired, Format format) { - clearFormatHolderAndInputBuffer(); - int result = - sampleQueue.read( - formatHolder, - inputBuffer, - formatRequired, - /* loadingFinished= */ false, - /* decodeOnlyUntilUs= */ 0); - assertThat(result).isEqualTo(RESULT_FORMAT_READ); - // formatHolder should be populated. - assertThat(formatHolder.format).isEqualTo(format); - // inputBuffer should not be populated. - assertInputBufferContainsNoSampleData(); - assertInputBufferHasNoDefaultFlagsSet(); - } - - private void assertReadEncryptedSample(int sampleIndex) { - byte[] sampleData = new byte[ENCRYPTED_SAMPLE_SIZES[sampleIndex]]; - Arrays.fill(sampleData, (byte) 1); - boolean isKeyFrame = (ENCRYPTED_SAMPLES_FLAGS[sampleIndex] & C.BUFFER_FLAG_KEY_FRAME) != 0; - boolean isEncrypted = (ENCRYPTED_SAMPLES_FLAGS[sampleIndex] & C.BUFFER_FLAG_ENCRYPTED) != 0; - assertReadSample( - ENCRYPTED_SAMPLE_TIMESTAMPS[sampleIndex], - isKeyFrame, - isEncrypted, - sampleData, - /* offset= */ 0, - ENCRYPTED_SAMPLE_SIZES[sampleIndex] - (isEncrypted ? 2 : 0)); - } - - /** - * Asserts {@link SampleQueue#read} returns {@link C#RESULT_BUFFER_READ} and that the buffer is - * filled with the specified sample data. - * - * @param timeUs The expected buffer timestamp. - * @param isKeyFrame The expected keyframe flag. - * @param isEncrypted The expected encrypted flag. - * @param sampleData An array containing 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. - */ - private void assertReadSample( - long timeUs, - boolean isKeyFrame, - boolean isEncrypted, - byte[] sampleData, - int offset, - int length) { - clearFormatHolderAndInputBuffer(); - int result = - sampleQueue.read( - formatHolder, - inputBuffer, - /* formatRequired= */ false, - /* loadingFinished= */ false, - /* decodeOnlyUntilUs= */ 0); - assertThat(result).isEqualTo(RESULT_BUFFER_READ); - // formatHolder should not be populated. - assertThat(formatHolder.format).isNull(); - // inputBuffer should be populated. - assertThat(inputBuffer.timeUs).isEqualTo(timeUs); - assertThat(inputBuffer.isKeyFrame()).isEqualTo(isKeyFrame); - assertThat(inputBuffer.isDecodeOnly()).isFalse(); - assertThat(inputBuffer.isEncrypted()).isEqualTo(isEncrypted); - inputBuffer.flip(); - assertThat(inputBuffer.data.limit()).isEqualTo(length); - byte[] readData = new byte[length]; - inputBuffer.data.get(readData); - assertThat(readData).isEqualTo(copyOfRange(sampleData, offset, offset + length)); - } - - /** - * Asserts the number of allocations currently in use by {@code sampleQueue}. - * - * @param count The expected number of allocations. - */ - private void assertAllocationCount(int count) { - assertThat(allocator.getTotalBytesAllocated()).isEqualTo(ALLOCATION_SIZE * count); - } - - /** - * Asserts {@code inputBuffer} does not contain any sample data. - */ - private void assertInputBufferContainsNoSampleData() { - if (inputBuffer.data == null) { - return; - } - inputBuffer.flip(); - assertThat(inputBuffer.data.limit()).isEqualTo(0); - } - - private void assertInputBufferHasNoDefaultFlagsSet() { - assertThat(inputBuffer.isEndOfStream()).isFalse(); - assertThat(inputBuffer.isDecodeOnly()).isFalse(); - assertThat(inputBuffer.isEncrypted()).isFalse(); - } - - private void clearFormatHolderAndInputBuffer() { - formatHolder.format = null; - inputBuffer.clear(); - } - - private static Format adjustFormat(@Nullable Format format, long sampleOffsetUs) { - return format == null || sampleOffsetUs == 0 - ? format - : format.buildUpon().setSubsampleOffsetUs(sampleOffsetUs).build(); - } - - private static Format buildFormat(String id) { - return new Format.Builder().setId(id).setSubsampleOffsetUs(0).build(); - } - - private static Format copyWithLabel(Format format, String label) { - return format.buildUpon().setLabel(label).build(); - } -} |