Skip to content

Commit

Permalink
Correctly resolve Uris according to RFC3986.
Browse files Browse the repository at this point in the history
Issue: #327
  • Loading branch information
ojw28 committed Mar 5, 2015
1 parent 457557b commit 462fea3
Show file tree
Hide file tree
Showing 15 changed files with 343 additions and 146 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ protected void consumeStream(NonBlockingInputStream stream) throws IOException {
}
if ((result & Extractor.RESULT_READ_INDEX) != 0) {
representationHolders.get(format.id).segmentIndex =
new DashWrappingSegmentIndex(extractor.getIndex(), uri, indexAnchor);
new DashWrappingSegmentIndex(extractor.getIndex(), uri.toString(), indexAnchor);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,23 @@
import com.google.android.exoplayer.dash.mpd.RangedUri;
import com.google.android.exoplayer.util.Util;

import android.net.Uri;

/**
* An implementation of {@link DashSegmentIndex} that wraps a {@link SegmentIndex} parsed from a
* media stream.
*/
public class DashWrappingSegmentIndex implements DashSegmentIndex {

private final SegmentIndex segmentIndex;
private final Uri uri;
private final String uri;
private final long indexAnchor;

/**
* @param segmentIndex The {@link SegmentIndex} to wrap.
* @param uri The {@link Uri} where the data is located.
* @param uri The URI where the data is located.
* @param indexAnchor The index anchor point. This value is added to the byte offsets specified
* in the wrapped {@link SegmentIndex}.
*/
public DashWrappingSegmentIndex(SegmentIndex segmentIndex, Uri uri, long indexAnchor) {
public DashWrappingSegmentIndex(SegmentIndex segmentIndex, String uri, long indexAnchor) {
this.segmentIndex = segmentIndex;
this.uri = uri;
this.indexAnchor = indexAnchor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
import com.google.android.exoplayer.upstream.NetworkLoadable;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.UriUtil;
import com.google.android.exoplayer.util.Util;

import android.net.Uri;
import android.text.TextUtils;

import org.xml.sax.helpers.DefaultHandler;
Expand Down Expand Up @@ -83,7 +83,7 @@ public MediaPresentationDescription parse(String connectionUrl, InputStream inpu
throw new ParserException(
"inputStream does not contain a valid media presentation description");
}
return parseMediaPresentationDescription(xpp, Util.parseBaseUri(connectionUrl));
return parseMediaPresentationDescription(xpp, connectionUrl);
} catch (XmlPullParserException e) {
throw new ParserException(e);
} catch (ParseException e) {
Expand All @@ -92,7 +92,7 @@ public MediaPresentationDescription parse(String connectionUrl, InputStream inpu
}

protected MediaPresentationDescription parseMediaPresentationDescription(XmlPullParser xpp,
Uri baseUrl) throws XmlPullParserException, IOException, ParseException {
String baseUrl) throws XmlPullParserException, IOException, ParseException {
long availabilityStartTime = parseDateTime(xpp, "availabilityStartTime", -1);
long durationMs = parseDuration(xpp, "mediaPresentationDuration", -1);
long minBufferTimeMs = parseDuration(xpp, "minBufferTime", -1);
Expand Down Expand Up @@ -137,7 +137,7 @@ protected UtcTimingElement buildUtcTimingElement(String schemeIdUri, String valu
return new UtcTimingElement(schemeIdUri, value);
}

protected Period parsePeriod(XmlPullParser xpp, Uri baseUrl, long mpdDurationMs)
protected Period parsePeriod(XmlPullParser xpp, String baseUrl, long mpdDurationMs)
throws XmlPullParserException, IOException {
String id = xpp.getAttributeValue(null, "id");
long startMs = parseDuration(xpp, "start", 0);
Expand Down Expand Up @@ -170,7 +170,7 @@ protected Period buildPeriod(

// AdaptationSet parsing.

protected AdaptationSet parseAdaptationSet(XmlPullParser xpp, Uri baseUrl, long periodStartMs,
protected AdaptationSet parseAdaptationSet(XmlPullParser xpp, String baseUrl, long periodStartMs,
long periodDurationMs, SegmentBase segmentBase) throws XmlPullParserException, IOException {

String mimeType = xpp.getAttributeValue(null, "mimeType");
Expand Down Expand Up @@ -287,9 +287,9 @@ protected void parseAdaptationSetChild(XmlPullParser xpp)

// Representation parsing.

protected Representation parseRepresentation(XmlPullParser xpp, Uri baseUrl, long periodStartMs,
long periodDurationMs, String mimeType, String language, SegmentBase segmentBase)
throws XmlPullParserException, IOException {
protected Representation parseRepresentation(XmlPullParser xpp, String baseUrl,
long periodStartMs, long periodDurationMs, String mimeType, String language,
SegmentBase segmentBase) throws XmlPullParserException, IOException {
String id = xpp.getAttributeValue(null, "id");
int bandwidth = parseInt(xpp, "bandwidth");
int audioSamplingRate = parseInt(xpp, "audioSamplingRate");
Expand Down Expand Up @@ -335,7 +335,7 @@ protected Representation buildRepresentation(long periodStartMs, long periodDura

// SegmentBase, SegmentList and SegmentTemplate parsing.

protected SingleSegmentBase parseSegmentBase(XmlPullParser xpp, Uri baseUrl,
protected SingleSegmentBase parseSegmentBase(XmlPullParser xpp, String baseUrl,
SingleSegmentBase parent) throws XmlPullParserException, IOException {

long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
Expand Down Expand Up @@ -364,12 +364,12 @@ protected SingleSegmentBase parseSegmentBase(XmlPullParser xpp, Uri baseUrl,
}

protected SingleSegmentBase buildSingleSegmentBase(RangedUri initialization, long timescale,
long presentationTimeOffset, Uri baseUrl, long indexStart, long indexLength) {
long presentationTimeOffset, String baseUrl, long indexStart, long indexLength) {
return new SingleSegmentBase(initialization, timescale, presentationTimeOffset, baseUrl,
indexStart, indexLength);
}

protected SegmentList parseSegmentList(XmlPullParser xpp, Uri baseUrl, SegmentList parent,
protected SegmentList parseSegmentList(XmlPullParser xpp, String baseUrl, SegmentList parent,
long periodDurationMs) throws XmlPullParserException, IOException {

long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
Expand Down Expand Up @@ -413,7 +413,7 @@ protected SegmentList buildSegmentList(RangedUri initialization, long timescale,
startNumber, duration, timeline, segments);
}

protected SegmentTemplate parseSegmentTemplate(XmlPullParser xpp, Uri baseUrl,
protected SegmentTemplate parseSegmentTemplate(XmlPullParser xpp, String baseUrl,
SegmentTemplate parent, long periodDurationMs) throws XmlPullParserException, IOException {

long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
Expand Down Expand Up @@ -450,7 +450,7 @@ protected SegmentTemplate parseSegmentTemplate(XmlPullParser xpp, Uri baseUrl,
protected SegmentTemplate buildSegmentTemplate(RangedUri initialization, long timescale,
long presentationTimeOffset, long periodDurationMs, int startNumber, long duration,
List<SegmentTimelineElement> timeline, UrlTemplate initializationTemplate,
UrlTemplate mediaTemplate, Uri baseUrl) {
UrlTemplate mediaTemplate, String baseUrl) {
return new SegmentTemplate(initialization, timescale, presentationTimeOffset, periodDurationMs,
startNumber, duration, timeline, initializationTemplate, mediaTemplate, baseUrl);
}
Expand Down Expand Up @@ -487,15 +487,15 @@ protected UrlTemplate parseUrlTemplate(XmlPullParser xpp, String name,
return defaultValue;
}

protected RangedUri parseInitialization(XmlPullParser xpp, Uri baseUrl) {
protected RangedUri parseInitialization(XmlPullParser xpp, String baseUrl) {
return parseRangedUrl(xpp, baseUrl, "sourceURL", "range");
}

protected RangedUri parseSegmentUrl(XmlPullParser xpp, Uri baseUrl) {
protected RangedUri parseSegmentUrl(XmlPullParser xpp, String baseUrl) {
return parseRangedUrl(xpp, baseUrl, "media", "mediaRange");
}

protected RangedUri parseRangedUrl(XmlPullParser xpp, Uri baseUrl, String urlAttribute,
protected RangedUri parseRangedUrl(XmlPullParser xpp, String baseUrl, String urlAttribute,
String rangeAttribute) {
String urlText = xpp.getAttributeValue(null, urlAttribute);
long rangeStart = 0;
Expand All @@ -509,7 +509,7 @@ protected RangedUri parseRangedUrl(XmlPullParser xpp, Uri baseUrl, String urlAtt
return buildRangedUri(baseUrl, urlText, rangeStart, rangeLength);
}

protected RangedUri buildRangedUri(Uri baseUrl, String urlText, long rangeStart,
protected RangedUri buildRangedUri(String baseUrl, String urlText, long rangeStart,
long rangeLength) {
return new RangedUri(baseUrl, urlText, rangeStart, rangeLength);
}
Expand Down Expand Up @@ -548,15 +548,10 @@ protected static long parseDateTime(XmlPullParser xpp, String name, long default
}
}

protected static Uri parseBaseUrl(XmlPullParser xpp, Uri parentBaseUrl)
protected static String parseBaseUrl(XmlPullParser xpp, String parentBaseUrl)
throws XmlPullParserException, IOException {
xpp.next();
String newBaseUrlText = xpp.getText();
Uri newBaseUri = Uri.parse(newBaseUrlText);
if (!newBaseUri.isAbsolute()) {
newBaseUri = Uri.withAppendedPath(parentBaseUrl, newBaseUrlText);
}
return newBaseUri;
return UriUtil.resolve(parentBaseUrl, xpp.getText());
}

protected static int parseInt(XmlPullParser xpp, String name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
package com.google.android.exoplayer.dash.mpd;

import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.Util;
import com.google.android.exoplayer.util.UriUtil;

import android.net.Uri;

Expand All @@ -35,31 +35,28 @@ public final class RangedUri {
*/
public final long length;

// The {@link Uri} is stored internally in two parts, {@link #baseUri} and {@link uriString}.
// 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 {@code Uri} being passed as the {@link #baseUri} to many
// 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 Uri baseUri;
private final String stringUri;
private final String baseUri;
private final String referenceUri;

private int hashCode;

/**
* Constructs an ranged uri.
* <p>
* See {@link Util#getMergedUri(Uri, String)} for a description of how {@code baseUri} and
* {@code stringUri} are merged.
*
* @param baseUri A uri that can form the base of the uri defined by the instance.
* @param stringUri A relative or absolute uri in string form.
* @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 length The length of the range, or -1 to indicate that the range is unbounded.
*/
public RangedUri(Uri baseUri, String stringUri, long start, long length) {
Assertions.checkArgument(baseUri != null || stringUri != null);
public RangedUri(String baseUri, String referenceUri, long start, long length) {
Assertions.checkArgument(baseUri != null || referenceUri != null);
this.baseUri = baseUri;
this.stringUri = stringUri;
this.referenceUri = referenceUri;
this.start = start;
this.length = length;
}
Expand All @@ -70,7 +67,16 @@ public RangedUri(Uri baseUri, String stringUri, long start, long length) {
* @return The {@link Uri} represented by the instance.
*/
public Uri getUri() {
return Util.getMergedUri(baseUri, stringUri);
return UriUtil.resolveToUri(baseUri, referenceUri);
}

/**
* Returns the uri represented by the instance as a string.
*
* @return The uri represented by the instance.
*/
public String getUriString() {
return UriUtil.resolve(baseUri, referenceUri);
}

/**
Expand All @@ -85,13 +91,13 @@ public Uri getUri() {
* @return The merged {@link RangedUri} if the merge was successful. Null otherwise.
*/
public RangedUri attemptMerge(RangedUri other) {
if (other == null || !getUri().equals(other.getUri())) {
if (other == null || !getUriString().equals(other.getUriString())) {
return null;
} else if (length != -1 && start + length == other.start) {
return new RangedUri(baseUri, stringUri, start,
return new RangedUri(baseUri, referenceUri, start,
other.length == -1 ? -1 : length + other.length);
} else if (other.length != -1 && other.start + other.length == start) {
return new RangedUri(baseUri, stringUri, other.start,
return new RangedUri(baseUri, referenceUri, other.start,
length == -1 ? -1 : other.length + length);
} else {
return null;
Expand All @@ -104,7 +110,7 @@ public int hashCode() {
int result = 17;
result = 31 * result + (int) start;
result = 31 * result + (int) length;
result = 31 * result + getUri().hashCode();
result = 31 * result + getUriString().hashCode();
hashCode = result;
}
return hashCode;
Expand All @@ -121,7 +127,7 @@ public boolean equals(Object obj) {
RangedUri other = (RangedUri) obj;
return this.start == other.start
&& this.length == other.length
&& getUri().equals(other.getUri());
&& getUriString().equals(other.getUriString());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public String getCacheKey() {
public static class SingleSegmentRepresentation extends Representation {

/**
* The {@link Uri} of the single segment.
* The uri of the single segment.
*/
public final Uri uri;

Expand All @@ -174,7 +174,7 @@ public static class SingleSegmentRepresentation extends Representation {
* @param contentLength The content length, or -1 if unknown.
*/
public static SingleSegmentRepresentation newInstance(long periodStartMs, long periodDurationMs,
String contentId, long revisionId, Format format, Uri uri, long initializationStart,
String contentId, long revisionId, Format format, String uri, long initializationStart,
long initializationEnd, long indexStart, long indexEnd, long contentLength) {
RangedUri rangedUri = new RangedUri(uri, null, initializationStart,
initializationEnd - initializationStart + 1);
Expand All @@ -197,13 +197,13 @@ public static SingleSegmentRepresentation newInstance(long periodStartMs, long p
public SingleSegmentRepresentation(long periodStartMs, long periodDurationMs, String contentId,
long revisionId, Format format, SingleSegmentBase segmentBase, long contentLength) {
super(periodStartMs, periodDurationMs, contentId, revisionId, format, segmentBase);
this.uri = segmentBase.uri;
this.uri = Uri.parse(segmentBase.uri);
this.indexUri = segmentBase.getIndex();
this.contentLength = contentLength;
// 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.
segmentIndex = indexUri != null ? null : new DashSingleSegmentIndex(periodStartMs * 1000,
periodDurationMs * 1000, new RangedUri(uri, null, 0, -1));
periodDurationMs * 1000, new RangedUri(segmentBase.uri, null, 0, -1));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
import com.google.android.exoplayer.dash.DashSegmentIndex;
import com.google.android.exoplayer.util.Util;

import android.net.Uri;

import java.util.List;

/**
Expand Down Expand Up @@ -73,7 +71,7 @@ public static class SingleSegmentBase extends SegmentBase {
/**
* The uri of the segment.
*/
public final Uri uri;
public final String uri;

/* package */ final long indexStart;
/* package */ final long indexLength;
Expand All @@ -89,7 +87,7 @@ public static class SingleSegmentBase extends SegmentBase {
* @param indexLength The length of the index data in bytes.
*/
public SingleSegmentBase(RangedUri initialization, long timescale, long presentationTimeOffset,
Uri uri, long indexStart, long indexLength) {
String uri, long indexStart, long indexLength) {
super(initialization, timescale, presentationTimeOffset);
this.uri = uri;
this.indexStart = indexStart;
Expand All @@ -99,7 +97,7 @@ public SingleSegmentBase(RangedUri initialization, long timescale, long presenta
/**
* @param uri The uri of the segment.
*/
public SingleSegmentBase(Uri uri) {
public SingleSegmentBase(String uri) {
this(null, 1, 0, uri, 0, -1);
}

Expand Down Expand Up @@ -289,7 +287,7 @@ public static class SegmentTemplate extends MultiSegmentBase {
/* package */ final UrlTemplate initializationTemplate;
/* package */ final UrlTemplate mediaTemplate;

private final Uri baseUrl;
private final String baseUrl;

/**
* @param initialization A {@link RangedUri} corresponding to initialization data, if such data
Expand All @@ -315,7 +313,7 @@ public static class SegmentTemplate extends MultiSegmentBase {
public SegmentTemplate(RangedUri initialization, long timescale, long presentationTimeOffset,
long periodDurationMs, int startNumber, long duration,
List<SegmentTimelineElement> segmentTimeline, UrlTemplate initializationTemplate,
UrlTemplate mediaTemplate, Uri baseUrl) {
UrlTemplate mediaTemplate, String baseUrl) {
super(initialization, timescale, presentationTimeOffset, periodDurationMs, startNumber,
duration, segmentTimeline);
this.initializationTemplate = initializationTemplate;
Expand Down
Loading

0 comments on commit 462fea3

Please sign in to comment.