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 "ProgramInformation.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);
53 parseProgramInformation(DOMHelper::getFirstChildElementByName(root, "ProgramInformation"), mpd);
61 void IsoffMainParser::setMPDAttributes ()
63 const std::map<std::string, std::string> attr = this->root->getAttributes();
65 std::map<std::string, std::string>::const_iterator it;
67 it = attr.find("mediaPresentationDuration");
69 this->mpd->setDuration(IsoTime(it->second));
71 it = attr.find("minBufferTime");
73 this->mpd->setMinBufferTime(IsoTime(it->second));
75 it = attr.find("type");
77 mpd->setType(it->second);
79 it = attr.find("availabilityStartTime");
81 mpd->setAvailabilityStartTime(UTCTime(it->second));
83 it = attr.find("timeShiftBufferDepth");
85 mpd->setTimeShiftBufferDepth(IsoTime(it->second));
88 void IsoffMainParser::parsePeriods(Node *root)
90 std::vector<Node *> periods = DOMHelper::getElementByTagName(root, "Period", false);
91 std::vector<Node *>::const_iterator it;
93 for(it = periods.begin(); it != periods.end(); it++)
95 Period *period = new (std::nothrow) Period(mpd);
98 parseSegmentInformation(*it, period);
99 if((*it)->hasAttribute("start"))
100 period->startTime.Set(IsoTime((*it)->getAttributeValue("start")));
101 setAdaptationSets(*it, period);
102 mpd->addPeriod(period);
106 size_t IsoffMainParser::parseSegmentTemplate(Node *templateNode, SegmentInformation *info)
109 if (templateNode == NULL || !templateNode->hasAttribute("media"))
112 std::string mediaurl = templateNode->getAttributeValue("media");
113 SegmentTemplate *mediaTemplate = NULL;
114 if(mediaurl.empty() || !(mediaTemplate = new (std::nothrow) SegmentTemplate(info)) )
116 mediaTemplate->setSourceUrl(mediaurl);
118 if(templateNode->hasAttribute("startNumber"))
119 mediaTemplate->setStartIndex(Integer<uint64_t>(templateNode->getAttributeValue("startNumber")));
121 if(templateNode->hasAttribute("duration"))
122 mediaTemplate->duration.Set(Integer<mtime_t>(templateNode->getAttributeValue("duration")));
124 if(templateNode->hasAttribute("timescale"))
125 mediaTemplate->timescale.Set(Integer<uint64_t>(templateNode->getAttributeValue("timescale")));
127 InitSegmentTemplate *initTemplate = NULL;
129 if(templateNode->hasAttribute("initialization"))
131 std::string initurl = templateNode->getAttributeValue("initialization");
132 if(!initurl.empty() && (initTemplate = new (std::nothrow) InitSegmentTemplate(info)))
133 initTemplate->setSourceUrl(initurl);
136 info->setSegmentTemplate(mediaTemplate, SegmentInformation::INFOTYPE_MEDIA);
137 info->setSegmentTemplate(initTemplate, SegmentInformation::INFOTYPE_INIT);
139 total += ( mediaTemplate != NULL );
144 size_t IsoffMainParser::parseSegmentInformation(Node *node, SegmentInformation *info)
147 parseSegmentBase(DOMHelper::getFirstChildElementByName(node, "SegmentBase"), info);
148 total += parseSegmentList(DOMHelper::getFirstChildElementByName(node, "SegmentList"), info);
149 total += parseSegmentTemplate(DOMHelper::getFirstChildElementByName(node, "SegmentTemplate" ), info);
150 if(node->hasAttribute("bitstreamSwitching"))
151 info->setBitstreamSwitching(node->getAttributeValue("bitstreamSwitching") == "true");
152 if(node->hasAttribute("timescale"))
153 info->timescale.Set(Integer<uint64_t>(node->getAttributeValue("timescale")));
157 void IsoffMainParser::setAdaptationSets (Node *periodNode, Period *period)
159 std::vector<Node *> adaptationSets = DOMHelper::getElementByTagName(periodNode, "AdaptationSet", false);
160 std::vector<Node *>::const_iterator it;
162 for(it = adaptationSets.begin(); it != adaptationSets.end(); it++)
164 AdaptationSet *adaptationSet = new AdaptationSet(period);
167 if((*it)->hasAttribute("mimeType"))
168 adaptationSet->setMimeType((*it)->getAttributeValue("mimeType"));
170 parseSegmentInformation( *it, adaptationSet );
172 setRepresentations((*it), adaptationSet);
173 period->addAdaptationSet(adaptationSet);
176 void IsoffMainParser::setRepresentations (Node *adaptationSetNode, AdaptationSet *adaptationSet)
178 std::vector<Node *> representations = DOMHelper::getElementByTagName(adaptationSetNode, "Representation", false);
180 for(size_t i = 0; i < representations.size(); i++)
182 this->currentRepresentation = new Representation(adaptationSet, getMPD());
183 Node *repNode = representations.at(i);
185 std::vector<Node *> baseUrls = DOMHelper::getChildElementByTagName(repNode, "BaseURL");
186 if(!baseUrls.empty())
187 currentRepresentation->setBaseUrl( new BaseUrl( baseUrls.front()->getText() ) );
189 if(repNode->hasAttribute("id"))
190 currentRepresentation->setId(repNode->getAttributeValue("id"));
192 if(repNode->hasAttribute("width"))
193 this->currentRepresentation->setWidth(atoi(repNode->getAttributeValue("width").c_str()));
195 if(repNode->hasAttribute("height"))
196 this->currentRepresentation->setHeight(atoi(repNode->getAttributeValue("height").c_str()));
198 if(repNode->hasAttribute("bandwidth"))
199 this->currentRepresentation->setBandwidth(atoi(repNode->getAttributeValue("bandwidth").c_str()));
201 if(repNode->hasAttribute("mimeType"))
202 currentRepresentation->setMimeType(repNode->getAttributeValue("mimeType"));
204 size_t totalmediasegments = parseSegmentInformation(repNode, currentRepresentation);
205 if(!totalmediasegments)
207 /* unranged & segment less representation, add fake segment */
208 SegmentList *list = new SegmentList();
209 Segment *seg = new Segment(currentRepresentation);
212 list->addSegment(seg);
213 currentRepresentation->setSegmentList(list);
222 adaptationSet->addRepresentation(this->currentRepresentation);
226 void IsoffMainParser::parseSegmentBase(Node * segmentBaseNode, SegmentInformation *info)
231 else if(segmentBaseNode->hasAttribute("indexRange"))
233 SegmentList *list = new SegmentList();
236 size_t start = 0, end = 0;
237 if (std::sscanf(segmentBaseNode->getAttributeValue("indexRange").c_str(), "%zu-%zu", &start, &end) == 2)
239 seg = new IndexSegment(info);
240 seg->setByteRange(start, end);
241 list->addSegment(seg);
242 /* index must be before data, so data starts at index end */
243 seg = new Segment(info);
244 seg->setByteRange(end + 1, 0);
248 seg = new Segment(info);
251 list->addSegment(seg);
252 info->setSegmentList(list);
254 std::vector<Node *> initSeg = DOMHelper::getElementByTagName(segmentBaseNode, "Initialization", false);
257 SegmentBase *base = new SegmentBase();
258 setInitSegment(segmentBaseNode, base);
259 info->setSegmentBase(base);
264 SegmentBase *base = new SegmentBase();
265 setInitSegment(segmentBaseNode, base);
266 info->setSegmentBase(base);
270 size_t IsoffMainParser::parseSegmentList(Node * segListNode, SegmentInformation *info)
273 mtime_t totaltime = 0;
276 std::vector<Node *> segments = DOMHelper::getElementByTagName(segListNode, "SegmentURL", false);
278 if(!segments.empty() && (list = new (std::nothrow) SegmentList()))
280 if(segListNode->hasAttribute("duration"))
281 list->setDuration(Integer<mtime_t>(segListNode->getAttributeValue("duration")));
283 std::vector<Node *>::const_iterator it;
284 for(it = segments.begin(); it != segments.end(); it++)
286 Node *segmentURL = *it;
287 std::string mediaUrl = segmentURL->getAttributeValue("media");
291 Segment *seg = new (std::nothrow) Segment(info);
295 seg->setSourceUrl(segmentURL->getAttributeValue("media"));
297 if(segmentURL->hasAttribute("mediaRange"))
299 std::string range = segmentURL->getAttributeValue("mediaRange");
300 size_t pos = range.find("-");
301 seg->setByteRange(atoi(range.substr(0, pos).c_str()), atoi(range.substr(pos + 1, range.size()).c_str()));
304 if(totaltime || list->getDuration())
306 seg->startTime.Set(totaltime);
307 totaltime += list->getDuration();
310 list->addSegment(seg);
314 info->setSegmentList(list);
320 void IsoffMainParser::setInitSegment (dash::xml::Node *segBaseNode, SegmentBase *base)
322 std::vector<Node *> initSeg = DOMHelper::getElementByTagName(segBaseNode, "Initialisation", false);
324 if(initSeg.size() == 0)
325 initSeg = DOMHelper::getElementByTagName(segBaseNode, "Initialization", false);
327 if(initSeg.size() > 0)
329 Segment *seg = new InitSegment( currentRepresentation );
330 seg->setSourceUrl(initSeg.at(0)->getAttributeValue("sourceURL"));
332 if(initSeg.at(0)->hasAttribute("range"))
334 std::string range = initSeg.at(0)->getAttributeValue("range");
335 size_t pos = range.find("-");
336 seg->setByteRange(atoi(range.substr(0, pos).c_str()), atoi(range.substr(pos + 1, range.size()).c_str()));
339 base->addInitSegment(seg);
343 void IsoffMainParser::parseProgramInformation(Node * node, MPD *mpd)
348 ProgramInformation *info = new (std::nothrow) ProgramInformation();
351 Node *child = DOMHelper::getFirstChildElementByName(node, "Title");
353 info->setTitle(child->getText());
355 child = DOMHelper::getFirstChildElementByName(node, "Source");
357 info->setSource(child->getText());
359 child = DOMHelper::getFirstChildElementByName(node, "Copyright");
361 info->setCopyright(child->getText());
363 if(node->hasAttribute("moreInformationURL"))
364 info->setMoreInformationUrl(node->getAttributeValue("moreInformationURL"));
366 mpd->setProgramInformation(info);
370 void IsoffMainParser::print ()
374 msg_Dbg(p_stream, "MPD profile=%s mediaPresentationDuration=%ld minBufferTime=%ld",
375 static_cast<std::string>(mpd->getProfile()).c_str(),
377 mpd->getMinBufferTime());
378 msg_Dbg(p_stream, "BaseUrl=%s", mpd->getUrlSegment().toString().c_str());
380 std::vector<Period *>::const_iterator i;
381 for(i = mpd->getPeriods().begin(); i != mpd->getPeriods().end(); i++)
383 std::vector<std::string> debug = (*i)->toString();
384 std::vector<std::string>::const_iterator l;
385 for(l = debug.begin(); l < debug.end(); l++)
387 msg_Dbg(p_stream, "%s", (*l).c_str());
393 IsoTime::IsoTime(const std::string &str)
395 time = str_duration(str.c_str());
398 IsoTime::operator mtime_t () const
403 /* i_year: year - 1900 i_month: 0-11 i_mday: 1-31 i_hour: 0-23 i_minute: 0-59 i_second: 0-59 */
404 static int64_t vlc_timegm( int i_year, int i_month, int i_mday, int i_hour, int i_minute, int i_second )
406 static const int pn_day[12+1] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
410 i_month < 0 || i_month > 11 || i_mday < 1 || i_mday > 31 ||
411 i_hour < 0 || i_hour > 23 || i_minute < 0 || i_minute > 59 || i_second < 0 || i_second > 59 )
414 /* Count the number of days */
415 i_day = 365 * (i_year-70) + pn_day[i_month] + i_mday - 1;
416 #define LEAP(y) ( ((y)%4) == 0 && (((y)%100) != 0 || ((y)%400) == 0) ? 1 : 0)
417 for( int i = 70; i < i_year; i++ )
418 i_day += LEAP(1900+i);
420 i_day += LEAP(1900+i_year);
423 return ((24*i_day + i_hour)*60 + i_minute)*60 + i_second;
426 UTCTime::UTCTime(const std::string &str)
428 enum { YEAR = 0, MON, DAY, HOUR, MIN, SEC, TZ };
430 std::istringstream in(str);
435 for(int i=YEAR;i<=DAY && !in.eof();i++)
442 if (!in.eof() && in.peek() == 'T')
444 for(int i=HOUR;i<=SEC && !in.eof();i++)
451 if (!in.eof() && in.peek() == 'Z')
463 time = vlc_timegm( values[YEAR] - 1900, values[MON] - 1, values[DAY],
464 values[HOUR], values[MIN], values[SEC] );
465 time += values[TZ] * 3600;
471 UTCTime::operator mtime_t () const