[vlc-devel] upgrade MPEG DASH handling of relative URLs
Robert Forsman
bob.forsman at ericsson.com
Tue Feb 14 22:08:46 CET 2012
I started with
commit 1a459c1ccb0d617580ec97bae992f01a799a5e9b
and applied the "download and buffer" patches for DASH
http://www-itec.uni-klu.ac.at/dash/?p=434
although I'm not sure which of the items on
http://www-itec.uni-klu.ac.at/dash/?page_id=6 is the download and
buffer patches, maybe they got retracted.
Anyway, I decided that VLC's DASH plugin was a little too inflexible in
resolving URLs for media files, so I rehacked things a little. I added
logic to fall back on the URL of the MPD file in case the MPD had no
<BaseURL> tags (which I anticipate will be 99% of MPDs in the future).
This is my first patch for VLC, and my first C++ in years, so you'll
want to give it a shakedown.
diff --git a/modules/stream_filter/dash/Modules.am b/modules/stream_filter/dash/Modules.am
index 749dc52..c17d348 100644
--- a/modules/stream_filter/dash/Modules.am
+++ b/modules/stream_filter/dash/Modules.am
@@ -22,6 +22,7 @@ SOURCES_stream_filter_dash = \
http/IHTTPConnection.h \
mpd/AdaptationSet.cpp \
mpd/AdaptationSet.h \
+ mpd/BaseUrl.cpp \
mpd/BaseUrl.h \
mpd/BasicCMManager.cpp \
mpd/BasicCMManager.h \
diff --git a/modules/stream_filter/dash/exceptions/MalformedURLException.h b/modules/stream_filter/dash/exceptions/MalformedURLException.h
new file mode 100644
index 0000000..41e989f
--- /dev/null
+++ b/modules/stream_filter/dash/exceptions/MalformedURLException.h
@@ -0,0 +1,21 @@
+
+#ifndef MALFORMEDURLEXCEPTION_H_
+#define MALFORMEDURLEXCEPTION_H_
+
+#include <stdexcept>
+
+namespace dash
+{
+ namespace exception
+ {
+ class MalformedURLException : public std::exception
+ {
+ const char *message;
+ public:
+ MalformedURLException(const char *msg) { message=msg; }
+ const char * what() const throw() { return message; }
+ };
+ }
+}
+
+#endif /* MALFORMEDURLEXCEPTION_H_ */
diff --git a/modules/stream_filter/dash/mpd/BaseUrl.cpp b/modules/stream_filter/dash/mpd/BaseUrl.cpp
new file mode 100644
index 0000000..bf07804
--- /dev/null
+++ b/modules/stream_filter/dash/mpd/BaseUrl.cpp
@@ -0,0 +1,53 @@
+#include "../exceptions/MalformedURLException.h"
+#include "BaseUrl.h"
+
+
+std::string dash::mpd::BaseUrl::maybeRelative(std::string spec) const
+{
+ if (spec[0] == '/') {
+ return protoHostPort()+spec;
+
+ } else if (hasProtocol(spec)) {
+ return spec;
+
+ } else {
+ int idx = url.rfind('/');
+ if (idx<0)
+ throw dash::exception::MalformedURLException(url.c_str());
+
+ return url.substr(0, idx+1) + spec;
+ }
+}
+
+/**
+returns the http://host:port without a trailing /
+ */
+std::string dash::mpd::BaseUrl::protoHostPort() const
+{
+ int i1 = url.find("://");
+ if (i1<0)
+ throw dash::exception::MalformedURLException(url.c_str());
+ int i2 = url.find('/', i1+3);
+ if (i2<0)
+ throw dash::exception::MalformedURLException(url.c_str());
+
+ return url.substr(0, i2);
+}
+
+/**
+ if spec matches /^[a-z]+:/ then it has a "protocol" on the front
+ */
+bool dash::mpd::BaseUrl::hasProtocol(const std::string &spec)
+{
+ for (int i=0; i<spec.length(); i++) {
+ char ch = spec[i];
+ // yeah, I'm just faking it. Maybe read the RFC later.
+ if (ch == ':') {
+ return i>0;
+ } else if ((ch<'a' || ch > 'z') && (ch < 'A' || ch > 'Z')) {
+ return false;
+ }
+ }
+
+ return false;
+}
diff --git a/modules/stream_filter/dash/mpd/BaseUrl.h b/modules/stream_filter/dash/mpd/BaseUrl.h
index f7b5548..da1ef84 100644
--- a/modules/stream_filter/dash/mpd/BaseUrl.h
+++ b/modules/stream_filter/dash/mpd/BaseUrl.h
@@ -38,7 +38,11 @@ namespace dash
virtual ~BaseUrl() {}
const std::string& getUrl() const { return this->url; }
+ std::string maybeRelative(std::string spec) const;
+ std::string protoHostPort() const;
+
+ static bool hasProtocol(const std::string&);
private:
std::string url;
};
diff --git a/modules/stream_filter/dash/mpd/BasicCMParser.cpp b/modules/stream_filter/dash/mpd/BasicCMParser.cpp
index fc0b0ea..146eebc 100644
--- a/modules/stream_filter/dash/mpd/BasicCMParser.cpp
+++ b/modules/stream_filter/dash/mpd/BasicCMParser.cpp
@@ -147,10 +147,18 @@ void BasicCMParser::setMPDBaseUrl (Node *root)
{
std::vector<Node *> baseUrls = DOMHelper::getChildElementByTagName(root, "BaseURL");
- for(size_t i = 0; i < baseUrls.size(); i++)
- {
- BaseUrl *url = new BaseUrl(baseUrls.at(i)->getText());
- this->mpd->addBaseUrl(url);
+ if (baseUrls.size() >0) {
+
+ for(size_t i = 0; i < baseUrls.size(); i++)
+ {
+ BaseUrl *url = new BaseUrl(baseUrls.at(i)->getText());
+ this->mpd->addBaseUrl(url);
+ }
+ } else {
+ std::string url_ = std::string(p_stream->psz_access)+"://"+p_stream->psz_path;
+ //url_ = url_.substr(0, url_.rfind('/')+1);
+ BaseUrl *url = new BaseUrl(url_);
+ this->mpd->addBaseUrl(url);
}
}
@@ -224,7 +232,15 @@ void BasicCMParser::parseSegmentInfoCommon(Node *node, SegmentInfoCommon *segmen
segmentInfo->appendBaseURL( (*it)->getText() );
++it;
}
+ } else {
+ std::vector<BaseUrl*> inherited = mpd->getBaseUrls();
+ std::vector<BaseUrl*>::const_iterator it = inherited.begin();
+ std::vector<BaseUrl*>::const_iterator end = inherited.end();
+ while (it != end) {
+ segmentInfo->appendBaseURL((*it)->getUrl());
+ }
}
+
std::map<std::string, std::string>::const_iterator it = attr.begin();
this->setInitSegment( node, segmentInfo );
diff --git a/modules/stream_filter/dash/mpd/IsoffMainParser.cpp b/modules/stream_filter/dash/mpd/IsoffMainParser.cpp
index 888c347..87e3bcd 100644
--- a/modules/stream_filter/dash/mpd/IsoffMainParser.cpp
+++ b/modules/stream_filter/dash/mpd/IsoffMainParser.cpp
@@ -79,10 +79,18 @@ void IsoffMainParser::setMPDBaseUrl ()
{
std::vector<Node *> baseUrls = DOMHelper::getChildElementByTagName(this->root, "BaseURL");
- for(size_t i = 0; i < baseUrls.size(); i++)
- {
- BaseUrl *url = new BaseUrl(baseUrls.at(i)->getText());
- this->mpd->addBaseUrl(url);
+ if (baseUrls.size() >0) {
+
+ for(size_t i = 0; i < baseUrls.size(); i++)
+ {
+ BaseUrl *url = new BaseUrl(baseUrls.at(i)->getText());
+ this->mpd->addBaseUrl(url);
+ }
+ } else {
+ std::string url_ = std::string(p_stream->psz_access)+"://"+p_stream->psz_path;
+ //url_ = url_.substr(0, url_.rfind('/')+1);
+ BaseUrl *url = new BaseUrl(url_);
+ this->mpd->addBaseUrl(url);
}
}
void IsoffMainParser::setPeriods ()
diff --git a/modules/stream_filter/dash/mpd/Segment.cpp b/modules/stream_filter/dash/mpd/Segment.cpp
index aa0f834..0959be4 100644
--- a/modules/stream_filter/dash/mpd/Segment.cpp
+++ b/modules/stream_filter/dash/mpd/Segment.cpp
@@ -97,16 +97,13 @@ dash::http::Chunk* Segment::toChunk ()
if(this->baseUrls.size() > 0)
{
- std::stringstream ss;
- ss << this->baseUrls.at(0)->getUrl() << this->sourceUrl;
- chunk->setUrl(ss.str());
- ss.clear();
+ std::string resolved = this->baseUrls.at(0) ->maybeRelative(this->sourceUrl) ;
+ chunk->setUrl(resolved);
for(size_t i = 1; i < this->baseUrls.size(); i++)
{
- ss << this->baseUrls.at(i)->getUrl() << this->sourceUrl;
- chunk->addOptionalUrl(ss.str());
- ss.clear();
+ resolved = this->baseUrls.at(i) ->maybeRelative(this->sourceUrl);
+ chunk->addOptionalUrl(resolved);
}
}
else
More information about the vlc-devel
mailing list