Fix moe config

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=166914821
This commit is contained in:
olly 2017-08-29 15:38:04 -07:00 committed by Oliver Woodman
parent 5bed2bf503
commit b0df6dce98
6 changed files with 681 additions and 292 deletions

View File

@ -1,123 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.offline;
import android.test.InstrumentationTestCase;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.DummyDataSource;
import com.google.android.exoplayer2.upstream.cache.Cache;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.mockito.Mockito;
/**
* Unit tests for {@link ProgressiveDownloadAction}.
*/
public class ProgressiveDownloadActionTest extends InstrumentationTestCase {
public void testDownloadActionIsNotRemoveAction() throws Exception {
ProgressiveDownloadAction action = new ProgressiveDownloadAction("uri", null, false);
assertFalse(action.isRemoveAction());
}
public void testRemoveActionIsRemoveAction() throws Exception {
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction("uri", null, true);
assertTrue(action2.isRemoveAction());
}
public void testCreateDownloader() throws Exception {
TestUtil.setUpMockito(this);
ProgressiveDownloadAction action = new ProgressiveDownloadAction("uri", null, false);
DownloaderConstructorHelper constructorHelper = new DownloaderConstructorHelper(
Mockito.mock(Cache.class), DummyDataSource.FACTORY);
assertNotNull(action.createDownloader(constructorHelper));
}
public void testSameUriCacheKeyDifferentAction_IsSameMedia() throws Exception {
ProgressiveDownloadAction action1 = new ProgressiveDownloadAction("uri", null, true);
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction("uri", null, false);
assertTrue(action1.isSameMedia(action2));
}
public void testNullCacheKeyDifferentUriAction_IsNotSameMedia() throws Exception {
ProgressiveDownloadAction action3 = new ProgressiveDownloadAction("uri2", null, true);
ProgressiveDownloadAction action4 = new ProgressiveDownloadAction("uri", null, false);
assertFalse(action3.isSameMedia(action4));
}
public void testSameCacheKeyDifferentUriAction_IsSameMedia() throws Exception {
ProgressiveDownloadAction action5 = new ProgressiveDownloadAction("uri2", "key", true);
ProgressiveDownloadAction action6 = new ProgressiveDownloadAction("uri", "key", false);
assertTrue(action5.isSameMedia(action6));
}
public void testSameUriDifferentCacheKeyAction_IsNotSameMedia() throws Exception {
ProgressiveDownloadAction action7 = new ProgressiveDownloadAction("uri", "key", true);
ProgressiveDownloadAction action8 = new ProgressiveDownloadAction("uri", "key2", false);
assertFalse(action7.isSameMedia(action8));
}
public void testEquals() throws Exception {
ProgressiveDownloadAction action1 = new ProgressiveDownloadAction("uri", null, true);
assertTrue(action1.equals(action1));
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction("uri", null, true);
ProgressiveDownloadAction action3 = new ProgressiveDownloadAction("uri", null, true);
assertTrue(action2.equals(action3));
ProgressiveDownloadAction action4 = new ProgressiveDownloadAction("uri", null, true);
ProgressiveDownloadAction action5 = new ProgressiveDownloadAction("uri", null, false);
assertFalse(action4.equals(action5));
ProgressiveDownloadAction action6 = new ProgressiveDownloadAction("uri", null, true);
ProgressiveDownloadAction action7 = new ProgressiveDownloadAction("uri", "key", true);
assertFalse(action6.equals(action7));
ProgressiveDownloadAction action8 = new ProgressiveDownloadAction("uri", "key2", true);
ProgressiveDownloadAction action9 = new ProgressiveDownloadAction("uri", "key", true);
assertFalse(action8.equals(action9));
ProgressiveDownloadAction action10 = new ProgressiveDownloadAction("uri", null, true);
ProgressiveDownloadAction action11 = new ProgressiveDownloadAction("uri2", null, true);
assertFalse(action10.equals(action11));
}
public void testSerializerGetType() throws Exception {
ProgressiveDownloadAction action = new ProgressiveDownloadAction("uri", null, false);
assertNotNull(action.getType());
}
public void testSerializerWriteRead() throws Exception {
doTestSerializationRoundTrip(new ProgressiveDownloadAction("uri1", null, false));
doTestSerializationRoundTrip(new ProgressiveDownloadAction("uri2", "key", true));
}
private void doTestSerializationRoundTrip(ProgressiveDownloadAction action1) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(out);
action1.writeToStream(output);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
DataInputStream input = new DataInputStream(in);
DownloadAction action2 = ProgressiveDownloadAction.DESERIALIZER.readFromStream(input);
assertEquals(action1, action2);
}
}

