Commit 462fea3e by Oliver Woodman

Correctly resolve Uris according to RFC3986.

Issue: #327
parent 457557b5
......@@ -581,7 +581,7 @@ public class DashChunkSource implements ChunkSource {
}
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);
}
}
......
......@@ -19,8 +19,6 @@ import com.google.android.exoplayer.chunk.parser.SegmentIndex;
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.
......@@ -28,16 +26,16 @@ import android.net.Uri;
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;
......
......@@ -24,9 +24,9 @@ import com.google.android.exoplayer.dash.mpd.SegmentBase.SingleSegmentBase;
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;
......@@ -83,7 +83,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
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) {
......@@ -92,7 +92,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
}
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);
......@@ -137,7 +137,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
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);
......@@ -170,7 +170,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
// 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");
......@@ -287,9 +287,9 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
// 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");
......@@ -335,7 +335,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
// 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);
......@@ -364,12 +364,12 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
}
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);
......@@ -413,7 +413,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
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);
......@@ -450,7 +450,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
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);
}
......@@ -487,15 +487,15 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
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;
......@@ -509,7 +509,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
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);
}
......@@ -548,15 +548,10 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
}
}
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) {
......
......@@ -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;
......@@ -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;
}
......@@ -70,7 +67,16 @@ public final class RangedUri {
* @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);
}
/**
......@@ -85,13 +91,13 @@ public final class RangedUri {
* @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;
......@@ -104,7 +110,7 @@ public final class RangedUri {
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;
......@@ -121,7 +127,7 @@ public final class RangedUri {
RangedUri other = (RangedUri) obj;
return this.start == other.start
&& this.length == other.length
&& getUri().equals(other.getUri());
&& getUriString().equals(other.getUriString());
}
}
......@@ -147,7 +147,7 @@ public abstract class Representation {
public static class SingleSegmentRepresentation extends Representation {
/**
* The {@link Uri} of the single segment.
* The uri of the single segment.
*/
public final Uri uri;
......@@ -174,7 +174,7 @@ public abstract class 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);
......@@ -197,13 +197,13 @@ public abstract class Representation {
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
......
......@@ -19,8 +19,6 @@ import com.google.android.exoplayer.C;
import com.google.android.exoplayer.dash.DashSegmentIndex;
import com.google.android.exoplayer.util.Util;
import android.net.Uri;
import java.util.List;
/**
......@@ -73,7 +71,7 @@ public abstract class SegmentBase {
/**
* The uri of the segment.
*/
public final Uri uri;
public final String uri;
/* package */ final long indexStart;
/* package */ final long indexLength;
......@@ -89,7 +87,7 @@ public abstract class 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;
......@@ -99,7 +97,7 @@ public abstract class SegmentBase {
/**
* @param uri The uri of the segment.
*/
public SingleSegmentBase(Uri uri) {
public SingleSegmentBase(String uri) {
this(null, 1, 0, uri, 0, -1);
}
......@@ -289,7 +287,7 @@ public abstract class SegmentBase {
/* 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
......@@ -315,7 +313,7 @@ public abstract class SegmentBase {
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;
......
......@@ -27,6 +27,7 @@ import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSpec;
import com.google.android.exoplayer.upstream.HttpDataSource.InvalidResponseCodeException;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.UriUtil;
import com.google.android.exoplayer.util.Util;
import android.net.Uri;
......@@ -121,7 +122,7 @@ public class HlsChunkSource {
private final Variant[] enabledVariants;
private final BandwidthMeter bandwidthMeter;
private final int adaptiveMode;
private final Uri baseUri;
private final String baseUri;
private final int maxWidth;
private final int maxHeight;
private final int targetBufferSize;
......@@ -301,11 +302,11 @@ public class HlsChunkSource {
}
HlsMediaPlaylist.Segment segment = mediaPlaylist.segments.get(chunkIndex);
Uri chunkUri = Util.getMergedUri(mediaPlaylist.baseUri, segment.url);
Uri chunkUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, segment.url);
// Check if encryption is specified.
if (HlsMediaPlaylist.ENCRYPTION_METHOD_AES_128.equals(segment.encryptionMethod)) {
Uri keyUri = Util.getMergedUri(mediaPlaylist.baseUri, segment.encryptionKeyUri);
Uri keyUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, segment.encryptionKeyUri);
if (!keyUri.equals(encryptionKeyUri)) {
// Encryption is specified and the key has changed.
HlsChunk toReturn = newEncryptionKeyChunk(keyUri, segment.encryptionIV);
......@@ -437,7 +438,7 @@ public class HlsChunkSource {
}
private MediaPlaylistChunk newMediaPlaylistChunk(int variantIndex) {
Uri mediaPlaylistUri = Util.getMergedUri(baseUri, enabledVariants[variantIndex].url);
Uri mediaPlaylistUri = UriUtil.resolveToUri(baseUri, enabledVariants[variantIndex].url);
DataSpec dataSpec = new DataSpec(mediaPlaylistUri, 0, C.LENGTH_UNBOUNDED, null,
DataSpec.FLAG_ALLOW_GZIP);
return new MediaPlaylistChunk(variantIndex, upstreamDataSource, dataSpec,
......
......@@ -15,8 +15,6 @@
*/
package com.google.android.exoplayer.hls;
import android.net.Uri;
import java.util.List;
/**
......@@ -26,7 +24,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
public final List<Variant> variants;
public HlsMasterPlaylist(Uri baseUri, List<Variant> variants) {
public HlsMasterPlaylist(String baseUri, List<Variant> variants) {
super(baseUri, HlsPlaylist.TYPE_MASTER);
this.variants = variants;
}
......
......@@ -17,8 +17,6 @@ package com.google.android.exoplayer.hls;
import com.google.android.exoplayer.C;
import android.net.Uri;
import java.util.List;
/**
......@@ -70,7 +68,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
public final boolean live;
public final long durationUs;
public HlsMediaPlaylist(Uri baseUri, int mediaSequence, int targetDurationSecs, int version,
public HlsMediaPlaylist(String baseUri, int mediaSequence, int targetDurationSecs, int version,
boolean live, List<Segment> segments) {
super(baseUri, HlsPlaylist.TYPE_MEDIA);
this.mediaSequence = mediaSequence;
......
......@@ -15,7 +15,6 @@
*/
package com.google.android.exoplayer.hls;
import android.net.Uri;
/**
* Represents an HLS playlist.
......@@ -25,10 +24,10 @@ public abstract class HlsPlaylist {
public final static int TYPE_MASTER = 0;
public final static int TYPE_MEDIA = 1;
public final Uri baseUri;
public final String baseUri;
public final int type;
protected HlsPlaylist(Uri baseUri, int type) {
protected HlsPlaylist(String baseUri, int type) {
this.baseUri = baseUri;
this.type = type;
}
......
......@@ -19,9 +19,6 @@ import com.google.android.exoplayer.C;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.hls.HlsMediaPlaylist.Segment;
import com.google.android.exoplayer.upstream.NetworkLoadable;
import com.google.android.exoplayer.util.Util;
import android.net.Uri;
import java.io.BufferedReader;
import java.io.IOException;
......@@ -86,7 +83,6 @@ public final class HlsPlaylistParser implements NetworkLoadable.Parser<HlsPlayli
@Override
public HlsPlaylist parse(String connectionUrl, InputStream inputStream)
throws IOException, ParserException {
Uri baseUri = Util.parseBaseUri(connectionUrl);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
Queue<String> extraLines = new LinkedList<String>();
String line;
......@@ -97,7 +93,7 @@ public final class HlsPlaylistParser implements NetworkLoadable.Parser<HlsPlayli
// Do nothing.
} else if (line.startsWith(STREAM_INF_TAG)) {
extraLines.add(line);
return parseMasterPlaylist(new LineIterator(extraLines, reader), baseUri);
return parseMasterPlaylist(new LineIterator(extraLines, reader), connectionUrl);
} else if (line.startsWith(TARGET_DURATION_TAG)
|| line.startsWith(MEDIA_SEQUENCE_TAG)
|| line.startsWith(MEDIA_DURATION_TAG)
......@@ -106,7 +102,7 @@ public final class HlsPlaylistParser implements NetworkLoadable.Parser<HlsPlayli
|| line.equals(DISCONTINUITY_TAG)
|| line.equals(ENDLIST_TAG)) {
extraLines.add(line);
return parseMediaPlaylist(new LineIterator(extraLines, reader), baseUri);
return parseMediaPlaylist(new LineIterator(extraLines, reader), connectionUrl);
} else if (line.startsWith(VERSION_TAG)) {
extraLines.add(line);
} else if (!line.startsWith("#")) {
......@@ -119,7 +115,7 @@ public final class HlsPlaylistParser implements NetworkLoadable.Parser<HlsPlayli
throw new ParserException("Failed to parse the playlist, could not identify any tags.");
}
private static HlsMasterPlaylist parseMasterPlaylist(LineIterator iterator, Uri baseUri)
private static HlsMasterPlaylist parseMasterPlaylist(LineIterator iterator, String baseUri)
throws IOException {
List<Variant> variants = new ArrayList<Variant>();
int bandwidth = 0;
......@@ -160,7 +156,7 @@ public final class HlsPlaylistParser implements NetworkLoadable.Parser<HlsPlayli
return new HlsMasterPlaylist(baseUri, Collections.unmodifiableList(variants));
}
private static HlsMediaPlaylist parseMediaPlaylist(LineIterator iterator, Uri baseUri)
private static HlsMediaPlaylist parseMediaPlaylist(LineIterator iterator, String baseUri)
throws IOException {
int mediaSequence = 0;
int targetDurationSecs = 0;
......
......@@ -17,6 +17,7 @@ package com.google.android.exoplayer.smoothstreaming;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.UriUtil;
import com.google.android.exoplayer.util.Util;
import android.net.Uri;
......@@ -197,14 +198,14 @@ public class SmoothStreamingManifest {
public final TrackElement[] tracks;
public final int chunkCount;
private final Uri baseUri;
private final String baseUri;
private final String chunkTemplate;
private final List<Long> chunkStartTimes;
private final long[] chunkStartTimesUs;
private final long lastChunkDurationUs;
public StreamElement(Uri baseUri, String chunkTemplate, int type, String subType,
public StreamElement(String baseUri, String chunkTemplate, int type, String subType,
long timescale, String name, int qualityLevels, int maxWidth, int maxHeight,
int displayWidth, int displayHeight, String language, TrackElement[] tracks,
List<Long> chunkStartTimes, long lastChunkDuration) {
......@@ -274,7 +275,7 @@ public class SmoothStreamingManifest {
String chunkUrl = chunkTemplate
.replace(URL_PLACEHOLDER_BITRATE, Integer.toString(tracks[track].bitrate))
.replace(URL_PLACEHOLDER_START_TIME, chunkStartTimes.get(chunkIndex).toString());
return Util.getMergedUri(baseUri, chunkUrl);
return UriUtil.resolveToUri(baseUri, chunkUrl);
}
}
......
......@@ -23,9 +23,7 @@ import com.google.android.exoplayer.upstream.NetworkLoadable;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.CodecSpecificDataUtil;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.Util;
import android.net.Uri;
import android.util.Base64;
import android.util.Pair;
......@@ -65,8 +63,8 @@ public class SmoothStreamingManifestParser implements
try {
XmlPullParser xmlParser = xmlParserFactory.newPullParser();
xmlParser.setInput(inputStream, null);
SmoothStreamMediaParser smoothStreamMediaParser = new SmoothStreamMediaParser(null,
Util.parseBaseUri(connectionUrl));
SmoothStreamMediaParser smoothStreamMediaParser =
new SmoothStreamMediaParser(null, connectionUrl);
return (SmoothStreamingManifest) smoothStreamMediaParser.parse(xmlParser);
} catch (XmlPullParserException e) {
throw new ParserException(e);
......@@ -89,13 +87,13 @@ public class SmoothStreamingManifestParser implements
*/
private static abstract class ElementParser {
private final Uri baseUri;
private final String baseUri;
private final String tag;
private final ElementParser parent;
private final List<Pair<String, Object>> normalizedAttributes;
public ElementParser(ElementParser parent, Uri baseUri, String tag) {
public ElementParser(ElementParser parent, String baseUri, String tag) {
this.parent = parent;
this.baseUri = baseUri;
this.tag = tag;
......@@ -158,7 +156,7 @@ public class SmoothStreamingManifestParser implements
}
}
private ElementParser newChildParser(ElementParser parent, String name, Uri baseUri) {
private ElementParser newChildParser(ElementParser parent, String name, String baseUri) {
if (TrackElementParser.TAG.equals(name)) {
return new TrackElementParser(parent, baseUri);
} else if (ProtectionElementParser.TAG.equals(name)) {
......@@ -342,7 +340,7 @@ public class SmoothStreamingManifestParser implements
private ProtectionElement protectionElement;
private List<StreamElement> streamElements;
public SmoothStreamMediaParser(ElementParser parent, Uri baseUri) {
public SmoothStreamMediaParser(ElementParser parent, String baseUri) {
super(parent, baseUri, TAG);
lookAheadCount = -1;
protectionElement = null;
......@@ -392,7 +390,7 @@ public class SmoothStreamingManifestParser implements
private UUID uuid;
private byte[] initData;
public ProtectionElementParser(ElementParser parent, Uri baseUri) {
public ProtectionElementParser(ElementParser parent, String baseUri) {
super(parent, baseUri, TAG);
}
......@@ -455,7 +453,7 @@ public class SmoothStreamingManifestParser implements
private static final String KEY_FRAGMENT_START_TIME = "t";
private static final String KEY_FRAGMENT_REPEAT_COUNT = "r";
private final Uri baseUri;
private final String baseUri;
private final List<TrackElement> tracks;
private int type;
......@@ -473,7 +471,7 @@ public class SmoothStreamingManifestParser implements
private long lastChunkDuration;
public StreamElementParser(ElementParser parent, Uri baseUri) {
public StreamElementParser(ElementParser parent, String baseUri) {
super(parent, baseUri, TAG);
this.baseUri = baseUri;
tracks = new LinkedList<TrackElement>();
......@@ -615,7 +613,7 @@ public class SmoothStreamingManifestParser implements
private int nalUnitLengthField;
private String content;
public TrackElementParser(ElementParser parent, Uri baseUri) {
public TrackElementParser(ElementParser parent, String baseUri) {
super(parent, baseUri, TAG);
this.csd = new LinkedList<byte[]>();
}
......
......@@ -17,7 +17,6 @@ package com.google.android.exoplayer.util;
import com.google.android.exoplayer.upstream.DataSource;
import android.net.Uri;
import android.text.TextUtils;
import java.io.IOException;
......@@ -135,54 +134,6 @@ public final class Util {
}
/**
* Like {@link Uri#parse(String)}, but discards the part of the uri that follows the final
* forward slash.
*
* @param uriString An RFC 2396-compliant, encoded uri.
* @return The parsed base uri.
*/
public static Uri parseBaseUri(String uriString) {
return Uri.parse(uriString.substring(0, uriString.lastIndexOf('/')));
}
/**
* Merges a uri and a string to produce a new uri.
* <p>
* The uri is built according to the following rules:
* <ul>
* <li>If {@code baseUri} is null or if {@code stringUri} is absolute, then {@code baseUri} is
* ignored and the uri consists solely of {@code stringUri}.
* <li>If {@code stringUri} is null, then the uri consists solely of {@code baseUrl}.
* <li>Otherwise, the uri consists of the concatenation of {@code baseUri} and {@code stringUri}.
* </ul>
*
* @param baseUri A uri that can form the base of the merged uri.
* @param stringUri A relative or absolute uri in string form.
* @return The merged uri.
*/
public static Uri getMergedUri(Uri baseUri, String stringUri) {
if (stringUri == null) {
return baseUri;
}
if (baseUri == null) {
return Uri.parse(stringUri);
}
if (stringUri.startsWith("/")) {
stringUri = stringUri.substring(1);
return new Uri.Builder()
.scheme(baseUri.getScheme())
.authority(baseUri.getAuthority())
.appendEncodedPath(stringUri)
.build();
}
Uri uri = Uri.parse(stringUri);
if (uri.isAbsolute()) {
return uri;
}
return Uri.withAppendedPath(baseUri, stringUri);
}
/**
* Returns the index of the largest value in an array that is less than (or optionally equal to)
* a specified key.
* <p>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment