Push tests.

This commit is contained in:
Oliver Woodman 2015-03-06 16:39:00 +00:00
parent 462fea3eaf
commit fbd0a57e5c
37 changed files with 3057 additions and 0 deletions

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="src" path="java"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry combineaccessrules="false" kind="src" path="/ExoPlayerDemo"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

62
library/src/test/.project Normal file
View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ExoPlayerTests</name>
<comment></comment>
<projects>
<project>ExoPlayerLib</project>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
<linkedResources>
<link>
<name>libs/dexmaker-1.2.jar</name>
<type>1</type>
<locationURI>$%7BPARENT-3-PROJECT_LOC%7D/third_party/dexmaker/dexmaker-1.2.jar</locationURI>
</link>
<link>
<name>libs/dexmaker-mockito-1.2.jar</name>
<type>1</type>
<locationURI>$%7BPARENT-3-PROJECT_LOC%7D/third_party/dexmaker/dexmaker-mockito-1.2.jar</locationURI>
</link>
<link>
<name>libs/mockito-all-1.9.5.jar</name>
<type>1</type>
<locationURI>$%7BPARENT-3-PROJECT_LOC%7D/third_party/mockito/mockito-all-1.9.5.jar</locationURI>
</link>
</linkedResources>
<filteredResources>
<filter>
<id>1425657306619</id>
<name></name>
<type>14</type>
<matcher>
<id>org.eclipse.ui.ide.multiFilter</id>
<arguments>1.0-name-matches-true-false-BUILD</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.exoplayer.tests">
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="21"/>
<application>
<uses-library android:name="android.test.runner"/>
</application>
<instrumentation
android:targetPackage="com.google.android.exoplayer.demo"
android:name="android.test.InstrumentationTestRunner"/>
</manifest>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
availabilityStartTime="2014-06-19T23:07:42"
minBufferTime="PT1.500S"
minimumUpdatePeriod="PT5.000S"
profiles="urn:mpeg:dash:profile:isoff-main:2011"
timeShiftBufferDepth="PT129600.000S"
type="dynamic"
xmlns="urn:mpeg:DASH:schema:MPD:2011"
xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd"
yt:earliestMediaSequence="1266404" >
<Period start="PT6462826.784S" >
<SegmentList
presentationTimeOffset="34740095"
startNumber="1292317"
timescale="1000" >
<SegmentTimeline>
<S d="4804" />
<S d="5338" />
<S d="4938" />
</SegmentTimeline>
</SegmentList>
<AdaptationSet
mimeType="audio/mp4"
subsegmentAlignment="true" >
<Role
schemeIdUri="urn:mpeg:DASH:role:2011"
value="main" />
<Representation
id="141"
audioSamplingRate="48000"
bandwidth="272000"
codecs="mp4a.40.2"
startWithSAP="1" >
<AudioChannelConfiguration
schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011"
value="2" />
<BaseURL>
http://www.test.com/141
</BaseURL>
<SegmentList>
<Initialization
range="0-591"
sourceURL="sq/0/clen/79480/lmt/1403219262956762/dur/4.805" />
<SegmentURL media="sq/1292317/clen/77447/lmt/1409671169987621/dur/4.805" />
<SegmentURL media="sq/1292318/clen/86958/lmt/1409671174832549/dur/5.339" />
<SegmentURL media="sq/1292319/clen/85018/lmt/1409671179719956/dur/4.938" />
</SegmentList>
</Representation>
</AdaptationSet>
<AdaptationSet
mimeType="video/mp4"
subsegmentAlignment="true" >
<Role
schemeIdUri="urn:mpeg:DASH:role:2011"
value="main" />
<Representation
id="135"
bandwidth="1116000"
codecs="avc1.42c01f"
height="480"
startWithSAP="1"
width="854" >
<BaseURL>
http://www.test.com/135
</BaseURL>
<SegmentList>
<Initialization
range="0-671"
sourceURL="sq/0/clen/1221137/lmt/1403219262956762/dur/4.805" />
<SegmentURL media="sq/1292317/clen/1279915/lmt/1409671169987621/dur/4.805" />
<SegmentURL media="sq/1292318/clen/1310650/lmt/1409671174832549/dur/5.339" />
<SegmentURL media="sq/1292319/clen/1486558/lmt/1409671179719956/dur/4.938" />
</SegmentList>
</Representation>
</AdaptationSet>
<AdaptationSet
lang="en"
mimeType="text/vtt" >
<Role
schemeIdUri="urn:mpeg:DASH:role:2011"
value="caption" />
<Representation
id="en"
bandwidth="0"
codecs="" >
<BaseURL>
http://www.test.com/vtt
</BaseURL>
<SegmentList>
<SegmentURL media="sq/1292317" />
<SegmentURL media="sq/1292318" />
<SegmentURL media="sq/1292319" />
</SegmentList>
</Representation>
</AdaptationSet>
</Period>
</MPD>

Binary file not shown.

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,8 @@
WEBVTT
X-TIMESTAMP-MAP=LOCAL:00:00.000,MPEGTS:450000
00:00.000 --> 00:01.234
This is the first subtitle.
00:02.345 --> 00:03.456
This is the second subtitle.

View File

@ -0,0 +1,10 @@
WEBVTT
X-TIMESTAMP-MAP=LOCAL:00:00.000,MPEGTS:450000
1
00:00.000 --> 00:01.234
This is the first subtitle.
2
00:02.345 --> 00:03.456
This is the second subtitle.

View File

@ -0,0 +1,14 @@
WEBVTT
X-TIMESTAMP-MAP=LOCAL:00:00.000,MPEGTS:450000
00:00.000 --> 00:01.234
This is the <i>first</i> subtitle.
00:02.345 --> 00:03.456
This is the <b><i>second</b></i> subtitle.
00:04.000 --> 00:05.000
This is the <c.red.caps>third</c> subtitle.
00:06.000 --> 00:07.000
This is&nbsp;the &lt;fourth&gt; &amp;subtitle.

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2014 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.exoplayer;
import com.google.android.exoplayer.util.Util;
import android.annotation.TargetApi;
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.List;
/**
* Unit test for {@link MediaFormat}.
*/
public class MediaFormatTest extends TestCase {
public void testConversionToFrameworkFormat() {
if (Util.SDK_INT < 16) {
// Test doesn't apply.
return;
}
byte[] initData1 = new byte[] {1, 2, 3};
byte[] initData2 = new byte[] {4, 5, 6};
List<byte[]> initData = new ArrayList<byte[]>();
initData.add(initData1);
initData.add(initData2);
testConversionToFrameworkFormatV16(
MediaFormat.createVideoFormat("video/xyz", 102400, 1280, 720, 1.5f, initData));
testConversionToFrameworkFormatV16(
MediaFormat.createAudioFormat("audio/xyz", 102400, 5, 44100, initData));
}
@TargetApi(16)
private void testConversionToFrameworkFormatV16(MediaFormat format) {
// Convert to a framework MediaFormat and back again.
MediaFormat convertedFormat = MediaFormat.createFromFrameworkMediaFormatV16(
format.getFrameworkMediaFormatV16());
// Assert that we end up with an equivalent object to the one we started with.
assertEquals(format.hashCode(), convertedFormat.hashCode());
assertEquals(format, convertedFormat);
}
}

View File