View File

@ -0,0 +1,102 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.source.dash.offline;
import android.net.Uri;
import com.google.android.exoplayer2.util.ClosedSource;
/**
* Data for DASH downloading tests.
*/
@ClosedSource(reason = "Not ready yet")
/* package */ interface DashDownloadTestData {
Uri TEST_MPD_URI = Uri.parse("test.mpd");
byte[] TEST_MPD =
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" type=\"static\" "
+ " mediaPresentationDuration=\"PT31S\">\n"
+ " <Period duration=\"PT16S\" >\n"
+ " <AdaptationSet>\n"
+ " <SegmentList>\n"
+ " <SegmentTimeline>\n"
+ " <S d=\"5\" />\n"
+ " <S d=\"5\" />\n"
+ " <S d=\"5\" />\n"
+ " </SegmentTimeline>\n"
+ " </SegmentList>\n"
+ " <Representation>\n"
+ " <SegmentList>\n"
// Bounded range data
+ " <Initialization range=\"0-9\" sourceURL=\"audio_init_data\" />\n"
// Unbounded range data
+ " <SegmentURL media=\"audio_segment_1\" />\n"
+ " <SegmentURL media=\"audio_segment_2\" />\n"
+ " <SegmentURL media=\"audio_segment_3\" />\n"
+ " </SegmentList>\n"
+ " </Representation>\n"
+ " </AdaptationSet>\n"
+ " <AdaptationSet>\n"
// This segment list has a 1 second offset to make sure the progressive download order
+ " <SegmentList>\n"
+ " <SegmentTimeline>\n"
+ " <S t=\"1\" d=\"5\" />\n" // 1s offset
+ " <S d=\"5\" />\n"
+ " <S d=\"5\" />\n"
+ " </SegmentTimeline>\n"
+ " </SegmentList>\n"
+ " <Representation>\n"
+ " <SegmentList>\n"
+ " <SegmentURL media=\"text_segment_1\" />\n"
+ " <SegmentURL media=\"text_segment_2\" />\n"
+ " <SegmentURL media=\"text_segment_3\" />\n"
+ " </SegmentList>\n"
+ " </Representation>\n"
+ " </AdaptationSet>\n"
+ " </Period>\n"
+ " <Period>\n"
+ " <SegmentList>\n"
+ " <SegmentTimeline>\n"
+ " <S d=\"5\" />\n"
+ " <S d=\"5\" />\n"
+ " <S d=\"5\" />\n"
+ " </SegmentTimeline>\n"
+ " </SegmentList>\n"
+ " <AdaptationSet>\n"
+ " <Representation>\n"
+ " <SegmentList>\n"
+ " <SegmentURL media=\"period_2_segment_1\" />\n"
+ " <SegmentURL media=\"period_2_segment_2\" />\n"
+ " <SegmentURL media=\"period_2_segment_3\" />\n"
+ " </SegmentList>\n"
+ " </Representation>\n"
+ " </AdaptationSet>\n"
+ " </Period>\n"
+ "</MPD>").getBytes();
byte[] TEST_MPD_NO_INDEX =
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" type=\"dynamic\">\n"
+ " <Period start=\"PT6462826.784S\" >\n"
+ " <AdaptationSet>\n"
+ " <Representation>\n"
+ " <SegmentBase indexRange='0-10'/>\n"
+ " </Representation>\n"
+ " </AdaptationSet>\n"
+ " </Period>\n"
+ "</MPD>").getBytes();
}

View File

