Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
9e16dec2
authored
Jul 09, 2014
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Add support for relative baseUrls in DASH manifests.
Ref: Issue #2
parent
1b957268
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
74 additions
and
33 deletions
library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionFetcher.java
library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionParser.java
library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifestFetcher.java
library/src/main/java/com/google/android/exoplayer/util/ManifestFetcher.java
library/src/main/java/com/google/android/exoplayer/util/Util.java
library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionFetcher.java
View file @
9e16dec2
...
...
@@ -18,6 +18,8 @@ package com.google.android.exoplayer.dash.mpd;
import
com.google.android.exoplayer.ParserException
;
import
com.google.android.exoplayer.util.ManifestFetcher
;
import
android.net.Uri
;
import
org.xmlpull.v1.XmlPullParserException
;
import
java.io.IOException
;
...
...
@@ -57,9 +59,9 @@ public final class MediaPresentationDescriptionFetcher extends
@Override
protected
MediaPresentationDescription
parse
(
InputStream
stream
,
String
inputEncoding
,
String
contentId
)
throws
IOException
,
ParserException
{
String
contentId
,
Uri
baseUrl
)
throws
IOException
,
ParserException
{
try
{
return
parser
.
parseMediaPresentationDescription
(
stream
,
inputEncoding
,
contentId
);
return
parser
.
parseMediaPresentationDescription
(
stream
,
inputEncoding
,
contentId
,
baseUrl
);
}
catch
(
XmlPullParserException
e
)
{
throw
new
ParserException
(
e
);
}
...
...
library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionParser.java
View file @
9e16dec2
...
...
@@ -64,14 +64,15 @@ public class MediaPresentationDescriptionParser extends DefaultHandler {
* @param inputStream The stream from which to parse the manifest.
* @param inputEncoding The encoding of the input.
* @param contentId The content id of the media.
* @param baseUrl The url that any relative urls defined within the manifest are relative to.
* @return The parsed manifest.
* @throws IOException If a problem occurred reading from the stream.
* @throws XmlPullParserException If a problem occurred parsing the stream as xml.
* @throws ParserException If a problem occurred parsing the xml as a DASH mpd.
*/
public
MediaPresentationDescription
parseMediaPresentationDescription
(
InputStream
inputStream
,
String
inputEncoding
,
String
contentId
)
throws
XmlPullParserException
,
IO
Exception
,
ParserException
{
String
inputEncoding
,
String
contentId
,
Uri
baseUrl
)
throws
XmlPullParser
Exception
,
IOException
,
ParserException
{
XmlPullParser
xpp
=
xmlParserFactory
.
newPullParser
();
xpp
.
setInput
(
inputStream
,
inputEncoding
);
int
eventType
=
xpp
.
next
();
...
...
@@ -79,11 +80,12 @@ public class MediaPresentationDescriptionParser extends DefaultHandler {
throw
new
ParserException
(
"inputStream does not contain a valid media presentation description"
);
}
return
parseMediaPresentationDescription
(
xpp
,
contentId
);
return
parseMediaPresentationDescription
(
xpp
,
contentId
,
baseUrl
);
}
private
MediaPresentationDescription
parseMediaPresentationDescription
(
XmlPullParser
xpp
,
String
contentId
)
throws
XmlPullParserException
,
IOException
{
String
contentId
,
Uri
parentBaseUrl
)
throws
XmlPullParserException
,
IOException
{
Uri
baseUrl
=
parentBaseUrl
;
long
duration
=
parseDurationMs
(
xpp
,
"mediaPresentationDuration"
);
long
minBufferTime
=
parseDurationMs
(
xpp
,
"minBufferTime"
);
String
typeString
=
xpp
.
getAttributeValue
(
null
,
"type"
);
...
...
@@ -93,8 +95,10 @@ public class MediaPresentationDescriptionParser extends DefaultHandler {
List
<
Period
>
periods
=
new
ArrayList
<
Period
>();
do
{
xpp
.
next
();
if
(
isStartTag
(
xpp
,
"Period"
))
{
periods
.
add
(
parsePeriod
(
xpp
,
contentId
,
duration
));
if
(
isStartTag
(
xpp
,
"BaseURL"
))
{
baseUrl
=
parseBaseUrl
(
xpp
,
parentBaseUrl
);
}
else
if
(
isStartTag
(
xpp
,
"Period"
))
{
periods
.
add
(
parsePeriod
(
xpp
,
contentId
,
baseUrl
,
duration
));
}
}
while
(!
isEndTag
(
xpp
,
"MPD"
));
...
...
@@ -102,8 +106,9 @@ public class MediaPresentationDescriptionParser extends DefaultHandler {
periods
);
}
private
Period
parsePeriod
(
XmlPullParser
xpp
,
String
contentId
,
long
mediaPresentationDuration
)
throws
XmlPullParserException
,
IOException
{
private
Period
parsePeriod
(
XmlPullParser
xpp
,
String
contentId
,
Uri
parentBaseUrl
,
long
mediaPresentationDuration
)
throws
XmlPullParserException
,
IOException
{
Uri
baseUrl
=
parentBaseUrl
;
int
id
=
parseInt
(
xpp
,
"id"
);
long
start
=
parseDurationMs
(
xpp
,
"start"
,
0
);
long
duration
=
parseDurationMs
(
xpp
,
"duration"
,
mediaPresentationDuration
);
...
...
@@ -115,8 +120,10 @@ public class MediaPresentationDescriptionParser extends DefaultHandler {
long
presentationTimeOffset
=
0
;
do
{
xpp
.
next
();
if
(
isStartTag
(
xpp
,
"AdaptationSet"
))
{
adaptationSets
.
add
(
parseAdaptationSet
(
xpp
,
contentId
,
start
,
duration
,
if
(
isStartTag
(
xpp
,
"BaseURL"
))
{
baseUrl
=
parseBaseUrl
(
xpp
,
parentBaseUrl
);
}
else
if
(
isStartTag
(
xpp
,
"AdaptationSet"
))
{
adaptationSets
.
add
(
parseAdaptationSet
(
xpp
,
contentId
,
baseUrl
,
start
,
duration
,
segmentTimelineList
));
}
else
if
(
isStartTag
(
xpp
,
"SegmentList"
))
{
segmentStartNumber
=
parseInt
(
xpp
,
"startNumber"
);
...
...
@@ -151,9 +158,10 @@ public class MediaPresentationDescriptionParser extends DefaultHandler {
return
segmentTimelineList
;
}
private
AdaptationSet
parseAdaptationSet
(
XmlPullParser
xpp
,
String
contentId
,
long
periodStart
,
long
periodDuration
,
List
<
Segment
.
Timeline
>
segmentTimelineList
)
private
AdaptationSet
parseAdaptationSet
(
XmlPullParser
xpp
,
String
contentId
,
Uri
parentBaseUrl
,
long
period
Start
,
long
period
Duration
,
List
<
Segment
.
Timeline
>
segmentTimelineList
)
throws
XmlPullParserException
,
IOException
{
Uri
baseUrl
=
parentBaseUrl
;
int
id
=
-
1
;
int
contentType
=
AdaptationSet
.
TYPE_UNKNOWN
;
...
...
@@ -175,7 +183,9 @@ public class MediaPresentationDescriptionParser extends DefaultHandler {
do
{
xpp
.
next
();
if
(
contentType
!=
AdaptationSet
.
TYPE_UNKNOWN
)
{
if
(
isStartTag
(
xpp
,
"ContentProtection"
))
{
if
(
isStartTag
(
xpp
,
"BaseURL"
))
{
baseUrl
=
parseBaseUrl
(
xpp
,
parentBaseUrl
);
}
else
if
(
isStartTag
(
xpp
,
"ContentProtection"
))
{
if
(
contentProtections
==
null
)
{
contentProtections
=
new
ArrayList
<
ContentProtection
>();
}
...
...
@@ -187,8 +197,8 @@ public class MediaPresentationDescriptionParser extends DefaultHandler {
:
"audio"
.
equals
(
contentTypeString
)
?
AdaptationSet
.
TYPE_AUDIO
:
AdaptationSet
.
TYPE_UNKNOWN
;
}
else
if
(
isStartTag
(
xpp
,
"Representation"
))
{
representations
.
add
(
parseRepresentation
(
xpp
,
contentId
,
periodStart
,
periodDuration
,
mimeType
,
segmentTimelineList
));
representations
.
add
(
parseRepresentation
(
xpp
,
contentId
,
baseUrl
,
periodStart
,
periodDuration
,
mimeType
,
segmentTimelineList
));
}
}
}
while
(!
isEndTag
(
xpp
,
"AdaptationSet"
));
...
...
@@ -208,9 +218,10 @@ public class MediaPresentationDescriptionParser extends DefaultHandler {
return
new
ContentProtection
(
schemeUriId
,
null
);
}
private
Representation
parseRepresentation
(
XmlPullParser
xpp
,
String
contentId
,
long
periodStart
,
long
periodDuration
,
String
parentMimeType
,
List
<
Segment
.
Timeline
>
segmentTimelineList
)
throws
XmlPullParserException
,
IOException
{
private
Representation
parseRepresentation
(
XmlPullParser
xpp
,
String
contentId
,
Uri
parentBaseUrl
,
long
periodStart
,
long
periodDuration
,
String
parentMimeType
,
List
<
Segment
.
Timeline
>
segmentTimelineList
)
throws
XmlPullParserException
,
IOException
{
Uri
baseUrl
=
parentBaseUrl
;
String
id
=
xpp
.
getAttributeValue
(
null
,
"id"
);
int
bandwidth
=
parseInt
(
xpp
,
"bandwidth"
)
/
8
;
int
audioSamplingRate
=
parseInt
(
xpp
,
"audioSamplingRate"
);
...
...
@@ -222,7 +233,6 @@ public class MediaPresentationDescriptionParser extends DefaultHandler {
mimeType
=
parentMimeType
;
}
String
representationUrl
=
null
;
long
indexStart
=
-
1
;
long
indexEnd
=
-
1
;
long
initializationStart
=
-
1
;
...
...
@@ -232,8 +242,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler {
do
{
xpp
.
next
();
if
(
isStartTag
(
xpp
,
"BaseURL"
))
{
xpp
.
next
();
representationUrl
=
xpp
.
getText
();
baseUrl
=
parseBaseUrl
(
xpp
,
parentBaseUrl
);
}
else
if
(
isStartTag
(
xpp
,
"AudioChannelConfiguration"
))
{
numChannels
=
Integer
.
parseInt
(
xpp
.
getAttributeValue
(
null
,
"value"
));
}
else
if
(
isStartTag
(
xpp
,
"SegmentBase"
))
{
...
...
@@ -249,15 +258,14 @@ public class MediaPresentationDescriptionParser extends DefaultHandler {
}
}
while
(!
isEndTag
(
xpp
,
"Representation"
));
Uri
uri
=
Uri
.
parse
(
representationUrl
);
Format
format
=
new
Format
(
id
,
mimeType
,
width
,
height
,
numChannels
,
audioSamplingRate
,
bandwidth
);
if
(
segmentList
==
null
)
{
return
new
Representation
(
contentId
,
-
1
,
format
,
uri
,
DataSpec
.
LENGTH_UNBOUNDED
,
return
new
Representation
(
contentId
,
-
1
,
format
,
baseUrl
,
DataSpec
.
LENGTH_UNBOUNDED
,
initializationStart
,
initializationEnd
,
indexStart
,
indexEnd
,
periodStart
,
periodDuration
);
}
else
{
return
new
SegmentedRepresentation
(
contentId
,
format
,
uri
,
initializationStart
,
return
new
SegmentedRepresentation
(
contentId
,
format
,
baseUrl
,
initializationStart
,
initializationEnd
,
indexStart
,
indexEnd
,
periodStart
,
periodDuration
,
segmentList
);
}
}
...
...
@@ -321,7 +329,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler {
return
parseDurationMs
(
xpp
,
name
,
-
1
);
}
private
long
parseDurationMs
(
XmlPullParser
xpp
,
String
name
,
long
defaultValue
)
{
private
static
long
parseDurationMs
(
XmlPullParser
xpp
,
String
name
,
long
defaultValue
)
{
String
value
=
xpp
.
getAttributeValue
(
null
,
name
);
if
(
value
!=
null
)
{
Matcher
matcher
=
DURATION
.
matcher
(
value
);
...
...
@@ -340,4 +348,16 @@ public class MediaPresentationDescriptionParser extends DefaultHandler {
return
defaultValue
;
}
private
static
Uri
parseBaseUrl
(
XmlPullParser
xpp
,
Uri
parentBaseUrl
)
throws
XmlPullParserException
,
IOException
{
xpp
.
next
();
String
newBaseUrlText
=
xpp
.
getText
();
Uri
newBaseUri
=
Uri
.
parse
(
newBaseUrlText
);
if
(
newBaseUri
.
isAbsolute
())
{
return
newBaseUri
;
}
else
{
return
parentBaseUrl
.
buildUpon
().
appendEncodedPath
(
newBaseUrlText
).
build
();
}
}
}
library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifestFetcher.java
View file @
9e16dec2
...
...
@@ -18,6 +18,8 @@ package com.google.android.exoplayer.smoothstreaming;
import
com.google.android.exoplayer.ParserException
;
import
com.google.android.exoplayer.util.ManifestFetcher
;
import
android.net.Uri
;
import
org.xmlpull.v1.XmlPullParserException
;
import
java.io.IOException
;
...
...
@@ -56,7 +58,7 @@ public final class SmoothStreamingManifestFetcher extends ManifestFetcher<Smooth
@Override
protected
SmoothStreamingManifest
parse
(
InputStream
stream
,
String
inputEncoding
,
String
contentId
)
throws
IOException
,
ParserException
{
String
contentId
,
Uri
baseUrl
)
throws
IOException
,
ParserException
{
try
{
return
parser
.
parse
(
stream
,
inputEncoding
);
}
catch
(
XmlPullParserException
e
)
{
...
...
library/src/main/java/com/google/android/exoplayer/util/ManifestFetcher.java
View file @
9e16dec2
...
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer.util;
import
com.google.android.exoplayer.ParserException
;
import
android.net.Uri
;
import
android.os.AsyncTask
;
import
java.io.IOException
;
...
...
@@ -84,14 +85,15 @@ public abstract class ManifestFetcher<T> extends AsyncTask<String, Void, T> {
protected
final
T
doInBackground
(
String
...
data
)
{
try
{
contentId
=
data
.
length
>
1
?
data
[
1
]
:
null
;
URL
url
=
new
URL
(
data
[
0
])
;
String
urlString
=
data
[
0
]
;
String
inputEncoding
=
null
;
InputStream
inputStream
=
null
;
try
{
HttpURLConnection
connection
=
configureHttpConnection
(
url
);
Uri
baseUrl
=
Util
.
parseBaseUri
(
urlString
);
HttpURLConnection
connection
=
configureHttpConnection
(
new
URL
(
urlString
));
inputStream
=
connection
.
getInputStream
();
inputEncoding
=
connection
.
getContentEncoding
();
return
parse
(
inputStream
,
inputEncoding
,
contentId
);
return
parse
(
inputStream
,
inputEncoding
,
contentId
,
baseUrl
);
}
finally
{
if
(
inputStream
!=
null
)
{
inputStream
.
close
();
...
...
@@ -119,11 +121,13 @@ public abstract class ManifestFetcher<T> extends AsyncTask<String, Void, T> {
* @param stream The input stream to read.
* @param inputEncoding The encoding of the input stream.
* @param contentId The content id of the media.
* @param baseUrl Required where the manifest contains urls that are relative to a base url. May
* be null where this is not the case.
* @throws IOException If an error occurred loading the data.
* @throws ParserException If an error occurred parsing the loaded data.
*/
protected
abstract
T
parse
(
InputStream
stream
,
String
inputEncoding
,
String
contentId
)
throws
IOException
,
ParserException
;
protected
abstract
T
parse
(
InputStream
stream
,
String
inputEncoding
,
String
contentId
,
Uri
baseUrl
)
throws
IOException
,
ParserException
;
private
HttpURLConnection
configureHttpConnection
(
URL
url
)
throws
IOException
{
HttpURLConnection
connection
=
(
HttpURLConnection
)
url
.
openConnection
();
...
...
library/src/main/java/com/google/android/exoplayer/util/Util.java
View file @
9e16dec2
...
...
@@ -17,6 +17,8 @@ package com.google.android.exoplayer.util;
import
com.google.android.exoplayer.upstream.DataSource
;
import
android.net.Uri
;
import
java.io.IOException
;
import
java.net.URL
;
import
java.util.Arrays
;
...
...
@@ -116,6 +118,17 @@ 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
(
'/'
)));
}
/**
* Returns the index of the largest value in an array that is less than (or optionally equal to)
* a specified key.
* <p>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment