move baseUrl from segments to representations: V2
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=138136090
This commit is contained in:
parent
6c7ead5d0c
commit
e2081f40fb
@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mpeg:DASH:schema:MPD:2011" xmlns:yt="http://youtube.com/yt/2012/10/10" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd" minBufferTime="PT1.500S" profiles="urn:mpeg:dash:profile:isoff-main:2011" type="dynamic" availabilityStartTime="2016-10-14T17:00:17" timeShiftBufferDepth="PT7200.000S" minimumUpdatePeriod="PT2.000S" yt:earliestMediaSequence="0" yt:mpdRequestTime="2016-10-14T18:29:17.082" yt:mpdResponseTime="2016-10-14T18:29:17.194">
|
||||||
|
<Period start="PT0.000S" yt:segmentIngestTime="2016-10-14T17:00:14.257">
|
||||||
|
<SegmentTemplate startNumber="0" timescale="1000" media="sq/$Number$">
|
||||||
|
<SegmentTimeline>
|
||||||
|
<S d="2002" t="6009" r="2"/>
|
||||||
|
<S d="1985"/>
|
||||||
|
<S d="2000"/>
|
||||||
|
</SegmentTimeline>
|
||||||
|
</SegmentTemplate>
|
||||||
|
<AdaptationSet id="0" mimeType="audio/mp4" subsegmentAlignment="true">
|
||||||
|
<Role schemeIdUri="urn:mpeg:DASH:role:2011" value="main"/>
|
||||||
|
<Representation id="140" codecs="mp4a.40.2" audioSamplingRate="48000" startWithSAP="1" bandwidth="144000">
|
||||||
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
|
<BaseURL>http://redirector.googlevideo.com/videoplayback/id/BktsoMO3OMs.0/itag/140/source/yt_live_broadcast/ratebypass/yes/cmbypass/yes/mime/audio%2Fmp4/live/1/gir/yes/noclen/1/signature/B5137EA0CC278C07DD056D204E863CC81EDEB39E.1AD5D242EBC94922EDA7165353A89A5E08A4103A/key/dg_test0/mpd_version/5/ip/0.0.0.0/ipbits/0/expire/1476490914/sparams/ip,ipbits,expire,id,itag,source,ratebypass,cmbypass,mime,live,gir,noclen/</BaseURL>
|
||||||
|
</Representation>
|
||||||
|
</AdaptationSet>
|
||||||
|
<AdaptationSet id="1" mimeType="video/mp4" subsegmentAlignment="true">
|
||||||
|
<Role schemeIdUri="urn:mpeg:DASH:role:2011" value="main"/>
|
||||||
|
<Representation id="133" codecs="avc1.4d4015" width="426" height="240" startWithSAP="1" maxPlayoutRate="1" bandwidth="258000" frameRate="30">
|
||||||
|
<BaseURL>http://redirector.googlevideo.com/videoplayback/id/BktsoMO3OMs.0/itag/133/source/yt_live_broadcast/ratebypass/yes/cmbypass/yes/mime/video%2Fmp4/live/1/gir/yes/noclen/1/signature/90154AE9C5C9D9D519CBF2E43AB0A1778375992D.40E2E855ADFB38FA7E95E168FEEEA6796B080BD7/key/dg_test0/mpd_version/5/ip/0.0.0.0/ipbits/0/expire/1476490914/sparams/ip,ipbits,expire,id,itag,source,ratebypass,cmbypass,mime,live,gir,noclen/</BaseURL>
|
||||||
|
</Representation>
|
||||||
|
<Representation id="134" codecs="avc1.4d401e" width="640" height="360" startWithSAP="1" maxPlayoutRate="1" bandwidth="646000" frameRate="30">
|
||||||
|
<BaseURL>http://redirector.googlevideo.com/videoplayback/id/BktsoMO3OMs.0/itag/134/source/yt_live_broadcast/ratebypass/yes/cmbypass/yes/mime/video%2Fmp4/live/1/gir/yes/noclen/1/signature/5C094AEFDCEB1A4D2F3C05F8BD095C336EF0E1C3.7AE6B9951B0237AAE6F031927AACAC4974BAFFAA/key/dg_test0/mpd_version/5/ip/0.0.0.0/ipbits/0/expire/1476490914/sparams/ip,ipbits,expire,id,itag,source,ratebypass,cmbypass,mime,live,gir,noclen/</BaseURL>
|
||||||
|
</Representation>
|
||||||
|
<Representation id="135" codecs="avc1.4d401f" width="854" height="480" startWithSAP="1" maxPlayoutRate="1" bandwidth="1171000" frameRate="30">
|
||||||
|
<BaseURL>http://redirector.googlevideo.com/videoplayback/id/BktsoMO3OMs.0/itag/135/source/yt_live_broadcast/ratebypass/yes/cmbypass/yes/mime/video%2Fmp4/live/1/gir/yes/noclen/1/signature/1F7660CA4E5B4AE4D60E18795680E34CDD2EF3C9.800B0A1D5F490DE142CCF4C88C64FD21D42129/key/dg_test0/mpd_version/5/ip/0.0.0.0/ipbits/0/expire/1476490914/sparams/ip,ipbits,expire,id,itag,source,ratebypass,cmbypass,mime,live,gir,noclen/</BaseURL>
|
||||||
|
</Representation>
|
||||||
|
<Representation id="160" codecs="avc1.42c00b" width="256" height="144" startWithSAP="1" maxPlayoutRate="1" bandwidth="124000" frameRate="30">
|
||||||
|
<BaseURL>http://redirector.googlevideo.com/videoplayback/id/BktsoMO3OMs.0/itag/160/source/yt_live_broadcast/ratebypass/yes/cmbypass/yes/mime/video%2Fmp4/live/1/gir/yes/noclen/1/signature/94EB61673784DF0C4237A1A866F2E171C8A64ADB.AEC00AA06C2278FEA8702FB62693B70D8977F46C/key/dg_test0/mpd_version/5/ip/0.0.0.0/ipbits/0/expire/1476490914/sparams/ip,ipbits,expire,id,itag,source,ratebypass,cmbypass,mime,live,gir,noclen/</BaseURL>
|
||||||
|
</Representation>
|
||||||
|
<Representation id="136" codecs="avc1.4d401f" width="1280" height="720" startWithSAP="1" maxPlayoutRate="1" bandwidth="2326000" frameRate="30">
|
||||||
|
<BaseURL>http://redirector.googlevideo.com/videoplayback/id/BktsoMO3OMs.0/itag/136/source/yt_live_broadcast/ratebypass/yes/cmbypass/yes/mime/video%2Fmp4/live/1/gir/yes/noclen/1/signature/6D8C34FC30A1F1A4F700B61180D1C4CCF6274844.29EBCB4A837DE626C52C66CF650519E61C2FF0BF/key/dg_test0/mpd_version/5/ip/0.0.0.0/ipbits/0/expire/1476490914/sparams/ip,ipbits,expire,id,itag,source,ratebypass,cmbypass,mime,live,gir,noclen/</BaseURL>
|
||||||
|
</Representation>
|
||||||
|
</AdaptationSet>
|
||||||
|
</Period>
|
||||||
|
</MPD>
|
||||||
|
|
@ -28,6 +28,8 @@ public class DashManifestParserTest extends InstrumentationTestCase {
|
|||||||
private static final String SAMPLE_MPD_1 = "dash/sample_mpd_1";
|
private static final String SAMPLE_MPD_1 = "dash/sample_mpd_1";
|
||||||
private static final String SAMPLE_MPD_2_UNKNOWN_MIME_TYPE =
|
private static final String SAMPLE_MPD_2_UNKNOWN_MIME_TYPE =
|
||||||
"dash/sample_mpd_2_unknown_mime_type";
|
"dash/sample_mpd_2_unknown_mime_type";
|
||||||
|
private static final String SAMPLE_MPD_3_SEGMENT_TEMPLATE =
|
||||||
|
"dash/sample_mpd_3_segment_template";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple test to ensure the sample manifests parse without any exceptions being thrown.
|
* Simple test to ensure the sample manifests parse without any exceptions being thrown.
|
||||||
@ -40,4 +42,30 @@ public class DashManifestParserTest extends InstrumentationTestCase {
|
|||||||
TestUtil.getInputStream(getInstrumentation(), SAMPLE_MPD_2_UNKNOWN_MIME_TYPE));
|
TestUtil.getInputStream(getInstrumentation(), SAMPLE_MPD_2_UNKNOWN_MIME_TYPE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testParseMediaPresentationDescriptionWithSegmentTemplate() throws IOException {
|
||||||
|
DashManifestParser parser = new DashManifestParser();
|
||||||
|
DashManifest mpd = parser.parse(Uri.parse("https://example.com/test.mpd"),
|
||||||
|
TestUtil.getInputStream(getInstrumentation(), SAMPLE_MPD_3_SEGMENT_TEMPLATE));
|
||||||
|
|
||||||
|
assertEquals(1, mpd.getPeriodCount());
|
||||||
|
|
||||||
|
Period period = mpd.getPeriod(0);
|
||||||
|
assertNotNull(period);
|
||||||
|
assertEquals(2, period.adaptationSets.size());
|
||||||
|
|
||||||
|
for (AdaptationSet adaptationSet : period.adaptationSets) {
|
||||||
|
assertNotNull(adaptationSet);
|
||||||
|
for (Representation representation : adaptationSet.representations) {
|
||||||
|
if (representation instanceof Representation.MultiSegmentRepresentation) {
|
||||||
|
Representation.MultiSegmentRepresentation multiSegmentRepresentation =
|
||||||
|
(Representation.MultiSegmentRepresentation) representation;
|
||||||
|
int firstSegmentIndex = multiSegmentRepresentation.getFirstSegmentNum();
|
||||||
|
RangedUri uri = multiSegmentRepresentation.getSegmentUrl(firstSegmentIndex);
|
||||||
|
assertTrue(uri.resolveUriString(representation.baseUrl).contains(
|
||||||
|
"redirector.googlevideo.com"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,56 +23,64 @@ import junit.framework.TestCase;
|
|||||||
*/
|
*/
|
||||||
public class RangedUriTest extends TestCase {
|
public class RangedUriTest extends TestCase {
|
||||||
|
|
||||||
private static final String FULL_URI = "http://www.test.com/path/file.ext";
|
private static final String BASE_URI = "http://www.test.com/";
|
||||||
|
private static final String PARTIAL_URI = "path/file.ext";
|
||||||
|
private static final String FULL_URI = BASE_URI + PARTIAL_URI;
|
||||||
|
|
||||||
public void testMerge() {
|
public void testMerge() {
|
||||||
RangedUri rangeA = new RangedUri(null, FULL_URI, 0, 10);
|
RangedUri rangeA = new RangedUri(FULL_URI, 0, 10);
|
||||||
RangedUri rangeB = new RangedUri(null, FULL_URI, 10, 10);
|
RangedUri rangeB = new RangedUri(FULL_URI, 10, 10);
|
||||||
RangedUri expected = new RangedUri(null, FULL_URI, 0, 20);
|
RangedUri expected = new RangedUri(FULL_URI, 0, 20);
|
||||||
assertMerge(rangeA, rangeB, expected);
|
assertMerge(rangeA, rangeB, expected, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMergeUnbounded() {
|
public void testMergeUnbounded() {
|
||||||
RangedUri rangeA = new RangedUri(null, FULL_URI, 0, 10);
|
RangedUri rangeA = new RangedUri(FULL_URI, 0, 10);
|
||||||
RangedUri rangeB = new RangedUri(null, FULL_URI, 10, C.LENGTH_UNSET);
|
RangedUri rangeB = new RangedUri(FULL_URI, 10, C.LENGTH_UNSET);
|
||||||
RangedUri expected = new RangedUri(null, FULL_URI, 0, C.LENGTH_UNSET);
|
RangedUri expected = new RangedUri(FULL_URI, 0, C.LENGTH_UNSET);
|
||||||
assertMerge(rangeA, rangeB, expected);
|
assertMerge(rangeA, rangeB, expected, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testNonMerge() {
|
public void testNonMerge() {
|
||||||
// A and B do not overlap, so should not merge
|
// A and B do not overlap, so should not merge
|
||||||
RangedUri rangeA = new RangedUri(null, FULL_URI, 0, 10);
|
RangedUri rangeA = new RangedUri(FULL_URI, 0, 10);
|
||||||
RangedUri rangeB = new RangedUri(null, FULL_URI, 11, 10);
|
RangedUri rangeB = new RangedUri(FULL_URI, 11, 10);
|
||||||
assertNonMerge(rangeA, rangeB);
|
assertNonMerge(rangeA, rangeB, null);
|
||||||
|
|
||||||
// A and B do not overlap, so should not merge
|
// A and B do not overlap, so should not merge
|
||||||
rangeA = new RangedUri(null, FULL_URI, 0, 10);
|
rangeA = new RangedUri(FULL_URI, 0, 10);
|
||||||
rangeB = new RangedUri(null, FULL_URI, 11, C.LENGTH_UNSET);
|
rangeB = new RangedUri(FULL_URI, 11, C.LENGTH_UNSET);
|
||||||
assertNonMerge(rangeA, rangeB);
|
assertNonMerge(rangeA, rangeB, null);
|
||||||
|
|
||||||
// A and B are bounded but overlap, so should not merge
|
// A and B are bounded but overlap, so should not merge
|
||||||
rangeA = new RangedUri(null, FULL_URI, 0, 11);
|
rangeA = new RangedUri(FULL_URI, 0, 11);
|
||||||
rangeB = new RangedUri(null, FULL_URI, 10, 10);
|
rangeB = new RangedUri(FULL_URI, 10, 10);
|
||||||
assertNonMerge(rangeA, rangeB);
|
assertNonMerge(rangeA, rangeB, null);
|
||||||
|
|
||||||
// A and B overlap due to unboundedness, so should not merge
|
// A and B overlap due to unboundedness, so should not merge
|
||||||
rangeA = new RangedUri(null, FULL_URI, 0, C.LENGTH_UNSET);
|
rangeA = new RangedUri(FULL_URI, 0, C.LENGTH_UNSET);
|
||||||
rangeB = new RangedUri(null, FULL_URI, 10, C.LENGTH_UNSET);
|
rangeB = new RangedUri(FULL_URI, 10, C.LENGTH_UNSET);
|
||||||
assertNonMerge(rangeA, rangeB);
|
assertNonMerge(rangeA, rangeB, null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertMerge(RangedUri rangeA, RangedUri rangeB, RangedUri expected) {
|
public void testMergeWithBaseUri() {
|
||||||
RangedUri merged = rangeA.attemptMerge(rangeB);
|
RangedUri rangeA = new RangedUri(PARTIAL_URI, 0, 10);
|
||||||
|
RangedUri rangeB = new RangedUri(FULL_URI, 10, 10);
|
||||||
|
RangedUri expected = new RangedUri(FULL_URI, 0, 20);
|
||||||
|
assertMerge(rangeA, rangeB, expected, BASE_URI);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertMerge(RangedUri rangeA, RangedUri rangeB, RangedUri expected, String baseUrl) {
|
||||||
|
RangedUri merged = rangeA.attemptMerge(rangeB, baseUrl);
|
||||||
assertEquals(expected, merged);
|
assertEquals(expected, merged);
|
||||||
merged = rangeB.attemptMerge(rangeA);
|
merged = rangeB.attemptMerge(rangeA, baseUrl);
|
||||||
assertEquals(expected, merged);
|
assertEquals(expected, merged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertNonMerge(RangedUri rangeA, RangedUri rangeB) {
|
private void assertNonMerge(RangedUri rangeA, RangedUri rangeB, String baseUrl) {
|
||||||
RangedUri merged = rangeA.attemptMerge(rangeB);
|
RangedUri merged = rangeA.attemptMerge(rangeB, baseUrl);
|
||||||
assertNull(merged);
|
assertNull(merged);
|
||||||
merged = rangeB.attemptMerge(rangeA);
|
merged = rangeB.attemptMerge(rangeA, baseUrl);
|
||||||
assertNull(merged);
|
assertNull(merged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,16 +27,17 @@ public class RepresentationTest extends TestCase {
|
|||||||
|
|
||||||
public void testGetCacheKey() {
|
public void testGetCacheKey() {
|
||||||
String uri = "http://www.google.com";
|
String uri = "http://www.google.com";
|
||||||
SegmentBase base = new SingleSegmentBase(new RangedUri(uri, null, 0, 1), 1, 0, uri, 1, 1);
|
SegmentBase base = new SingleSegmentBase(new RangedUri(null, 0, 1), 1, 0, 1, 1);
|
||||||
Format format = Format.createVideoContainerFormat("0", MimeTypes.APPLICATION_MP4, null,
|
Format format = Format.createVideoContainerFormat("0", MimeTypes.APPLICATION_MP4, null,
|
||||||
MimeTypes.VIDEO_H264, 2500000, 1920, 1080, Format.NO_VALUE, null);
|
MimeTypes.VIDEO_H264, 2500000, 1920, 1080, Format.NO_VALUE, null);
|
||||||
Representation representation = Representation.newInstance("test_stream_1", 3, format, base);
|
Representation representation = Representation.newInstance("test_stream_1", 3, format, uri,
|
||||||
|
base);
|
||||||
assertEquals("test_stream_1.0.3", representation.getCacheKey());
|
assertEquals("test_stream_1.0.3", representation.getCacheKey());
|
||||||
|
|
||||||
format = Format.createVideoContainerFormat("150", MimeTypes.APPLICATION_MP4, null,
|
format = Format.createVideoContainerFormat("150", MimeTypes.APPLICATION_MP4, null,
|
||||||
MimeTypes.VIDEO_H264, 2500000, 1920, 1080, Format.NO_VALUE, null);
|
MimeTypes.VIDEO_H264, 2500000, 1920, 1080, Format.NO_VALUE, null);
|
||||||
representation = Representation.newInstance("test_stream_1", Representation.REVISION_ID_DEFAULT,
|
representation = Representation.newInstance("test_stream_1", Representation.REVISION_ID_DEFAULT,
|
||||||
format, base);
|
format, uri, base);
|
||||||
assertEquals("test_stream_1.150.-1", representation.getCacheKey());
|
assertEquals("test_stream_1.150.-1", representation.getCacheKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@ import com.google.android.exoplayer2.source.dash.manifest.RangedUri;
|
|||||||
/* package */ final class DashWrappingSegmentIndex implements DashSegmentIndex {
|
/* package */ final class DashWrappingSegmentIndex implements DashSegmentIndex {
|
||||||
|
|
||||||
private final ChunkIndex chunkIndex;
|
private final ChunkIndex chunkIndex;
|
||||||
private final String uri;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param chunkIndex The {@link ChunkIndex} to wrap.
|
* @param chunkIndex The {@link ChunkIndex} to wrap.
|
||||||
@ -33,7 +32,6 @@ import com.google.android.exoplayer2.source.dash.manifest.RangedUri;
|
|||||||
*/
|
*/
|
||||||
public DashWrappingSegmentIndex(ChunkIndex chunkIndex, String uri) {
|
public DashWrappingSegmentIndex(ChunkIndex chunkIndex, String uri) {
|
||||||
this.chunkIndex = chunkIndex;
|
this.chunkIndex = chunkIndex;
|
||||||
this.uri = uri;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -58,7 +56,7 @@ import com.google.android.exoplayer2.source.dash.manifest.RangedUri;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RangedUri getSegmentUrl(int segmentNum) {
|
public RangedUri getSegmentUrl(int segmentNum) {
|
||||||
return new RangedUri(uri, null, chunkIndex.offsets[segmentNum], chunkIndex.sizes[segmentNum]);
|
return new RangedUri(null, chunkIndex.offsets[segmentNum], chunkIndex.sizes[segmentNum]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -288,18 +288,19 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
DataSource dataSource, Format trackFormat, int trackSelectionReason,
|
DataSource dataSource, Format trackFormat, int trackSelectionReason,
|
||||||
Object trackSelectionData, RangedUri initializationUri, RangedUri indexUri) {
|
Object trackSelectionData, RangedUri initializationUri, RangedUri indexUri) {
|
||||||
RangedUri requestUri;
|
RangedUri requestUri;
|
||||||
|
String baseUrl = representationHolder.representation.baseUrl;
|
||||||
if (initializationUri != null) {
|
if (initializationUri != null) {
|
||||||
// It's common for initialization and index data to be stored adjacently. Attempt to merge
|
// It's common for initialization and index data to be stored adjacently. Attempt to merge
|
||||||
// the two requests together to request both at once.
|
// the two requests together to request both at once.
|
||||||
requestUri = initializationUri.attemptMerge(indexUri);
|
requestUri = initializationUri.attemptMerge(indexUri, baseUrl);
|
||||||
if (requestUri == null) {
|
if (requestUri == null) {
|
||||||
requestUri = initializationUri;
|
requestUri = initializationUri;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
requestUri = indexUri;
|
requestUri = indexUri;
|
||||||
}
|
}
|
||||||
DataSpec dataSpec = new DataSpec(requestUri.getUri(), requestUri.start, requestUri.length,
|
DataSpec dataSpec = new DataSpec(requestUri.resolveUri(baseUrl), requestUri.start,
|
||||||
representationHolder.representation.getCacheKey());
|
requestUri.length, representationHolder.representation.getCacheKey());
|
||||||
return new InitializationChunk(dataSource, dataSpec, trackFormat,
|
return new InitializationChunk(dataSource, dataSpec, trackFormat,
|
||||||
trackSelectionReason, trackSelectionData, representationHolder.extractorWrapper);
|
trackSelectionReason, trackSelectionData, representationHolder.extractorWrapper);
|
||||||
}
|
}
|
||||||
@ -311,8 +312,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
long startTimeUs = representationHolder.getSegmentStartTimeUs(segmentNum);
|
long startTimeUs = representationHolder.getSegmentStartTimeUs(segmentNum);
|
||||||
long endTimeUs = representationHolder.getSegmentEndTimeUs(segmentNum);
|
long endTimeUs = representationHolder.getSegmentEndTimeUs(segmentNum);
|
||||||
RangedUri segmentUri = representationHolder.getSegmentUrl(segmentNum);
|
RangedUri segmentUri = representationHolder.getSegmentUrl(segmentNum);
|
||||||
DataSpec dataSpec = new DataSpec(segmentUri.getUri(), segmentUri.start, segmentUri.length,
|
DataSpec dataSpec = new DataSpec(segmentUri.resolveUri(representation.baseUrl),
|
||||||
representation.getCacheKey());
|
segmentUri.start, segmentUri.length, representation.getCacheKey());
|
||||||
|
|
||||||
if (representationHolder.extractorWrapper == null) {
|
if (representationHolder.extractorWrapper == null) {
|
||||||
return new SingleSampleMediaChunk(dataSource, dataSpec, trackFormat, trackSelectionReason,
|
return new SingleSampleMediaChunk(dataSource, dataSpec, trackFormat, trackSelectionReason,
|
||||||
|
@ -205,11 +205,11 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "AdaptationSet")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "AdaptationSet")) {
|
||||||
adaptationSets.add(parseAdaptationSet(xpp, baseUrl, segmentBase));
|
adaptationSets.add(parseAdaptationSet(xpp, baseUrl, segmentBase));
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
|
||||||
segmentBase = parseSegmentBase(xpp, baseUrl, null);
|
segmentBase = parseSegmentBase(xpp, null);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
|
||||||
segmentBase = parseSegmentList(xpp, baseUrl, null);
|
segmentBase = parseSegmentList(xpp, null);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
|
||||||
segmentBase = parseSegmentTemplate(xpp, baseUrl, null);
|
segmentBase = parseSegmentTemplate(xpp, null);
|
||||||
}
|
}
|
||||||
} while (!XmlPullParserUtil.isEndTag(xpp, "Period"));
|
} while (!XmlPullParserUtil.isEndTag(xpp, "Period"));
|
||||||
|
|
||||||
@ -263,11 +263,11 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "AudioChannelConfiguration")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "AudioChannelConfiguration")) {
|
||||||
audioChannels = parseAudioChannelConfiguration(xpp);
|
audioChannels = parseAudioChannelConfiguration(xpp);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
|
||||||
segmentBase = parseSegmentBase(xpp, baseUrl, (SingleSegmentBase) segmentBase);
|
segmentBase = parseSegmentBase(xpp, (SingleSegmentBase) segmentBase);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
|
||||||
segmentBase = parseSegmentList(xpp, baseUrl, (SegmentList) segmentBase);
|
segmentBase = parseSegmentList(xpp, (SegmentList) segmentBase);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
|
||||||
segmentBase = parseSegmentTemplate(xpp, baseUrl, (SegmentTemplate) segmentBase);
|
segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp)) {
|
} else if (XmlPullParserUtil.isStartTag(xpp)) {
|
||||||
parseAdaptationSetChild(xpp);
|
parseAdaptationSetChild(xpp);
|
||||||
}
|
}
|
||||||
@ -390,11 +390,11 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "AudioChannelConfiguration")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "AudioChannelConfiguration")) {
|
||||||
audioChannels = parseAudioChannelConfiguration(xpp);
|
audioChannels = parseAudioChannelConfiguration(xpp);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
|
||||||
segmentBase = parseSegmentBase(xpp, baseUrl, (SingleSegmentBase) segmentBase);
|
segmentBase = parseSegmentBase(xpp, (SingleSegmentBase) segmentBase);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
|
||||||
segmentBase = parseSegmentList(xpp, baseUrl, (SegmentList) segmentBase);
|
segmentBase = parseSegmentList(xpp, (SegmentList) segmentBase);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
|
||||||
segmentBase = parseSegmentTemplate(xpp, baseUrl, (SegmentTemplate) segmentBase);
|
segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "ContentProtection")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "ContentProtection")) {
|
||||||
SchemeData contentProtection = parseContentProtection(xpp);
|
SchemeData contentProtection = parseContentProtection(xpp);
|
||||||
if (contentProtection != null) {
|
if (contentProtection != null) {
|
||||||
@ -407,7 +407,7 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
audioSamplingRate, bandwidth, adaptationSetLanguage, codecs);
|
audioSamplingRate, bandwidth, adaptationSetLanguage, codecs);
|
||||||
segmentBase = segmentBase != null ? segmentBase : new SingleSegmentBase(baseUrl);
|
segmentBase = segmentBase != null ? segmentBase : new SingleSegmentBase(baseUrl);
|
||||||
|
|
||||||
return new RepresentationInfo(format, segmentBase, drmSchemeDatas);
|
return new RepresentationInfo(format, baseUrl, segmentBase, drmSchemeDatas);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Format buildFormat(String id, String containerMimeType, int width, int height,
|
protected Format buildFormat(String id, String containerMimeType, int width, int height,
|
||||||
@ -441,13 +441,13 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
format = format.copyWithDrmInitData(new DrmInitData(drmSchemeDatas));
|
format = format.copyWithDrmInitData(new DrmInitData(drmSchemeDatas));
|
||||||
}
|
}
|
||||||
return Representation.newInstance(contentId, Representation.REVISION_ID_DEFAULT, format,
|
return Representation.newInstance(contentId, Representation.REVISION_ID_DEFAULT, format,
|
||||||
representationInfo.segmentBase);
|
representationInfo.baseUrl, representationInfo.segmentBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SegmentBase, SegmentList and SegmentTemplate parsing.
|
// SegmentBase, SegmentList and SegmentTemplate parsing.
|
||||||
|
|
||||||
protected SingleSegmentBase parseSegmentBase(XmlPullParser xpp, String baseUrl,
|
protected SingleSegmentBase parseSegmentBase(XmlPullParser xpp, SingleSegmentBase parent)
|
||||||
SingleSegmentBase parent) throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
|
|
||||||
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
||||||
long presentationTimeOffset = parseLong(xpp, "presentationTimeOffset",
|
long presentationTimeOffset = parseLong(xpp, "presentationTimeOffset",
|
||||||
@ -466,21 +466,21 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
do {
|
do {
|
||||||
xpp.next();
|
xpp.next();
|
||||||
if (XmlPullParserUtil.isStartTag(xpp, "Initialization")) {
|
if (XmlPullParserUtil.isStartTag(xpp, "Initialization")) {
|
||||||
initialization = parseInitialization(xpp, baseUrl);
|
initialization = parseInitialization(xpp);
|
||||||
}
|
}
|
||||||
} while (!XmlPullParserUtil.isEndTag(xpp, "SegmentBase"));
|
} while (!XmlPullParserUtil.isEndTag(xpp, "SegmentBase"));
|
||||||
|
|
||||||
return buildSingleSegmentBase(initialization, timescale, presentationTimeOffset, baseUrl,
|
return buildSingleSegmentBase(initialization, timescale, presentationTimeOffset, indexStart,
|
||||||
indexStart, indexLength);
|
indexLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SingleSegmentBase buildSingleSegmentBase(RangedUri initialization, long timescale,
|
protected SingleSegmentBase buildSingleSegmentBase(RangedUri initialization, long timescale,
|
||||||
long presentationTimeOffset, String baseUrl, long indexStart, long indexLength) {
|
long presentationTimeOffset, long indexStart, long indexLength) {
|
||||||
return new SingleSegmentBase(initialization, timescale, presentationTimeOffset, baseUrl,
|
return new SingleSegmentBase(initialization, timescale, presentationTimeOffset, indexStart,
|
||||||
indexStart, indexLength);
|
indexLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SegmentList parseSegmentList(XmlPullParser xpp, String baseUrl, SegmentList parent)
|
protected SegmentList parseSegmentList(XmlPullParser xpp, SegmentList parent)
|
||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
|
|
||||||
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
||||||
@ -496,14 +496,14 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
do {
|
do {
|
||||||
xpp.next();
|
xpp.next();
|
||||||
if (XmlPullParserUtil.isStartTag(xpp, "Initialization")) {
|
if (XmlPullParserUtil.isStartTag(xpp, "Initialization")) {
|
||||||
initialization = parseInitialization(xpp, baseUrl);
|
initialization = parseInitialization(xpp);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTimeline")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTimeline")) {
|
||||||
timeline = parseSegmentTimeline(xpp);
|
timeline = parseSegmentTimeline(xpp);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentURL")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentURL")) {
|
||||||
if (segments == null) {
|
if (segments == null) {
|
||||||
segments = new ArrayList<>();
|
segments = new ArrayList<>();
|
||||||
}
|
}
|
||||||
segments.add(parseSegmentUrl(xpp, baseUrl));
|
segments.add(parseSegmentUrl(xpp));
|
||||||
}
|
}
|
||||||
} while (!XmlPullParserUtil.isEndTag(xpp, "SegmentList"));
|
} while (!XmlPullParserUtil.isEndTag(xpp, "SegmentList"));
|
||||||
|
|
||||||
@ -524,8 +524,8 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
startNumber, duration, timeline, segments);
|
startNumber, duration, timeline, segments);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SegmentTemplate parseSegmentTemplate(XmlPullParser xpp, String baseUrl,
|
protected SegmentTemplate parseSegmentTemplate(XmlPullParser xpp, SegmentTemplate parent)
|
||||||
SegmentTemplate parent) throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
||||||
long presentationTimeOffset = parseLong(xpp, "presentationTimeOffset",
|
long presentationTimeOffset = parseLong(xpp, "presentationTimeOffset",
|
||||||
parent != null ? parent.presentationTimeOffset : 0);
|
parent != null ? parent.presentationTimeOffset : 0);
|
||||||
@ -542,7 +542,7 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
do {
|
do {
|
||||||
xpp.next();
|
xpp.next();
|
||||||
if (XmlPullParserUtil.isStartTag(xpp, "Initialization")) {
|
if (XmlPullParserUtil.isStartTag(xpp, "Initialization")) {
|
||||||
initialization = parseInitialization(xpp, baseUrl);
|
initialization = parseInitialization(xpp);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTimeline")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTimeline")) {
|
||||||
timeline = parseSegmentTimeline(xpp);
|
timeline = parseSegmentTimeline(xpp);
|
||||||
}
|
}
|
||||||
@ -554,15 +554,15 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
return buildSegmentTemplate(initialization, timescale, presentationTimeOffset,
|
return buildSegmentTemplate(initialization, timescale, presentationTimeOffset,
|
||||||
startNumber, duration, timeline, initializationTemplate, mediaTemplate, baseUrl);
|
startNumber, duration, timeline, initializationTemplate, mediaTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SegmentTemplate buildSegmentTemplate(RangedUri initialization, long timescale,
|
protected SegmentTemplate buildSegmentTemplate(RangedUri initialization, long timescale,
|
||||||
long presentationTimeOffset, int startNumber, long duration,
|
long presentationTimeOffset, int startNumber, long duration,
|
||||||
List<SegmentTimelineElement> timeline, UrlTemplate initializationTemplate,
|
List<SegmentTimelineElement> timeline, UrlTemplate initializationTemplate,
|
||||||
UrlTemplate mediaTemplate, String baseUrl) {
|
UrlTemplate mediaTemplate) {
|
||||||
return new SegmentTemplate(initialization, timescale, presentationTimeOffset,
|
return new SegmentTemplate(initialization, timescale, presentationTimeOffset,
|
||||||
startNumber, duration, timeline, initializationTemplate, mediaTemplate, baseUrl);
|
startNumber, duration, timeline, initializationTemplate, mediaTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<SegmentTimelineElement> parseSegmentTimeline(XmlPullParser xpp)
|
protected List<SegmentTimelineElement> parseSegmentTimeline(XmlPullParser xpp)
|
||||||
@ -597,15 +597,15 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RangedUri parseInitialization(XmlPullParser xpp, String baseUrl) {
|
protected RangedUri parseInitialization(XmlPullParser xpp) {
|
||||||
return parseRangedUrl(xpp, baseUrl, "sourceURL", "range");
|
return parseRangedUrl(xpp, "sourceURL", "range");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RangedUri parseSegmentUrl(XmlPullParser xpp, String baseUrl) {
|
protected RangedUri parseSegmentUrl(XmlPullParser xpp) {
|
||||||
return parseRangedUrl(xpp, baseUrl, "media", "mediaRange");
|
return parseRangedUrl(xpp, "media", "mediaRange");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RangedUri parseRangedUrl(XmlPullParser xpp, String baseUrl, String urlAttribute,
|
protected RangedUri parseRangedUrl(XmlPullParser xpp, String urlAttribute,
|
||||||
String rangeAttribute) {
|
String rangeAttribute) {
|
||||||
String urlText = xpp.getAttributeValue(null, urlAttribute);
|
String urlText = xpp.getAttributeValue(null, urlAttribute);
|
||||||
long rangeStart = 0;
|
long rangeStart = 0;
|
||||||
@ -618,12 +618,11 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
rangeLength = Long.parseLong(rangeTextArray[1]) - rangeStart + 1;
|
rangeLength = Long.parseLong(rangeTextArray[1]) - rangeStart + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return buildRangedUri(baseUrl, urlText, rangeStart, rangeLength);
|
return buildRangedUri(urlText, rangeStart, rangeLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RangedUri buildRangedUri(String baseUrl, String urlText, long rangeStart,
|
protected RangedUri buildRangedUri(String urlText, long rangeStart, long rangeLength) {
|
||||||
long rangeLength) {
|
return new RangedUri(urlText, rangeStart, rangeLength);
|
||||||
return new RangedUri(baseUrl, urlText, rangeStart, rangeLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AudioChannelConfiguration parsing.
|
// AudioChannelConfiguration parsing.
|
||||||
@ -788,12 +787,14 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
private static final class RepresentationInfo {
|
private static final class RepresentationInfo {
|
||||||
|
|
||||||
public final Format format;
|
public final Format format;
|
||||||
|
public final String baseUrl;
|
||||||
public final SegmentBase segmentBase;
|
public final SegmentBase segmentBase;
|
||||||
public final ArrayList<SchemeData> drmSchemeDatas;
|
public final ArrayList<SchemeData> drmSchemeDatas;
|
||||||
|
|
||||||
public RepresentationInfo(Format format, SegmentBase segmentBase,
|
public RepresentationInfo(Format format, String baseUrl, SegmentBase segmentBase,
|
||||||
ArrayList<SchemeData> drmSchemeDatas) {
|
ArrayList<SchemeData> drmSchemeDatas) {
|
||||||
this.format = format;
|
this.format = format;
|
||||||
|
this.baseUrl = baseUrl;
|
||||||
this.segmentBase = segmentBase;
|
this.segmentBase = segmentBase;
|
||||||
this.drmSchemeDatas = drmSchemeDatas;
|
this.drmSchemeDatas = drmSchemeDatas;
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,10 @@ package com.google.android.exoplayer2.source.dash.manifest;
|
|||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
|
||||||
import com.google.android.exoplayer2.util.UriUtil;
|
import com.google.android.exoplayer2.util.UriUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a range of data located at a {@link Uri}.
|
* Defines a range of data located at a reference uri.
|
||||||
*/
|
*/
|
||||||
public final class RangedUri {
|
public final class RangedUri {
|
||||||
|
|
||||||
@ -35,12 +34,6 @@ public final class RangedUri {
|
|||||||
*/
|
*/
|
||||||
public final long length;
|
public final long length;
|
||||||
|
|
||||||
// The URI is stored internally in two parts: reference URI and a base URI to use when
|
|
||||||
// resolving it. This helps optimize memory usage in the same way that DASH manifests allow many
|
|
||||||
// URLs to be expressed concisely in the form of a single BaseURL and many relative paths. Note
|
|
||||||
// that this optimization relies on the same object being passed as the base URI to many
|
|
||||||
// instances of this class.
|
|
||||||
private final String baseUri;
|
|
||||||
private final String referenceUri;
|
private final String referenceUri;
|
||||||
|
|
||||||
private int hashCode;
|
private int hashCode;
|
||||||
@ -48,57 +41,59 @@ public final class RangedUri {
|
|||||||
/**
|
/**
|
||||||
* Constructs an ranged uri.
|
* Constructs an ranged uri.
|
||||||
*
|
*
|
||||||
* @param baseUri A uri that can form the base of the uri defined by the instance.
|
* @param referenceUri The reference uri.
|
||||||
* @param referenceUri A reference uri that should be resolved with respect to {@code baseUri}.
|
|
||||||
* @param start The (zero based) index of the first byte of the range.
|
* @param start The (zero based) index of the first byte of the range.
|
||||||
* @param length The length of the range, or {@link C#LENGTH_UNSET} to indicate that the range is
|
* @param length The length of the range, or {@link C#LENGTH_UNSET} to indicate that the range is
|
||||||
* unbounded.
|
* unbounded.
|
||||||
*/
|
*/
|
||||||
public RangedUri(String baseUri, String referenceUri, long start, long length) {
|
public RangedUri(String referenceUri, long start, long length) {
|
||||||
Assertions.checkArgument(baseUri != null || referenceUri != null);
|
this.referenceUri = referenceUri == null ? "" : referenceUri;
|
||||||
this.baseUri = baseUri;
|
|
||||||
this.referenceUri = referenceUri;
|
|
||||||
this.start = start;
|
this.start = start;
|
||||||
this.length = length;
|
this.length = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link Uri} represented by the instance.
|
* Returns the resolved {@link Uri} represented by the instance.
|
||||||
*
|
*
|
||||||
|
* @param baseUri The base Uri.
|
||||||
* @return The {@link Uri} represented by the instance.
|
* @return The {@link Uri} represented by the instance.
|
||||||
*/
|
*/
|
||||||
public Uri getUri() {
|
public Uri resolveUri(String baseUri) {
|
||||||
return UriUtil.resolveToUri(baseUri, referenceUri);
|
return UriUtil.resolveToUri(baseUri, referenceUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the uri represented by the instance as a string.
|
* Returns the resolved uri represented by the instance as a string.
|
||||||
*
|
*
|
||||||
|
* @param baseUri The base Uri.
|
||||||
* @return The uri represented by the instance.
|
* @return The uri represented by the instance.
|
||||||
*/
|
*/
|
||||||
public String getUriString() {
|
public String resolveUriString(String baseUri) {
|
||||||
return UriUtil.resolve(baseUri, referenceUri);
|
return UriUtil.resolve(baseUri, referenceUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to merge this {@link RangedUri} with another.
|
* Attempts to merge this {@link RangedUri} with another and an optional common base uri.
|
||||||
* <p>
|
* <p>
|
||||||
* A merge is successful if both instances define the same {@link Uri}, and if one starts the byte
|
* A merge is successful if both instances define the same {@link Uri} after resolution with the
|
||||||
* after the other ends, forming a contiguous region with no overlap.
|
* base uri, and if one starts the byte after the other ends, forming a contiguous region with
|
||||||
|
* no overlap.
|
||||||
* <p>
|
* <p>
|
||||||
* If {@code other} is null then the merge is considered unsuccessful, and null is returned.
|
* If {@code other} is null then the merge is considered unsuccessful, and null is returned.
|
||||||
*
|
*
|
||||||
* @param other The {@link RangedUri} to merge.
|
* @param other The {@link RangedUri} to merge.
|
||||||
|
* @param baseUri The optional base Uri.
|
||||||
* @return The merged {@link RangedUri} if the merge was successful. Null otherwise.
|
* @return The merged {@link RangedUri} if the merge was successful. Null otherwise.
|
||||||
*/
|
*/
|
||||||
public RangedUri attemptMerge(RangedUri other) {
|
public RangedUri attemptMerge(RangedUri other, String baseUri) {
|
||||||
if (other == null || !getUriString().equals(other.getUriString())) {
|
final String resolvedUri = resolveUriString(baseUri);
|
||||||
|
if (other == null || !resolvedUri.equals(other.resolveUriString(baseUri))) {
|
||||||
return null;
|
return null;
|
||||||
} else if (length != C.LENGTH_UNSET && start + length == other.start) {
|
} else if (length != C.LENGTH_UNSET && start + length == other.start) {
|
||||||
return new RangedUri(baseUri, referenceUri, start,
|
return new RangedUri(resolvedUri, start,
|
||||||
other.length == C.LENGTH_UNSET ? C.LENGTH_UNSET : length + other.length);
|
other.length == C.LENGTH_UNSET ? C.LENGTH_UNSET : length + other.length);
|
||||||
} else if (other.length != C.LENGTH_UNSET && other.start + other.length == start) {
|
} else if (other.length != C.LENGTH_UNSET && other.start + other.length == start) {
|
||||||
return new RangedUri(baseUri, referenceUri, other.start,
|
return new RangedUri(resolvedUri, other.start,
|
||||||
length == C.LENGTH_UNSET ? C.LENGTH_UNSET : other.length + length);
|
length == C.LENGTH_UNSET ? C.LENGTH_UNSET : other.length + length);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
@ -111,7 +106,7 @@ public final class RangedUri {
|
|||||||
int result = 17;
|
int result = 17;
|
||||||
result = 31 * result + (int) start;
|
result = 31 * result + (int) start;
|
||||||
result = 31 * result + (int) length;
|
result = 31 * result + (int) length;
|
||||||
result = 31 * result + getUriString().hashCode();
|
result = 31 * result + referenceUri.hashCode();
|
||||||
hashCode = result;
|
hashCode = result;
|
||||||
}
|
}
|
||||||
return hashCode;
|
return hashCode;
|
||||||
@ -128,7 +123,7 @@ public final class RangedUri {
|
|||||||
RangedUri other = (RangedUri) obj;
|
RangedUri other = (RangedUri) obj;
|
||||||
return this.start == other.start
|
return this.start == other.start
|
||||||
&& this.length == other.length
|
&& this.length == other.length
|
||||||
&& getUriString().equals(other.getUriString());
|
&& referenceUri.equals(other.referenceUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,10 @@ public abstract class Representation {
|
|||||||
* The format of the representation.
|
* The format of the representation.
|
||||||
*/
|
*/
|
||||||
public final Format format;
|
public final Format format;
|
||||||
|
/**
|
||||||
|
* The base URL of the representation.
|
||||||
|
*/
|
||||||
|
public final String baseUrl;
|
||||||
/**
|
/**
|
||||||
* The offset of the presentation timestamps in the media stream relative to media time.
|
* The offset of the presentation timestamps in the media stream relative to media time.
|
||||||
*/
|
*/
|
||||||
@ -65,12 +69,13 @@ public abstract class Representation {
|
|||||||
* @param contentId Identifies the piece of content to which this representation belongs.
|
* @param contentId Identifies the piece of content to which this representation belongs.
|
||||||
* @param revisionId Identifies the revision of the content.
|
* @param revisionId Identifies the revision of the content.
|
||||||
* @param format The format of the representation.
|
* @param format The format of the representation.
|
||||||
|
* @param baseUrl The base URL.
|
||||||
* @param segmentBase A segment base element for the representation.
|
* @param segmentBase A segment base element for the representation.
|
||||||
* @return The constructed instance.
|
* @return The constructed instance.
|
||||||
*/
|
*/
|
||||||
public static Representation newInstance(String contentId, long revisionId, Format format,
|
public static Representation newInstance(String contentId, long revisionId, Format format,
|
||||||
SegmentBase segmentBase) {
|
String baseUrl, SegmentBase segmentBase) {
|
||||||
return newInstance(contentId, revisionId, format, segmentBase, null);
|
return newInstance(contentId, revisionId, format, baseUrl, segmentBase, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -79,18 +84,19 @@ public abstract class Representation {
|
|||||||
* @param contentId Identifies the piece of content to which this representation belongs.
|
* @param contentId Identifies the piece of content to which this representation belongs.
|
||||||
* @param revisionId Identifies the revision of the content.
|
* @param revisionId Identifies the revision of the content.
|
||||||
* @param format The format of the representation.
|
* @param format The format of the representation.
|
||||||
|
* @param baseUrl The base URL of the representation.
|
||||||
* @param segmentBase A segment base element for the representation.
|
* @param segmentBase A segment base element for the representation.
|
||||||
* @param customCacheKey A custom value to be returned from {@link #getCacheKey()}, or null. This
|
* @param customCacheKey A custom value to be returned from {@link #getCacheKey()}, or null. This
|
||||||
* parameter is ignored if {@code segmentBase} consists of multiple segments.
|
* parameter is ignored if {@code segmentBase} consists of multiple segments.
|
||||||
* @return The constructed instance.
|
* @return The constructed instance.
|
||||||
*/
|
*/
|
||||||
public static Representation newInstance(String contentId, long revisionId, Format format,
|
public static Representation newInstance(String contentId, long revisionId, Format format,
|
||||||
SegmentBase segmentBase, String customCacheKey) {
|
String baseUrl, SegmentBase segmentBase, String customCacheKey) {
|
||||||
if (segmentBase instanceof SingleSegmentBase) {
|
if (segmentBase instanceof SingleSegmentBase) {
|
||||||
return new SingleSegmentRepresentation(contentId, revisionId, format,
|
return new SingleSegmentRepresentation(contentId, revisionId, format, baseUrl,
|
||||||
(SingleSegmentBase) segmentBase, customCacheKey, C.LENGTH_UNSET);
|
(SingleSegmentBase) segmentBase, customCacheKey, C.LENGTH_UNSET);
|
||||||
} else if (segmentBase instanceof MultiSegmentBase) {
|
} else if (segmentBase instanceof MultiSegmentBase) {
|
||||||
return new MultiSegmentRepresentation(contentId, revisionId, format,
|
return new MultiSegmentRepresentation(contentId, revisionId, format, baseUrl,
|
||||||
(MultiSegmentBase) segmentBase);
|
(MultiSegmentBase) segmentBase);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("segmentBase must be of type SingleSegmentBase or "
|
throw new IllegalArgumentException("segmentBase must be of type SingleSegmentBase or "
|
||||||
@ -98,11 +104,12 @@ public abstract class Representation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Representation(String contentId, long revisionId, Format format,
|
private Representation(String contentId, long revisionId, Format format, String baseUrl,
|
||||||
SegmentBase segmentBase) {
|
SegmentBase segmentBase) {
|
||||||
this.contentId = contentId;
|
this.contentId = contentId;
|
||||||
this.revisionId = revisionId;
|
this.revisionId = revisionId;
|
||||||
this.format = format;
|
this.format = format;
|
||||||
|
this.baseUrl = baseUrl;
|
||||||
initializationUri = segmentBase.getInitialization(this);
|
initializationUri = segmentBase.getInitialization(this);
|
||||||
presentationTimeOffsetUs = segmentBase.getPresentationTimeOffsetUs();
|
presentationTimeOffsetUs = segmentBase.getPresentationTimeOffsetUs();
|
||||||
}
|
}
|
||||||
@ -166,26 +173,27 @@ public abstract class Representation {
|
|||||||
public static SingleSegmentRepresentation newInstance(String contentId, long revisionId,
|
public static SingleSegmentRepresentation newInstance(String contentId, long revisionId,
|
||||||
Format format, String uri, long initializationStart, long initializationEnd,
|
Format format, String uri, long initializationStart, long initializationEnd,
|
||||||
long indexStart, long indexEnd, String customCacheKey, long contentLength) {
|
long indexStart, long indexEnd, String customCacheKey, long contentLength) {
|
||||||
RangedUri rangedUri = new RangedUri(uri, null, initializationStart,
|
RangedUri rangedUri = new RangedUri(null, initializationStart,
|
||||||
initializationEnd - initializationStart + 1);
|
initializationEnd - initializationStart + 1);
|
||||||
SingleSegmentBase segmentBase = new SingleSegmentBase(rangedUri, 1, 0, uri, indexStart,
|
SingleSegmentBase segmentBase = new SingleSegmentBase(rangedUri, 1, 0, indexStart,
|
||||||
indexEnd - indexStart + 1);
|
indexEnd - indexStart + 1);
|
||||||
return new SingleSegmentRepresentation(contentId, revisionId,
|
return new SingleSegmentRepresentation(contentId, revisionId,
|
||||||
format, segmentBase, customCacheKey, contentLength);
|
format, uri, segmentBase, customCacheKey, contentLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param contentId Identifies the piece of content to which this representation belongs.
|
* @param contentId Identifies the piece of content to which this representation belongs.
|
||||||
* @param revisionId Identifies the revision of the content.
|
* @param revisionId Identifies the revision of the content.
|
||||||
* @param format The format of the representation.
|
* @param format The format of the representation.
|
||||||
|
* @param baseUrl The base URL of the representation.
|
||||||
* @param segmentBase The segment base underlying the representation.
|
* @param segmentBase The segment base underlying the representation.
|
||||||
* @param customCacheKey A custom value to be returned from {@link #getCacheKey()}, or null.
|
* @param customCacheKey A custom value to be returned from {@link #getCacheKey()}, or null.
|
||||||
* @param contentLength The content length, or {@link C#LENGTH_UNSET} if unknown.
|
* @param contentLength The content length, or {@link C#LENGTH_UNSET} if unknown.
|
||||||
*/
|
*/
|
||||||
public SingleSegmentRepresentation(String contentId, long revisionId, Format format,
|
public SingleSegmentRepresentation(String contentId, long revisionId, Format format,
|
||||||
SingleSegmentBase segmentBase, String customCacheKey, long contentLength) {
|
String baseUrl, SingleSegmentBase segmentBase, String customCacheKey, long contentLength) {
|
||||||
super(contentId, revisionId, format, segmentBase);
|
super(contentId, revisionId, format, baseUrl, segmentBase);
|
||||||
this.uri = Uri.parse(segmentBase.uri);
|
this.uri = Uri.parse(baseUrl);
|
||||||
this.indexUri = segmentBase.getIndex();
|
this.indexUri = segmentBase.getIndex();
|
||||||
this.cacheKey = customCacheKey != null ? customCacheKey
|
this.cacheKey = customCacheKey != null ? customCacheKey
|
||||||
: contentId != null ? contentId + "." + format.id + "." + revisionId : null;
|
: contentId != null ? contentId + "." + format.id + "." + revisionId : null;
|
||||||
@ -193,7 +201,7 @@ public abstract class Representation {
|
|||||||
// If we have an index uri then the index is defined externally, and we shouldn't return one
|
// If we have an index uri then the index is defined externally, and we shouldn't return one
|
||||||
// directly. If we don't, then we can't do better than an index defining a single segment.
|
// directly. If we don't, then we can't do better than an index defining a single segment.
|
||||||
segmentIndex = indexUri != null ? null
|
segmentIndex = indexUri != null ? null
|
||||||
: new SingleSegmentIndex(new RangedUri(segmentBase.uri, null, 0, contentLength));
|
: new SingleSegmentIndex(new RangedUri(null, 0, contentLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -225,11 +233,12 @@ public abstract class Representation {
|
|||||||
* @param contentId Identifies the piece of content to which this representation belongs.
|
* @param contentId Identifies the piece of content to which this representation belongs.
|
||||||
* @param revisionId Identifies the revision of the content.
|
* @param revisionId Identifies the revision of the content.
|
||||||
* @param format The format of the representation.
|
* @param format The format of the representation.
|
||||||
|
* @param baseUrl The base URL of the representation.
|
||||||
* @param segmentBase The segment base underlying the representation.
|
* @param segmentBase The segment base underlying the representation.
|
||||||
*/
|
*/
|
||||||
public MultiSegmentRepresentation(String contentId, long revisionId, Format format,
|
public MultiSegmentRepresentation(String contentId, long revisionId, Format format,
|
||||||
MultiSegmentBase segmentBase) {
|
String baseUrl, MultiSegmentBase segmentBase) {
|
||||||
super(contentId, revisionId, format, segmentBase);
|
super(contentId, revisionId, format, baseUrl, segmentBase);
|
||||||
this.segmentBase = segmentBase;
|
this.segmentBase = segmentBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,11 +65,6 @@ public abstract class SegmentBase {
|
|||||||
*/
|
*/
|
||||||
public static class SingleSegmentBase extends SegmentBase {
|
public static class SingleSegmentBase extends SegmentBase {
|
||||||
|
|
||||||
/**
|
|
||||||
* The uri of the segment.
|
|
||||||
*/
|
|
||||||
public final String uri;
|
|
||||||
|
|
||||||
/* package */ final long indexStart;
|
/* package */ final long indexStart;
|
||||||
/* package */ final long indexLength;
|
/* package */ final long indexLength;
|
||||||
|
|
||||||
@ -79,27 +74,22 @@ public abstract class SegmentBase {
|
|||||||
* @param timescale The timescale in units per second.
|
* @param timescale The timescale in units per second.
|
||||||
* @param presentationTimeOffset The presentation time offset. The value in seconds is the
|
* @param presentationTimeOffset The presentation time offset. The value in seconds is the
|
||||||
* division of this value and {@code timescale}.
|
* division of this value and {@code timescale}.
|
||||||
* @param uri The uri of the segment.
|
|
||||||
* @param indexStart The byte offset of the index data in the segment.
|
* @param indexStart The byte offset of the index data in the segment.
|
||||||
* @param indexLength The length of the index data in bytes.
|
* @param indexLength The length of the index data in bytes.
|
||||||
*/
|
*/
|
||||||
public SingleSegmentBase(RangedUri initialization, long timescale, long presentationTimeOffset,
|
public SingleSegmentBase(RangedUri initialization, long timescale, long presentationTimeOffset,
|
||||||
String uri, long indexStart, long indexLength) {
|
long indexStart, long indexLength) {
|
||||||
super(initialization, timescale, presentationTimeOffset);
|
super(initialization, timescale, presentationTimeOffset);
|
||||||
this.uri = uri;
|
|
||||||
this.indexStart = indexStart;
|
this.indexStart = indexStart;
|
||||||
this.indexLength = indexLength;
|
this.indexLength = indexLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param uri The uri of the segment.
|
|
||||||
*/
|
|
||||||
public SingleSegmentBase(String uri) {
|
public SingleSegmentBase(String uri) {
|
||||||
this(null, 1, 0, uri, 0, 0);
|
this(null, 1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RangedUri getIndex() {
|
public RangedUri getIndex() {
|
||||||
return indexLength <= 0 ? null : new RangedUri(uri, null, indexStart, indexLength);
|
return indexLength <= 0 ? null : new RangedUri(null, indexStart, indexLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -279,8 +269,6 @@ public abstract class SegmentBase {
|
|||||||
/* package */ final UrlTemplate initializationTemplate;
|
/* package */ final UrlTemplate initializationTemplate;
|
||||||
/* package */ final UrlTemplate mediaTemplate;
|
/* package */ final UrlTemplate mediaTemplate;
|
||||||
|
|
||||||
private final String baseUrl;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param initialization A {@link RangedUri} corresponding to initialization data, if such data
|
* @param initialization A {@link RangedUri} corresponding to initialization data, if such data
|
||||||
* exists. The value of this parameter is ignored if {@code initializationTemplate} is
|
* exists. The value of this parameter is ignored if {@code initializationTemplate} is
|
||||||
@ -299,16 +287,14 @@ public abstract class SegmentBase {
|
|||||||
* such data exists. If non-null then the {@code initialization} parameter is ignored. If
|
* such data exists. If non-null then the {@code initialization} parameter is ignored. If
|
||||||
* null then {@code initialization} will be used.
|
* null then {@code initialization} will be used.
|
||||||
* @param mediaTemplate A template defining the location of each media segment.
|
* @param mediaTemplate A template defining the location of each media segment.
|
||||||
* @param baseUrl A url to use as the base for relative urls generated by the templates.
|
|
||||||
*/
|
*/
|
||||||
public SegmentTemplate(RangedUri initialization, long timescale, long presentationTimeOffset,
|
public SegmentTemplate(RangedUri initialization, long timescale, long presentationTimeOffset,
|
||||||
int startNumber, long duration, List<SegmentTimelineElement> segmentTimeline,
|
int startNumber, long duration, List<SegmentTimelineElement> segmentTimeline,
|
||||||
UrlTemplate initializationTemplate, UrlTemplate mediaTemplate, String baseUrl) {
|
UrlTemplate initializationTemplate, UrlTemplate mediaTemplate) {
|
||||||
super(initialization, timescale, presentationTimeOffset, startNumber,
|
super(initialization, timescale, presentationTimeOffset, startNumber,
|
||||||
duration, segmentTimeline);
|
duration, segmentTimeline);
|
||||||
this.initializationTemplate = initializationTemplate;
|
this.initializationTemplate = initializationTemplate;
|
||||||
this.mediaTemplate = mediaTemplate;
|
this.mediaTemplate = mediaTemplate;
|
||||||
this.baseUrl = baseUrl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -316,7 +302,7 @@ public abstract class SegmentBase {
|
|||||||
if (initializationTemplate != null) {
|
if (initializationTemplate != null) {
|
||||||
String urlString = initializationTemplate.buildUri(representation.format.id, 0,
|
String urlString = initializationTemplate.buildUri(representation.format.id, 0,
|
||||||
representation.format.bitrate, 0);
|
representation.format.bitrate, 0);
|
||||||
return new RangedUri(baseUrl, urlString, 0, C.LENGTH_UNSET);
|
return new RangedUri(urlString, 0, C.LENGTH_UNSET);
|
||||||
} else {
|
} else {
|
||||||
return super.getInitialization(representation);
|
return super.getInitialization(representation);
|
||||||
}
|
}
|
||||||
@ -332,7 +318,7 @@ public abstract class SegmentBase {
|
|||||||
}
|
}
|
||||||
String uriString = mediaTemplate.buildUri(representation.format.id, sequenceNumber,
|
String uriString = mediaTemplate.buildUri(representation.format.id, sequenceNumber,
|
||||||
representation.format.bitrate, time);
|
representation.format.bitrate, time);
|
||||||
return new RangedUri(baseUrl, uriString, 0, C.LENGTH_UNSET);
|
return new RangedUri(uriString, 0, C.LENGTH_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
x
Reference in New Issue
Block a user