]> git.sesse.net Git - vlc/blob - modules/demux/dash/mpd/Url.cpp
demux: ts: adjust PTS based on PCR's (fix #13803)
[vlc] / modules / demux / dash / mpd / Url.cpp
1 /*
2  * Url.cpp
3  *****************************************************************************
4  * Copyright (C) 2014 - VideoLAN Authors
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published
8  * by the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  *****************************************************************************/
20 #include "Url.hpp"
21 #include "Representation.h"
22 #include "SegmentTemplate.h"
23 #include "SegmentTimeline.h"
24 #include "MPD.h"
25
26 #include <sstream>
27 using namespace dash::mpd;
28
29 Url::Url()
30 {
31 }
32
33 Url::Url(const Component & comp)
34 {
35     prepend(comp);
36 }
37
38 Url::Url(const std::string &str)
39 {
40     prepend(Component(str));
41 }
42
43 Url & Url::prepend(const Component & comp)
44 {
45     components.insert(components.begin(), comp);
46     return *this;
47 }
48
49 Url & Url::append(const Component & comp)
50 {
51     components.push_back(comp);
52     return *this;
53 }
54
55 Url & Url::prepend(const Url &url)
56 {
57     components.insert(components.begin(), url.components.begin(), url.components.end());
58     return *this;
59 }
60
61 Url & Url::append(const Url &url)
62 {
63     components.insert(components.end(), url.components.begin(), url.components.end());
64     return *this;
65 }
66
67 std::string Url::toString() const
68 {
69     return toString(0, NULL);
70 }
71
72 std::string Url::toString(size_t index, const Representation *rep) const
73 {
74     std::string ret;
75     std::vector<Component>::const_iterator it;
76     for(it = components.begin(); it != components.end(); it++)
77     {
78         ret.append((*it).contextualize(index, rep));
79     }
80     return ret;
81 }
82
83 Url::Component::Component(const std::string & str, const MediaSegmentTemplate *templ_)
84 {
85     component = str;
86     templ = templ_;
87 }
88
89 mtime_t Url::Component::getScaledTimeBySegmentNumber(size_t index, const Representation *) const
90 {
91     mtime_t time = 0;
92     if(templ->segmentTimeline.Get())
93     {
94         time = templ->segmentTimeline.Get()->getScaledPlaybackTimeByElementNumber(index);
95     }
96     else if(templ->duration.Get())
97     {
98         time = templ->duration.Get() * index;
99     }
100     return time;
101 }
102
103 size_t Url::Component::getSegmentNumber(size_t index, const Representation *rep) const
104 {
105     index += templ->startNumber.Get();
106     /* live streams / templated */
107     if(rep->getMPD()->isLive())
108     {
109         if(templ->segmentTimeline.Get())
110         {
111             // do nothing ?
112         }
113         else if(templ->duration.Get())
114         {
115             mtime_t playbackstart = rep->getMPD()->playbackStart.Get();
116             mtime_t streamstart = rep->getMPD()->availabilityStartTime.Get();
117             streamstart += rep->getPeriodStart();
118             mtime_t duration = templ->duration.Get();
119             uint64_t timescale = templ->inheritTimescale();
120             if(duration && timescale)
121                 index += (playbackstart - streamstart) * timescale / duration;
122         }
123     }
124     return index;
125 }
126
127 std::string Url::Component::contextualize(size_t index, const Representation *rep) const
128 {
129     std::string ret(component);
130     size_t pos;
131
132     if(!rep)
133         return ret;
134
135     if(templ)
136     {
137         pos = ret.find("$Time$");
138         if(pos != std::string::npos)
139         {
140             std::stringstream ss;
141             ss << getScaledTimeBySegmentNumber(index, rep);
142             ret.replace(pos, std::string("$Time$").length(), ss.str());
143         }
144
145         pos = ret.find("$Number$");
146         if(pos != std::string::npos)
147         {
148             std::stringstream ss;
149             ss << getSegmentNumber(index, rep);
150             ret.replace(pos, std::string("$Number$").length(), ss.str());
151         }
152         else
153         {
154             pos = ret.find("$Number%");
155             size_t tokenlength = std::string("$Number%").length();
156             size_t fmtstart = pos + tokenlength;
157             if(pos != std::string::npos && fmtstart < ret.length())
158             {
159                 size_t fmtend = ret.find('$', fmtstart);
160                 if(fmtend != std::string::npos)
161                 {
162                     std::istringstream iss(ret.substr(fmtstart, fmtend - fmtstart + 1));
163                     try
164                     {
165                         size_t width;
166                         iss >> width;
167                         if (iss.peek() != '$')
168                             throw VLC_EGENERIC;
169                         std::stringstream oss;
170                         oss.width(width); /* set format string length */
171                         oss.fill('0');
172                         oss << getSegmentNumber(index, rep);
173                         ret.replace(pos, fmtend - pos + 1, oss.str());
174                     } catch(int) {}
175                 }
176             }
177         }
178     }
179
180     pos = ret.find("$Bandwidth$");
181     if(pos != std::string::npos)
182     {
183         std::stringstream ss;
184         ss << rep->getBandwidth();
185         ret.replace(pos, std::string("$Bandwidth$").length(), ss.str());
186     }
187
188     pos = ret.find("$RepresentationID$");
189     if(pos != std::string::npos)
190     {
191         std::stringstream ss;
192         ss << rep->getId();
193         ret.replace(pos, std::string("$RepresentationID$").length(), ss.str());
194     }
195
196     return ret;
197 }