@ -0,0 +1,350 @@
/*
* Copyright (C) 2014 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.exoplayer.chunk.parser.webm;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.upstream.ByteArrayNonBlockingInputStream;
import com.google.android.exoplayer.upstream.NonBlockingInputStream;
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Tests {@link DefaultEbmlReader}.
*/
public class DefaultEbmlReaderTest extends TestCase {
private final EventCapturingEbmlEventHandler eventHandler =
new EventCapturingEbmlEventHandler();
public void testNothing() {
NonBlockingInputStream input = createTestInputStream();
assertNoEvents(input, EbmlReader.READ_RESULT_END_OF_STREAM);
}
public void testMasterElement() {
NonBlockingInputStream input =
createTestInputStream(0x1A, 0x45, 0xDF, 0xA3, 0x84, 0x42, 0x85, 0x81, 0x01);
EventCapturingEbmlEventHandler expected = new EventCapturingEbmlEventHandler();
expected.onMasterElementStart(EventCapturingEbmlEventHandler.ID_EBML, 0, 5, 4);
expected.onIntegerElement(EventCapturingEbmlEventHandler.ID_DOC_TYPE_READ_VERSION, 1);
expected.onMasterElementEnd(EventCapturingEbmlEventHandler.ID_EBML);
assertEvents(input, EbmlReader.READ_RESULT_END_OF_STREAM, expected.events);
}
public void testMasterElementEmpty() {
NonBlockingInputStream input = createTestInputStream(0x18, 0x53, 0x80, 0x67, 0x80);
EventCapturingEbmlEventHandler expected = new EventCapturingEbmlEventHandler();
expected.onMasterElementStart(EventCapturingEbmlEventHandler.ID_SEGMENT, 0, 5, 0);
expected.onMasterElementEnd(EventCapturingEbmlEventHandler.ID_SEGMENT);
assertEvents(input, EbmlReader.READ_RESULT_END_OF_STREAM, expected.events);
}
public void testUnsignedIntegerElement() {
// 0xFE is chosen because for signed integers it should be interpreted as -2
NonBlockingInputStream input = createTestInputStream(0x42, 0xF7, 0x81, 0xFE);
EventCapturingEbmlEventHandler expected = new EventCapturingEbmlEventHandler();
expected.onIntegerElement(EventCapturingEbmlEventHandler.ID_EBML_READ_VERSION, 254);
assertEvents(input, EbmlReader.READ_RESULT_END_OF_STREAM, expected.events);
}
public void testUnsignedIntegerElementLarge() {
NonBlockingInputStream input =
createTestInputStream(0x42, 0xF7, 0x88, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
EventCapturingEbmlEventHandler expected = new EventCapturingEbmlEventHandler();
expected.onIntegerElement(EventCapturingEbmlEventHandler.ID_EBML_READ_VERSION, Long.MAX_VALUE);
assertEvents(input, EbmlReader.READ_RESULT_END_OF_STREAM, expected.events);
}
public void testUnsignedIntegerElementTooLargeBecomesNegative() {
NonBlockingInputStream input =
createTestInputStream(0x42, 0xF7, 0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
EventCapturingEbmlEventHandler expected = new EventCapturingEbmlEventHandler();
expected.onIntegerElement(EventCapturingEbmlEventHandler.ID_EBML_READ_VERSION, -1);
assertEvents(input, EbmlReader.READ_RESULT_END_OF_STREAM, expected.events);
}
public void testStringElement() {
NonBlockingInputStream input =
createTestInputStream(0x42, 0x82, 0x86, 0x41, 0x62, 0x63, 0x31, 0x32, 0x33);
EventCapturingEbmlEventHandler expected = new EventCapturingEbmlEventHandler();
expected.onStringElement(EventCapturingEbmlEventHandler.ID_DOC_TYPE, "Abc123");
assertEvents(input, EbmlReader.READ_RESULT_END_OF_STREAM, expected.events);
}
public void testStringElementEmpty() {
NonBlockingInputStream input = createTestInputStream(0x42, 0x82, 0x80);
EventCapturingEbmlEventHandler expected = new EventCapturingEbmlEventHandler();
expected.onStringElement(EventCapturingEbmlEventHandler.ID_DOC_TYPE, "");
assertEvents(input, EbmlReader.READ_RESULT_END_OF_STREAM, expected.events);
}
public void testFloatElementThreeBytes() {
try {
eventHandler.read(createTestInputStream(0x44, 0x89, 0x83, 0x3F, 0x80, 0x00));
fail();
} catch (IllegalStateException exception) {
// Expected
}
assertNoEvents();
}
public void testFloatElementFourBytes() {
NonBlockingInputStream input =
createTestInputStream(0x44, 0x89, 0x84, 0x3F, 0x80, 0x00, 0x00);
EventCapturingEbmlEventHandler expected = new EventCapturingEbmlEventHandler();
expected.onFloatElement(EventCapturingEbmlEventHandler.ID_DURATION, 1.0);
assertEvents(input, EbmlReader.READ_RESULT_END_OF_STREAM, expected.events);
}
public void testFloatElementEightBytes() {
NonBlockingInputStream input =
createTestInputStream(0x44, 0x89, 0x88, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
EventCapturingEbmlEventHandler expected = new EventCapturingEbmlEventHandler();
expected.onFloatElement(EventCapturingEbmlEventHandler.ID_DURATION, -2.0);
assertEvents(input, EbmlReader.READ_RESULT_END_OF_STREAM, expected.events);
}
public void testBinaryElementReadBytes() {
eventHandler.binaryElementHandler = EventCapturingEbmlEventHandler.HANDLER_READ_BYTES;
NonBlockingInputStream input =
createTestInputStream(0xA3, 0x88, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08);
EventCapturingEbmlEventHandler expected = new EventCapturingEbmlEventHandler();
expected.binaryElementHandler = EventCapturingEbmlEventHandler.HANDLER_READ_BYTES;
expected.onBinaryElement(
EventCapturingEbmlEventHandler.ID_SIMPLE_BLOCK, 0, 0, 8,
createTestInputStream(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08));
assertEvents(input, EbmlReader.READ_RESULT_END_OF_STREAM, expected.events);
}
public void testBinaryElementReadVarint() {
eventHandler.binaryElementHandler = EventCapturingEbmlEventHandler.HANDLER_READ_VARINT;
NonBlockingInputStream input = createTestInputStream(0xA3, 0x82, 0x40, 0x2A);
EventCapturingEbmlEventHandler expected = new EventCapturingEbmlEventHandler();
expected.binaryElementHandler = EventCapturingEbmlEventHandler.HANDLER_READ_VARINT;
expected.onBinaryElement(
EventCapturingEbmlEventHandler.ID_SIMPLE_BLOCK, 0, 0, 0,
createTestInputStream(0x40, 0x2A));
assertEvents(input, EbmlReader.READ_RESULT_END_OF_STREAM, expected.events);
}
public void testBinaryElementSkipBytes() {
eventHandler.binaryElementHandler = EventCapturingEbmlEventHandler.HANDLER_SKIP_BYTES;
NonBlockingInputStream input =
createTestInputStream(0xA3, 0x88, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08);
EventCapturingEbmlEventHandler expected = new EventCapturingEbmlEventHandler();
expected.binaryElementHandler = EventCapturingEbmlEventHandler.HANDLER_SKIP_BYTES;
expected.onBinaryElement(
EventCapturingEbmlEventHandler.ID_SIMPLE_BLOCK, 0, 0, 8,
createTestInputStream(0, 0, 0, 0, 0, 0, 0, 0));
assertEvents(input, EbmlReader.READ_RESULT_END_OF_STREAM, expected.events);
}
public void testBinaryElementDoNothing() {
eventHandler.binaryElementHandler = EventCapturingEbmlEventHandler.HANDLER_DO_NOTHING;
try {
eventHandler.read(
createTestInputStream(0xA3, 0x88, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08));
fail();
} catch (IllegalStateException exception) {
// Expected
}
assertNoEvents();
}
public void testBinaryElementNotEnoughBytes() {
NonBlockingInputStream input = createTestInputStream(0xA3, 0x88, 0x01, 0x02, 0x03);
assertNoEvents(input, EbmlReader.READ_RESULT_NEED_MORE_DATA);
}
public void testUnknownElement() {
NonBlockingInputStream input = createTestInputStream(0xEC, 0x81, 0x00);
assertNoEvents(input, EbmlReader.READ_RESULT_END_OF_STREAM);
}
/**
* Helper to build a {@link ByteArrayNonBlockingInputStream} quickly from zero or more
* integer arguments.
*
* <p>Each argument must be able to cast to a byte value.
*
* @param data Zero or more integers with values between {@code 0x00} and {@code 0xFF}
* @return A {@link ByteArrayNonBlockingInputStream} containing the given byte values
*/
private NonBlockingInputStream createTestInputStream(int... data) {
byte[] bytes = new byte[data.length];
for (int i = 0; i < data.length; i++) {
bytes[i] = (byte) data[i];
}
return new ByteArrayNonBlockingInputStream(bytes);
}
private void assertReads(NonBlockingInputStream input, int continues, int finalResult) {
for (int i = 0; i < continues; i++) {
assertEquals(EbmlReader.READ_RESULT_CONTINUE, eventHandler.read(input));
}
assertEquals(finalResult, eventHandler.read(input));
}
private void assertNoEvents() {
assertEvents(Collections.<String>emptyList());
}
private void assertEvents(List<String> events) {
assertEquals(events.size(), eventHandler.events.size());
for (int i = 0; i < events.size(); i++) {
assertEquals(events.get(i), eventHandler.events.get(i));
}
}
private void assertNoEvents(NonBlockingInputStream input, int finalResult) {
assertReads(input, 0, finalResult);
assertNoEvents();
}
private void assertEvents(NonBlockingInputStream input, int finalResult, List<String> events) {
assertReads(input, events.size(), finalResult);
assertEvents(events);
}
/**
* An {@link EbmlEventHandler} which captures all event callbacks made by
* {@link DefaultEbmlReader} for testing purposes.
*/
private static final class EventCapturingEbmlEventHandler implements EbmlEventHandler {
// Element IDs
private static final int ID_EBML = 0x1A45DFA3;
private static final int ID_EBML_READ_VERSION = 0x42F7;
private static final int ID_DOC_TYPE = 0x4282;
private static final int ID_DOC_TYPE_READ_VERSION = 0x4285;
private static final int ID_SEGMENT = 0x18538067;
private static final int ID_DURATION = 0x4489;
private static final int ID_SIMPLE_BLOCK = 0xA3;
// Various ways to handle things in onBinaryElement()
private static final int HANDLER_DO_NOTHING = 0;
private static final int HANDLER_READ_BYTES = 1;
private static final int HANDLER_READ_VARINT = 2;
private static final int HANDLER_SKIP_BYTES = 3;
private final EbmlReader reader = new DefaultEbmlReader();
private final List<String> events = new ArrayList<String>();
private int binaryElementHandler;
private EventCapturingEbmlEventHandler() {
reader.setEventHandler(this);
}
private int read(NonBlockingInputStream inputStream) {
try {
return reader.read(inputStream);
} catch (ParserException e) {
// should never happen.
fail();
return -1;
}
}
@Override
public int getElementType(int id) {
switch (id) {
case ID_EBML:
case ID_SEGMENT:
return EbmlReader.TYPE_MASTER;
case ID_EBML_READ_VERSION:
case ID_DOC_TYPE_READ_VERSION:
return EbmlReader.TYPE_UNSIGNED_INT;
case ID_DOC_TYPE:
return EbmlReader.TYPE_STRING;
case ID_SIMPLE_BLOCK:
return EbmlReader.TYPE_BINARY;
case ID_DURATION:
return EbmlReader.TYPE_FLOAT;
default:
return EbmlReader.TYPE_UNKNOWN;
}
}
@Override
public void onMasterElementStart(
int id, long elementOffset, int headerSize, long contentsSize) {
events.add(formatEvent(id, "start elementOffset=" + elementOffset
+ " headerSize=" + headerSize + " contentsSize=" + contentsSize));
}
@Override
public void onMasterElementEnd(int id) {
events.add(formatEvent(id, "end"));
}
@Override
public void onIntegerElement(int id, long value) {
events.add(formatEvent(id, "integer=" + String.valueOf(value)));
}
@Override
public void onFloatElement(int id, double value) {
events.add(formatEvent(id, "float=" + String.valueOf(value)));
}
@Override
public void onStringElement(int id, String value) {
events.add(formatEvent(id, "string=" + value));
}
@Override
public boolean onBinaryElement(
int id, long elementOffset, int headerSize, int contentsSize,
NonBlockingInputStream inputStream) {
switch (binaryElementHandler) {
case HANDLER_READ_BYTES:
byte[] bytes = new byte[contentsSize];
reader.readBytes(inputStream, bytes, contentsSize);
events.add(formatEvent(id, "bytes=" + Arrays.toString(bytes)));
break;
case HANDLER_READ_VARINT:
long value = reader.readVarint(inputStream);
events.add(formatEvent(id, "varint=" + String.valueOf(value)));
break;
case HANDLER_SKIP_BYTES:
reader.skipBytes(inputStream, contentsSize);
events.add(formatEvent(id, "skipped " + contentsSize + " byte(s)"));
break;
case HANDLER_DO_NOTHING:
default:
// pass
}
return true;
}
private static String formatEvent(int id, String event) {
return "[" + Integer.toHexString(id) + "] " + event;
}
}
}

View File

@ -0,0 +1,523 @@
/*
* Copyright (C) 2014 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.exoplayer.chunk.parser.webm;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.chunk.parser.SegmentIndex;
import com.google.android.exoplayer.upstream.ByteArrayNonBlockingInputStream;
import com.google.android.exoplayer.upstream.NonBlockingInputStream;
import com.google.android.exoplayer.util.MimeTypes;
import android.test.InstrumentationTestCase;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
public class WebmExtractorTest extends InstrumentationTestCase {
private static final int INFO_ELEMENT_BYTE_SIZE = 31;
private static final int TRACKS_ELEMENT_BYTE_SIZE = 48;
private static final int CUES_ELEMENT_BYTE_SIZE = 12;
private static final int CUE_POINT_ELEMENT_BYTE_SIZE = 31;
private static final int DEFAULT_TIMECODE_SCALE = 1000000;
private static final long TEST_DURATION_US = 9920000L;
private static final int TEST_WIDTH = 1280;
private static final int TEST_HEIGHT = 720;
private static final int TEST_CHANNEL_COUNT = 1;
private static final int TEST_SAMPLE_RATE = 48000;
private static final long TEST_CODEC_DELAY = 6500000;
private static final long TEST_SEEK_PRE_ROLL = 80000000;
private static final int TEST_OPUS_CODEC_PRIVATE_SIZE = 2;
private static final String TEST_VORBIS_CODEC_PRIVATE = "webm/vorbis_codec_private";
private static final int TEST_VORBIS_INFO_SIZE = 30;
private static final int TEST_VORBIS_BOOKS_SIZE = 4140;
private static final int ID_VP9 = 0;
private static final int ID_OPUS = 1;
private static final int ID_VORBIS = 2;
private static final int EXPECTED_INIT_RESULT = WebmExtractor.RESULT_READ_INIT
| WebmExtractor.RESULT_READ_INDEX | WebmExtractor.RESULT_END_OF_STREAM;
private static final int EXPECTED_INIT_AND_SAMPLE_RESULT = WebmExtractor.RESULT_READ_INIT
| WebmExtractor.RESULT_READ_INDEX | WebmExtractor.RESULT_READ_SAMPLE;
private final WebmExtractor extractor = new WebmExtractor();
private final SampleHolder sampleHolder =
new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_DISABLED);
@Override
public void setUp() {
sampleHolder.data = ByteBuffer.allocate(1024);
}
public void testPrepare() throws ParserException {
NonBlockingInputStream testInputStream = new ByteArrayNonBlockingInputStream(
createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE, ID_VP9));
assertEquals(EXPECTED_INIT_RESULT, extractor.read(testInputStream, sampleHolder));
assertFormat();
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
}
public void testPrepareOpus() throws ParserException {
NonBlockingInputStream testInputStream = new ByteArrayNonBlockingInputStream(
createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE, ID_OPUS));
assertEquals(EXPECTED_INIT_RESULT, extractor.read(testInputStream, sampleHolder));
assertAudioFormat(ID_OPUS);
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
}
public void testPrepareVorbis() throws ParserException {
NonBlockingInputStream testInputStream = new ByteArrayNonBlockingInputStream(
createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE, ID_VORBIS));
assertEquals(EXPECTED_INIT_RESULT, extractor.read(testInputStream, sampleHolder));
assertAudioFormat(ID_VORBIS);
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
}
public void testPrepareThreeCuePoints() throws ParserException {
NonBlockingInputStream testInputStream = new ByteArrayNonBlockingInputStream(
createInitializationSegment(3, 0, true, DEFAULT_TIMECODE_SCALE, ID_VP9));
assertEquals(EXPECTED_INIT_RESULT, extractor.read(testInputStream, sampleHolder));
assertFormat();
assertIndex(
new IndexPoint(0, 0, 10000),
new IndexPoint(10000, 0, 10000),
new IndexPoint(20000, 0, TEST_DURATION_US - 20000));
}
public void testPrepareCustomTimecodeScale() throws ParserException {
NonBlockingInputStream testInputStream = new ByteArrayNonBlockingInputStream(
createInitializationSegment(3, 0, true, 1000, ID_VP9));
assertEquals(EXPECTED_INIT_RESULT, extractor.read(testInputStream, sampleHolder));
assertFormat();
assertIndex(
new IndexPoint(0, 0, 10),
new IndexPoint(10, 0, 10),
new IndexPoint(20, 0, (TEST_DURATION_US / 1000) - 20));
}
public void testPrepareNoCuePoints() {
NonBlockingInputStream testInputStream = new ByteArrayNonBlockingInputStream(
createInitializationSegment(0, 0, true, DEFAULT_TIMECODE_SCALE, ID_VP9));
try {
extractor.read(testInputStream, sampleHolder);
fail();
} catch (ParserException exception) {
assertEquals("Invalid/missing cue points", exception.getMessage());
}
}
public void testPrepareInvalidDocType() {
NonBlockingInputStream testInputStream = new ByteArrayNonBlockingInputStream(
createInitializationSegment(1, 0, false, DEFAULT_TIMECODE_SCALE, ID_VP9));
try {
extractor.read(testInputStream, sampleHolder);
fail();
} catch (ParserException exception) {
assertEquals("DocType webB not supported", exception.getMessage());
}
}
public void testReadSampleKeyframe() throws ParserException {
MediaSegment mediaSegment = createMediaSegment(100, 0, 0, true, false, true);
byte[] testInputData = joinByteArrays(
createInitializationSegment(
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE, ID_VP9),
mediaSegment.clusterBytes);
NonBlockingInputStream testInputStream = new ByteArrayNonBlockingInputStream(testInputData);
assertEquals(EXPECTED_INIT_AND_SAMPLE_RESULT, extractor.read(testInputStream, sampleHolder));
assertFormat();
assertSample(mediaSegment, 0, true, false);
assertEquals(WebmExtractor.RESULT_END_OF_STREAM, extractor.read(testInputStream, sampleHolder));
}
public void testReadBlock() throws ParserException {
MediaSegment mediaSegment = createMediaSegment(100, 0, 0, true, false, false);
byte[] testInputData = joinByteArrays(
createInitializationSegment(
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE, ID_OPUS),
mediaSegment.clusterBytes);
NonBlockingInputStream testInputStream = new ByteArrayNonBlockingInputStream(testInputData);
assertEquals(EXPECTED_INIT_AND_SAMPLE_RESULT, extractor.read(testInputStream, sampleHolder));
assertAudioFormat(ID_OPUS);
assertSample(mediaSegment, 0, true, false);
assertEquals(WebmExtractor.RESULT_END_OF_STREAM, extractor.read(testInputStream, sampleHolder));
}
public void testReadSampleInvisible() throws ParserException {
MediaSegment mediaSegment = createMediaSegment(100, 12, 13, false, true, true);
byte[] testInputData = joinByteArrays(
createInitializationSegment(
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE, ID_VP9),
mediaSegment.clusterBytes);
NonBlockingInputStream testInputStream = new ByteArrayNonBlockingInputStream(testInputData);
assertEquals(EXPECTED_INIT_AND_SAMPLE_RESULT, extractor.read(testInputStream, sampleHolder));
assertFormat();
assertSample(mediaSegment, 25000, false, true);
assertEquals(WebmExtractor.RESULT_END_OF_STREAM, extractor.read(testInputStream, sampleHolder));
}
public void testReadSampleCustomTimescale() throws ParserException {
MediaSegment mediaSegment = createMediaSegment(100, 12, 13, false, false, true);
byte[] testInputData = joinByteArrays(
createInitializationSegment(
1, mediaSegment.clusterBytes.length, true, 1000, ID_VP9),
mediaSegment.clusterBytes);
NonBlockingInputStream testInputStream = new ByteArrayNonBlockingInputStream(testInputData);
assertEquals(EXPECTED_INIT_AND_SAMPLE_RESULT, extractor.read(testInputStream, sampleHolder));
assertFormat();
assertSample(mediaSegment, 25, false, false);
assertEquals(WebmExtractor.RESULT_END_OF_STREAM, extractor.read(testInputStream, sampleHolder));
}
public void testReadSampleNegativeSimpleBlockTimecode() throws ParserException {
MediaSegment mediaSegment = createMediaSegment(100, 13, -12, true, true, true);
byte[] testInputData = joinByteArrays(
createInitializationSegment(
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE, ID_VP9),
mediaSegment.clusterBytes);
NonBlockingInputStream testInputStream = new ByteArrayNonBlockingInputStream(testInputData);
assertEquals(EXPECTED_INIT_AND_SAMPLE_RESULT, extractor.read(testInputStream, sampleHolder));
assertFormat();
assertSample(mediaSegment, 1000, true, true);
assertEquals(WebmExtractor.RESULT_END_OF_STREAM, extractor.read(testInputStream, sampleHolder));
}
private void assertFormat() {
MediaFormat format = extractor.getFormat();
assertEquals(TEST_WIDTH, format.width);
assertEquals(TEST_HEIGHT, format.height);
assertEquals(MimeTypes.VIDEO_VP9, format.mimeType);
}
private void assertAudioFormat(int codecId) {
MediaFormat format = extractor.getFormat();
assertEquals(TEST_CHANNEL_COUNT, format.channelCount);
assertEquals(TEST_SAMPLE_RATE, format.sampleRate);
if (codecId == ID_OPUS) {
assertEquals(MimeTypes.AUDIO_OPUS, format.mimeType);
assertEquals(3, format.initializationData.size());
assertEquals(TEST_OPUS_CODEC_PRIVATE_SIZE, format.initializationData.get(0).length);
assertEquals(TEST_CODEC_DELAY, ByteBuffer.wrap(format.initializationData.get(1)).getLong());
assertEquals(TEST_SEEK_PRE_ROLL, ByteBuffer.wrap(format.initializationData.get(2)).getLong());
} else if (codecId == ID_VORBIS) {
assertEquals(MimeTypes.AUDIO_VORBIS, format.mimeType);
assertEquals(2, format.initializationData.size());
assertEquals(TEST_VORBIS_INFO_SIZE, format.initializationData.get(0).length);
assertEquals(TEST_VORBIS_BOOKS_SIZE, format.initializationData.get(1).length);
}
}
private void assertIndex(IndexPoint... indexPoints) {
SegmentIndex index = extractor.getIndex();
assertEquals(CUES_ELEMENT_BYTE_SIZE + CUE_POINT_ELEMENT_BYTE_SIZE * indexPoints.length,
index.sizeBytes);
assertEquals(indexPoints.length, index.length);
for (int i = 0; i < indexPoints.length; i++) {
IndexPoint indexPoint = indexPoints[i];
assertEquals(indexPoint.timeUs, index.timesUs[i]);
assertEquals(indexPoint.size, index.sizes[i]);
assertEquals(indexPoint.durationUs, index.durationsUs[i]);
}
}
private void assertSample(
MediaSegment mediaSegment, int timeUs, boolean keyframe, boolean invisible) {
assertTrue(Arrays.equals(
mediaSegment.videoBytes, Arrays.copyOf(sampleHolder.data.array(), sampleHolder.size)));
assertEquals(timeUs, sampleHolder.timeUs);
assertEquals(keyframe, (sampleHolder.flags & C.SAMPLE_FLAG_SYNC) != 0);
assertEquals(invisible, sampleHolder.decodeOnly);
}
private byte[] createInitializationSegment(
int cuePoints, int mediaSegmentSize, boolean docTypeIsWebm, int timecodeScale,
int codecId) {
int initalizationSegmentSize = INFO_ELEMENT_BYTE_SIZE + TRACKS_ELEMENT_BYTE_SIZE
+ CUES_ELEMENT_BYTE_SIZE + CUE_POINT_ELEMENT_BYTE_SIZE * cuePoints;
byte[] tracksElement = null;
switch (codecId) {
case ID_VP9:
tracksElement = createTracksElementWithVideo(true, TEST_WIDTH, TEST_HEIGHT);
break;
case ID_OPUS:
tracksElement = createTracksElementWithOpusAudio(TEST_CHANNEL_COUNT);
break;
case ID_VORBIS:
tracksElement = createTracksElementWithVorbisAudio(TEST_CHANNEL_COUNT);
break;
}
byte[] bytes = joinByteArrays(createEbmlElement(1, docTypeIsWebm, 2),
createSegmentElement(initalizationSegmentSize + mediaSegmentSize),
createInfoElement(timecodeScale),
tracksElement,
createCuesElement(CUE_POINT_ELEMENT_BYTE_SIZE * cuePoints));
for (int i = 0; i < cuePoints; i++) {
bytes = joinByteArrays(bytes, createCuePointElement(10 * i, initalizationSegmentSize));
}
return bytes;
}
private static MediaSegment createMediaSegment(int videoBytesLength, int clusterTimecode,
int blockTimecode, boolean keyframe, boolean invisible, boolean isSimple) {
byte[] videoBytes = createVideoBytes(videoBytesLength);
byte[] blockBytes;
if (isSimple) {
blockBytes = createSimpleBlockElement(videoBytes.length, blockTimecode,
keyframe, invisible, true);
} else {
blockBytes = createBlockElement(videoBytes.length, blockTimecode, invisible, true);
}
byte[] clusterBytes =
createClusterElement(blockBytes.length + videoBytes.length, clusterTimecode);
return new MediaSegment(joinByteArrays(clusterBytes, blockBytes, videoBytes), videoBytes);
}
private static byte[] joinByteArrays(byte[]... byteArrays) {
int length = 0;
for (byte[] byteArray : byteArrays) {
length += byteArray.length;
}
byte[] joined = new byte[length];
length = 0;
for (byte[] byteArray : byteArrays) {
System.arraycopy(byteArray, 0, joined, length, byteArray.length);
length += byteArray.length;
}
return joined;
}
private static byte[] createEbmlElement(
int ebmlReadVersion, boolean docTypeIsWebm, int docTypeReadVersion) {
return createByteArray(
0x1A, 0x45, 0xDF, 0xA3, // EBML
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, // size=15
0x42, 0xF7, // EBMLReadVersion
0x81, ebmlReadVersion, // size=1
0x42, 0x82, // DocType
0x84, 0x77, 0x65, 0x62, docTypeIsWebm ? 0x6D : 0x42, // size=4 value=webm/B
0x42, 0x85, // DocTypeReadVersion
0x81, docTypeReadVersion); // size=1
}
private static byte[] createSegmentElement(int size) {
byte[] sizeBytes = getIntegerBytes(size);
return createByteArray(
0x18, 0x53, 0x80, 0x67, // Segment
0x01, 0x00, 0x00, 0x00, sizeBytes[0], sizeBytes[1], sizeBytes[2], sizeBytes[3]);
}
private static byte[] createInfoElement(int timecodeScale) {
byte[] scaleBytes = getIntegerBytes(timecodeScale);
return createByteArray(
0x15, 0x49, 0xA9, 0x66, // Info
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, // size=19
0x2A, 0xD7, 0xB1, // TimecodeScale
0x84, scaleBytes[0], scaleBytes[1], scaleBytes[2], scaleBytes[3], // size=4
0x44, 0x89, // Duration
0x88, 0x40, 0xC3, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00); // size=8 value=9920.0
}
private static byte[] createTracksElementWithVideo(
boolean codecIsVp9, int pixelWidth, int pixelHeight) {
byte[] widthBytes = getIntegerBytes(pixelWidth);
byte[] heightBytes = getIntegerBytes(pixelHeight);
return createByteArray(
0x16, 0x54, 0xAE, 0x6B, // Tracks
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, // size=36
0xAE, // TrackEntry
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, // size=27
0x86, // CodecID
0x85, 0x56, 0x5F, 0x56, 0x50, codecIsVp9 ? 0x39 : 0x30, // size=5 value=V_VP9/0
0xE0, // Video
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, // size=8
0xB0, // PixelWidth
0x82, widthBytes[2], widthBytes[3], // size=2
0xBA, // PixelHeight
0x82, heightBytes[2], heightBytes[3]); // size=2
}
private static byte[] createTracksElementWithOpusAudio(int channelCount) {
byte[] channelCountBytes = getIntegerBytes(channelCount);
return createByteArray(
0x16, 0x54, 0xAE, 0x6B, // Tracks
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, // size=57
0xAE, // TrackEntry
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, // size=48
0x86, // CodecID
0x86, 0x41, 0x5F, 0x4F, 0x50, 0x55, 0x53, // size=6 value=A_OPUS
0x56, 0xAA, // CodecDelay
0x83, 0x63, 0x2E, 0xA0, // size=3 value=6500000
0x56, 0xBB, // SeekPreRoll
0x84, 0x04, 0xC4, 0xB4, 0x00, // size=4 value=80000000
0xE1, // Audio
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, // size=13
0x9F, // Channels
0x81, channelCountBytes[3], // size=1
0xB5, // SamplingFrequency
0x88, 0x40, 0xE7, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, // size=8 value=48000
0x63, 0xA2, // CodecPrivate
0x82, 0x00, 0x00); // size=2
}
private byte[] createTracksElementWithVorbisAudio(int channelCount) {
byte[] channelCountBytes = getIntegerBytes(channelCount);
byte[] tracksElement = createByteArray(
0x16, 0x54, 0xAE, 0x6B, // Tracks
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x9C, // size=4252
0xAE, // TrackEntry
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x93, // size=4243 (36+4207)
0x86, // CodecID
0x88, 0x41, 0x5f, 0x56, 0x4f, 0x52, 0x42, 0x49, 0x53, // size=8 value=A_VORBIS
0xE1, // Audio
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, // size=13
0x9F, // Channels
0x81, channelCountBytes[3], // size=1
0xB5, // SamplingFrequency
0x88, 0x40, 0xE7, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, // size=8 value=48000
0x63, 0xA2, // CodecPrivate
0x50, 0x6F); // size=4207
byte[] codecPrivate = new byte[4207];
try {
getInstrumentation().getContext().getResources().getAssets().open(TEST_VORBIS_CODEC_PRIVATE)
.read(codecPrivate);
} catch (IOException e) {
fail(); // should never happen
}
return joinByteArrays(tracksElement, codecPrivate);
}
private static byte[] createCuesElement(int size) {
byte[] sizeBytes = getIntegerBytes(size);
return createByteArray(
0x1C, 0x53, 0xBB, 0x6B, // Cues
0x01, 0x00, 0x00, 0x00, sizeBytes[0], sizeBytes[1], sizeBytes[2], sizeBytes[3]); // size=31
}
private static byte[] createCuePointElement(int cueTime, int cueClusterPosition) {
byte[] positionBytes = getIntegerBytes(cueClusterPosition);
return createByteArray(
0xBB, // CuePoint
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, // size=22
0xB3, // CueTime
0x81, cueTime, // size=1
0xB7, // CueTrackPositions
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, // size=10
0xF1, // CueClusterPosition
0x88, 0x00, 0x00, 0x00, 0x00, positionBytes[0], positionBytes[1],
positionBytes[2], positionBytes[3]); // size=8
}
private static byte[] createClusterElement(int size, int timecode) {
byte[] sizeBytes = getIntegerBytes(size);
byte[] timeBytes = getIntegerBytes(timecode);
return createByteArray(
0x1F, 0x43, 0xB6, 0x75, // Cluster
0x01, 0x00, 0x00, 0x00, sizeBytes[0], sizeBytes[1], sizeBytes[2], sizeBytes[3],
0xE7, // Timecode
0x84, timeBytes[0], timeBytes[1], timeBytes[2], timeBytes[3]); // size=4
}
private static byte[] createSimpleBlockElement(
int size, int timecode, boolean keyframe, boolean invisible, boolean noLacing) {
byte[] sizeBytes = getIntegerBytes(size + 4);
byte[] timeBytes = getIntegerBytes(timecode);
byte flags = (byte)
((keyframe ? 0x80 : 0x00) | (invisible ? 0x08 : 0x00) | (noLacing ? 0x00 : 0x06));
return createByteArray(
0xA3, // SimpleBlock
0x01, 0x00, 0x00, 0x00, sizeBytes[0], sizeBytes[1], sizeBytes[2], sizeBytes[3],
0x81, // Track number value=1
timeBytes[2], timeBytes[3], flags); // Timecode and flags
}
private static byte[] createBlockElement(
int size, int timecode, boolean invisible, boolean noLacing) {
int blockSize = size + 4;
byte[] blockSizeBytes = getIntegerBytes(blockSize);
byte[] timeBytes = getIntegerBytes(timecode);
int blockElementSize = 1 + 8 + blockSize; // id + size + length of data
byte[] sizeBytes = getIntegerBytes(blockElementSize);
byte flags = (byte) ((invisible ? 0x08 : 0x00) | (noLacing ? 0x00 : 0x06));
return createByteArray(
0xA0, // BlockGroup
0x01, 0x00, 0x00, 0x00, sizeBytes[0], sizeBytes[1], sizeBytes[2], sizeBytes[3],
0xA1, // Block
0x01, 0x00, 0x00, 0x00,
blockSizeBytes[0], blockSizeBytes[1], blockSizeBytes[2], blockSizeBytes[3],
0x81, // Track number value=1
timeBytes[2], timeBytes[3], flags); // Timecode and flags
}
private static byte[] createVideoBytes(int size) {
byte[] videoBytes = new byte[size];
for (int i = 0; i < size; i++) {
videoBytes[i] = (byte) i;
}
return videoBytes;
}
private static byte[] getIntegerBytes(int value) {
return createByteArray(
(value & 0xFF000000) >> 24,
(value & 0x00FF0000) >> 16,
(value & 0x0000FF00) >> 8,
(value & 0x000000FF));
}
private static byte[] createByteArray(int... intArray) {
byte[] byteArray = new byte[intArray.length];
for (int i = 0; i < byteArray.length; i++) {
byteArray[i] = (byte) intArray[i];
}
return byteArray;
}
/** Used by {@link #createMediaSegment} to return both cluster and video bytes together. */
private static final class MediaSegment {
private final byte[] clusterBytes;
private final byte[] videoBytes;
private MediaSegment(byte[] clusterBytes, byte[] videoBytes) {
this.clusterBytes = clusterBytes;
this.videoBytes = videoBytes;
}
}
/** Used by {@link #assertIndex(IndexPoint...)} to validate index elements. */
private static final class IndexPoint {
private final long timeUs;
private final int size;
private final long durationUs;
private IndexPoint(long timeUs, int size, long durationUs) {
this.timeUs = timeUs;
this.size = size;
this.durationUs = durationUs;
}
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2014 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.exoplayer.dash;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.chunk.Format;
import com.google.android.exoplayer.dash.mpd.Representation;
import com.google.android.exoplayer.dash.mpd.SegmentBase.SingleSegmentBase;
import junit.framework.TestCase;
/**
* Tests {@link DashChunkSource}.
*/
public class DashChunkSourceTest extends TestCase {
public void testMaxVideoDimensions() {
SingleSegmentBase segmentBase1 = new SingleSegmentBase("https://example.com/1.mp4");
Format format1 = new Format("1", "video/mp4", 100, 200, -1, -1, 1000);
Representation representation1 =
Representation.newInstance(0, 0, null, 0, format1, segmentBase1);
SingleSegmentBase segmentBase2 = new SingleSegmentBase("https://example.com/2.mp4");
Format format2 = new Format("2", "video/mp4", 400, 50, -1, -1, 1000);
Representation representation2 =
Representation.newInstance(0, 0, null, 0, format2, segmentBase2);
DashChunkSource chunkSource = new DashChunkSource(null, null, representation1, representation2);
MediaFormat out = MediaFormat.createVideoFormat("video/h264", 1, 1, 1, 1, null);
chunkSource.getMaxVideoDimensions(out);
assertEquals(400, out.getMaxVideoWidth());
assertEquals(200, out.getMaxVideoHeight());
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 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.exoplayer.dash.mpd;
import android.test.InstrumentationTestCase;
import java.io.IOException;
import java.io.InputStream;
/**
* Unit tests for {@link MediaPresentationDescriptionParser}.
*/
public class MediaPresentationDescriptionParserTest extends InstrumentationTestCase {
private static final String SAMPLE_MPD_1 = "dash/sample_mpd_1";
public void testParseMediaPresentationDescription() throws IOException {
MediaPresentationDescriptionParser parser = new MediaPresentationDescriptionParser();
InputStream inputStream =
getInstrumentation().getContext().getResources().getAssets().open(SAMPLE_MPD_1);
// Simple test to ensure that the sample manifest parses without throwing any exceptions.
parser.parse("https://example.com/test.mpd", inputStream);
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 2014 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.exoplayer.dash.mpd;
import junit.framework.TestCase;
/**
* Unit test for {@link RangedUri}.
*/
public class RangedUriTest extends TestCase {
private static final String FULL_URI = "http://www.test.com/path/file.ext";
public void testMerge() {
RangedUri rangeA = new RangedUri(null, FULL_URI, 0, 10);
RangedUri rangeB = new RangedUri(null, FULL_URI, 10, 10);
RangedUri expected = new RangedUri(null, FULL_URI, 0, 20);
assertMerge(rangeA, rangeB, expected);
}
public void testMergeUnbounded() {
RangedUri rangeA = new RangedUri(null, FULL_URI, 0, 10);
RangedUri rangeB = new RangedUri(null, FULL_URI, 10, -1);
RangedUri expected = new RangedUri(null, FULL_URI, 0, -1);
assertMerge(rangeA, rangeB, expected);
}
public void testNonMerge() {
// A and B do not overlap, so should not merge
RangedUri rangeA = new RangedUri(null, FULL_URI, 0, 10);
RangedUri rangeB = new RangedUri(null, FULL_URI, 11, 10);
assertNonMerge(rangeA, rangeB);
// A and B do not overlap, so should not merge
rangeA = new RangedUri(null, FULL_URI, 0, 10);
rangeB = new RangedUri(null, FULL_URI, 11, -1);
assertNonMerge(rangeA, rangeB);
// A and B are bounded but overlap, so should not merge
rangeA = new RangedUri(null, FULL_URI, 0, 11);
rangeB = new RangedUri(null, FULL_URI, 10, 10);
assertNonMerge(rangeA, rangeB);
// A and B overlap due to unboundedness, so should not merge
rangeA = new RangedUri(null, FULL_URI, 0, -1);
rangeB = new RangedUri(null, FULL_URI, 10, -1);
assertNonMerge(rangeA, rangeB);
}
private void assertMerge(RangedUri rangeA, RangedUri rangeB, RangedUri expected) {
RangedUri merged = rangeA.attemptMerge(rangeB);
assertEquals(expected, merged);
merged = rangeB.attemptMerge(rangeA);
assertEquals(expected, merged);
}
private void assertNonMerge(RangedUri rangeA, RangedUri rangeB) {
RangedUri merged = rangeA.attemptMerge(rangeB);
assertNull(merged);
merged = rangeB.attemptMerge(rangeA);
assertNull(merged);
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2014 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.exoplayer.dash.mpd;
import com.google.android.exoplayer.chunk.Format;
import com.google.android.exoplayer.dash.mpd.SegmentBase.SingleSegmentBase;
import com.google.android.exoplayer.util.MimeTypes;
import junit.framework.TestCase;
/**
* Unit test for {@link Representation}.
*/
public class RepresentationTest extends TestCase {
public void testGetCacheKey() {
String uri = "http://www.google.com";
SegmentBase base = new SingleSegmentBase(new RangedUri(uri, null, 0, 1), 1, 0, uri, 1, 1);
Format format = new Format("0", MimeTypes.VIDEO_MP4, 1920, 1080, 0, 0, 2500000);
Representation representation = Representation.newInstance(-1, -1, "test_stream_1", 3,
format, base);
assertEquals("test_stream_1.0.3", representation.getCacheKey());
format = new Format("150", MimeTypes.VIDEO_MP4, 1920, 1080, 0, 0, 2500000);
representation = Representation.newInstance(-1, -1, "test_stream_1", -1, format, base);
assertEquals("test_stream_1.150.-1", representation.getCacheKey());
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2014 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.exoplayer.dash.mpd;
import junit.framework.TestCase;
/**
* Unit test for {@link UrlTemplate}.
*/
public class UrlTemplateTest extends TestCase {
public void testRealExamples() {
String template = "QualityLevels($Bandwidth$)/Fragments(video=$Time$,format=mpd-time-csf)";
UrlTemplate urlTemplate = UrlTemplate.compile(template);
String url = urlTemplate.buildUri("abc1", 10, 650000, 5000);
assertEquals("QualityLevels(650000)/Fragments(video=5000,format=mpd-time-csf)", url);
template = "$RepresentationID$/$Number$";
urlTemplate = UrlTemplate.compile(template);
url = urlTemplate.buildUri("abc1", 10, 650000, 5000);
assertEquals("abc1/10", url);
template = "chunk_ctvideo_cfm4s_rid$RepresentationID$_cn$Number$_w2073857842_mpd.m4s";
urlTemplate = UrlTemplate.compile(template);
url = urlTemplate.buildUri("abc1", 10, 650000, 5000);
assertEquals("chunk_ctvideo_cfm4s_ridabc1_cn10_w2073857842_mpd.m4s", url);
}
public void testFull() {
String template = "$Bandwidth$_a_$RepresentationID$_b_$Time$_c_$Number$";
UrlTemplate urlTemplate = UrlTemplate.compile(template);
String url = urlTemplate.buildUri("abc1", 10, 650000, 5000);
assertEquals("650000_a_abc1_b_5000_c_10", url);
}
public void testFullWithDollarEscaping() {
String template = "$$$Bandwidth$$$_a$$_$RepresentationID$_b_$Time$_c_$Number$$$";
UrlTemplate urlTemplate = UrlTemplate.compile(template);
String url = urlTemplate.buildUri("abc1", 10, 650000, 5000);
assertEquals("$650000$_a$_abc1_b_5000_c_10$", url);
}
public void testInvalidSubstitution() {
String template = "$IllegalId$";
try {
UrlTemplate.compile(template);
assertTrue(false);
} catch (IllegalArgumentException e) {
// Expected.
}
}
}

View File

@ -0,0 +1,108 @@
/*
* Copyright (C) 2014 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.exoplayer.hls;
import com.google.android.exoplayer.C;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
/**
* Test for {@link HlsMasterPlaylistParserTest}
*/
public class HlsMasterPlaylistParserTest extends TestCase {
public void testParseMasterPlaylist() {
String playlistUrl = "https://example.com/test.m3u8";
String playlistString = "#EXTM3U\n"
+ "\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n"
+ "http://example.com/low.m3u8\n"
+ "\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2 , avc1.66.30 \"\n"
+ "http://example.com/spaces_in_codecs.m3u8\n"
+ "\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=2560000,RESOLUTION=384x160\n"
+ "http://example.com/mid.m3u8\n"
+ "\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=7680000\n"
+ "http://example.com/hi.m3u8\n"
+ "\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\n"
+ "http://example.com/audio-only.m3u8";
ByteArrayInputStream inputStream = new ByteArrayInputStream(
playlistString.getBytes(Charset.forName(C.UTF8_NAME)));
try {
HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUrl, inputStream);
assertNotNull(playlist);
assertEquals(HlsPlaylist.TYPE_MASTER, playlist.type);
HlsMasterPlaylist masterPlaylist = (HlsMasterPlaylist) playlist;
List<Variant> variants = masterPlaylist.variants;
assertNotNull(variants);
assertEquals(5, variants.size());
assertEquals(0, variants.get(0).index);
assertEquals(1280000, variants.get(0).bandwidth);
assertNotNull(variants.get(0).codecs);
assertEquals(2, variants.get(0).codecs.length);
assertEquals("mp4a.40.2", variants.get(0).codecs[0]);
assertEquals("avc1.66.30", variants.get(0).codecs[1]);
assertEquals(304, variants.get(0).width);
assertEquals(128, variants.get(0).height);
assertEquals("http://example.com/low.m3u8", variants.get(0).url);
assertEquals(1, variants.get(1).index);
assertEquals(1280000, variants.get(1).bandwidth);
assertNotNull(variants.get(1).codecs);
assertEquals(2, variants.get(1).codecs.length);
assertEquals("mp4a.40.2", variants.get(1).codecs[0]);
assertEquals("avc1.66.30", variants.get(1).codecs[1]);
assertEquals("http://example.com/spaces_in_codecs.m3u8", variants.get(1).url);
assertEquals(2, variants.get(2).index);
assertEquals(2560000, variants.get(2).bandwidth);
assertEquals(null, variants.get(2).codecs);
assertEquals(384, variants.get(2).width);
assertEquals(160, variants.get(2).height);
assertEquals("http://example.com/mid.m3u8", variants.get(2).url);
assertEquals(3, variants.get(3).index);
assertEquals(7680000, variants.get(3).bandwidth);
assertEquals(null, variants.get(3).codecs);
assertEquals(-1, variants.get(3).width);
assertEquals(-1, variants.get(3).height);
assertEquals("http://example.com/hi.m3u8", variants.get(3).url);
assertEquals(4, variants.get(4).index);
assertEquals(65000, variants.get(4).bandwidth);
assertNotNull(variants.get(4).codecs);
assertEquals(1, variants.get(4).codecs.length);
assertEquals("mp4a.40.5", variants.get(4).codecs[0]);
assertEquals(-1, variants.get(4).width);
assertEquals(-1, variants.get(4).height);
assertEquals("http://example.com/audio-only.m3u8", variants.get(4).url);
} catch (IOException exception) {
fail(exception.getMessage());
}
}
}

View File

@ -0,0 +1,135 @@
/*
* Copyright (C) 2014 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.exoplayer.hls;
import com.google.android.exoplayer.C;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Locale;
/**
* Test for {@link HlsMediaPlaylistParserTest}
*/
public class HlsMediaPlaylistParserTest extends TestCase {
public void testParseMediaPlaylist() {
String playlistUrl = "https://example.com/test.m3u8";
String playlistString = "#EXTM3U\n"
+ "#EXT-X-VERSION:3\n"
+ "#EXT-X-TARGETDURATION:8\n"
+ "#EXT-X-MEDIA-SEQUENCE:2679\n"
+ "#EXT-X-ALLOW-CACHE:YES\n"
+ "\n"
+ "#EXTINF:7.975,\n"
+ "#EXT-X-BYTERANGE:51370@0\n"
+ "https://priv.example.com/fileSequence2679.ts\n"
+ "\n"
+ "#EXT-X-KEY:METHOD=AES-128,URI=\"https://priv.example.com/key.php?r=2680\",IV=0x1566B\n"
+ "#EXTINF:7.975,\n"
+ "#EXT-X-BYTERANGE:51501@51370\n"
+ "https://priv.example.com/fileSequence2680.ts\n"
+ "\n"
+ "#EXT-X-KEY:METHOD=NONE\n"
+ "#EXTINF:7.941,\n"
+ "#EXT-X-BYTERANGE:51501\n" // @102871
+ "https://priv.example.com/fileSequence2681.ts\n"
+ "\n"
+ "#EXT-X-DISCONTINUITY\n"
+ "#EXT-X-KEY:METHOD=AES-128,URI=\"https://priv.example.com/key.php?r=2682\"\n"
+ "#EXTINF:7.975,\n"
+ "#EXT-X-BYTERANGE:51740\n" // @154372
+ "https://priv.example.com/fileSequence2682.ts\n"
+ "\n"
+ "#EXTINF:7.975,\n"
+ "https://priv.example.com/fileSequence2683.ts\n"
+ "#EXT-X-ENDLIST";
InputStream inputStream = new ByteArrayInputStream(
playlistString.getBytes(Charset.forName(C.UTF8_NAME)));
try {
HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUrl, inputStream);
assertNotNull(playlist);
assertEquals(HlsPlaylist.TYPE_MEDIA, playlist.type);
HlsMediaPlaylist mediaPlaylist = (HlsMediaPlaylist) playlist;
assertEquals(2679, mediaPlaylist.mediaSequence);
assertEquals(8, mediaPlaylist.targetDurationSecs);
assertEquals(3, mediaPlaylist.version);
assertEquals(false, mediaPlaylist.live);
List<HlsMediaPlaylist.Segment> segments = mediaPlaylist.segments;
assertNotNull(segments);
assertEquals(5, segments.size());
assertEquals(false, segments.get(0).discontinuity);
assertEquals(7.975, segments.get(0).durationSecs);
assertEquals(null, segments.get(0).encryptionMethod);
assertEquals(null, segments.get(0).encryptionKeyUri);
assertEquals(null, segments.get(0).encryptionIV);
assertEquals(51370, segments.get(0).byterangeLength);
assertEquals(0, segments.get(0).byterangeOffset);
assertEquals("https://priv.example.com/fileSequence2679.ts", segments.get(0).url);
assertEquals(false, segments.get(1).discontinuity);
assertEquals(7.975, segments.get(1).durationSecs);
assertEquals("AES-128", segments.get(1).encryptionMethod);
assertEquals("https://priv.example.com/key.php?r=2680", segments.get(1).encryptionKeyUri);
assertEquals("0x1566B", segments.get(1).encryptionIV);
assertEquals(51501, segments.get(1).byterangeLength);
assertEquals(51370, segments.get(1).byterangeOffset);
assertEquals("https://priv.example.com/fileSequence2680.ts", segments.get(1).url);
assertEquals(false, segments.get(2).discontinuity);
assertEquals(7.941, segments.get(2).durationSecs);
assertEquals(HlsMediaPlaylist.ENCRYPTION_METHOD_NONE, segments.get(2).encryptionMethod);
assertEquals(null, segments.get(2).encryptionKeyUri);
assertEquals(null, segments.get(2).encryptionIV);
assertEquals(51501, segments.get(2).byterangeLength);
assertEquals(102871, segments.get(2).byterangeOffset);
assertEquals("https://priv.example.com/fileSequence2681.ts", segments.get(2).url);
assertEquals(true, segments.get(3).discontinuity);
assertEquals(7.975, segments.get(3).durationSecs);
assertEquals("AES-128", segments.get(3).encryptionMethod);
assertEquals("https://priv.example.com/key.php?r=2682", segments.get(3).encryptionKeyUri);
// 0xA7A == 2682.
assertNotNull(segments.get(3).encryptionIV);
assertEquals("A7A", segments.get(3).encryptionIV.toUpperCase(Locale.getDefault()));
assertEquals(51740, segments.get(3).byterangeLength);
assertEquals(154372, segments.get(3).byterangeOffset);
assertEquals("https://priv.example.com/fileSequence2682.ts", segments.get(3).url);
assertEquals(false, segments.get(4).discontinuity);
assertEquals(7.975, segments.get(4).durationSecs);
assertEquals("AES-128", segments.get(4).encryptionMethod);
assertEquals("https://priv.example.com/key.php?r=2682", segments.get(4).encryptionKeyUri);
// 0xA7A == 2682.
assertNotNull(segments.get(4).encryptionIV);
assertEquals("A7A", segments.get(4).encryptionIV.toUpperCase(Locale.getDefault()));
assertEquals(C.LENGTH_UNBOUNDED, segments.get(4).byterangeLength);
assertEquals(0, segments.get(4).byterangeOffset);
assertEquals("https://priv.example.com/fileSequence2683.ts", segments.get(4).url);
} catch (IOException exception) {
fail(exception.getMessage());
}
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2014 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.exoplayer.metadata;
import junit.framework.TestCase;
import java.util.Map;
/**
* Test for {@link Id3Parser}
*/
public class Id3ParserTest extends TestCase {
public void testParseTxxxFrames() {
byte[] rawId3 = new byte[] { 73, 68, 51, 4, 0, 0, 0, 0, 0, 41, 84, 88, 88, 88, 0, 0, 0, 31,
0, 0, 3, 0, 109, 100, 105, 97, 108, 111, 103, 95, 86, 73, 78, 68, 73, 67, 79, 49, 53, 50,
55, 54, 54, 52, 95, 115, 116, 97, 114, 116, 0 };
Id3Parser parser = new Id3Parser();
try {
Map<String, Object> metadata = parser.parse(rawId3, rawId3.length);
assertNotNull(metadata);
assertEquals(1, metadata.size());
TxxxMetadata txxx = (TxxxMetadata) metadata.get(TxxxMetadata.TYPE);
assertNotNull(txxx);
assertEquals("", txxx.description);
assertEquals("mdialog_VINDICO1527664_start", txxx.value);
} catch (Exception exception) {
fail(exception.getMessage());
}
}
}

View File

@ -0,0 +1,133 @@
/*
* Copyright (C) 2014 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.exoplayer.mp4;
import junit.framework.TestCase;
import java.util.Arrays;
/**
* Tests for {@link Mp4Util}.
*/
public class Mp4UtilTest extends TestCase {
private static final int TEST_PARTIAL_NAL_POSITION = 4;
private static final int TEST_NAL_POSITION = 10;
public void testFindNalUnit() {
byte[] data = buildTestData();
// Should find NAL unit.
int result = Mp4Util.findNalUnit(data, 0, data.length);
assertEquals(TEST_NAL_POSITION, result);
// Should find NAL unit whose prefix ends one byte before the limit.
result = Mp4Util.findNalUnit(data, 0, TEST_NAL_POSITION + 4);
assertEquals(TEST_NAL_POSITION, result);
// Shouldn't find NAL unit whose prefix ends at the limit (since the limit is exclusive).
result = Mp4Util.findNalUnit(data, 0, TEST_NAL_POSITION + 3);
assertEquals(TEST_NAL_POSITION + 3, result);
// Should find NAL unit whose prefix starts at the offset.
result = Mp4Util.findNalUnit(data, TEST_NAL_POSITION, data.length);
assertEquals(TEST_NAL_POSITION, result);
// Shouldn't find NAL unit whose prefix starts one byte past the offset.
result = Mp4Util.findNalUnit(data, TEST_NAL_POSITION + 1, data.length);
assertEquals(data.length, result);
}
public void testFindNalUnitWithPrefix() {
byte[] data = buildTestData();
// First byte of NAL unit in data1, rest in data2.
boolean[] prefixFlags = new boolean[3];
byte[] data1 = Arrays.copyOfRange(data, 0, TEST_NAL_POSITION + 1);
byte[] data2 = Arrays.copyOfRange(data, TEST_NAL_POSITION + 1, data.length);
int result = Mp4Util.findNalUnit(data1, 0, data1.length, prefixFlags);
assertEquals(data1.length, result);
result = Mp4Util.findNalUnit(data2, 0, data2.length, prefixFlags);
assertEquals(-1, result);
assertPrefixFlagsCleared(prefixFlags);
// First three bytes of NAL unit in data1, rest in data2.
prefixFlags = new boolean[3];
data1 = Arrays.copyOfRange(data, 0, TEST_NAL_POSITION + 3);
data2 = Arrays.copyOfRange(data, TEST_NAL_POSITION + 3, data.length);
result = Mp4Util.findNalUnit(data1, 0, data1.length, prefixFlags);
assertEquals(data1.length, result);
result = Mp4Util.findNalUnit(data2, 0, data2.length, prefixFlags);
assertEquals(-3, result);
assertPrefixFlagsCleared(prefixFlags);
// First byte of NAL unit in data1, second byte in data2, rest in data3.
prefixFlags = new boolean[3];
data1 = Arrays.copyOfRange(data, 0, TEST_NAL_POSITION + 1);
data2 = Arrays.copyOfRange(data, TEST_NAL_POSITION + 1, TEST_NAL_POSITION + 2);
byte[] data3 = Arrays.copyOfRange(data, TEST_NAL_POSITION + 2, data.length);
result = Mp4Util.findNalUnit(data1, 0, data1.length, prefixFlags);
assertEquals(data1.length, result);
result = Mp4Util.findNalUnit(data2, 0, data2.length, prefixFlags);
assertEquals(data2.length, result);
result = Mp4Util.findNalUnit(data3, 0, data3.length, prefixFlags);
assertEquals(-2, result);
assertPrefixFlagsCleared(prefixFlags);
// NAL unit split with one byte in four arrays.
prefixFlags = new boolean[3];
data1 = Arrays.copyOfRange(data, 0, TEST_NAL_POSITION + 1);
data2 = Arrays.copyOfRange(data, TEST_NAL_POSITION + 1, TEST_NAL_POSITION + 2);
data3 = Arrays.copyOfRange(data, TEST_NAL_POSITION + 2, TEST_NAL_POSITION + 3);
byte[] data4 = Arrays.copyOfRange(data, TEST_NAL_POSITION + 2, data.length);
result = Mp4Util.findNalUnit(data1, 0, data1.length, prefixFlags);
assertEquals(data1.length, result);
result = Mp4Util.findNalUnit(data2, 0, data2.length, prefixFlags);
assertEquals(data2.length, result);
result = Mp4Util.findNalUnit(data3, 0, data3.length, prefixFlags);
assertEquals(data3.length, result);
result = Mp4Util.findNalUnit(data4, 0, data4.length, prefixFlags);
assertEquals(-3, result);
assertPrefixFlagsCleared(prefixFlags);
// NAL unit entirely in data2. data1 ends with partial prefix.
prefixFlags = new boolean[3];
data1 = Arrays.copyOfRange(data, 0, TEST_PARTIAL_NAL_POSITION + 2);
data2 = Arrays.copyOfRange(data, TEST_PARTIAL_NAL_POSITION + 2, data.length);
result = Mp4Util.findNalUnit(data1, 0, data1.length, prefixFlags);
assertEquals(data1.length, result);
result = Mp4Util.findNalUnit(data2, 0, data2.length, prefixFlags);
assertEquals(4, result);
assertPrefixFlagsCleared(prefixFlags);
}
private static byte[] buildTestData() {
byte[] data = new byte[20];
for (int i = 0; i < data.length; i++) {
data[i] = (byte) 0xFF;
}
// Insert an incomplete NAL unit start code.
data[TEST_PARTIAL_NAL_POSITION] = 0;
data[TEST_PARTIAL_NAL_POSITION + 1] = 0;
// Insert a complete NAL unit start code.
data[TEST_NAL_POSITION] = 0;
data[TEST_NAL_POSITION + 1] = 0;
data[TEST_NAL_POSITION + 2] = 1;
data[TEST_NAL_POSITION + 3] = 5;
return data;
}
private static void assertPrefixFlagsCleared(boolean[] flags) {
assertEquals(false, flags[0] || flags[1] || flags[2]);
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 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.exoplayer.testutil;
import java.util.Random;
/**
* Utility methods for tests.
*/
public class Util {
private Util() {}
public static byte[] buildTestData(int length) {
return buildTestData(length, length);
}
public static byte[] buildTestData(int length, int seed) {
Random random = new Random(seed);
byte[] source = new byte[length];
random.nextBytes(source);
return source;
}
}

View File

@ -0,0 +1,134 @@
/*
* Copyright (C) 2014 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.exoplayer.text.webvtt;
import com.google.android.exoplayer.C;
import android.test.InstrumentationTestCase;
import java.io.IOException;
import java.io.InputStream;
/**
* Unit test for {@link WebvttParser}.
*/
public class WebvttParserTest extends InstrumentationTestCase {
private static final String TYPICAL_WEBVTT_FILE = "webvtt/typical";
private static final String TYPICAL_WITH_IDS_WEBVTT_FILE = "webvtt/typical_with_identifiers";
private static final String TYPICAL_WITH_TAGS_WEBVTT_FILE = "webvtt/typical_with_tags";
private static final String EMPTY_WEBVTT_FILE = "webvtt/empty";
public void testParseNullWebvttFile() throws IOException {
WebvttParser parser = new WebvttParser();
InputStream inputStream =
getInstrumentation().getContext().getResources().getAssets().open(EMPTY_WEBVTT_FILE);
try {
parser.parse(inputStream, C.UTF8_NAME, 0);
fail("Expected IOException");
} catch (IOException expected) {
// Do nothing.
}
}
public void testParseTypicalWebvttFile() throws IOException {
WebvttParser parser = new WebvttParser();
InputStream inputStream =
getInstrumentation().getContext().getResources().getAssets().open(TYPICAL_WEBVTT_FILE);
WebvttSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME, 0);
// test start time and event count
long startTimeUs = 5000000;
assertEquals(startTimeUs, subtitle.getStartTime());
assertEquals(4, subtitle.getEventTimeCount());
// test first cue
assertEquals(startTimeUs, subtitle.getEventTime(0));
assertEquals("This is the first subtitle.",
subtitle.getText(subtitle.getEventTime(0)));
assertEquals(startTimeUs + 1234000, subtitle.getEventTime(1));
// test second cue
assertEquals(startTimeUs + 2345000, subtitle.getEventTime(2));
assertEquals("This is the second subtitle.",
subtitle.getText(subtitle.getEventTime(2)));
assertEquals(startTimeUs + 3456000, subtitle.getEventTime(3));
}
public void testParseTypicalWithIdsWebvttFile() throws IOException {
WebvttParser parser = new WebvttParser();
InputStream inputStream =
getInstrumentation().getContext().getResources().getAssets()
.open(TYPICAL_WITH_IDS_WEBVTT_FILE);
WebvttSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME, 0);
// test start time and event count
long startTimeUs = 5000000;
assertEquals(startTimeUs, subtitle.getStartTime());
assertEquals(4, subtitle.getEventTimeCount());
// test first cue
assertEquals(startTimeUs, subtitle.getEventTime(0));
assertEquals("This is the first subtitle.",
subtitle.getText(subtitle.getEventTime(0)));
assertEquals(startTimeUs + 1234000, subtitle.getEventTime(1));
// test second cue
assertEquals(startTimeUs + 2345000, subtitle.getEventTime(2));
assertEquals("This is the second subtitle.",
subtitle.getText(subtitle.getEventTime(2)));
assertEquals(startTimeUs + 3456000, subtitle.getEventTime(3));
}
public void testParseTypicalWithTagsWebvttFile() throws IOException {
WebvttParser parser = new WebvttParser();
InputStream inputStream =
getInstrumentation().getContext().getResources().getAssets()
.open(TYPICAL_WITH_TAGS_WEBVTT_FILE);
WebvttSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME, 0);
// test start time and event count
long startTimeUs = 5000000;
assertEquals(startTimeUs, subtitle.getStartTime());
assertEquals(8, subtitle.getEventTimeCount());
// test first cue
assertEquals(startTimeUs, subtitle.getEventTime(0));
assertEquals("This is the first subtitle.",
subtitle.getText(subtitle.getEventTime(0)));
assertEquals(startTimeUs + 1234000, subtitle.getEventTime(1));
// test second cue
assertEquals(startTimeUs + 2345000, subtitle.getEventTime(2));
assertEquals("This is the second subtitle.",
subtitle.getText(subtitle.getEventTime(2)));
assertEquals(startTimeUs + 3456000, subtitle.getEventTime(3));
// test third cue
assertEquals(startTimeUs + 4000000, subtitle.getEventTime(4));
assertEquals("This is the third subtitle.",
subtitle.getText(subtitle.getEventTime(4)));
assertEquals(startTimeUs + 5000000, subtitle.getEventTime(5));
// test fourth cue
assertEquals(startTimeUs + 6000000, subtitle.getEventTime(6));
assertEquals("This is the <fourth> &subtitle.",
subtitle.getText(subtitle.getEventTime(6)));
assertEquals(startTimeUs + 7000000, subtitle.getEventTime(7));
}
}

View File

@ -0,0 +1,204 @@
/*
* Copyright (C) 2014 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.exoplayer.text.webvtt;
import junit.framework.TestCase;
/**
* Unit test for {@link WebvttSubtitle}.
*/
public class WebvttSubtitleTest extends TestCase {
private static final String FIRST_SUBTITLE_STRING = "This is the first subtitle.";
private static final String SECOND_SUBTITLE_STRING = "This is the second subtitle.";
private static final String FIRST_AND_SECOND_SUBTITLE_STRING =
FIRST_SUBTITLE_STRING + SECOND_SUBTITLE_STRING;
private WebvttSubtitle emptySubtitle = new WebvttSubtitle(new String[] {}, 0, new long[] {});
private WebvttSubtitle simpleSubtitle = new WebvttSubtitle(
new String[] {FIRST_SUBTITLE_STRING, SECOND_SUBTITLE_STRING}, 0,
new long[] {1000000, 2000000, 3000000, 4000000});
private WebvttSubtitle overlappingSubtitle = new WebvttSubtitle(
new String[] {FIRST_SUBTITLE_STRING, SECOND_SUBTITLE_STRING}, 0,
new long[] {1000000, 3000000, 2000000, 4000000});
private WebvttSubtitle nestedSubtitle = new WebvttSubtitle(
new String[] {FIRST_SUBTITLE_STRING, SECOND_SUBTITLE_STRING}, 0,
new long[] {1000000, 4000000, 2000000, 3000000});
public void testEventCount() {
assertEquals(0, emptySubtitle.getEventTimeCount());
assertEquals(4, simpleSubtitle.getEventTimeCount());
assertEquals(4, overlappingSubtitle.getEventTimeCount());
assertEquals(4, nestedSubtitle.getEventTimeCount());
}
public void testStartTime() {
assertEquals(0, emptySubtitle.getStartTime());
assertEquals(0, simpleSubtitle.getStartTime());
assertEquals(0, overlappingSubtitle.getStartTime());
assertEquals(0, nestedSubtitle.getStartTime());
}
public void testLastEventTime() {
assertEquals(-1, emptySubtitle.getLastEventTime());
assertEquals(4000000, simpleSubtitle.getLastEventTime());
assertEquals(4000000, overlappingSubtitle.getLastEventTime());
assertEquals(4000000, nestedSubtitle.getLastEventTime());
}
public void testSimpleSubtitleEventTimes() {
testSubtitleEventTimesHelper(simpleSubtitle);
}
public void testSimpleSubtitleEventIndices() {
testSubtitleEventIndicesHelper(simpleSubtitle);
}
public void testSimpleSubtitleText() {
// Test before first subtitle
assertNull(simpleSubtitle.getText(0));
assertNull(simpleSubtitle.getText(500000));
assertNull(simpleSubtitle.getText(999999));
// Test first subtitle
assertEquals(FIRST_SUBTITLE_STRING, simpleSubtitle.getText(1000000));
assertEquals(FIRST_SUBTITLE_STRING, simpleSubtitle.getText(1500000));
assertEquals(FIRST_SUBTITLE_STRING, simpleSubtitle.getText(1999999));
// Test after first subtitle, before second subtitle
assertNull(simpleSubtitle.getText(2000000));
assertNull(simpleSubtitle.getText(2500000));
assertNull(simpleSubtitle.getText(2999999));
// Test second subtitle
assertEquals(SECOND_SUBTITLE_STRING, simpleSubtitle.getText(3000000));
assertEquals(SECOND_SUBTITLE_STRING, simpleSubtitle.getText(3500000));
assertEquals(SECOND_SUBTITLE_STRING, simpleSubtitle.getText(3999999));
// Test after second subtitle
assertNull(simpleSubtitle.getText(4000000));
assertNull(simpleSubtitle.getText(4500000));
assertNull(simpleSubtitle.getText(Long.MAX_VALUE));
}
public void testOverlappingSubtitleEventTimes() {
testSubtitleEventTimesHelper(overlappingSubtitle);
}
public void testOverlappingSubtitleEventIndices() {
testSubtitleEventIndicesHelper(overlappingSubtitle);
}
public void testOverlappingSubtitleText() {
// Test before first subtitle
assertNull(overlappingSubtitle.getText(0));
assertNull(overlappingSubtitle.getText(500000));
assertNull(overlappingSubtitle.getText(999999));
// Test first subtitle
assertEquals(FIRST_SUBTITLE_STRING, overlappingSubtitle.getText(1000000));
assertEquals(FIRST_SUBTITLE_STRING, overlappingSubtitle.getText(1500000));
assertEquals(FIRST_SUBTITLE_STRING, overlappingSubtitle.getText(1999999));
// Test after first and second subtitle
assertEquals(FIRST_AND_SECOND_SUBTITLE_STRING, overlappingSubtitle.getText(2000000));
assertEquals(FIRST_AND_SECOND_SUBTITLE_STRING, overlappingSubtitle.getText(2500000));
assertEquals(FIRST_AND_SECOND_SUBTITLE_STRING, overlappingSubtitle.getText(2999999));
// Test second subtitle
assertEquals(SECOND_SUBTITLE_STRING, overlappingSubtitle.getText(3000000));
assertEquals(SECOND_SUBTITLE_STRING, overlappingSubtitle.getText(3500000));
assertEquals(SECOND_SUBTITLE_STRING, overlappingSubtitle.getText(3999999));
// Test after second subtitle
assertNull(overlappingSubtitle.getText(4000000));
assertNull(overlappingSubtitle.getText(4500000));
assertNull(overlappingSubtitle.getText(Long.MAX_VALUE));
}
public void testNestedSubtitleEventTimes() {
testSubtitleEventTimesHelper(nestedSubtitle);
}
public void testNestedSubtitleEventIndices() {
testSubtitleEventIndicesHelper(nestedSubtitle);
}
public void testNestedSubtitleText() {
// Test before first subtitle
assertNull(nestedSubtitle.getText(0));
assertNull(nestedSubtitle.getText(500000));
assertNull(nestedSubtitle.getText(999999));
// Test first subtitle
assertEquals(FIRST_SUBTITLE_STRING, nestedSubtitle.getText(1000000));
assertEquals(FIRST_SUBTITLE_STRING, nestedSubtitle.getText(1500000));
assertEquals(FIRST_SUBTITLE_STRING, nestedSubtitle.getText(1999999));
// Test after first and second subtitle
assertEquals(FIRST_AND_SECOND_SUBTITLE_STRING, nestedSubtitle.getText(2000000));
assertEquals(FIRST_AND_SECOND_SUBTITLE_STRING, nestedSubtitle.getText(2500000));
assertEquals(FIRST_AND_SECOND_SUBTITLE_STRING, nestedSubtitle.getText(2999999));
// Test first subtitle
assertEquals(FIRST_SUBTITLE_STRING, nestedSubtitle.getText(3000000));
assertEquals(FIRST_SUBTITLE_STRING, nestedSubtitle.getText(3500000));
assertEquals(FIRST_SUBTITLE_STRING, nestedSubtitle.getText(3999999));
// Test after second subtitle
assertNull(nestedSubtitle.getText(4000000));
assertNull(nestedSubtitle.getText(4500000));
assertNull(nestedSubtitle.getText(Long.MAX_VALUE));
}
private void testSubtitleEventTimesHelper(WebvttSubtitle subtitle) {
assertEquals(1000000, subtitle.getEventTime(0));
assertEquals(2000000, subtitle.getEventTime(1));
assertEquals(3000000, subtitle.getEventTime(2));
assertEquals(4000000, subtitle.getEventTime(3));
}
private void testSubtitleEventIndicesHelper(WebvttSubtitle subtitle) {
// Test first event
assertEquals(0, subtitle.getNextEventTimeIndex(0));
assertEquals(0, subtitle.getNextEventTimeIndex(500000));
assertEquals(0, subtitle.getNextEventTimeIndex(999999));
// Test second event
assertEquals(1, subtitle.getNextEventTimeIndex(1000000));
assertEquals(1, subtitle.getNextEventTimeIndex(1500000));
assertEquals(1, subtitle.getNextEventTimeIndex(1999999));
// Test third event
assertEquals(2, subtitle.getNextEventTimeIndex(2000000));
assertEquals(2, subtitle.getNextEventTimeIndex(2500000));
assertEquals(2, subtitle.getNextEventTimeIndex(2999999));
// Test fourth event
assertEquals(3, subtitle.getNextEventTimeIndex(3000000));
assertEquals(3, subtitle.getNextEventTimeIndex(3500000));
assertEquals(3, subtitle.getNextEventTimeIndex(3999999));
// Test null event (i.e. look for events after the last event)
assertEquals(-1, subtitle.getNextEventTimeIndex(4000000));
assertEquals(-1, subtitle.getNextEventTimeIndex(4500000));
assertEquals(-1, subtitle.getNextEventTimeIndex(Long.MAX_VALUE));
}
}

View File

@ -0,0 +1,151 @@
/*
* Copyright (C) 2014 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.exoplayer.upstream;
import com.google.android.exoplayer.C;
import junit.framework.TestCase;
import java.io.IOException;
/**
* Unit tests for {@link ByteArrayDataSource}.
*/
public class ByteArrayDataSourceTest extends TestCase {
private static final byte[] TEST_DATA = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
private static final byte[] TEST_DATA_ODD = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
public void testFullReadSingleBytes() {
readTestData(TEST_DATA, 0, C.LENGTH_UNBOUNDED, 1, 0, 1, false);
}
public void testFullReadAllBytes() {
readTestData(TEST_DATA, 0, C.LENGTH_UNBOUNDED, 100, 0, 100, false);
}
public void testLimitReadSingleBytes() {
// Limit set to the length of the data.
readTestData(TEST_DATA, 0, TEST_DATA.length, 1, 0, 1, false);
// And less.
readTestData(TEST_DATA, 0, 6, 1, 0, 1, false);
}
public void testFullReadTwoBytes() {
// Try with the total data length an exact multiple of the size of each individual read.
readTestData(TEST_DATA, 0, C.LENGTH_UNBOUNDED, 2, 0, 2, false);
// And not.
readTestData(TEST_DATA_ODD, 0, C.LENGTH_UNBOUNDED, 2, 0, 2, false);
}
public void testLimitReadTwoBytes() {
// Try with the limit an exact multiple of the size of each individual read.
readTestData(TEST_DATA, 0, 6, 2, 0, 2, false);
// And not.
readTestData(TEST_DATA, 0, 7, 2, 0, 2, false);
}
public void testReadFromValidOffsets() {
// Read from an offset without bound.
readTestData(TEST_DATA, 1, C.LENGTH_UNBOUNDED, 1, 0, 1, false);
// And with bound.
readTestData(TEST_DATA, 1, 6, 1, 0, 1, false);
// Read from the last possible offset without bound.
readTestData(TEST_DATA, TEST_DATA.length - 1, C.LENGTH_UNBOUNDED, 1, 0, 1, false);
// And with bound.
readTestData(TEST_DATA, TEST_DATA.length - 1, 1, 1, 0, 1, false);
}
public void testReadFromInvalidOffsets() {
// Read from first invalid offset and check failure without bound.
readTestData(TEST_DATA, TEST_DATA.length, C.LENGTH_UNBOUNDED, 1, 0, 1, true);
// And with bound.
readTestData(TEST_DATA, TEST_DATA.length, 1, 1, 0, 1, true);
}
public void testReadWithInvalidLength() {
// Read more data than is available.
readTestData(TEST_DATA, 0, TEST_DATA.length + 1, 1, 0, 1, true);
// And with bound.
readTestData(TEST_DATA, 1, TEST_DATA.length, 1, 0, 1, true);
}
/**
* Tests reading from a {@link ByteArrayDataSource} with various parameters.
*
* @param testData The data that the {@link ByteArrayDataSource} will wrap.
* @param dataOffset The offset from which to read data.
* @param dataLength The total length of data to read.
* @param outputBufferLength The length of the target buffer for each read.
* @param writeOffset The offset into {@code outputBufferLength} for each read.
* @param maxReadLength The maximum length of each read.
* @param expectFailOnOpen Whether it is expected that opening the source will fail.
*/
private void readTestData(byte[] testData, int dataOffset, int dataLength, int outputBufferLength,
int writeOffset, int maxReadLength, boolean expectFailOnOpen) {
int expectedFinalBytesRead =
dataLength == C.LENGTH_UNBOUNDED ? (testData.length - dataOffset) : dataLength;
ByteArrayDataSource dataSource = new ByteArrayDataSource(testData);
boolean opened = false;
try {
// Open the source.
long length = dataSource.open(new DataSpec(null, dataOffset, dataLength, null));
opened = true;
assertFalse(expectFailOnOpen);
// Verify the resolved length is as we expect.
assertEquals(expectedFinalBytesRead, length);
byte[] outputBuffer = new byte[outputBufferLength];
int accumulatedBytesRead = 0;
while (true) {
// Calculate a valid length for the next read, constraining by the specified output buffer
// length, write offset and maximum write length input parameters.
int requestedReadLength = Math.min(maxReadLength, outputBufferLength - writeOffset);
assertTrue(requestedReadLength > 0);
int bytesRead = dataSource.read(outputBuffer, writeOffset, requestedReadLength);
if (bytesRead != -1) {
assertTrue(bytesRead > 0);
assertTrue(bytesRead <= requestedReadLength);
// Check the data read was correct.
for (int i = 0; i < bytesRead; i++) {
assertEquals(testData[dataOffset + accumulatedBytesRead + i],
outputBuffer[writeOffset + i]);
}
// Check that we haven't read more data than we were expecting.
accumulatedBytesRead += bytesRead;
assertTrue(accumulatedBytesRead <= expectedFinalBytesRead);
// If we haven't read all of the bytes the request should have been satisfied in full.
assertTrue(accumulatedBytesRead == expectedFinalBytesRead
|| bytesRead == requestedReadLength);
} else {
// We're done. Check we read the expected number of bytes.
assertEquals(expectedFinalBytesRead, accumulatedBytesRead);
return;
}
}
} catch (IOException e) {
if (expectFailOnOpen && !opened) {
// Expected.
return;
}
// Unexpected failure.
fail();
}
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2014 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.exoplayer.upstream;
import com.google.android.exoplayer.testutil.Util;
import junit.framework.TestCase;
import java.io.IOException;
import java.util.Arrays;
/**
* Unit tests for {@link DataSourceStream}.
*/
public class DataSourceStreamTest extends TestCase {
private static final int DATA_LENGTH = 1024;
private static final int BUFFER_LENGTH = 128;
public void testGetLoadedData() throws IOException, InterruptedException {
byte[] testData = Util.buildTestData(DATA_LENGTH);
DataSource dataSource = new ByteArrayDataSource(testData);
DataSpec dataSpec = new DataSpec(null, 0, DATA_LENGTH, null);
DataSourceStream dataSourceStream = new DataSourceStream(dataSource, dataSpec,
new BufferPool(BUFFER_LENGTH));
dataSourceStream.load();
// Assert that the read and load positions are correct.
assertEquals(0, dataSourceStream.getReadPosition());
assertEquals(testData.length, dataSourceStream.getLoadPosition());
int halfTestDataLength = testData.length / 2;
byte[] readData = new byte[testData.length];
int bytesRead = dataSourceStream.read(readData, 0, halfTestDataLength);
// Assert that the read position is updated correctly.
assertEquals(halfTestDataLength, bytesRead);
assertEquals(halfTestDataLength, dataSourceStream.getReadPosition());
bytesRead += dataSourceStream.read(readData, bytesRead, testData.length - bytesRead);
// Assert that the read position was updated correctly.
assertEquals(testData.length, bytesRead);
assertEquals(testData.length, dataSourceStream.getReadPosition());
// Assert that the data read using the two read calls either side of getLoadedData is correct.
assertTrue(Arrays.equals(testData, readData));
}
}

View File

@ -0,0 +1,124 @@
/*
* Copyright (C) 2014 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.exoplayer.util;
import junit.framework.TestCase;
import java.util.Arrays;
/**
* Tests for {@link ParsableByteArray}.
*/
public class ParsableByteArrayTest extends TestCase {
private static final byte[] ARRAY_ELEMENTS =
new byte[] {0x0F, (byte) 0xFF, (byte) 0x42, (byte) 0x0F, 0x00, 0x00, 0x00, 0x00};
private ParsableByteArray parsableByteArray;
@Override
public void setUp() {
parsableByteArray = new ParsableByteArray(ARRAY_ELEMENTS.length);
System.arraycopy(ARRAY_ELEMENTS, 0, parsableByteArray.data, 0, ARRAY_ELEMENTS.length);
}
public void testReadInt() {
// When reading a signed integer
int value = parsableByteArray.readInt();
// Then the read value is equal to the array elements interpreted as an int.
assertEquals((0xFF & ARRAY_ELEMENTS[0]) << 24 | (0xFF & ARRAY_ELEMENTS[1]) << 16
| (0xFF & ARRAY_ELEMENTS[2]) << 8 | (0xFF & ARRAY_ELEMENTS[3]), value);
}
public void testSkipBack() {
// When reading an unsigned integer
long value = parsableByteArray.readUnsignedInt();
// Then skipping back and reading gives the same value.
parsableByteArray.skip(-4);
assertEquals(value, parsableByteArray.readUnsignedInt());
}
public void testReadingMovesPosition() {
// Given an array at the start
assertEquals(0, parsableByteArray.getPosition());
// When reading an integer, the position advances
parsableByteArray.readUnsignedInt();
assertEquals(4, parsableByteArray.getPosition());
}
public void testOutOfBoundsThrows() {
// Given an array at the end
parsableByteArray.readUnsignedLongToLong();
assertEquals(ARRAY_ELEMENTS.length, parsableByteArray.getPosition());
// Then reading more data throws.
try {
parsableByteArray.readUnsignedInt();
fail();
} catch (Exception e) {
// Expected.
}
}
public void testModificationsAffectParsableArray() {
// When modifying the wrapped byte array
byte[] data = parsableByteArray.data;
long readValue = parsableByteArray.readUnsignedInt();
data[0] = (byte) (ARRAY_ELEMENTS[0] + 1);
parsableByteArray.setPosition(0);
// Then the parsed value changes.
assertFalse(parsableByteArray.readUnsignedInt() == readValue);
}
public void testReadingUnsignedLongWithMsbSetThrows() {
// Given an array with the most-significant bit set on the top byte
byte[] data = parsableByteArray.data;
data[0] = (byte) 0x80;
// Then reading an unsigned long throws.
try {
parsableByteArray.readUnsignedLongToLong();
fail();
} catch (Exception e) {
// Expected.
}
}
public void testReadUnsignedFixedPoint1616() {
// When reading the integer part of a 16.16 fixed point value
int value = parsableByteArray.readUnsignedFixedPoint1616();
// Then the read value is equal to the array elements interpreted as a short.
assertEquals((0xFF & ARRAY_ELEMENTS[0]) << 8 | (ARRAY_ELEMENTS[1] & 0xFF), value);
assertEquals(4, parsableByteArray.getPosition());
}
public void testReadingBytesReturnsCopy() {
// When reading all the bytes back
int length = parsableByteArray.limit();
assertEquals(ARRAY_ELEMENTS.length, length);
byte[] copy = new byte[length];
parsableByteArray.readBytes(copy, 0, length);
// Then the array elements are the same.
assertTrue(Arrays.equals(parsableByteArray.data, copy));
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright (C) 2014 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.exoplayer.util;
import junit.framework.TestCase;
/**
* Unit tests for {@link UriUtil}.
*/
public class UriUtilTest extends TestCase {
/**
* Tests normal usage of {@link UriUtil#resolve(String, String)}.
* <p>
* The test cases are taken from RFC-3986 5.4.1.
*/
public void testResolveNormal() {
String base = "http://a/b/c/d;p?q";
assertEquals("g:h", UriUtil.resolve(base, "g:h"));
assertEquals("http://a/b/c/g", UriUtil.resolve(base, "g"));
assertEquals("http://a/b/c/g/", UriUtil.resolve(base, "g/"));
assertEquals("http://a/g", UriUtil.resolve(base, "/g"));
assertEquals("http://g", UriUtil.resolve(base, "//g"));
assertEquals("http://a/b/c/d;p?y", UriUtil.resolve(base, "?y"));
assertEquals("http://a/b/c/g?y", UriUtil.resolve(base, "g?y"));
assertEquals("http://a/b/c/d;p?q#s", UriUtil.resolve(base, "#s"));
assertEquals("http://a/b/c/g#s", UriUtil.resolve(base, "g#s"));
assertEquals("http://a/b/c/g?y#s", UriUtil.resolve(base, "g?y#s"));
assertEquals("http://a/b/c/;x", UriUtil.resolve(base, ";x"));
assertEquals("http://a/b/c/g;x", UriUtil.resolve(base, "g;x"));
assertEquals("http://a/b/c/g;x?y#s", UriUtil.resolve(base, "g;x?y#s"));
assertEquals("http://a/b/c/d;p?q", UriUtil.resolve(base, ""));
assertEquals("http://a/b/c/", UriUtil.resolve(base, "."));
assertEquals("http://a/b/c/", UriUtil.resolve(base, "./"));
assertEquals("http://a/b/", UriUtil.resolve(base, ".."));
assertEquals("http://a/b/", UriUtil.resolve(base, "../"));
assertEquals("http://a/b/g", UriUtil.resolve(base, "../g"));
assertEquals("http://a/", UriUtil.resolve(base, "../.."));
assertEquals("http://a/", UriUtil.resolve(base, "../../"));
assertEquals("http://a/g", UriUtil.resolve(base, "../../g"));
}
/**
* Tests abnormal usage of {@link UriUtil#resolve(String, String)}.
* <p>
* The test cases are taken from RFC-3986 5.4.2.
*/
public void testResolveAbnormal() {
String base = "http://a/b/c/d;p?q";
assertEquals("http://a/g", UriUtil.resolve(base, "../../../g"));
assertEquals("http://a/g", UriUtil.resolve(base, "../../../../g"));
assertEquals("http://a/g", UriUtil.resolve(base, "/./g"));
assertEquals("http://a/g", UriUtil.resolve(base, "/../g"));
assertEquals("http://a/b/c/g.", UriUtil.resolve(base, "g."));
assertEquals("http://a/b/c/.g", UriUtil.resolve(base, ".g"));
assertEquals("http://a/b/c/g..", UriUtil.resolve(base, "g.."));
assertEquals("http://a/b/c/..g", UriUtil.resolve(base, "..g"));
assertEquals("http://a/b/g", UriUtil.resolve(base, "./../g"));
assertEquals("http://a/b/c/g/", UriUtil.resolve(base, "./g/."));
assertEquals("http://a/b/c/g/h", UriUtil.resolve(base, "g/./h"));
assertEquals("http://a/b/c/h", UriUtil.resolve(base, "g/../h"));
assertEquals("http://a/b/c/g;x=1/y", UriUtil.resolve(base, "g;x=1/./y"));
assertEquals("http://a/b/c/y", UriUtil.resolve(base, "g;x=1/../y"));
assertEquals("http://a/b/c/g?y/./x", UriUtil.resolve(base, "g?y/./x"));
assertEquals("http://a/b/c/g?y/../x", UriUtil.resolve(base, "g?y/../x"));
assertEquals("http://a/b/c/g#s/./x", UriUtil.resolve(base, "g#s/./x"));
assertEquals("http://a/b/c/g#s/../x", UriUtil.resolve(base, "g#s/../x"));
assertEquals("http:g", UriUtil.resolve(base, "http:g"));
}
/**
* Tests additional abnormal usage of {@link UriUtil#resolve(String, String)}.
*/
public void testResolveAbnormalAdditional() {
assertEquals("c:e", UriUtil.resolve("http://a/b", "c:d/../e"));
assertEquals("a:c", UriUtil.resolve("a:b", "../c"));
}
}

View File

@ -0,0 +1,147 @@
/*
* Copyright (C) 2014 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.exoplayer.util;
import junit.framework.TestCase;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
/**
* Unit tests for {@link Util}.
*/
public class UtilTest extends TestCase {
public void testArrayBinarySearchFloor() {
long[] values = new long[0];
assertEquals(-1, Util.binarySearchFloor(values, 0, false, false));
assertEquals(0, Util.binarySearchFloor(values, 0, false, true));
values = new long[] {1, 3, 5};
assertEquals(-1, Util.binarySearchFloor(values, 0, false, false));
assertEquals(-1, Util.binarySearchFloor(values, 0, true, false));
assertEquals(0, Util.binarySearchFloor(values, 0, false, true));
assertEquals(0, Util.binarySearchFloor(values, 0, true, true));
assertEquals(-1, Util.binarySearchFloor(values, 1, false, false));
assertEquals(0, Util.binarySearchFloor(values, 1, true, false));
assertEquals(0, Util.binarySearchFloor(values, 1, false, true));
assertEquals(0, Util.binarySearchFloor(values, 1, true, true));
assertEquals(1, Util.binarySearchFloor(values, 4, false, false));
assertEquals(1, Util.binarySearchFloor(values, 4, true, false));
assertEquals(1, Util.binarySearchFloor(values, 5, false, false));
assertEquals(2, Util.binarySearchFloor(values, 5, true, false));
assertEquals(2, Util.binarySearchFloor(values, 6, false, false));
assertEquals(2, Util.binarySearchFloor(values, 6, true, false));
}
public void testListBinarySearchFloor() {
List<Integer> values = new ArrayList<Integer>();
assertEquals(-1, Util.binarySearchFloor(values, 0, false, false));
assertEquals(0, Util.binarySearchFloor(values, 0, false, true));
values.add(1);
values.add(3);
values.add(5);
assertEquals(-1, Util.binarySearchFloor(values, 0, false, false));
assertEquals(-1, Util.binarySearchFloor(values, 0, true, false));
assertEquals(0, Util.binarySearchFloor(values, 0, false, true));
assertEquals(0, Util.binarySearchFloor(values, 0, true, true));
assertEquals(-1, Util.binarySearchFloor(values, 1, false, false));
assertEquals(0, Util.binarySearchFloor(values, 1, true, false));
assertEquals(0, Util.binarySearchFloor(values, 1, false, true));
assertEquals(0, Util.binarySearchFloor(values, 1, true, true));
assertEquals(1, Util.binarySearchFloor(values, 4, false, false));
assertEquals(1, Util.binarySearchFloor(values, 4, true, false));
assertEquals(1, Util.binarySearchFloor(values, 5, false, false));
assertEquals(2, Util.binarySearchFloor(values, 5, true, false));
assertEquals(2, Util.binarySearchFloor(values, 6, false, false));
assertEquals(2, Util.binarySearchFloor(values, 6, true, false));
}
public void testArrayBinarySearchCeil() {
long[] values = new long[0];
assertEquals(0, Util.binarySearchCeil(values, 0, false, false));
assertEquals(-1, Util.binarySearchCeil(values, 0, false, true));
values = new long[] {1, 3, 5};
assertEquals(0, Util.binarySearchCeil(values, 0, false, false));
assertEquals(0, Util.binarySearchCeil(values, 0, true, false));
assertEquals(1, Util.binarySearchCeil(values, 1, false, false));
assertEquals(0, Util.binarySearchCeil(values, 1, true, false));
assertEquals(1, Util.binarySearchCeil(values, 2, false, false));
assertEquals(1, Util.binarySearchCeil(values, 2, true, false));
assertEquals(3, Util.binarySearchCeil(values, 5, false, false));
assertEquals(2, Util.binarySearchCeil(values, 5, true, false));
assertEquals(2, Util.binarySearchCeil(values, 5, false, true));
assertEquals(2, Util.binarySearchCeil(values, 5, true, true));
assertEquals(3, Util.binarySearchCeil(values, 6, false, false));
assertEquals(3, Util.binarySearchCeil(values, 6, true, false));
assertEquals(2, Util.binarySearchCeil(values, 6, false, true));
assertEquals(2, Util.binarySearchCeil(values, 6, true, true));
}
public void testListBinarySearchCeil() {
List<Integer> values = new ArrayList<Integer>();
assertEquals(0, Util.binarySearchCeil(values, 0, false, false));
assertEquals(-1, Util.binarySearchCeil(values, 0, false, true));
values.add(1);
values.add(3);
values.add(5);
assertEquals(0, Util.binarySearchCeil(values, 0, false, false));
assertEquals(0, Util.binarySearchCeil(values, 0, true, false));
assertEquals(1, Util.binarySearchCeil(values, 1, false, false));
assertEquals(0, Util.binarySearchCeil(values, 1, true, false));
assertEquals(1, Util.binarySearchCeil(values, 2, false, false));
assertEquals(1, Util.binarySearchCeil(values, 2, true, false));
assertEquals(3, Util.binarySearchCeil(values, 5, false, false));
assertEquals(2, Util.binarySearchCeil(values, 5, true, false));
assertEquals(2, Util.binarySearchCeil(values, 5, false, true));
assertEquals(2, Util.binarySearchCeil(values, 5, true, true));
assertEquals(3, Util.binarySearchCeil(values, 6, false, false));
assertEquals(3, Util.binarySearchCeil(values, 6, true, false));
assertEquals(2, Util.binarySearchCeil(values, 6, false, true));
assertEquals(2, Util.binarySearchCeil(values, 6, true, true));
}
public void testParseXsDuration() {
assertEquals(150279L, Util.parseXsDuration("PT150.279S"));
assertEquals(1500L, Util.parseXsDuration("PT1.500S"));
}
public void testParseXsDateTime() throws ParseException {
assertEquals(1403219262000L, Util.parseXsDateTime("2014-06-19T23:07:42"));
assertEquals(1407322800000L, Util.parseXsDateTime("2014-08-06T11:00:00Z"));
}
}

View File

@ -0,0 +1 @@
This file is needed to make sure the libs directory is present.

View File

@ -0,0 +1,14 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-21

View File

@ -0,0 +1,2 @@
This file is needed to make sure the res directory is present.
The file is ignored by the Android toolchain because its name starts with a dot.

201
third_party/dexmaker/LICENSE vendored Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

BIN
third_party/dexmaker/dexmaker-1.2.jar vendored Normal file

Binary file not shown.

Binary file not shown.

21
third_party/mockito/LICENSE vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2008-2010 Mockito contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Binary file not shown.