@ -0,0 +1,406 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.source.dash.offline;
import static com.google.android.exoplayer2.source.dash.offline.DashDownloadTestData.TEST_MPD;
import static com.google.android.exoplayer2.source.dash.offline.DashDownloadTestData.TEST_MPD_NO_INDEX;
import static com.google.android.exoplayer2.source.dash.offline.DashDownloadTestData.TEST_MPD_URI;
import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCacheEmpty;
import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCachedData;
import static com.google.android.exoplayer2.testutil.CacheAsserts.assertDataCached;
import android.test.InstrumentationTestCase;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.DownloadException;
import com.google.android.exoplayer2.offline.Downloader.ProgressListener;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
import com.google.android.exoplayer2.testutil.FakeDataSet;
import com.google.android.exoplayer2.testutil.FakeDataSource;
import com.google.android.exoplayer2.testutil.FakeDataSource.Factory;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Util;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import org.mockito.InOrder;
import org.mockito.Mockito;
/**
* Unit tests for {@link DashDownloader}.
*/
public class DashDownloaderTest extends InstrumentationTestCase {
private SimpleCache cache;
private File tempFolder;
@Override
public void setUp() throws Exception {
super.setUp();
TestUtil.setUpMockito(this);
tempFolder = Util.createTempDirectory(getInstrumentation().getContext(), "ExoPlayerTest");
cache = new SimpleCache(tempFolder, new NoOpCacheEvictor());
}
@Override
public void tearDown() throws Exception {
Util.recursiveDelete(tempFolder);
super.tearDown();
}
public void testGetManifest() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet()
.setData(TEST_MPD_URI, TEST_MPD);
DashDownloader dashDownloader = getDashDownloader(fakeDataSet);
DashManifest manifest = dashDownloader.getManifest();
assertNotNull(manifest);
assertCachedData(cache, fakeDataSet);
}
public void testDownloadManifestFailure() throws Exception {
byte[] testMpdFirstPart = Arrays.copyOf(TEST_MPD, 10);
byte[] testMpdSecondPart = Arrays.copyOfRange(TEST_MPD, 10, TEST_MPD.length);
FakeDataSet fakeDataSet = new FakeDataSet()
.newData(TEST_MPD_URI)
.appendReadData(testMpdFirstPart)
.appendReadError(new IOException())
.appendReadData(testMpdSecondPart)
.endData();
DashDownloader dashDownloader = getDashDownloader(fakeDataSet);
// fails on the first try
try {
dashDownloader.getManifest();
fail();
} catch (IOException e) {
// ignore
}
assertDataCached(cache, TEST_MPD_URI, testMpdFirstPart);
// on the second try it downloads the rest of the data
DashManifest manifest = dashDownloader.getManifest();
assertNotNull(manifest);
assertCachedData(cache, fakeDataSet);
}
public void testDownloadRepresentation() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet()
.setData(TEST_MPD_URI, TEST_MPD)
.setRandomData("audio_init_data", 10)
.setRandomData("audio_segment_1", 4)
.setRandomData("audio_segment_2", 5)
.setRandomData("audio_segment_3", 6);
DashDownloader dashDownloader = getDashDownloader(fakeDataSet);
dashDownloader.selectRepresentations(new RepresentationKey[] {new RepresentationKey(0, 0, 0)});
dashDownloader.download(null);
assertCachedData(cache, fakeDataSet);
}
public void testDownloadRepresentationInSmallParts() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet()
.setData(TEST_MPD_URI, TEST_MPD)
.setRandomData("audio_init_data", 10)
.newData("audio_segment_1")
.appendReadData(TestUtil.buildTestData(10))
.appendReadData(TestUtil.buildTestData(10))
.appendReadData(TestUtil.buildTestData(10))
.endData()
.setRandomData("audio_segment_2", 5)
.setRandomData("audio_segment_3", 6);
DashDownloader dashDownloader = getDashDownloader(fakeDataSet);
dashDownloader.selectRepresentations(new RepresentationKey[] {new RepresentationKey(0, 0, 0)});
dashDownloader.download(null);
assertCachedData(cache, fakeDataSet);
}
public void testDownloadRepresentations() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet()
.setData(TEST_MPD_URI, TEST_MPD)
.setRandomData("audio_init_data", 10)
.setRandomData("audio_segment_1", 4)
.setRandomData("audio_segment_2", 5)
.setRandomData("audio_segment_3", 6)
.setRandomData("text_segment_1", 1)
.setRandomData("text_segment_2", 2)
.setRandomData("text_segment_3", 3);
DashDownloader dashDownloader = getDashDownloader(fakeDataSet);
dashDownloader.selectRepresentations(
new RepresentationKey[] {new RepresentationKey(0, 0, 0), new RepresentationKey(0, 1, 0)});
dashDownloader.download(null);
assertCachedData(cache, fakeDataSet);
}
public void testDownloadAllRepresentations() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet()
.setData(TEST_MPD_URI, TEST_MPD)
.setRandomData("audio_init_data", 10)
.setRandomData("audio_segment_1", 4)
.setRandomData("audio_segment_2", 5)
.setRandomData("audio_segment_3", 6)
.setRandomData("text_segment_1", 1)
.setRandomData("text_segment_2", 2)
.setRandomData("text_segment_3", 3)
.setRandomData("period_2_segment_1", 1)
.setRandomData("period_2_segment_2", 2)
.setRandomData("period_2_segment_3", 3);
DashDownloader dashDownloader = getDashDownloader(fakeDataSet);
// dashDownloader.selectRepresentations() isn't called
dashDownloader.download(null);
assertCachedData(cache, fakeDataSet);
dashDownloader.remove();
// select something random
dashDownloader.selectRepresentations(new RepresentationKey[] {new RepresentationKey(0, 0, 0)});
// clear selection
dashDownloader.selectRepresentations(null);
dashDownloader.download(null);
assertCachedData(cache, fakeDataSet);
dashDownloader.remove();
dashDownloader.selectRepresentations(new RepresentationKey[0]);
dashDownloader.download(null);
assertCachedData(cache, fakeDataSet);
dashDownloader.remove();
}
public void testProgressiveDownload() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet()
.setData(TEST_MPD_URI, TEST_MPD)
.setRandomData("audio_init_data", 10)
.setRandomData("audio_segment_1", 4)
.setRandomData("audio_segment_2", 5)
.setRandomData("audio_segment_3", 6)
.setRandomData("text_segment_1", 1)
.setRandomData("text_segment_2", 2)
.setRandomData("text_segment_3", 3);
FakeDataSource fakeDataSource = new FakeDataSource(fakeDataSet);
Factory factory = Mockito.mock(Factory.class);
Mockito.when(factory.createDataSource()).thenReturn(fakeDataSource);
DashDownloader dashDownloader = new DashDownloader(TEST_MPD_URI,
new DownloaderConstructorHelper(cache, factory));
dashDownloader.selectRepresentations(
new RepresentationKey[] {new RepresentationKey(0, 0, 0), new RepresentationKey(0, 1, 0)});
dashDownloader.download(null);
DataSpec[] openedDataSpecs = fakeDataSource.getAndClearOpenedDataSpecs();
assertEquals(8, openedDataSpecs.length);
assertEquals(TEST_MPD_URI, openedDataSpecs[0].uri);
assertEquals("audio_init_data", openedDataSpecs[1].uri.getPath());
assertEquals("audio_segment_1", openedDataSpecs[2].uri.getPath());
assertEquals("text_segment_1", openedDataSpecs[3].uri.getPath());
assertEquals("audio_segment_2", openedDataSpecs[4].uri.getPath());
assertEquals("text_segment_2", openedDataSpecs[5].uri.getPath());
assertEquals("audio_segment_3", openedDataSpecs[6].uri.getPath());
assertEquals("text_segment_3", openedDataSpecs[7].uri.getPath());
}
public void testProgressiveDownloadSeparatePeriods() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet()
.setData(TEST_MPD_URI, TEST_MPD)
.setRandomData("audio_init_data", 10)
.setRandomData("audio_segment_1", 4)
.setRandomData("audio_segment_2", 5)
.setRandomData("audio_segment_3", 6)
.setRandomData("period_2_segment_1", 1)
.setRandomData("period_2_segment_2", 2)
.setRandomData("period_2_segment_3", 3);
FakeDataSource fakeDataSource = new FakeDataSource(fakeDataSet);
Factory factory = Mockito.mock(Factory.class);
Mockito.when(factory.createDataSource()).thenReturn(fakeDataSource);
DashDownloader dashDownloader = new DashDownloader(TEST_MPD_URI,
new DownloaderConstructorHelper(cache, factory));
dashDownloader.selectRepresentations(
new RepresentationKey[] {new RepresentationKey(0, 0, 0), new RepresentationKey(1, 0, 0)});
dashDownloader.download(null);
DataSpec[] openedDataSpecs = fakeDataSource.getAndClearOpenedDataSpecs();
assertEquals(8, openedDataSpecs.length);
assertEquals(TEST_MPD_URI, openedDataSpecs[0].uri);
assertEquals("audio_init_data", openedDataSpecs[1].uri.getPath());
assertEquals("audio_segment_1", openedDataSpecs[2].uri.getPath());
assertEquals("audio_segment_2", openedDataSpecs[3].uri.getPath());
assertEquals("audio_segment_3", openedDataSpecs[4].uri.getPath());
assertEquals("period_2_segment_1", openedDataSpecs[5].uri.getPath());
assertEquals("period_2_segment_2", openedDataSpecs[6].uri.getPath());
assertEquals("period_2_segment_3", openedDataSpecs[7].uri.getPath());
}
public void testDownloadRepresentationFailure() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet()
.setData(TEST_MPD_URI, TEST_MPD)
.setRandomData("audio_init_data", 10)
.setRandomData("audio_segment_1", 4)
.newData("audio_segment_2")
.appendReadData(TestUtil.buildTestData(2))
.appendReadError(new IOException())
.appendReadData(TestUtil.buildTestData(3))
.endData()
.setRandomData("audio_segment_3", 6);
DashDownloader dashDownloader = getDashDownloader(fakeDataSet);
dashDownloader.selectRepresentations(new RepresentationKey[] {new RepresentationKey(0, 0, 0)});
// downloadRepresentations fails on the first try
try {
dashDownloader.download(null);
fail();
} catch (IOException e) {
// ignore
}
dashDownloader.download(null);
assertCachedData(cache, fakeDataSet);
}
public void testCounters() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet()
.setData(TEST_MPD_URI, TEST_MPD)
.setRandomData("audio_init_data", 10)
.setRandomData("audio_segment_1", 4)
.newData("audio_segment_2")
.appendReadData(TestUtil.buildTestData(2))
.appendReadError(new IOException())
.appendReadData(TestUtil.buildTestData(3))
.endData()
.setRandomData("audio_segment_3", 6);
DashDownloader dashDownloader = getDashDownloader(fakeDataSet);
assertCounters(dashDownloader, C.LENGTH_UNSET, C.LENGTH_UNSET, C.LENGTH_UNSET);
dashDownloader.selectRepresentations(new RepresentationKey[] {new RepresentationKey(0, 0, 0)});
dashDownloader.init();
assertCounters(dashDownloader, C.LENGTH_UNSET, C.LENGTH_UNSET, C.LENGTH_UNSET);
// downloadRepresentations fails after downloading init data, segment 1 and 2 bytes in segment 2
try {
dashDownloader.download(null);
fail();
} catch (IOException e) {
// ignore
}
dashDownloader.init();
assertCounters(dashDownloader, 4, 2, 10 + 4 + 2);
dashDownloader.download(null);
assertCounters(dashDownloader, 4, 4, 10 + 4 + 5 + 6);
}
public void testListener() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet()
.setData(TEST_MPD_URI, TEST_MPD)
.setRandomData("audio_init_data", 10)
.setRandomData("audio_segment_1", 4)
.setRandomData("audio_segment_2", 5)
.setRandomData("audio_segment_3", 6);
DashDownloader dashDownloader = getDashDownloader(fakeDataSet);
dashDownloader.selectRepresentations(new RepresentationKey[] {new RepresentationKey(0, 0, 0)});
ProgressListener mockListener = Mockito.mock(ProgressListener.class);
dashDownloader.download(mockListener);
InOrder inOrder = Mockito.inOrder(mockListener);
inOrder.verify(mockListener).onDownloadProgress(dashDownloader, 0.0f, 0);
inOrder.verify(mockListener).onDownloadProgress(dashDownloader, 25.0f, 10);
inOrder.verify(mockListener).onDownloadProgress(dashDownloader, 50.0f, 14);
inOrder.verify(mockListener).onDownloadProgress(dashDownloader, 75.0f, 19);
inOrder.verify(mockListener).onDownloadProgress(dashDownloader, 100.0f, 25);
inOrder.verifyNoMoreInteractions();
}
public void testRemoveAll() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet()
.setData(TEST_MPD_URI, TEST_MPD)
.setRandomData("audio_init_data", 10)
.setRandomData("audio_segment_1", 4)
.setRandomData("audio_segment_2", 5)
.setRandomData("audio_segment_3", 6)
.setRandomData("text_segment_1", 1)
.setRandomData("text_segment_2", 2)
.setRandomData("text_segment_3", 3);
DashDownloader dashDownloader = getDashDownloader(fakeDataSet);
dashDownloader.selectRepresentations(
new RepresentationKey[] {new RepresentationKey(0, 0, 0), new RepresentationKey(0, 1, 0)});
dashDownloader.download(null);
dashDownloader.remove();
assertCacheEmpty(cache);
}
public void testRepresentationWithoutIndex() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet()
.setData(TEST_MPD_URI, TEST_MPD_NO_INDEX)
.setRandomData("test_segment_1", 4);
DashDownloader dashDownloader = getDashDownloader(fakeDataSet);
dashDownloader.selectRepresentations(new RepresentationKey[] {new RepresentationKey(0, 0, 0)});
dashDownloader.init();
try {
dashDownloader.download(null);
fail();
} catch (DownloadException e) {
// expected exception.
}
dashDownloader.remove();
assertCacheEmpty(cache);
}
public void testSelectRepresentationsClearsPreviousSelection() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet()
.setData(TEST_MPD_URI, TEST_MPD)
.setRandomData("audio_init_data", 10)
.setRandomData("audio_segment_1", 4)
.setRandomData("audio_segment_2", 5)
.setRandomData("audio_segment_3", 6);
DashDownloader dashDownloader = getDashDownloader(fakeDataSet);
dashDownloader.selectRepresentations(
new RepresentationKey[] {new RepresentationKey(0, 0, 0), new RepresentationKey(0, 1, 0)});
dashDownloader.selectRepresentations(new RepresentationKey[] {new RepresentationKey(0, 0, 0)});
dashDownloader.download(null);
assertCachedData(cache, fakeDataSet);
}
private DashDownloader getDashDownloader(FakeDataSet fakeDataSet) {
Factory factory = new Factory(null).setFakeDataSet(fakeDataSet);
return new DashDownloader(TEST_MPD_URI, new DownloaderConstructorHelper(cache, factory));
}
private static void assertCounters(DashDownloader dashDownloader, int totalSegments,
int downloadedSegments, int downloadedBytes) {
assertEquals(totalSegments, dashDownloader.getTotalSegments());
assertEquals(downloadedSegments, dashDownloader.getDownloadedSegments());
assertEquals(downloadedBytes, dashDownloader.getDownloadedBytes());
}
}

