[vlc-devel] upgrade MPEG DASH handling of relative URLs

Christopher Müller christopher.mueller at itec.uni-klu.ac.at
Wed Feb 15 07:03:13 CET 2012


> Von: vlc-devel-bounces at videolan.org [mailto:vlc-devel-
> bounces at videolan.org] Im Auftrag von Christopher Müller
> Gesendet: Dienstag, 14. Februar 2012 23:11
> An: 'Mailing list for VLC media player developers'
> Betreff: Re: [vlc-devel] upgrade MPEG DASH handling of relative URLs
> 
> > Von: vlc-devel-bounces at videolan.org [mailto:vlc-devel-
> > bounces at videolan.org] Im Auftrag von Robert Forsman
> > Gesendet: Dienstag, 14. Februar 2012 22:09
> > An: vlc-devel at videolan.org
> > Betreff: [vlc-devel] upgrade MPEG DASH handling of relative URLs
> >
> >
> > 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).
> 

So if give it a second look maybe it was too late last night ;). It should
work also with mpds where the segments contain absolute urls due to
mayberealtive.

But it would be better to solve this special case in the HTTPConnection
parseUrl. There you can prove if the url is valid and if not you can set it
relative. This is one if/else and would work for every profile and also for
further profiles. Another problem is that baseurls could also occur on more
levels in the future and must not contain a protocol. The url will then be
resolved as a concatenation of this baseurls and the segment.

> 
> >
> >
> > 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
> > _______________________________________________
> > vlc-devel mailing list
> > To unsubscribe or modify your subscription options:
> > http://mailman.videolan.org/listinfo/vlc-devel
> 
> 
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> http://mailman.videolan.org/listinfo/vlc-devel





More information about the vlc-devel mailing list