mirror of
https://github.com/androidx/media.git
synced 2025-05-16 03:59:54 +08:00
Make tests independent
PiperOrigin-RevId: 289521837
This commit is contained in:
parent
ccce9948a9
commit
4c74f3cffd
BIN
library/core/src/test/assets/id3/apic.id3
Normal file
BIN
library/core/src/test/assets/id3/apic.id3
Normal file
Binary file not shown.
BIN
library/core/src/test/assets/id3/comm_apic.id3
Normal file
BIN
library/core/src/test/assets/id3/comm_apic.id3
Normal file
Binary file not shown.
BIN
library/core/src/test/assets/ogg/continued_packet_at_start
Normal file
BIN
library/core/src/test/assets/ogg/continued_packet_at_start
Normal file
Binary file not shown.
Binary file not shown.
BIN
library/core/src/test/assets/ogg/continued_packet_over_two_pages
Normal file
BIN
library/core/src/test/assets/ogg/continued_packet_over_two_pages
Normal file
Binary file not shown.
BIN
library/core/src/test/assets/ogg/eof_header
Normal file
BIN
library/core/src/test/assets/ogg/eof_header
Normal file
Binary file not shown.
BIN
library/core/src/test/assets/ogg/flac_header
Normal file
BIN
library/core/src/test/assets/ogg/flac_header
Normal file
Binary file not shown.
BIN
library/core/src/test/assets/ogg/four_packets_with_empty_page
Normal file
BIN
library/core/src/test/assets/ogg/four_packets_with_empty_page
Normal file
Binary file not shown.
BIN
library/core/src/test/assets/ogg/invalid_header
Normal file
BIN
library/core/src/test/assets/ogg/invalid_header
Normal file
Binary file not shown.
BIN
library/core/src/test/assets/ogg/invalid_ogg_header
Normal file
BIN
library/core/src/test/assets/ogg/invalid_ogg_header
Normal file
Binary file not shown.
BIN
library/core/src/test/assets/ogg/opus_header
Normal file
BIN
library/core/src/test/assets/ogg/opus_header
Normal file
Binary file not shown.
Binary file not shown.
BIN
library/core/src/test/assets/ogg/page_header
Normal file
BIN
library/core/src/test/assets/ogg/page_header
Normal file
Binary file not shown.
BIN
library/core/src/test/assets/ogg/random_1000_pages
Normal file
BIN
library/core/src/test/assets/ogg/random_1000_pages
Normal file
Binary file not shown.
BIN
library/core/src/test/assets/ogg/three_headers
Normal file
BIN
library/core/src/test/assets/ogg/three_headers
Normal file
Binary file not shown.
BIN
library/core/src/test/assets/ogg/vorbis_header
Normal file
BIN
library/core/src/test/assets/ogg/vorbis_header
Normal file
Binary file not shown.
Binary file not shown.
@ -16,13 +16,15 @@
|
||||
|
||||
package com.google.android.exoplayer2.extractor;
|
||||
|
||||
import static com.google.android.exoplayer2.testutil.TestUtil.getByteArray;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.metadata.id3.ApicFrame;
|
||||
import com.google.android.exoplayer2.metadata.id3.CommentFrame;
|
||||
import com.google.android.exoplayer2.metadata.id3.Id3DecoderTest;
|
||||
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
|
||||
import java.io.IOException;
|
||||
import org.junit.Test;
|
||||
@ -41,7 +43,7 @@ public final class Id3PeekerTest {
|
||||
.setData(new byte[] {1, 'I', 'D', '3', 2, 3, 4, 5, 6, 7, 8, 9, 10})
|
||||
.build();
|
||||
|
||||
Metadata metadata = id3Peeker.peekId3Data(input, /* id3FramePredicate= */ null);
|
||||
@Nullable Metadata metadata = id3Peeker.peekId3Data(input, /* id3FramePredicate= */ null);
|
||||
assertThat(metadata).isNull();
|
||||
}
|
||||
|
||||
@ -49,17 +51,13 @@ public final class Id3PeekerTest {
|
||||
public void testPeekId3Data_returnId3Tag_ifId3TagPresent()
|
||||
throws IOException, InterruptedException {
|
||||
Id3Peeker id3Peeker = new Id3Peeker();
|
||||
FakeExtractorInput input =
|
||||
new FakeExtractorInput.Builder()
|
||||
.setData(getByteArray(ApplicationProvider.getApplicationContext(), "id3/apic.id3"))
|
||||
.build();
|
||||
|
||||
byte[] rawId3 =
|
||||
Id3DecoderTest.buildSingleFrameTag(
|
||||
"APIC",
|
||||
new byte[] {
|
||||
3, 105, 109, 97, 103, 101, 47, 106, 112, 101, 103, 0, 16, 72, 101, 108, 108, 111, 32,
|
||||
87, 111, 114, 108, 100, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0
|
||||
});
|
||||
FakeExtractorInput input = new FakeExtractorInput.Builder().setData(rawId3).build();
|
||||
|
||||
Metadata metadata = id3Peeker.peekId3Data(input, /* id3FramePredicate= */ null);
|
||||
@Nullable Metadata metadata = id3Peeker.peekId3Data(input, /* id3FramePredicate= */ null);
|
||||
assertThat(metadata).isNotNull();
|
||||
assertThat(metadata.length()).isEqualTo(1);
|
||||
|
||||
ApicFrame apicFrame = (ApicFrame) metadata.get(0);
|
||||
@ -74,28 +72,18 @@ public final class Id3PeekerTest {
|
||||
public void testPeekId3Data_returnId3TagAccordingToGivenPredicate_ifId3TagPresent()
|
||||
throws IOException, InterruptedException {
|
||||
Id3Peeker id3Peeker = new Id3Peeker();
|
||||
FakeExtractorInput input =
|
||||
new FakeExtractorInput.Builder()
|
||||
.setData(getByteArray(ApplicationProvider.getApplicationContext(), "id3/comm_apic.id3"))
|
||||
.build();
|
||||
|
||||
byte[] rawId3 =
|
||||
Id3DecoderTest.buildMultiFramesTag(
|
||||
new Id3DecoderTest.FrameSpec(
|
||||
"COMM",
|
||||
new byte[] {
|
||||
3, 101, 110, 103, 100, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 0, 116,
|
||||
101, 120, 116, 0
|
||||
}),
|
||||
new Id3DecoderTest.FrameSpec(
|
||||
"APIC",
|
||||
new byte[] {
|
||||
3, 105, 109, 97, 103, 101, 47, 106, 112, 101, 103, 0, 16, 72, 101, 108, 108, 111,
|
||||
32, 87, 111, 114, 108, 100, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0
|
||||
}));
|
||||
FakeExtractorInput input = new FakeExtractorInput.Builder().setData(rawId3).build();
|
||||
|
||||
@Nullable
|
||||
Metadata metadata =
|
||||
id3Peeker.peekId3Data(
|
||||
input,
|
||||
(majorVersion, id0, id1, id2, id3) ->
|
||||
id0 == 'C' && id1 == 'O' && id2 == 'M' && id3 == 'M');
|
||||
assertThat(metadata).isNotNull();
|
||||
assertThat(metadata.length()).isEqualTo(1);
|
||||
|
||||
CommentFrame commentFrame = (CommentFrame) metadata.get(0);
|
||||
|
@ -15,9 +15,11 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.extractor.ogg;
|
||||
|
||||
import static com.google.android.exoplayer2.testutil.TestUtil.getByteArray;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
||||
@ -34,7 +36,7 @@ import org.junit.runner.RunWith;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class DefaultOggSeekerTest {
|
||||
|
||||
private final Random random = new Random(0);
|
||||
private final Random random = new Random(/* seed= */ 0);
|
||||
|
||||
@Test
|
||||
public void testSetupWithUnsetEndPositionFails() {
|
||||
@ -53,113 +55,24 @@ public final class DefaultOggSeekerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSeeking() throws IOException, InterruptedException {
|
||||
Random random = new Random(0);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
testSeeking(random);
|
||||
}
|
||||
}
|
||||
public void testSeeking() throws Exception {
|
||||
byte[] data =
|
||||
getByteArray(ApplicationProvider.getApplicationContext(), "ogg/random_1000_pages");
|
||||
int granuleCount = 49269395;
|
||||
int firstPayloadPageSize = 2023;
|
||||
int firstPayloadPageGranuleCount = 57058;
|
||||
int lastPayloadPageSize = 282;
|
||||
int lastPayloadPageGranuleCount = 20806;
|
||||
|
||||
@Test
|
||||
public void testSkipToNextPage() throws Exception {
|
||||
FakeExtractorInput extractorInput =
|
||||
OggTestData.createInput(
|
||||
TestUtil.joinByteArrays(
|
||||
TestUtil.buildTestData(4000, random),
|
||||
new byte[] {'O', 'g', 'g', 'S'},
|
||||
TestUtil.buildTestData(4000, random)),
|
||||
false);
|
||||
skipToNextPage(extractorInput);
|
||||
assertThat(extractorInput.getPosition()).isEqualTo(4000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipToNextPageOverlap() throws Exception {
|
||||
FakeExtractorInput extractorInput =
|
||||
OggTestData.createInput(
|
||||
TestUtil.joinByteArrays(
|
||||
TestUtil.buildTestData(2046, random),
|
||||
new byte[] {'O', 'g', 'g', 'S'},
|
||||
TestUtil.buildTestData(4000, random)),
|
||||
false);
|
||||
skipToNextPage(extractorInput);
|
||||
assertThat(extractorInput.getPosition()).isEqualTo(2046);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipToNextPageInputShorterThanPeekLength() throws Exception {
|
||||
FakeExtractorInput extractorInput =
|
||||
OggTestData.createInput(
|
||||
TestUtil.joinByteArrays(new byte[] {'x', 'O', 'g', 'g', 'S'}), false);
|
||||
skipToNextPage(extractorInput);
|
||||
assertThat(extractorInput.getPosition()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipToNextPageNoMatch() throws Exception {
|
||||
FakeExtractorInput extractorInput =
|
||||
OggTestData.createInput(new byte[] {'g', 'g', 'S', 'O', 'g', 'g'}, false);
|
||||
try {
|
||||
skipToNextPage(extractorInput);
|
||||
fail();
|
||||
} catch (EOFException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadGranuleOfLastPage() throws IOException, InterruptedException {
|
||||
FakeExtractorInput input =
|
||||
OggTestData.createInput(
|
||||
TestUtil.joinByteArrays(
|
||||
TestUtil.buildTestData(100, random),
|
||||
OggTestData.buildOggHeader(0x00, 20000, 66, 3),
|
||||
TestUtil.createByteArray(254, 254, 254), // laces
|
||||
TestUtil.buildTestData(3 * 254, random),
|
||||
OggTestData.buildOggHeader(0x00, 40000, 67, 3),
|
||||
TestUtil.createByteArray(254, 254, 254), // laces
|
||||
TestUtil.buildTestData(3 * 254, random),
|
||||
OggTestData.buildOggHeader(0x05, 60000, 68, 3),
|
||||
TestUtil.createByteArray(254, 254, 254), // laces
|
||||
TestUtil.buildTestData(3 * 254, random)),
|
||||
false);
|
||||
assertReadGranuleOfLastPage(input, 60000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadGranuleOfLastPageAfterLastHeader() throws IOException, InterruptedException {
|
||||
FakeExtractorInput input = OggTestData.createInput(TestUtil.buildTestData(100, random), false);
|
||||
try {
|
||||
assertReadGranuleOfLastPage(input, 60000);
|
||||
fail();
|
||||
} catch (EOFException e) {
|
||||
// Ignored.
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadGranuleOfLastPageWithUnboundedLength()
|
||||
throws IOException, InterruptedException {
|
||||
FakeExtractorInput input = OggTestData.createInput(new byte[0], true);
|
||||
try {
|
||||
assertReadGranuleOfLastPage(input, 60000);
|
||||
fail();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Ignored.
|
||||
}
|
||||
}
|
||||
|
||||
private void testSeeking(Random random) throws IOException, InterruptedException {
|
||||
OggTestFile testFile = OggTestFile.generate(random, 1000);
|
||||
FakeExtractorInput input = new FakeExtractorInput.Builder().setData(testFile.data).build();
|
||||
FakeExtractorInput input = new FakeExtractorInput.Builder().setData(data).build();
|
||||
TestStreamReader streamReader = new TestStreamReader();
|
||||
DefaultOggSeeker oggSeeker =
|
||||
new DefaultOggSeeker(
|
||||
/* streamReader= */ streamReader,
|
||||
streamReader,
|
||||
/* payloadStartPosition= */ 0,
|
||||
/* payloadEndPosition= */ testFile.data.length,
|
||||
/* firstPayloadPageSize= */ testFile.firstPayloadPageSize,
|
||||
/* firstPayloadPageGranulePosition= */ testFile.firstPayloadPageGranuleCount,
|
||||
/* payloadEndPosition= */ data.length,
|
||||
firstPayloadPageSize,
|
||||
/* firstPayloadPageGranulePosition= */ firstPayloadPageGranuleCount,
|
||||
/* firstPayloadPageIsLastPage= */ false);
|
||||
OggPageHeader pageHeader = new OggPageHeader();
|
||||
|
||||
@ -177,30 +90,30 @@ public final class DefaultOggSeekerTest {
|
||||
assertThat(input.getPosition()).isEqualTo(0);
|
||||
|
||||
// Test granule 0 from file end.
|
||||
granule = seekTo(input, oggSeeker, 0, testFile.data.length - 1);
|
||||
granule = seekTo(input, oggSeeker, 0, data.length - 1);
|
||||
assertThat(granule).isEqualTo(0);
|
||||
assertThat(input.getPosition()).isEqualTo(0);
|
||||
|
||||
// Test last granule.
|
||||
granule = seekTo(input, oggSeeker, testFile.granuleCount - 1, 0);
|
||||
assertThat(granule).isEqualTo(testFile.granuleCount - testFile.lastPayloadPageGranuleCount);
|
||||
assertThat(input.getPosition()).isEqualTo(testFile.data.length - testFile.lastPayloadPageSize);
|
||||
granule = seekTo(input, oggSeeker, granuleCount - 1, 0);
|
||||
assertThat(granule).isEqualTo(granuleCount - lastPayloadPageGranuleCount);
|
||||
assertThat(input.getPosition()).isEqualTo(data.length - lastPayloadPageSize);
|
||||
|
||||
for (int i = 0; i < 100; i += 1) {
|
||||
long targetGranule = random.nextInt(testFile.granuleCount);
|
||||
int initialPosition = random.nextInt(testFile.data.length);
|
||||
long targetGranule = random.nextInt(granuleCount);
|
||||
int initialPosition = random.nextInt(data.length);
|
||||
granule = seekTo(input, oggSeeker, targetGranule, initialPosition);
|
||||
long currentPosition = input.getPosition();
|
||||
int currentPosition = (int) input.getPosition();
|
||||
if (granule == 0) {
|
||||
assertThat(currentPosition).isEqualTo(0);
|
||||
} else {
|
||||
int previousPageStart = testFile.findPreviousPageStart(currentPosition);
|
||||
int previousPageStart = findPreviousPageStart(data, currentPosition);
|
||||
input.setPosition(previousPageStart);
|
||||
pageHeader.populate(input, false);
|
||||
assertThat(granule).isEqualTo(pageHeader.granulePosition);
|
||||
}
|
||||
|
||||
input.setPosition((int) currentPosition);
|
||||
input.setPosition(currentPosition);
|
||||
pageHeader.populate(input, false);
|
||||
// The target granule should be within the current page.
|
||||
assertThat(granule).isAtMost(targetGranule);
|
||||
@ -208,6 +121,85 @@ public final class DefaultOggSeekerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipToNextPage() throws Exception {
|
||||
FakeExtractorInput extractorInput =
|
||||
createInput(
|
||||
TestUtil.joinByteArrays(
|
||||
TestUtil.buildTestData(4000, random),
|
||||
new byte[] {'O', 'g', 'g', 'S'},
|
||||
TestUtil.buildTestData(4000, random)),
|
||||
/* simulateUnknownLength= */ false);
|
||||
skipToNextPage(extractorInput);
|
||||
assertThat(extractorInput.getPosition()).isEqualTo(4000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipToNextPageOverlap() throws Exception {
|
||||
FakeExtractorInput extractorInput =
|
||||
createInput(
|
||||
TestUtil.joinByteArrays(
|
||||
TestUtil.buildTestData(2046, random),
|
||||
new byte[] {'O', 'g', 'g', 'S'},
|
||||
TestUtil.buildTestData(4000, random)),
|
||||
/* simulateUnknownLength= */ false);
|
||||
skipToNextPage(extractorInput);
|
||||
assertThat(extractorInput.getPosition()).isEqualTo(2046);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipToNextPageInputShorterThanPeekLength() throws Exception {
|
||||
FakeExtractorInput extractorInput =
|
||||
createInput(
|
||||
TestUtil.joinByteArrays(new byte[] {'x', 'O', 'g', 'g', 'S'}),
|
||||
/* simulateUnknownLength= */ false);
|
||||
skipToNextPage(extractorInput);
|
||||
assertThat(extractorInput.getPosition()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipToNextPageNoMatch() throws Exception {
|
||||
FakeExtractorInput extractorInput =
|
||||
createInput(new byte[] {'g', 'g', 'S', 'O', 'g', 'g'}, /* simulateUnknownLength= */ false);
|
||||
try {
|
||||
skipToNextPage(extractorInput);
|
||||
fail();
|
||||
} catch (EOFException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadGranuleOfLastPage() throws IOException, InterruptedException {
|
||||
// This test stream has three headers with granule numbers 20000, 40000 and 60000.
|
||||
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/three_headers");
|
||||
FakeExtractorInput input = createInput(data, /* simulateUnknownLength= */ false);
|
||||
assertReadGranuleOfLastPage(input, 60000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadGranuleOfLastPageAfterLastHeader() throws Exception {
|
||||
FakeExtractorInput input =
|
||||
createInput(TestUtil.buildTestData(100, random), /* simulateUnknownLength= */ false);
|
||||
try {
|
||||
assertReadGranuleOfLastPage(input, 60000);
|
||||
fail();
|
||||
} catch (EOFException e) {
|
||||
// Ignored.
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadGranuleOfLastPageWithUnboundedLength() throws Exception {
|
||||
FakeExtractorInput input = createInput(new byte[0], /* simulateUnknownLength= */ true);
|
||||
try {
|
||||
assertReadGranuleOfLastPage(input, 60000);
|
||||
fail();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Ignored.
|
||||
}
|
||||
}
|
||||
|
||||
private static void skipToNextPage(ExtractorInput extractorInput)
|
||||
throws IOException, InterruptedException {
|
||||
DefaultOggSeeker oggSeeker =
|
||||
@ -248,6 +240,15 @@ public final class DefaultOggSeekerTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static FakeExtractorInput createInput(byte[] data, boolean simulateUnknownLength) {
|
||||
return new FakeExtractorInput.Builder()
|
||||
.setData(data)
|
||||
.setSimulateIOErrors(true)
|
||||
.setSimulateUnknownLength(simulateUnknownLength)
|
||||
.setSimulatePartialReads(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
private static long seekTo(
|
||||
FakeExtractorInput input, DefaultOggSeeker oggSeeker, long targetGranule, int initialPosition)
|
||||
throws IOException, InterruptedException {
|
||||
@ -264,6 +265,16 @@ public final class DefaultOggSeekerTest {
|
||||
return -(nextSeekPosition + 2);
|
||||
}
|
||||
|
||||
private static int findPreviousPageStart(byte[] data, int position) {
|
||||
for (int i = position - 4; i >= 0; i--) {
|
||||
if (data[i] == 'O' && data[i + 1] == 'g' && data[i + 2] == 'g' && data[i + 3] == 'S') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
fail();
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static class TestStreamReader extends StreamReader {
|
||||
@Override
|
||||
protected long preparePayload(ParsableByteArray packet) {
|
||||
|
@ -15,12 +15,13 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.extractor.ogg;
|
||||
|
||||
import static com.google.android.exoplayer2.testutil.TestUtil.getByteArray;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.testutil.ExtractorAsserts;
|
||||
import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory;
|
||||
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import java.io.IOException;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -53,51 +54,38 @@ public final class OggExtractorTest {
|
||||
|
||||
@Test
|
||||
public void testSniffVorbis() throws Exception {
|
||||
byte[] data =
|
||||
TestUtil.joinByteArrays(
|
||||
OggTestData.buildOggHeader(0x02, 0, 1000, 1),
|
||||
TestUtil.createByteArray(7), // Laces
|
||||
new byte[] {0x01, 'v', 'o', 'r', 'b', 'i', 's'});
|
||||
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/vorbis_header");
|
||||
assertSniff(data, /* expectedResult= */ true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSniffFlac() throws Exception {
|
||||
byte[] data =
|
||||
TestUtil.joinByteArrays(
|
||||
OggTestData.buildOggHeader(0x02, 0, 1000, 1),
|
||||
TestUtil.createByteArray(5), // Laces
|
||||
new byte[] {0x7F, 'F', 'L', 'A', 'C'});
|
||||
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/flac_header");
|
||||
assertSniff(data, /* expectedResult= */ true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSniffFailsOpusFile() throws Exception {
|
||||
byte[] data =
|
||||
TestUtil.joinByteArrays(
|
||||
OggTestData.buildOggHeader(0x02, 0, 1000, 0x00), new byte[] {'O', 'p', 'u', 's'});
|
||||
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/opus_header");
|
||||
assertSniff(data, /* expectedResult= */ false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSniffFailsInvalidOggHeader() throws Exception {
|
||||
byte[] data = OggTestData.buildOggHeader(0x00, 0, 1000, 0x00);
|
||||
byte[] data =
|
||||
getByteArray(ApplicationProvider.getApplicationContext(), "ogg/invalid_ogg_header");
|
||||
assertSniff(data, /* expectedResult= */ false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSniffInvalidHeader() throws Exception {
|
||||
byte[] data =
|
||||
TestUtil.joinByteArrays(
|
||||
OggTestData.buildOggHeader(0x02, 0, 1000, 1),
|
||||
TestUtil.createByteArray(7), // Laces
|
||||
new byte[] {0x7F, 'X', 'o', 'r', 'b', 'i', 's'});
|
||||
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/invalid_header");
|
||||
assertSniff(data, /* expectedResult= */ false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSniffFailsEOF() throws Exception {
|
||||
byte[] data = OggTestData.buildOggHeader(0x02, 0, 1000, 0x00);
|
||||
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/eof_header");
|
||||
assertSniff(data, /* expectedResult= */ false);
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.extractor.ogg;
|
||||
|
||||
import static com.google.android.exoplayer2.testutil.TestUtil.getByteArray;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
@ -25,7 +26,6 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@ -35,14 +35,8 @@ public final class OggPacketTest {
|
||||
|
||||
private static final String TEST_FILE = "ogg/bear.opus";
|
||||
|
||||
private Random random;
|
||||
private OggPacket oggPacket;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
random = new Random(0);
|
||||
oggPacket = new OggPacket();
|
||||
}
|
||||
private final Random random = new Random(/* seed= */ 0);
|
||||
private final OggPacket oggPacket = new OggPacket();
|
||||
|
||||
@Test
|
||||
public void testReadPacketsWithEmptyPage() throws Exception {
|
||||
@ -50,26 +44,10 @@ public final class OggPacketTest {
|
||||
byte[] secondPacket = TestUtil.buildTestData(272, random);
|
||||
byte[] thirdPacket = TestUtil.buildTestData(256, random);
|
||||
byte[] fourthPacket = TestUtil.buildTestData(271, random);
|
||||
|
||||
FakeExtractorInput input =
|
||||
OggTestData.createInput(
|
||||
TestUtil.joinByteArrays(
|
||||
// First page with a single packet.
|
||||
OggTestData.buildOggHeader(0x02, 0, 1000, 0x01),
|
||||
TestUtil.createByteArray(0x08), // Laces
|
||||
firstPacket,
|
||||
// Second page with a single packet.
|
||||
OggTestData.buildOggHeader(0x00, 16, 1001, 0x02),
|
||||
TestUtil.createByteArray(0xFF, 0x11), // Laces
|
||||
secondPacket,
|
||||
// Third page with zero packets.
|
||||
OggTestData.buildOggHeader(0x00, 16, 1002, 0x00),
|
||||
// Fourth page with two packets.
|
||||
OggTestData.buildOggHeader(0x04, 128, 1003, 0x04),
|
||||
TestUtil.createByteArray(0xFF, 0x01, 0xFF, 0x10), // Laces
|
||||
thirdPacket,
|
||||
fourthPacket),
|
||||
true);
|
||||
createInput(
|
||||
getByteArray(
|
||||
ApplicationProvider.getApplicationContext(), "ogg/four_packets_with_empty_page"));
|
||||
|
||||
assertReadPacket(input, firstPacket);
|
||||
assertThat((oggPacket.getPageHeader().type & 0x02) == 0x02).isTrue();
|
||||
@ -113,15 +91,11 @@ public final class OggPacketTest {
|
||||
public void testReadPacketWithZeroSizeTerminator() throws Exception {
|
||||
byte[] firstPacket = TestUtil.buildTestData(255, random);
|
||||
byte[] secondPacket = TestUtil.buildTestData(8, random);
|
||||
|
||||
FakeExtractorInput input =
|
||||
OggTestData.createInput(
|
||||
TestUtil.joinByteArrays(
|
||||
OggTestData.buildOggHeader(0x06, 0, 1000, 0x04),
|
||||
TestUtil.createByteArray(0xFF, 0x00, 0x00, 0x08), // Laces.
|
||||
firstPacket,
|
||||
secondPacket),
|
||||
true);
|
||||
createInput(
|
||||
getByteArray(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
"ogg/packet_with_zero_size_terminator"));
|
||||
|
||||
assertReadPacket(input, firstPacket);
|
||||
assertReadPacket(input, secondPacket);
|
||||
@ -131,19 +105,11 @@ public final class OggPacketTest {
|
||||
@Test
|
||||
public void testReadContinuedPacketOverTwoPages() throws Exception {
|
||||
byte[] firstPacket = TestUtil.buildTestData(518);
|
||||
|
||||
FakeExtractorInput input =
|
||||
OggTestData.createInput(
|
||||
TestUtil.joinByteArrays(
|
||||
// First page.
|
||||
OggTestData.buildOggHeader(0x02, 0, 1000, 0x02),
|
||||
TestUtil.createByteArray(0xFF, 0xFF), // Laces.
|
||||
Arrays.copyOf(firstPacket, 510),
|
||||
// Second page (continued packet).
|
||||
OggTestData.buildOggHeader(0x05, 10, 1001, 0x01),
|
||||
TestUtil.createByteArray(0x08), // Laces.
|
||||
Arrays.copyOfRange(firstPacket, 510, 510 + 8)),
|
||||
true);
|
||||
createInput(
|
||||
getByteArray(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
"ogg/continued_packet_over_two_pages"));
|
||||
|
||||
assertReadPacket(input, firstPacket);
|
||||
assertThat((oggPacket.getPageHeader().type & 0x04) == 0x04).isTrue();
|
||||
@ -156,27 +122,11 @@ public final class OggPacketTest {
|
||||
@Test
|
||||
public void testReadContinuedPacketOverFourPages() throws Exception {
|
||||
byte[] firstPacket = TestUtil.buildTestData(1028);
|
||||
|
||||
FakeExtractorInput input =
|
||||
OggTestData.createInput(
|
||||
TestUtil.joinByteArrays(
|
||||
// First page.
|
||||
OggTestData.buildOggHeader(0x02, 0, 1000, 0x02),
|
||||
TestUtil.createByteArray(0xFF, 0xFF), // Laces.
|
||||
Arrays.copyOf(firstPacket, 510),
|
||||
// Second page (continued packet).
|
||||
OggTestData.buildOggHeader(0x01, 10, 1001, 0x01),
|
||||
TestUtil.createByteArray(0xFF), // Laces.
|
||||
Arrays.copyOfRange(firstPacket, 510, 510 + 255),
|
||||
// Third page (continued packet).
|
||||
OggTestData.buildOggHeader(0x01, 10, 1002, 0x01),
|
||||
TestUtil.createByteArray(0xFF), // Laces.
|
||||
Arrays.copyOfRange(firstPacket, 510 + 255, 510 + 255 + 255),
|
||||
// Fourth page (continued packet).
|
||||
OggTestData.buildOggHeader(0x05, 10, 1003, 0x01),
|
||||
TestUtil.createByteArray(0x08), // Laces.
|
||||
Arrays.copyOfRange(firstPacket, 510 + 255 + 255, 510 + 255 + 255 + 8)),
|
||||
true);
|
||||
createInput(
|
||||
getByteArray(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
"ogg/continued_packet_over_four_pages"));
|
||||
|
||||
assertReadPacket(input, firstPacket);
|
||||
assertThat((oggPacket.getPageHeader().type & 0x04) == 0x04).isTrue();
|
||||
@ -189,15 +139,10 @@ public final class OggPacketTest {
|
||||
@Test
|
||||
public void testReadDiscardContinuedPacketAtStart() throws Exception {
|
||||
byte[] pageBody = TestUtil.buildTestData(256 + 8);
|
||||
|
||||
FakeExtractorInput input =
|
||||
OggTestData.createInput(
|
||||
TestUtil.joinByteArrays(
|
||||
// Page with a continued packet at start.
|
||||
OggTestData.buildOggHeader(0x01, 10, 1001, 0x03),
|
||||
TestUtil.createByteArray(255, 1, 8), // Laces.
|
||||
pageBody),
|
||||
true);
|
||||
createInput(
|
||||
getByteArray(
|
||||
ApplicationProvider.getApplicationContext(), "ogg/continued_packet_at_start"));
|
||||
|
||||
// Expect the first partial packet to be discarded.
|
||||
assertReadPacket(input, Arrays.copyOfRange(pageBody, 256, 256 + 8));
|
||||
@ -209,20 +154,11 @@ public final class OggPacketTest {
|
||||
byte[] firstPacket = TestUtil.buildTestData(8, random);
|
||||
byte[] secondPacket = TestUtil.buildTestData(8, random);
|
||||
byte[] thirdPacket = TestUtil.buildTestData(8, random);
|
||||
|
||||
FakeExtractorInput input =
|
||||
OggTestData.createInput(
|
||||
TestUtil.joinByteArrays(
|
||||
OggTestData.buildOggHeader(0x02, 0, 1000, 0x01),
|
||||
TestUtil.createByteArray(0x08), // Laces.
|
||||
firstPacket,
|
||||
OggTestData.buildOggHeader(0x04, 0, 1001, 0x03),
|
||||
TestUtil.createByteArray(0x08, 0x00, 0x00), // Laces.
|
||||
secondPacket,
|
||||
OggTestData.buildOggHeader(0x04, 0, 1002, 0x03),
|
||||
TestUtil.createByteArray(0x08, 0x00, 0x00), // Laces.
|
||||
thirdPacket),
|
||||
true);
|
||||
createInput(
|
||||
getByteArray(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
"ogg/zero_sized_packets_at_end_of_stream"));
|
||||
|
||||
assertReadPacket(input, firstPacket);
|
||||
assertReadPacket(input, secondPacket);
|
||||
@ -241,6 +177,15 @@ public final class OggPacketTest {
|
||||
assertThat(packetCounter).isEqualTo(277);
|
||||
}
|
||||
|
||||
private static FakeExtractorInput createInput(byte[] data) {
|
||||
return new FakeExtractorInput.Builder()
|
||||
.setData(data)
|
||||
.setSimulateIOErrors(true)
|
||||
.setSimulateUnknownLength(true)
|
||||
.setSimulatePartialReads(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void assertReadPacket(FakeExtractorInput extractorInput, byte[] expected)
|
||||
throws IOException, InterruptedException {
|
||||
assertThat(readPacket(extractorInput)).isTrue();
|
||||
|
@ -15,13 +15,14 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.extractor.ogg;
|
||||
|
||||
import static com.google.android.exoplayer2.testutil.TestUtil.getByteArray;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
|
||||
import com.google.android.exoplayer2.testutil.FakeExtractorInput.SimulatedIOException;
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import java.io.IOException;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@ -30,13 +31,12 @@ import org.junit.runner.RunWith;
|
||||
public final class OggPageHeaderTest {
|
||||
|
||||
@Test
|
||||
public void testPopulatePageHeader() throws IOException, InterruptedException {
|
||||
FakeExtractorInput input = OggTestData.createInput(TestUtil.joinByteArrays(
|
||||
OggTestData.buildOggHeader(0x01, 123456, 4, 2),
|
||||
TestUtil.createByteArray(2, 2)
|
||||
), true);
|
||||
public void testPopulatePageHeader() throws Exception {
|
||||
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/page_header");
|
||||
|
||||
FakeExtractorInput input = createInput(data, /* simulateUnknownLength= */ true);
|
||||
OggPageHeader header = new OggPageHeader();
|
||||
populatePageHeader(input, header, false);
|
||||
populatePageHeader(input, header, /* quiet= */ false);
|
||||
|
||||
assertThat(header.type).isEqualTo(0x01);
|
||||
assertThat(header.headerSize).isEqualTo(27 + 2);
|
||||
@ -50,51 +50,51 @@ public final class OggPageHeaderTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopulatePageHeaderQuiteOnExceptionLessThan27Bytes()
|
||||
throws IOException, InterruptedException {
|
||||
FakeExtractorInput input = OggTestData.createInput(TestUtil.createByteArray(2, 2), false);
|
||||
public void testPopulatePageHeaderQuietOnExceptionLessThan27Bytes() throws Exception {
|
||||
FakeExtractorInput input =
|
||||
createInput(TestUtil.createByteArray(2, 2), /* simulateUnknownLength= */ false);
|
||||
OggPageHeader header = new OggPageHeader();
|
||||
assertThat(populatePageHeader(input, header, true)).isFalse();
|
||||
assertThat(populatePageHeader(input, header, /* quiet= */ true)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopulatePageHeaderQuiteOnExceptionNotOgg()
|
||||
throws IOException, InterruptedException {
|
||||
byte[] headerBytes = TestUtil.joinByteArrays(
|
||||
OggTestData.buildOggHeader(0x01, 123456, 4, 2),
|
||||
TestUtil.createByteArray(2, 2)
|
||||
);
|
||||
public void testPopulatePageHeaderQuietOnExceptionNotOgg() throws Exception {
|
||||
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/page_header");
|
||||
// change from 'O' to 'o'
|
||||
headerBytes[0] = 'o';
|
||||
FakeExtractorInput input = OggTestData.createInput(headerBytes, false);
|
||||
data[0] = 'o';
|
||||
FakeExtractorInput input = createInput(data, /* simulateUnknownLength= */ false);
|
||||
OggPageHeader header = new OggPageHeader();
|
||||
assertThat(populatePageHeader(input, header, true)).isFalse();
|
||||
assertThat(populatePageHeader(input, header, /* quiet= */ true)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopulatePageHeaderQuiteOnExceptionWrongRevision()
|
||||
throws IOException, InterruptedException {
|
||||
byte[] headerBytes = TestUtil.joinByteArrays(
|
||||
OggTestData.buildOggHeader(0x01, 123456, 4, 2),
|
||||
TestUtil.createByteArray(2, 2)
|
||||
);
|
||||
public void testPopulatePageHeaderQuiteOnExceptionWrongRevision() throws Exception {
|
||||
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/page_header");
|
||||
// change revision from 0 to 1
|
||||
headerBytes[4] = 0x01;
|
||||
FakeExtractorInput input = OggTestData.createInput(headerBytes, false);
|
||||
data[4] = 0x01;
|
||||
FakeExtractorInput input = createInput(data, /* simulateUnknownLength= */ false);
|
||||
OggPageHeader header = new OggPageHeader();
|
||||
assertThat(populatePageHeader(input, header, true)).isFalse();
|
||||
assertThat(populatePageHeader(input, header, /* quiet= */ true)).isFalse();
|
||||
}
|
||||
|
||||
private boolean populatePageHeader(FakeExtractorInput input, OggPageHeader header,
|
||||
boolean quite) throws IOException, InterruptedException {
|
||||
private static boolean populatePageHeader(
|
||||
FakeExtractorInput input, OggPageHeader header, boolean quiet) throws Exception {
|
||||
while (true) {
|
||||
try {
|
||||
return header.populate(input, quite);
|
||||
return header.populate(input, quiet);
|
||||
} catch (SimulatedIOException e) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static FakeExtractorInput createInput(byte[] data, boolean simulateUnknownLength) {
|
||||
return new FakeExtractorInput.Builder()
|
||||
.setData(data)
|
||||
.setSimulateIOErrors(true)
|
||||
.setSimulateUnknownLength(simulateUnknownLength)
|
||||
.setSimulatePartialReads(true)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.extractor.ogg;
|
||||
|
||||
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
|
||||
/** Provides ogg/vorbis test data in bytes for unit tests. */
|
||||
/* package */ final class OggTestData {
|
||||
|
||||
public static FakeExtractorInput createInput(byte[] data, boolean simulateUnknownLength) {
|
||||
return new FakeExtractorInput.Builder()
|
||||
.setData(data)
|
||||
.setSimulateIOErrors(true)
|
||||
.setSimulateUnknownLength(simulateUnknownLength)
|
||||
.setSimulatePartialReads(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static byte[] buildOggHeader(
|
||||
int headerType, long granule, int pageSequenceCounter, int pageSegmentCount) {
|
||||
return TestUtil.createByteArray(
|
||||
0x4F,
|
||||
0x67,
|
||||
0x67,
|
||||
0x53, // Oggs.
|
||||
0x00, // Stream revision.
|
||||
headerType,
|
||||
(int) (granule) & 0xFF,
|
||||
(int) (granule >> 8) & 0xFF,
|
||||
(int) (granule >> 16) & 0xFF,
|
||||
(int) (granule >> 24) & 0xFF,
|
||||
(int) (granule >> 32) & 0xFF,
|
||||
(int) (granule >> 40) & 0xFF,
|
||||
(int) (granule >> 48) & 0xFF,
|
||||
(int) (granule >> 56) & 0xFF,
|
||||
0x00, // LSB of data serial number.
|
||||
0x10,
|
||||
0x00,
|
||||
0x00, // MSB of data serial number.
|
||||
(pageSequenceCounter) & 0xFF,
|
||||
(pageSequenceCounter >> 8) & 0xFF,
|
||||
(pageSequenceCounter >> 16) & 0xFF,
|
||||
(pageSequenceCounter >> 24) & 0xFF,
|
||||
0x00, // LSB of page checksum.
|
||||
0x00,
|
||||
0x10,
|
||||
0x00, // MSB of page checksum.
|
||||
pageSegmentCount);
|
||||
}
|
||||
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.extractor.ogg;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
|
||||
/** Generates test data. */
|
||||
/* package */ final class OggTestFile {
|
||||
|
||||
private static final int MAX_PACKET_LENGTH = 2048;
|
||||
private static final int MAX_SEGMENT_COUNT = 10;
|
||||
private static final int MAX_GRANULES_IN_PAGE = 100000;
|
||||
|
||||
public final byte[] data;
|
||||
public final int granuleCount;
|
||||
public final int pageCount;
|
||||
public final int firstPayloadPageSize;
|
||||
public final int firstPayloadPageGranuleCount;
|
||||
public final int lastPayloadPageSize;
|
||||
public final int lastPayloadPageGranuleCount;
|
||||
|
||||
private OggTestFile(
|
||||
byte[] data,
|
||||
int granuleCount,
|
||||
int pageCount,
|
||||
int firstPayloadPageSize,
|
||||
int firstPayloadPageGranuleCount,
|
||||
int lastPayloadPageSize,
|
||||
int lastPayloadPageGranuleCount) {
|
||||
this.data = data;
|
||||
this.granuleCount = granuleCount;
|
||||
this.pageCount = pageCount;
|
||||
this.firstPayloadPageSize = firstPayloadPageSize;
|
||||
this.firstPayloadPageGranuleCount = firstPayloadPageGranuleCount;
|
||||
this.lastPayloadPageSize = lastPayloadPageSize;
|
||||
this.lastPayloadPageGranuleCount = lastPayloadPageGranuleCount;
|
||||
}
|
||||
|
||||
public static OggTestFile generate(Random random, int pageCount) {
|
||||
ArrayList<byte[]> fileData = new ArrayList<>();
|
||||
int fileSize = 0;
|
||||
int granuleCount = 0;
|
||||
int firstPayloadPageSize = 0;
|
||||
int firstPayloadPageGranuleCount = 0;
|
||||
int lastPageloadPageSize = 0;
|
||||
int lastPayloadPageGranuleCount = 0;
|
||||
int packetLength = -1;
|
||||
|
||||
for (int i = 0; i < pageCount; i++) {
|
||||
int headerType = 0x00;
|
||||
if (packetLength >= 0) {
|
||||
headerType |= 1;
|
||||
}
|
||||
if (i == 0) {
|
||||
headerType |= 2;
|
||||
}
|
||||
if (i == pageCount - 1) {
|
||||
headerType |= 4;
|
||||
}
|
||||
int pageGranuleCount = random.nextInt(MAX_GRANULES_IN_PAGE - 1) + 1;
|
||||
int pageSegmentCount = random.nextInt(MAX_SEGMENT_COUNT);
|
||||
granuleCount += pageGranuleCount;
|
||||
byte[] header = OggTestData.buildOggHeader(headerType, granuleCount, 0, pageSegmentCount);
|
||||
fileData.add(header);
|
||||
int pageSize = header.length;
|
||||
|
||||
byte[] laces = new byte[pageSegmentCount];
|
||||
int bodySize = 0;
|
||||
for (int j = 0; j < pageSegmentCount; j++) {
|
||||
if (packetLength < 0) {
|
||||
if (i < pageCount - 1) {
|
||||
packetLength = random.nextInt(MAX_PACKET_LENGTH);
|
||||
} else {
|
||||
int maxPacketLength = 255 * (pageSegmentCount - j) - 1;
|
||||
packetLength = random.nextInt(maxPacketLength);
|
||||
}
|
||||
} else if (i == pageCount - 1 && j == pageSegmentCount - 1) {
|
||||
packetLength = Math.min(packetLength, 254);
|
||||
}
|
||||
laces[j] = (byte) Math.min(packetLength, 255);
|
||||
bodySize += laces[j] & 0xFF;
|
||||
packetLength -= 255;
|
||||
}
|
||||
fileData.add(laces);
|
||||
pageSize += laces.length;
|
||||
|
||||
byte[] payload = TestUtil.buildTestData(bodySize, random);
|
||||
fileData.add(payload);
|
||||
pageSize += payload.length;
|
||||
|
||||
fileSize += pageSize;
|
||||
if (i == 0) {
|
||||
firstPayloadPageSize = pageSize;
|
||||
firstPayloadPageGranuleCount = pageGranuleCount;
|
||||
} else if (i == pageCount - 1) {
|
||||
lastPageloadPageSize = pageSize;
|
||||
lastPayloadPageGranuleCount = pageGranuleCount;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] file = new byte[fileSize];
|
||||
int position = 0;
|
||||
for (byte[] data : fileData) {
|
||||
System.arraycopy(data, 0, file, position, data.length);
|
||||
position += data.length;
|
||||
}
|
||||
return new OggTestFile(
|
||||
file,
|
||||
granuleCount,
|
||||
pageCount,
|
||||
firstPayloadPageSize,
|
||||
firstPayloadPageGranuleCount,
|
||||
lastPageloadPageSize,
|
||||
lastPayloadPageGranuleCount);
|
||||
}
|
||||
|
||||
public int findPreviousPageStart(long position) {
|
||||
for (int i = (int) (position - 4); i >= 0; i--) {
|
||||
if (data[i] == 'O' && data[i + 1] == 'g' && data[i + 2] == 'g' && data[i + 3] == 'S') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
fail();
|
||||
return -1;
|
||||
}
|
||||
}
|
@ -16,8 +16,7 @@
|
||||
|
||||
package com.google.android.exoplayer2.mediacodec;
|
||||
|
||||
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.areEqual;
|
||||
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.waitUntilAllEventsAreExecuted;
|
||||
import static com.google.android.exoplayer2.testutil.TestUtil.assertBufferInfosEqual;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
@ -28,12 +27,12 @@ import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Shadows;
|
||||
|
||||
/** Unit tests for {@link AsynchronousMediaCodecAdapter}. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@ -87,8 +86,7 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_afterFlushCompletes_returnsNextInputBuffer()
|
||||
throws InterruptedException {
|
||||
public void dequeueInputBufferIndex_afterFlushCompletes_returnsNextInputBuffer() {
|
||||
adapter.start();
|
||||
Handler handler = new Handler(looper);
|
||||
handler.post(
|
||||
@ -97,13 +95,13 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
handler.post(
|
||||
() -> adapter.getMediaCodecCallback().onInputBufferAvailable(codec, /* index=*/ 1));
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
// Wait until all tasks have been handled.
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThat(adapter.dequeueInputBufferIndex()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_afterFlushCompletesWithError_throwsException()
|
||||
throws InterruptedException {
|
||||
public void dequeueInputBufferIndex_afterFlushCompletesWithError_throwsException() {
|
||||
AtomicInteger calls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(
|
||||
() -> {
|
||||
@ -114,7 +112,8 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
adapter.start();
|
||||
adapter.flush();
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
// Wait until all tasks have been handled.
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThrows(
|
||||
IllegalStateException.class,
|
||||
() -> {
|
||||
@ -138,7 +137,7 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
adapter.getMediaCodecCallback().onOutputBufferAvailable(codec, /* index=*/ 0, outBufferInfo);
|
||||
|
||||
assertThat(adapter.dequeueOutputBufferIndex(bufferInfo)).isEqualTo(0);
|
||||
assertThat(areEqual(bufferInfo, outBufferInfo)).isTrue();
|
||||
assertBufferInfosEqual(bufferInfo, outBufferInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -153,8 +152,7 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueOutputBufferIndex_afterFlushCompletes_returnsNextOutputBuffer()
|
||||
throws InterruptedException {
|
||||
public void dequeueOutputBufferIndex_afterFlushCompletes_returnsNextOutputBuffer() {
|
||||
adapter.start();
|
||||
Handler handler = new Handler(looper);
|
||||
MediaCodec.BufferInfo info0 = new MediaCodec.BufferInfo();
|
||||
@ -166,14 +164,14 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
handler.post(
|
||||
() -> adapter.getMediaCodecCallback().onOutputBufferAvailable(codec, /* index=*/ 1, info1));
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
// Wait until all tasks have been handled.
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThat(adapter.dequeueOutputBufferIndex(bufferInfo)).isEqualTo(1);
|
||||
assertThat(areEqual(bufferInfo, info1)).isTrue();
|
||||
assertBufferInfosEqual(info1, bufferInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueOutputBufferIndex_afterFlushCompletesWithError_throwsException()
|
||||
throws InterruptedException {
|
||||
public void dequeueOutputBufferIndex_afterFlushCompletesWithError_throwsException() {
|
||||
AtomicInteger calls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(
|
||||
() -> {
|
||||
@ -184,7 +182,8 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
adapter.start();
|
||||
adapter.flush();
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
// Wait until all tasks have been handled.
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThrows(IllegalStateException.class, () -> adapter.dequeueOutputBufferIndex(bufferInfo));
|
||||
}
|
||||
|
||||
@ -213,26 +212,28 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOutputFormat_afterFlush_returnsPreviousFormat() throws InterruptedException {
|
||||
public void getOutputFormat_afterFlush_returnsPreviousFormat() {
|
||||
adapter.start();
|
||||
MediaFormat format = new MediaFormat();
|
||||
adapter.getMediaCodecCallback().onOutputFormatChanged(codec, format);
|
||||
adapter.dequeueOutputBufferIndex(bufferInfo);
|
||||
adapter.flush();
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
// Wait until all tasks have been handled.
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThat(adapter.getOutputFormat()).isEqualTo(format);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shutdown_withPendingFlush_cancelsFlush() throws InterruptedException {
|
||||
public void shutdown_withPendingFlush_cancelsFlush() {
|
||||
AtomicInteger onCodecStartCalled = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(() -> onCodecStartCalled.incrementAndGet());
|
||||
adapter.start();
|
||||
adapter.flush();
|
||||
adapter.shutdown();
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
// Wait until all tasks have been handled.
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThat(onCodecStartCalled.get()).isEqualTo(1);
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,7 @@
|
||||
|
||||
package com.google.android.exoplayer2.mediacodec;
|
||||
|
||||
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.areEqual;
|
||||
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.waitUntilAllEventsAreExecuted;
|
||||
import static com.google.android.exoplayer2.testutil.TestUtil.assertBufferInfosEqual;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
@ -29,13 +28,13 @@ import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.shadows.ShadowLooper;
|
||||
|
||||
/** Unit tests for {@link DedicatedThreadAsyncMediaCodecAdapter}. */
|
||||
@ -44,7 +43,7 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
private DedicatedThreadAsyncMediaCodecAdapter adapter;
|
||||
private MediaCodec codec;
|
||||
private TestHandlerThread handlerThread;
|
||||
private MediaCodec.BufferInfo bufferInfo = null;
|
||||
private MediaCodec.BufferInfo bufferInfo;
|
||||
|
||||
@Before
|
||||
public void setUp() throws IOException {
|
||||
@ -69,8 +68,7 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_withAfterFlushFailed_throwsException()
|
||||
throws InterruptedException {
|
||||
public void dequeueInputBufferIndex_withAfterFlushFailed_throwsException() {
|
||||
AtomicInteger codecStartCalls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(
|
||||
() -> {
|
||||
@ -81,11 +79,8 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
adapter.start();
|
||||
adapter.flush();
|
||||
|
||||
assertThat(
|
||||
waitUntilAllEventsAreExecuted(
|
||||
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
|
||||
.isTrue();
|
||||
|
||||
// Wait until all tasks have been handled.
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThrows(IllegalStateException.class, () -> adapter.dequeueInputBufferIndex());
|
||||
}
|
||||
|
||||
@ -114,8 +109,7 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_withFlushCompletedAndInputBuffer_returnsInputBuffer()
|
||||
throws InterruptedException {
|
||||
public void dequeueInputBufferIndex_withFlushCompletedAndInputBuffer_returnsInputBuffer() {
|
||||
adapter.start();
|
||||
Looper looper = handlerThread.getLooper();
|
||||
Handler handler = new Handler(looper);
|
||||
@ -128,8 +122,8 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
// Enqueue another onInputBufferAvailable after the flush event
|
||||
handler.post(() -> adapter.onInputBufferAvailable(codec, 10));
|
||||
|
||||
// Wait until all tasks have been handled
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
// Wait until all tasks have been handled.
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThat(adapter.dequeueInputBufferIndex()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@ -142,8 +136,7 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueOutputBufferIndex_withInternalException_throwsException()
|
||||
throws InterruptedException {
|
||||
public void dequeueOutputBufferIndex_withInternalException_throwsException() {
|
||||
AtomicInteger codecStartCalls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(
|
||||
() -> {
|
||||
@ -154,10 +147,8 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
adapter.start();
|
||||
adapter.flush();
|
||||
|
||||
assertThat(
|
||||
waitUntilAllEventsAreExecuted(
|
||||
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
|
||||
.isTrue();
|
||||
// Wait until all tasks have been handled.
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThrows(IllegalStateException.class, () -> adapter.dequeueOutputBufferIndex(bufferInfo));
|
||||
}
|
||||
|
||||
@ -176,7 +167,7 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
adapter.onOutputBufferAvailable(codec, 0, enqueuedBufferInfo);
|
||||
|
||||
assertThat(adapter.dequeueOutputBufferIndex((bufferInfo))).isEqualTo(0);
|
||||
assertThat(areEqual(bufferInfo, enqueuedBufferInfo)).isTrue();
|
||||
assertBufferInfosEqual(enqueuedBufferInfo, bufferInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -190,8 +181,7 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueOutputBufferIndex_withFlushCompletedAndOutputBuffer_returnsOutputBuffer()
|
||||
throws InterruptedException {
|
||||
public void dequeueOutputBufferIndex_withFlushCompletedAndOutputBuffer_returnsOutputBuffer() {
|
||||
adapter.start();
|
||||
Looper looper = handlerThread.getLooper();
|
||||
Handler handler = new Handler(looper);
|
||||
@ -208,10 +198,10 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
lastBufferInfo.presentationTimeUs = 10;
|
||||
handler.post(() -> adapter.onOutputBufferAvailable(codec, 10, lastBufferInfo));
|
||||
|
||||
// Wait until all tasks have been handled
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
// Wait until all tasks have been handled.
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThat(adapter.dequeueOutputBufferIndex(bufferInfo)).isEqualTo(10);
|
||||
assertThat(areEqual(bufferInfo, lastBufferInfo)).isTrue();
|
||||
assertBufferInfosEqual(lastBufferInfo, bufferInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -250,7 +240,7 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOutputFormat_afterFlush_returnsPreviousFormat() throws InterruptedException {
|
||||
public void getOutputFormat_afterFlush_returnsPreviousFormat() {
|
||||
MediaFormat format = new MediaFormat();
|
||||
adapter.start();
|
||||
adapter.onOutputFormatChanged(codec, format);
|
||||
@ -260,15 +250,14 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
assertThat(adapter.getOutputFormat()).isEqualTo(format);
|
||||
|
||||
adapter.flush();
|
||||
assertThat(
|
||||
waitUntilAllEventsAreExecuted(
|
||||
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
|
||||
.isTrue();
|
||||
|
||||
// Wait until all tasks have been handled.
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThat(adapter.getOutputFormat()).isEqualTo(format);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void flush_multipleTimes_onlyLastFlushExecutes() throws InterruptedException {
|
||||
public void flush_multipleTimes_onlyLastFlushExecutes() {
|
||||
AtomicInteger codecStartCalls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(() -> codecStartCalls.incrementAndGet());
|
||||
adapter.start();
|
||||
@ -290,22 +279,22 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
}
|
||||
assertThat(codecStartCalls.get()).isEqualTo(1);
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
// Wait until all tasks have been handled.
|
||||
shadowLooper.idle();
|
||||
assertThat(adapter.dequeueInputBufferIndex()).isEqualTo(3);
|
||||
assertThat(codecStartCalls.get()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void flush_andImmediatelyShutdown_flushIsNoOp() throws InterruptedException {
|
||||
public void flush_andImmediatelyShutdown_flushIsNoOp() {
|
||||
AtomicInteger onCodecStartCount = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(() -> onCodecStartCount.incrementAndGet());
|
||||
adapter.start();
|
||||
// Obtain looper when adapter is started
|
||||
Looper looper = handlerThread.getLooper();
|
||||
adapter.flush();
|
||||
adapter.shutdown();
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, 5, TimeUnit.SECONDS)).isTrue();
|
||||
// Wait until all tasks have been handled.
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
// Only adapter.start() calls onCodecStart.
|
||||
assertThat(onCodecStartCount.get()).isEqualTo(1);
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.mediacodec;
|
||||
|
||||
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.areEqual;
|
||||
import static com.google.android.exoplayer2.testutil.TestUtil.assertBufferInfosEqual;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@ -101,9 +101,9 @@ public class MediaCodecAsyncCallbackTest {
|
||||
MediaCodec.BufferInfo outBufferInfo = new MediaCodec.BufferInfo();
|
||||
|
||||
assertThat(mediaCodecAsyncCallback.dequeueOutputBufferIndex(outBufferInfo)).isEqualTo(0);
|
||||
assertThat(areEqual(outBufferInfo, bufferInfo1)).isTrue();
|
||||
assertBufferInfosEqual(bufferInfo1, outBufferInfo);
|
||||
assertThat(mediaCodecAsyncCallback.dequeueOutputBufferIndex(outBufferInfo)).isEqualTo(1);
|
||||
assertThat(areEqual(outBufferInfo, bufferInfo2)).isTrue();
|
||||
assertBufferInfosEqual(bufferInfo2, outBufferInfo);
|
||||
assertThat(mediaCodecAsyncCallback.dequeueOutputBufferIndex(outBufferInfo))
|
||||
.isEqualTo(MediaCodec.INFO_TRY_AGAIN_LATER);
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.mediacodec;
|
||||
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/** Testing utilities for MediaCodec related test classes */
|
||||
public class MediaCodecTestUtils {
|
||||
/**
|
||||
* Compares if two {@link android.media.MediaCodec.BufferInfo} are equal by inspecting {@link
|
||||
* android.media.MediaCodec.BufferInfo#flags}, {@link android.media.MediaCodec.BufferInfo#size},
|
||||
* {@link android.media.MediaCodec.BufferInfo#presentationTimeUs} and {@link
|
||||
* android.media.MediaCodec.BufferInfo#offset}.
|
||||
*/
|
||||
public static boolean areEqual(MediaCodec.BufferInfo lhs, MediaCodec.BufferInfo rhs) {
|
||||
return lhs.flags == rhs.flags
|
||||
&& lhs.offset == rhs.offset
|
||||
&& lhs.presentationTimeUs == rhs.presentationTimeUs
|
||||
&& lhs.size == rhs.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks until all events of a shadow looper are executed or the specified time elapses.
|
||||
*
|
||||
* @param looper the shadow looper
|
||||
* @param time the time to wait
|
||||
* @param unit the time units
|
||||
* @return true if all events are executed, false if the time elapsed.
|
||||
* @throws InterruptedException if the Thread was interrupted while waiting.
|
||||
*/
|
||||
public static boolean waitUntilAllEventsAreExecuted(Looper looper, long time, TimeUnit unit)
|
||||
throws InterruptedException {
|
||||
Handler handler = new Handler(looper);
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
handler.post(() -> latch.countDown());
|
||||
shadowOf(looper).idle();
|
||||
return latch.await(time, unit);
|
||||
}
|
||||
}
|
@ -16,8 +16,7 @@
|
||||
|
||||
package com.google.android.exoplayer2.mediacodec;
|
||||
|
||||
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.areEqual;
|
||||
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.waitUntilAllEventsAreExecuted;
|
||||
import static com.google.android.exoplayer2.testutil.TestUtil.assertBufferInfosEqual;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
@ -29,13 +28,13 @@ import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.shadows.ShadowLooper;
|
||||
|
||||
/** Unit tests for {@link MultiLockAsyncMediaCodecAdapter}. */
|
||||
@ -43,7 +42,7 @@ import org.robolectric.shadows.ShadowLooper;
|
||||
public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
private MultiLockAsyncMediaCodecAdapter adapter;
|
||||
private MediaCodec codec;
|
||||
private MediaCodec.BufferInfo bufferInfo = null;
|
||||
private MediaCodec.BufferInfo bufferInfo;
|
||||
private TestHandlerThread handlerThread;
|
||||
|
||||
@Before
|
||||
@ -81,10 +80,7 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
adapter.start();
|
||||
adapter.flush();
|
||||
|
||||
assertThat(
|
||||
waitUntilAllEventsAreExecuted(
|
||||
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
|
||||
.isTrue();
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThrows(IllegalStateException.class, () -> adapter.dequeueInputBufferIndex());
|
||||
}
|
||||
|
||||
@ -128,7 +124,7 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
handler.post(() -> adapter.onInputBufferAvailable(codec, 10));
|
||||
|
||||
// Wait until all tasks have been handled
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThat(adapter.dequeueInputBufferIndex()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@ -154,10 +150,7 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
adapter.start();
|
||||
adapter.flush();
|
||||
|
||||
assertThat(
|
||||
waitUntilAllEventsAreExecuted(
|
||||
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
|
||||
.isTrue();
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThrows(IllegalStateException.class, () -> adapter.dequeueOutputBufferIndex(bufferInfo));
|
||||
}
|
||||
|
||||
@ -176,7 +169,7 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
adapter.onOutputBufferAvailable(codec, 0, enqueuedBufferInfo);
|
||||
|
||||
assertThat(adapter.dequeueOutputBufferIndex((bufferInfo))).isEqualTo(0);
|
||||
assertThat(areEqual(bufferInfo, enqueuedBufferInfo)).isTrue();
|
||||
assertBufferInfosEqual(enqueuedBufferInfo, bufferInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -209,9 +202,9 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
handler.post(() -> adapter.onOutputBufferAvailable(codec, 10, lastBufferInfo));
|
||||
|
||||
// Wait until all tasks have been handled
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThat(adapter.dequeueOutputBufferIndex(bufferInfo)).isEqualTo(10);
|
||||
assertThat(areEqual(bufferInfo, lastBufferInfo)).isTrue();
|
||||
assertBufferInfosEqual(lastBufferInfo, bufferInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -250,7 +243,7 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOutputFormat_afterFlush_returnsPreviousFormat() throws InterruptedException {
|
||||
public void getOutputFormat_afterFlush_returnsPreviousFormat() {
|
||||
MediaFormat format = new MediaFormat();
|
||||
adapter.start();
|
||||
adapter.onOutputFormatChanged(codec, format);
|
||||
@ -260,15 +253,12 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
assertThat(adapter.getOutputFormat()).isEqualTo(format);
|
||||
|
||||
adapter.flush();
|
||||
assertThat(
|
||||
waitUntilAllEventsAreExecuted(
|
||||
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
|
||||
.isTrue();
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
assertThat(adapter.getOutputFormat()).isEqualTo(format);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void flush_multipleTimes_onlyLastFlushExecutes() throws InterruptedException {
|
||||
public void flush_multipleTimes_onlyLastFlushExecutes() {
|
||||
AtomicInteger codecStartCalls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(() -> codecStartCalls.incrementAndGet());
|
||||
adapter.start();
|
||||
@ -290,22 +280,20 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
}
|
||||
assertThat(codecStartCalls.get()).isEqualTo(1);
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
shadowLooper.idle();
|
||||
assertThat(adapter.dequeueInputBufferIndex()).isEqualTo(3);
|
||||
assertThat(codecStartCalls.get()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void flush_andImmediatelyShutdown_flushIsNoOp() throws InterruptedException {
|
||||
public void flush_andImmediatelyShutdown_flushIsNoOp() {
|
||||
AtomicInteger codecStartCalls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(() -> codecStartCalls.incrementAndGet());
|
||||
adapter.start();
|
||||
// Obtain looper when adapter is started.
|
||||
Looper looper = handlerThread.getLooper();
|
||||
adapter.flush();
|
||||
adapter.shutdown();
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, 5, TimeUnit.SECONDS)).isTrue();
|
||||
Shadows.shadowOf(handlerThread.getLooper()).idle();
|
||||
// Only adapter.start() called codec#start()
|
||||
assertThat(codecStartCalls.get()).isEqualTo(1);
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.database.DatabaseIOException;
|
||||
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
|
||||
import com.google.android.exoplayer2.database.VersionTable;
|
||||
import com.google.android.exoplayer2.testutil.DownloadBuilder;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -24,6 +24,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.offline.Download.State;
|
||||
import com.google.android.exoplayer2.scheduler.Requirements;
|
||||
import com.google.android.exoplayer2.testutil.DownloadBuilder;
|
||||
import com.google.android.exoplayer2.testutil.DummyMainThread;
|
||||
import com.google.android.exoplayer2.testutil.DummyMainThread.TestRunnable;
|
||||
import com.google.android.exoplayer2.testutil.TestDownloadManagerListener;
|
||||
|
@ -22,6 +22,7 @@ import static org.junit.Assert.fail;
|
||||
import android.net.Uri;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.IOException;
|
||||
import org.junit.Before;
|
||||
@ -45,7 +46,7 @@ public final class DataSchemeDataSourceTest {
|
||||
@Test
|
||||
public void testBase64Data() throws IOException {
|
||||
DataSpec dataSpec = buildDataSpec(DATA_SCHEME_URI);
|
||||
DataSourceAsserts.assertDataSourceContent(
|
||||
assertDataSourceContent(
|
||||
schemeDataDataSource,
|
||||
dataSpec,
|
||||
Util.getUtf8Bytes(
|
||||
@ -55,7 +56,7 @@ public final class DataSchemeDataSourceTest {
|
||||
|
||||
@Test
|
||||
public void testAsciiData() throws IOException {
|
||||
DataSourceAsserts.assertDataSourceContent(
|
||||
assertDataSourceContent(
|
||||
schemeDataDataSource,
|
||||
buildDataSpec("data:,A%20brief%20note"),
|
||||
Util.getUtf8Bytes("A brief note"));
|
||||
@ -78,22 +79,21 @@ public final class DataSchemeDataSourceTest {
|
||||
public void testSequentialRangeRequests() throws IOException {
|
||||
DataSpec dataSpec =
|
||||
buildDataSpec(DATA_SCHEME_URI, /* position= */ 1, /* length= */ C.LENGTH_UNSET);
|
||||
DataSourceAsserts.assertDataSourceContent(
|
||||
assertDataSourceContent(
|
||||
schemeDataDataSource,
|
||||
dataSpec,
|
||||
Util.getUtf8Bytes(
|
||||
"\"provider\":\"widevine_test\",\"content_id\":\"MjAxNV90ZWFycw==\",\"key_ids\":"
|
||||
+ "[\"00000000000000000000000000000000\"]}"));
|
||||
dataSpec = buildDataSpec(DATA_SCHEME_URI, /* position= */ 10, /* length= */ C.LENGTH_UNSET);
|
||||
DataSourceAsserts.assertDataSourceContent(
|
||||
assertDataSourceContent(
|
||||
schemeDataDataSource,
|
||||
dataSpec,
|
||||
Util.getUtf8Bytes(
|
||||
"\":\"widevine_test\",\"content_id\":\"MjAxNV90ZWFycw==\",\"key_ids\":"
|
||||
+ "[\"00000000000000000000000000000000\"]}"));
|
||||
dataSpec = buildDataSpec(DATA_SCHEME_URI, /* position= */ 15, /* length= */ 5);
|
||||
DataSourceAsserts.assertDataSourceContent(
|
||||
schemeDataDataSource, dataSpec, Util.getUtf8Bytes("devin"));
|
||||
assertDataSourceContent(schemeDataDataSource, dataSpec, Util.getUtf8Bytes("devin"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -154,4 +154,23 @@ public final class DataSchemeDataSourceTest {
|
||||
return new DataSpec(Uri.parse(uriString), position, length, /* key= */ null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that data read from a {@link DataSource} matches {@code expected}.
|
||||
*
|
||||
* @param dataSource The {@link DataSource} through which to read.
|
||||
* @param dataSpec The {@link DataSpec} to use when opening the {@link DataSource}.
|
||||
* @param expectedData The expected data.
|
||||
* @throws IOException If an error occurs reading fom the {@link DataSource}.
|
||||
*/
|
||||
private static void assertDataSourceContent(
|
||||
DataSource dataSource, DataSpec dataSpec, byte[] expectedData) throws IOException {
|
||||
try {
|
||||
long length = dataSource.open(dataSpec);
|
||||
assertThat(length).isEqualTo(expectedData.length);
|
||||
byte[] readData = TestUtil.readToEnd(dataSource);
|
||||
assertThat(readData).isEqualTo(expectedData);
|
||||
} finally {
|
||||
dataSource.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,50 +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.upstream;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Assertions for data source tests.
|
||||
*/
|
||||
/* package */ final class DataSourceAsserts {
|
||||
|
||||
/**
|
||||
* Asserts that data read from a {@link DataSource} matches {@code expected}.
|
||||
*
|
||||
* @param dataSource The {@link DataSource} through which to read.
|
||||
* @param dataSpec The {@link DataSpec} to use when opening the {@link DataSource}.
|
||||
* @param expectedData The expected data.
|
||||
* @throws IOException If an error occurs reading fom the {@link DataSource}.
|
||||
*/
|
||||
public static void assertDataSourceContent(DataSource dataSource, DataSpec dataSpec,
|
||||
byte[] expectedData) throws IOException {
|
||||
try {
|
||||
long length = dataSource.open(dataSpec);
|
||||
assertThat(length).isEqualTo(expectedData.length);
|
||||
byte[] readData = TestUtil.readToEnd(dataSource);
|
||||
assertThat(readData).isEqualTo(expectedData);
|
||||
} finally {
|
||||
dataSource.close();
|
||||
}
|
||||
}
|
||||
|
||||
private DataSourceAsserts() {}
|
||||
|
||||
}
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.upstream.cache;
|
||||
|
||||
import static com.google.android.exoplayer2.testutil.TestUtil.createTestFile;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
@ -103,12 +104,9 @@ public class CachedContentIndexTest {
|
||||
// add a span
|
||||
int cacheFileLength = 20;
|
||||
File cacheSpanFile =
|
||||
SimpleCacheSpanTest.createCacheSpanFile(
|
||||
cacheDir,
|
||||
cachedContent1.id,
|
||||
/* offset= */ 10,
|
||||
cacheFileLength,
|
||||
/* lastTouchTimestamp= */ 30);
|
||||
SimpleCacheSpan.getCacheFile(
|
||||
cacheDir, cachedContent1.id, /* position= */ 10, /* timestamp= */ 30);
|
||||
createTestFile(cacheSpanFile, cacheFileLength);
|
||||
SimpleCacheSpan span = SimpleCacheSpan.createCacheEntry(cacheSpanFile, cacheFileLength, index);
|
||||
assertThat(span).isNotNull();
|
||||
cachedContent1.addSpan(span);
|
||||
@ -288,12 +286,9 @@ public class CachedContentIndexTest {
|
||||
CachedContent cachedContent = index.getOrAdd("key1");
|
||||
long cacheFileLength = 20;
|
||||
File cacheFile =
|
||||
SimpleCacheSpanTest.createCacheSpanFile(
|
||||
cacheDir,
|
||||
cachedContent.id,
|
||||
/* offset= */ 10,
|
||||
cacheFileLength,
|
||||
/* lastTouchTimestamp= */ 30);
|
||||
SimpleCacheSpan.getCacheFile(
|
||||
cacheDir, cachedContent.id, /* position= */ 10, /* timestamp= */ 30);
|
||||
createTestFile(cacheFile, cacheFileLength);
|
||||
SimpleCacheSpan span = SimpleCacheSpan.createCacheEntry(cacheFile, cacheFileLength, index);
|
||||
cachedContent.addSpan(span);
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.upstream.cache;
|
||||
|
||||
import static com.google.android.exoplayer2.testutil.TestUtil.createTestFile;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
@ -24,7 +25,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
@ -37,13 +37,6 @@ import org.junit.runner.RunWith;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class SimpleCacheSpanTest {
|
||||
|
||||
public static File createCacheSpanFile(
|
||||
File cacheDir, int id, long offset, long length, long lastTouchTimestamp) throws IOException {
|
||||
File cacheFile = SimpleCacheSpan.getCacheFile(cacheDir, id, offset, lastTouchTimestamp);
|
||||
createTestFile(cacheFile, length);
|
||||
return cacheFile;
|
||||
}
|
||||
|
||||
private CachedContentIndex index;
|
||||
private File cacheDir;
|
||||
|
||||
@ -82,10 +75,10 @@ public class SimpleCacheSpanTest {
|
||||
public void testUpgradeFileName() throws Exception {
|
||||
String key = "abc%def";
|
||||
int id = index.assignIdForKey(key);
|
||||
File v3file = createTestFile(id + ".0.1.v3.exo");
|
||||
File v2file = createTestFile("abc%25def.1.2.v2.exo"); // %25 is '%' after escaping
|
||||
File wrongEscapedV2file = createTestFile("abc%2Gdef.3.4.v2.exo"); // 2G is invalid hex
|
||||
File v1File = createTestFile("abc%def.5.6.v1.exo"); // V1 did not escape
|
||||
File v3file = createTestFile(cacheDir, id + ".0.1.v3.exo");
|
||||
File v2file = createTestFile(cacheDir, "abc%25def.1.2.v2.exo"); // %25 is '%' after escaping
|
||||
File wrongEscapedV2file = createTestFile(cacheDir, "abc%2Gdef.3.4.v2.exo"); // 2G is invalid hex
|
||||
File v1File = createTestFile(cacheDir, "abc%def.5.6.v1.exo"); // V1 did not escape
|
||||
|
||||
for (File file : cacheDir.listFiles()) {
|
||||
SimpleCacheSpan cacheEntry = SimpleCacheSpan.createCacheEntry(file, file.length(), index);
|
||||
@ -125,26 +118,12 @@ public class SimpleCacheSpanTest {
|
||||
assertThat(cachedPositions.get(5)).isEqualTo(6);
|
||||
}
|
||||
|
||||
private static void createTestFile(File file, long length) throws IOException {
|
||||
FileOutputStream output = new FileOutputStream(file);
|
||||
for (int i = 0; i < length; i++) {
|
||||
output.write(i);
|
||||
}
|
||||
output.close();
|
||||
}
|
||||
|
||||
private File createTestFile(String name) throws IOException {
|
||||
File file = new File(cacheDir, name);
|
||||
createTestFile(file, 1);
|
||||
return file;
|
||||
}
|
||||
|
||||
private void assertCacheSpan(String key, long offset, long lastTouchTimestamp)
|
||||
throws IOException {
|
||||
int id = index.assignIdForKey(key);
|
||||
long cacheFileLength = 1;
|
||||
File cacheFile = createCacheSpanFile(cacheDir, id, offset, cacheFileLength, lastTouchTimestamp);
|
||||
SimpleCacheSpan cacheSpan = SimpleCacheSpan.createCacheEntry(cacheFile, cacheFileLength, index);
|
||||
File cacheFile = SimpleCacheSpan.getCacheFile(cacheDir, id, offset, lastTouchTimestamp);
|
||||
createTestFile(cacheFile, /* length= */ 1);
|
||||
SimpleCacheSpan cacheSpan = SimpleCacheSpan.createCacheEntry(cacheFile, /* length= */ 1, index);
|
||||
String message = cacheFile.toString();
|
||||
assertWithMessage(message).that(cacheSpan).isNotNull();
|
||||
assertWithMessage(message).that(cacheFile.getParentFile()).isEqualTo(cacheDir);
|
||||
|
@ -13,11 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.offline;
|
||||
package com.google.android.exoplayer2.testutil;
|
||||
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.offline.Download;
|
||||
import com.google.android.exoplayer2.offline.DownloadProgress;
|
||||
import com.google.android.exoplayer2.offline.DownloadRequest;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -29,7 +33,7 @@ import java.util.List;
|
||||
* creation for tests. Tests must avoid depending on the default values but explicitly set tested
|
||||
* parameters during test initialization.
|
||||
*/
|
||||
/* package */ final class DownloadBuilder {
|
||||
public final class DownloadBuilder {
|
||||
|
||||
private final DownloadProgress progress;
|
||||
|
||||
@ -47,7 +51,12 @@ import java.util.List;
|
||||
private int stopReason;
|
||||
private int failureReason;
|
||||
|
||||
/* package */ DownloadBuilder(String id) {
|
||||
/**
|
||||
* Creates a download builder for "uri" with type "type" and no stream keys.
|
||||
*
|
||||
* @param id The unique content identifier for the download.
|
||||
*/
|
||||
public DownloadBuilder(String id) {
|
||||
this(
|
||||
id,
|
||||
"type",
|
||||
@ -57,7 +66,12 @@ import java.util.List;
|
||||
new byte[0]);
|
||||
}
|
||||
|
||||
/* package */ DownloadBuilder(DownloadRequest request) {
|
||||
/**
|
||||
* Creates a download builder based on the attributes of the specified request.
|
||||
*
|
||||
* @param request A {@link DownloadRequest} defining the content to download.
|
||||
*/
|
||||
public DownloadBuilder(DownloadRequest request) {
|
||||
this(
|
||||
request.id,
|
||||
request.type,
|
||||
@ -67,12 +81,13 @@ import java.util.List;
|
||||
request.data);
|
||||
}
|
||||
|
||||
/* package */ DownloadBuilder(
|
||||
/** Creates a download builder. */
|
||||
private DownloadBuilder(
|
||||
String id,
|
||||
String type,
|
||||
Uri uri,
|
||||
List<StreamKey> streamKeys,
|
||||
String cacheKey,
|
||||
@Nullable String cacheKey,
|
||||
byte[] customMetadata) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
@ -86,76 +101,85 @@ import java.util.List;
|
||||
this.progress = new DownloadProgress();
|
||||
}
|
||||
|
||||
public DownloadBuilder setId(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see DownloadRequest#type */
|
||||
public DownloadBuilder setType(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see DownloadRequest#uri */
|
||||
public DownloadBuilder setUri(String uri) {
|
||||
this.uri = Uri.parse(uri);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see DownloadRequest#uri */
|
||||
public DownloadBuilder setUri(Uri uri) {
|
||||
this.uri = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see DownloadRequest#customCacheKey */
|
||||
public DownloadBuilder setCacheKey(@Nullable String cacheKey) {
|
||||
this.cacheKey = cacheKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see Download#state */
|
||||
public DownloadBuilder setState(@Download.State int state) {
|
||||
this.state = state;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see DownloadProgress#percentDownloaded */
|
||||
public DownloadBuilder setPercentDownloaded(float percentDownloaded) {
|
||||
progress.percentDownloaded = percentDownloaded;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see DownloadProgress#bytesDownloaded */
|
||||
public DownloadBuilder setBytesDownloaded(long bytesDownloaded) {
|
||||
progress.bytesDownloaded = bytesDownloaded;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see Download#contentLength */
|
||||
public DownloadBuilder setContentLength(long contentLength) {
|
||||
this.contentLength = contentLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see Download#failureReason */
|
||||
public DownloadBuilder setFailureReason(int failureReason) {
|
||||
this.failureReason = failureReason;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see Download#stopReason */
|
||||
public DownloadBuilder setStopReason(int stopReason) {
|
||||
this.stopReason = stopReason;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see Download#startTimeMs */
|
||||
public DownloadBuilder setStartTimeMs(long startTimeMs) {
|
||||
this.startTimeMs = startTimeMs;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see Download#updateTimeMs */
|
||||
public DownloadBuilder setUpdateTimeMs(long updateTimeMs) {
|
||||
this.updateTimeMs = updateTimeMs;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see DownloadRequest#streamKeys */
|
||||
public DownloadBuilder setStreamKeys(StreamKey... streamKeys) {
|
||||
this.streamKeys = Arrays.asList(streamKeys);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see DownloadRequest#data */
|
||||
public DownloadBuilder setCustomMetadata(byte[] customMetadata) {
|
||||
this.customMetadata = customMetadata;
|
||||
return this;
|
@ -24,6 +24,7 @@ import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.media.MediaCodec;
|
||||
import android.net.Uri;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.database.DatabaseProvider;
|
||||
@ -37,6 +38,8 @@ import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
@ -180,6 +183,26 @@ public class TestUtil {
|
||||
return joined;
|
||||
}
|
||||
|
||||
/** Writes one byte long dummy test data to the file and returns it. */
|
||||
public static File createTestFile(File directory, String name) throws IOException {
|
||||
return createTestFile(directory, name, /* length= */ 1);
|
||||
}
|
||||
|
||||
/** Writes dummy test data with the specified length to the file and returns it. */
|
||||
public static File createTestFile(File directory, String name, long length) throws IOException {
|
||||
return createTestFile(new File(directory, name), length);
|
||||
}
|
||||
|
||||
/** Writes dummy test data with the specified length to the file and returns it. */
|
||||
public static File createTestFile(File file, long length) throws IOException {
|
||||
FileOutputStream output = new FileOutputStream(file);
|
||||
for (long i = 0; i < length; i++) {
|
||||
output.write((int) i);
|
||||
}
|
||||
output.close();
|
||||
return file;
|
||||
}
|
||||
|
||||
/** Returns the bytes of an asset file. */
|
||||
public static byte[] getByteArray(Context context, String fileName) throws IOException {
|
||||
return Util.toByteArray(getInputStream(context, fileName));
|
||||
@ -240,6 +263,15 @@ public class TestUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns whether two {@link android.media.MediaCodec.BufferInfo BufferInfos} are equal. */
|
||||
public static void assertBufferInfosEqual(
|
||||
MediaCodec.BufferInfo expected, MediaCodec.BufferInfo actual) {
|
||||
assertThat(expected.flags).isEqualTo(actual.flags);
|
||||
assertThat(expected.offset).isEqualTo(actual.offset);
|
||||
assertThat(expected.presentationTimeUs).isEqualTo(actual.presentationTimeUs);
|
||||
assertThat(expected.size).isEqualTo(actual.size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts whether actual bitmap is very similar to the expected bitmap at some quality level.
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user