3 *****************************************************************************
4 * Copyright (C) 2010 - 2012 Klagenfurt University
6 * Created on: Jan 27, 2012
7 * Authors: Christopher Mueller <christopher.mueller@itec.uni-klu.ac.at>
8 * Christian Timmerer <christian.timmerer@itec.uni-klu.ac.at>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published
12 * by the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
29 #include "IsoffMainParser.h"
30 #include "SegmentTemplate.h"
31 #include "SegmentInfoDefault.h"
32 #include "xml/DOMHelper.h"
33 #include <vlc_strings.h>
34 #include <vlc_stream.h>
38 using namespace dash::mpd;
39 using namespace dash::xml;
41 IsoffMainParser::IsoffMainParser (Node *root, stream_t *p_stream) :
42 IMPDParser(root, NULL, p_stream, NULL)
45 IsoffMainParser::~IsoffMainParser ()
49 bool IsoffMainParser::parse (Profile profile)
51 mpd = new MPD(p_stream, profile);
60 void IsoffMainParser::setMPDAttributes ()
62 const std::map<std::string, std::string> attr = this->root->getAttributes();
64 std::map<std::string, std::string>::const_iterator it;
66 it = attr.find("mediaPresentationDuration");
68 this->mpd->setDuration(IsoTime(it->second));
70 it = attr.find("minBufferTime");
72 this->mpd->setMinBufferTime(IsoTime(it->second));
74 it = attr.find("type");
76 mpd->setType(it->second);
78 it = attr.find("availabilityStartTime");
80 mpd->setAvailabilityStartTime(UTCTime(it->second));
82 it = attr.find("timeShiftBufferDepth");
84 mpd->setTimeShiftBufferDepth(IsoTime(it->second));
87 void IsoffMainParser::parsePeriods(Node *root)
89 std::vector<Node *> periods = DOMHelper::getElementByTagName(root, "Period", false);
90 std::vector<Node *>::const_iterator it;
92 for(it = periods.begin(); it != periods.end(); it++)
94 Period *period = new (std::nothrow) Period(mpd);
97 parseSegmentInformation(*it, period);
98 if((*it)->hasAttribute("start"))
99 period->startTime.Set(IsoTime((*it)->getAttributeValue("start")));
100 setAdaptationSets(*it, period);
101 mpd->addPeriod(period);
105 size_t IsoffMainParser::parseSegmentTemplate(Node *templateNode, SegmentInformation *info)
108 if (templateNode == NULL || !templateNode->hasAttribute("media"))
111 std::string mediaurl = templateNode->getAttributeValue("media");
112 SegmentTemplate *mediaTemplate = NULL;
113 if(mediaurl.empty() || !(mediaTemplate = new (std::nothrow) SegmentTemplate(info)) )
115 mediaTemplate->setSourceUrl(mediaurl);
117 if(templateNode->hasAttribute("startNumber"))
119 std::istringstream in(templateNode->getAttributeValue("startNumber"));
122 mediaTemplate->setStartIndex(i);
125 if(templateNode->hasAttribute("duration"))
127 std::istringstream in(templateNode->getAttributeValue("duration"));
130 mediaTemplate->duration.Set(i);
133 if(templateNode->hasAttribute("timescale"))
135 std::istringstream in(templateNode->getAttributeValue("timescale"));
138 mediaTemplate->timescale.Set(i);
141 InitSegmentTemplate *initTemplate = NULL;
143 if(templateNode->hasAttribute("initialization"))
145 std::string initurl = templateNode->getAttributeValue("initialization");
146 if(!initurl.empty() && (initTemplate = new (std::nothrow) InitSegmentTemplate(info)))
147 initTemplate->setSourceUrl(initurl);
150 info->setSegmentTemplate(mediaTemplate, SegmentInformation::INFOTYPE_MEDIA);
151 info->setSegmentTemplate(initTemplate, SegmentInformation::INFOTYPE_INIT);
153 total += ( mediaTemplate != NULL );
158 size_t IsoffMainParser::parseSegmentInformation(Node *node, SegmentInformation *info)
161 parseSegmentBase(DOMHelper::getFirstChildElementByName(node, "SegmentBase"), info);
162 total += parseSegmentList(DOMHelper::getFirstChildElementByName(node, "SegmentList"), info);
163 total += parseSegmentTemplate(DOMHelper::getFirstChildElementByName(node, "SegmentTemplate" ), info);
164 if(node->hasAttribute("bitstreamSwitching"))
165 info->setBitstreamSwitching(node->getAttributeValue("bitstreamSwitching") == "true");
166 if(node->hasAttribute("timescale"))
168 std::istringstream in(node->getAttributeValue("timescale"));
171 info->timescale.Set(i);
176 void IsoffMainParser::setAdaptationSets (Node *periodNode, Period *period)
178 std::vector<Node *> adaptationSets = DOMHelper::getElementByTagName(periodNode, "AdaptationSet", false);
179 std::vector<Node *>::const_iterator it;
181 for(it = adaptationSets.begin(); it != adaptationSets.end(); it++)
183 AdaptationSet *adaptationSet = new AdaptationSet(period);
186 if((*it)->hasAttribute("mimeType"))
187 adaptationSet->setMimeType((*it)->getAttributeValue("mimeType"));
189 parseSegmentInformation( *it, adaptationSet );
191 setRepresentations((*it), adaptationSet);
192 period->addAdaptationSet(adaptationSet);
195 void IsoffMainParser::setRepresentations (Node *adaptationSetNode, AdaptationSet *adaptationSet)
197 std::vector<Node *> representations = DOMHelper::getElementByTagName(adaptationSetNode, "Representation", false);
199 for(size_t i = 0; i < representations.size(); i++)
201 this->currentRepresentation = new Representation(adaptationSet, getMPD());
202 Node *repNode = representations.at(i);
204 std::vector<Node *> baseUrls = DOMHelper::getChildElementByTagName(repNode, "BaseURL");
205 if(!baseUrls.empty())
206 currentRepresentation->setBaseUrl( new BaseUrl( baseUrls.front()->getText() ) );
208 if(repNode->hasAttribute("id"))
209 currentRepresentation->setId(repNode->getAttributeValue("id"));
211 if(repNode->hasAttribute("width"))
212 this->currentRepresentation->setWidth(atoi(repNode->getAttributeValue("width").c_str()));
214 if(repNode->hasAttribute("height"))
215 this->currentRepresentation->setHeight(atoi(repNode->getAttributeValue("height").c_str()));
217 if(repNode->hasAttribute("bandwidth"))
218 this->currentRepresentation->setBandwidth(atoi(repNode->getAttributeValue("bandwidth").c_str()));
220 if(repNode->hasAttribute("mimeType"))
221 currentRepresentation->setMimeType(repNode->getAttributeValue("mimeType"));
223 size_t totalmediasegments = parseSegmentInformation(repNode, currentRepresentation);
224 if(!totalmediasegments)
226 /* unranged & segment less representation, add fake segment */
227 SegmentList *list = new SegmentList();
228 Segment *seg = new Segment(currentRepresentation);
231 list->addSegment(seg);
232 currentRepresentation->setSegmentList(list);
241 adaptationSet->addRepresentation(this->currentRepresentation);
245 void IsoffMainParser::parseSegmentBase(Node * segmentBaseNode, SegmentInformation *info)
250 else if(segmentBaseNode->hasAttribute("indexRange"))
252 SegmentList *list = new SegmentList();
255 size_t start = 0, end = 0;
256 if (std::sscanf(segmentBaseNode->getAttributeValue("indexRange").c_str(), "%zu-%zu", &start, &end) == 2)
258 seg = new IndexSegment(info);
259 seg->setByteRange(start, end);
260 list->addSegment(seg);
261 /* index must be before data, so data starts at index end */
262 seg = new Segment(info);
263 seg->setByteRange(end + 1, 0);
267 seg = new Segment(info);
270 list->addSegment(seg);
271 info->setSegmentList(list);
273 std::vector<Node *> initSeg = DOMHelper::getElementByTagName(segmentBaseNode, "Initialization", false);
276 SegmentBase *base = new SegmentBase();
277 setInitSegment(segmentBaseNode, base);
278 info->setSegmentBase(base);
283 SegmentBase *base = new SegmentBase();
284 setInitSegment(segmentBaseNode, base);
285 info->setSegmentBase(base);
289 size_t IsoffMainParser::parseSegmentList(Node * segListNode, SegmentInformation *info)
294 std::vector<Node *> segments = DOMHelper::getElementByTagName(segListNode, "SegmentURL", false);
296 if(!segments.empty() && (list = new (std::nothrow) SegmentList()))
298 std::vector<Node *>::const_iterator it;
299 for(it = segments.begin(); it != segments.end(); it++)
301 Node *segmentURL = *it;
302 std::string mediaUrl = segmentURL->getAttributeValue("media");
306 Segment *seg = new (std::nothrow) Segment(info);
310 seg->setSourceUrl(segmentURL->getAttributeValue("media"));
312 if(segmentURL->hasAttribute("mediaRange"))
314 std::string range = segmentURL->getAttributeValue("mediaRange");
315 size_t pos = range.find("-");
316 seg->setByteRange(atoi(range.substr(0, pos).c_str()), atoi(range.substr(pos + 1, range.size()).c_str()));
319 list->addSegment(seg);
323 info->setSegmentList(list);
329 void IsoffMainParser::setInitSegment (dash::xml::Node *segBaseNode, SegmentBase *base)
331 std::vector<Node *> initSeg = DOMHelper::getElementByTagName(segBaseNode, "Initialisation", false);
333 if(initSeg.size() == 0)
334 initSeg = DOMHelper::getElementByTagName(segBaseNode, "Initialization", false);
336 if(initSeg.size() > 0)
338 Segment *seg = new InitSegment( currentRepresentation );
339 seg->setSourceUrl(initSeg.at(0)->getAttributeValue("sourceURL"));
341 if(initSeg.at(0)->hasAttribute("range"))
343 std::string range = initSeg.at(0)->getAttributeValue("range");
344 size_t pos = range.find("-");
345 seg->setByteRange(atoi(range.substr(0, pos).c_str()), atoi(range.substr(pos + 1, range.size()).c_str()));
348 base->addInitSegment(seg);
352 void IsoffMainParser::print ()
356 msg_Dbg(p_stream, "MPD profile=%s mediaPresentationDuration=%ld minBufferTime=%ld",
357 static_cast<std::string>(mpd->getProfile()).c_str(),
359 mpd->getMinBufferTime());
360 msg_Dbg(p_stream, "BaseUrl=%s", mpd->getUrlSegment().toString().c_str());
362 std::vector<Period *>::const_iterator i;
363 for(i = mpd->getPeriods().begin(); i != mpd->getPeriods().end(); i++)
365 std::vector<std::string> debug = (*i)->toString();
366 std::vector<std::string>::const_iterator l;
367 for(l = debug.begin(); l < debug.end(); l++)
369 msg_Dbg(p_stream, "%s", (*l).c_str());
375 IsoTime::IsoTime(const std::string &str)
377 time = str_duration(str.c_str());
380 IsoTime::operator mtime_t () const
385 /* i_year: year - 1900 i_month: 0-11 i_mday: 1-31 i_hour: 0-23 i_minute: 0-59 i_second: 0-59 */
386 static int64_t vlc_timegm( int i_year, int i_month, int i_mday, int i_hour, int i_minute, int i_second )
388 static const int pn_day[12+1] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
392 i_month < 0 || i_month > 11 || i_mday < 1 || i_mday > 31 ||
393 i_hour < 0 || i_hour > 23 || i_minute < 0 || i_minute > 59 || i_second < 0 || i_second > 59 )
396 /* Count the number of days */
397 i_day = 365 * (i_year-70) + pn_day[i_month] + i_mday - 1;
398 #define LEAP(y) ( ((y)%4) == 0 && (((y)%100) != 0 || ((y)%400) == 0) ? 1 : 0)
399 for( int i = 70; i < i_year; i++ )
400 i_day += LEAP(1900+i);
402 i_day += LEAP(1900+i_year);
405 return ((24*i_day + i_hour)*60 + i_minute)*60 + i_second;
408 UTCTime::UTCTime(const std::string &str)
410 enum { YEAR = 0, MON, DAY, HOUR, MIN, SEC, TZ };
412 std::istringstream in(str);
417 for(int i=YEAR;i<=DAY && !in.eof();i++)
424 if (!in.eof() && in.peek() == 'T')
426 for(int i=HOUR;i<=SEC && !in.eof();i++)
433 if (!in.eof() && in.peek() == 'Z')
445 time = vlc_timegm( values[YEAR] - 1900, values[MON] - 1, values[DAY],
446 values[HOUR], values[MIN], values[SEC] );
447 time += values[TZ] * 3600;
453 UTCTime::operator mtime_t () const