View File

@ -0,0 +1,173 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.source.dash.offline;
import android.net.Uri;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.ChunkIndex;
import com.google.android.exoplayer2.offline.DownloadException;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.offline.SegmentDownloader;
import com.google.android.exoplayer2.source.dash.DashSegmentIndex;
import com.google.android.exoplayer2.source.dash.DashUtil;
import com.google.android.exoplayer2.source.dash.DashWrappingSegmentIndex;
import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet;
import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
import com.google.android.exoplayer2.source.dash.manifest.Period;
import com.google.android.exoplayer2.source.dash.manifest.RangedUri;
import com.google.android.exoplayer2.source.dash.manifest.Representation;
import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Helper class to download DASH streams.
*
* <p>Except {@link #getTotalSegments()}, {@link #getDownloadedSegments()} and {@link
* #getDownloadedBytes()}, this class isn't thread safe.
*
* <p>Example usage:
*
* <pre>
* {@code
* SimpleCache cache = new SimpleCache(downloadFolder, new NoOpCacheEvictor());
* DefaultHttpDataSourceFactory factory = new DefaultHttpDataSourceFactory("ExoPlayer", null);
* DownloaderConstructorHelper constructorHelper =
* new DownloaderConstructorHelper(cache, factory);
* DashDownloader dashDownloader = new DashDownloader(manifestUrl, constructorHelper);
* // Select the first representation of the first adaptation set of the first period
* dashDownloader.selectRepresentations(new RepresentationKey[] {new RepresentationKey(0, 0, 0)});
* dashDownloader.download(new ProgressListener() {
* @Override
* public void onDownloadProgress(Downloader downloader, float downloadPercentage,
* long downloadedBytes) {
* // Invoked periodically during the download.
* }
* });
* // Access downloaded data using CacheDataSource
* CacheDataSource cacheDataSource =
* new CacheDataSource(cache, factory.createDataSource(), CacheDataSource.FLAG_BLOCK_ON_CACHE);}
* </pre>
*/
public final class DashDownloader extends SegmentDownloader<DashManifest, RepresentationKey> {
/**
* @see SegmentDownloader#SegmentDownloader(Uri, DownloaderConstructorHelper)
*/
public DashDownloader(Uri manifestUri, DownloaderConstructorHelper constructorHelper) {
super(manifestUri, constructorHelper);
}
@Override
public DashManifest getManifest(DataSource dataSource, Uri uri) throws IOException {
return DashUtil.loadManifest(dataSource, uri);
}
@Override
protected List<Segment> getAllSegments(DataSource dataSource, DashManifest manifest,
boolean allowIndexLoadErrors) throws InterruptedException, IOException {
ArrayList<Segment> segments = new ArrayList<>();
for (int periodIndex = 0; periodIndex < manifest.getPeriodCount(); periodIndex++) {
List<AdaptationSet> adaptationSets = manifest.getPeriod(periodIndex).adaptationSets;
for (int adaptationIndex = 0; adaptationIndex < adaptationSets.size(); adaptationIndex++) {
AdaptationSet adaptationSet = adaptationSets.get(adaptationIndex);
RepresentationKey[] keys = new RepresentationKey[adaptationSet.representations.size()];
for (int i = 0; i < keys.length; i++) {
keys[i] = new RepresentationKey(periodIndex, adaptationIndex, i);
}
segments.addAll(getSegments(dataSource, manifest, keys, allowIndexLoadErrors));
}
}
return segments;
}
@Override
protected List<Segment> getSegments(DataSource dataSource, DashManifest manifest,
RepresentationKey[] keys, boolean allowIndexLoadErrors)
throws InterruptedException, IOException {
ArrayList<Segment> segments = new ArrayList<>();
for (RepresentationKey key : keys) {
DashSegmentIndex index;
try {
index = getSegmentIndex(dataSource, manifest, key);
if (index == null) {
// Loading succeeded but there was no index. This is always a failure.
throw new DownloadException("No index for representation: " + key);
}
} catch (IOException e) {
if (allowIndexLoadErrors) {
// Loading failed, but load errors are allowed. Advance to the next key.
continue;
} else {
throw e;
}
}
int segmentCount = index.getSegmentCount(C.TIME_UNSET);
if (segmentCount == DashSegmentIndex.INDEX_UNBOUNDED) {
throw new DownloadException("Unbounded index for representation: " + key);
}
Period period = manifest.getPeriod(key.periodIndex);
Representation representation = period.adaptationSets.get(key.adaptationSetIndex)
.representations.get(key.representationIndex);
long startUs = C.msToUs(period.startMs);
String baseUrl = representation.baseUrl;
RangedUri initializationUri = representation.getInitializationUri();
if (initializationUri != null) {
addSegment(segments, startUs, baseUrl, initializationUri);
}
RangedUri indexUri = representation.getIndexUri();
if (indexUri != null) {
addSegment(segments, startUs, baseUrl, indexUri);
}
int firstSegmentNum = index.getFirstSegmentNum();
int lastSegmentNum = firstSegmentNum + segmentCount - 1;
for (int j = firstSegmentNum; j <= lastSegmentNum; j++) {
addSegment(segments, startUs + index.getTimeUs(j), baseUrl, index.getSegmentUrl(j));
}
}
return segments;
}
/**
* Returns DashSegmentIndex for given representation.
*/
private DashSegmentIndex getSegmentIndex(DataSource dataSource, DashManifest manifest,
RepresentationKey key) throws IOException, InterruptedException {
AdaptationSet adaptationSet = manifest.getPeriod(key.periodIndex).adaptationSets.get(
key.adaptationSetIndex);
Representation representation = adaptationSet.representations.get(key.representationIndex);
DashSegmentIndex index = representation.getIndex();
if (index != null) {
return index;
}
ChunkIndex seekMap = DashUtil.loadChunkIndex(dataSource, adaptationSet.type, representation);
return seekMap == null ? null : new DashWrappingSegmentIndex(seekMap);
}
private static void addSegment(ArrayList<Segment> segments, long startTimeUs, String baseUrl,
RangedUri rangedUri) {
DataSpec dataSpec = new DataSpec(rangedUri.resolveUri(baseUrl), rangedUri.start,
rangedUri.length, null);
segments.add(new Segment(startTimeUs, dataSpec));
}
}

View File

@ -1,83 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.source.hls.offline;
import android.net.Uri;
import com.google.android.exoplayer2.offline.DownloadAction;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.offline.SegmentDownloadAction;
import com.google.android.exoplayer2.util.ClosedSource;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/** An action to download or remove downloaded HLS streams. */
@ClosedSource(reason = "Not ready yet")
public final class HlsDownloadAction extends SegmentDownloadAction<String> {
public static final Deserializer DESERIALIZER = new SegmentDownloadActionDeserializer<String>() {
@Override
public String getType() {
return TYPE;
}
@Override
protected String readKey(DataInputStream input) throws IOException {
return input.readUTF();
}
@Override
protected String[] createKeyArray(int keyCount) {
return new String[0];
}
@Override
protected DownloadAction createDownloadAction(Uri manifestUri, boolean removeAction,
String[] keys) {
return new HlsDownloadAction(manifestUri, removeAction, keys);
}
};
private static final String TYPE = "HlsDownloadAction";
/** @see SegmentDownloadAction#SegmentDownloadAction(Uri, boolean, Object[]) */
public HlsDownloadAction(Uri manifestUri, boolean removeAction, String... keys) {
super(manifestUri, removeAction, keys);
}
@Override
public String getType() {
return TYPE;
}
@Override
public HlsDownloader createDownloader(DownloaderConstructorHelper constructorHelper)
throws IOException {
HlsDownloader downloader = new HlsDownloader(manifestUri, constructorHelper);
if (!isRemoveAction()) {
downloader.selectRepresentations(keys);
}
return downloader;
}
@Override
protected void writeKey(DataOutputStream output, String key) throws IOException {
output.writeUTF(key);
}
}

View File

@ -1,86 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.source.smoothstreaming.offline;
import android.net.Uri;
import com.google.android.exoplayer2.offline.DownloadAction;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.offline.SegmentDownloadAction;
import com.google.android.exoplayer2.source.smoothstreaming.manifest.TrackKey;
import com.google.android.exoplayer2.util.ClosedSource;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/** An action to download or remove downloaded SmoothStreaming streams. */
@ClosedSource(reason = "Not ready yet")
public final class SsDownloadAction extends SegmentDownloadAction<TrackKey> {
public static final Deserializer DESERIALIZER =
new SegmentDownloadActionDeserializer<TrackKey>() {
@Override
public String getType() {
return TYPE;
}
@Override
protected TrackKey readKey(DataInputStream input) throws IOException {
return new TrackKey(input.readInt(), input.readInt());
}
@Override
protected TrackKey[] createKeyArray(int keyCount) {
return new TrackKey[keyCount];
}
@Override
protected DownloadAction createDownloadAction(Uri manifestUri, boolean removeAction,
TrackKey[] keys) {
return new SsDownloadAction(manifestUri, removeAction, keys);
}
};
private static final String TYPE = "SsDownloadAction";
/** @see SegmentDownloadAction#SegmentDownloadAction(Uri, boolean, Object[]) */
public SsDownloadAction(Uri manifestUri, boolean removeAction, TrackKey... keys) {
super(manifestUri, removeAction, keys);
}
@Override
public String getType() {
return TYPE;
}
@Override
public SsDownloader createDownloader(DownloaderConstructorHelper constructorHelper)
throws IOException {
SsDownloader downloader = new SsDownloader(manifestUri, constructorHelper);
if (!isRemoveAction()) {
downloader.selectRepresentations(keys);
}
return downloader;
}
@Override
protected void writeKey(DataOutputStream output, TrackKey key) throws IOException {
output.writeInt(key.streamElementIndex);
output.writeInt(key.trackIndex);
}
}