1 /*****************************************************************************
2 * SegmentTimeline.cpp: Implement the SegmentTimeline tag.
3 *****************************************************************************
4 * Copyright (C) 1998-2007 VLC authors and VideoLAN
5 * $Id: cab205ca773394cb05cdf589f6abca52b4516d68 $
6 *
7 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include "SegmentTimeline.h"
28
29 #include <algorithm>
30 #include <limits>
31
32 using namespace adaptive::playlist;
33
SegmentTimeline(TimescaleAble * parent)34 SegmentTimeline::SegmentTimeline(TimescaleAble *parent)
35 :TimescaleAble(parent)
36 {
37 totalLength = 0;
38 }
39
SegmentTimeline(uint64_t scale)40 SegmentTimeline::SegmentTimeline(uint64_t scale)
41 :TimescaleAble(NULL)
42 {
43 setTimescale(scale);
44 totalLength = 0;
45 }
46
~SegmentTimeline()47 SegmentTimeline::~SegmentTimeline()
48 {
49 std::list<Element *>::iterator it;
50 for(it = elements.begin(); it != elements.end(); ++it)
51 delete *it;
52 }
53
addElement(uint64_t number,stime_t d,uint64_t r,stime_t t)54 void SegmentTimeline::addElement(uint64_t number, stime_t d, uint64_t r, stime_t t)
55 {
56 Element *element = new (std::nothrow) Element(number, d, r, t);
57 if(element)
58 {
59 if(!elements.empty() && !t)
60 {
61 const Element *el = elements.back();
62 element->t = el->t + (el->d * (el->r + 1));
63 }
64 elements.push_back(element);
65 totalLength += (d * (r + 1));
66 }
67 }
68
getMinAheadScaledTime(uint64_t number) const69 mtime_t SegmentTimeline::getMinAheadScaledTime(uint64_t number) const
70 {
71 stime_t totalscaledtime = 0;
72
73 if(!elements.size() ||
74 minElementNumber() > number ||
75 maxElementNumber() < number)
76 return 0;
77
78 std::list<Element *>::const_reverse_iterator it;
79 for(it = elements.rbegin(); it != elements.rend(); ++it)
80 {
81 const Element *el = *it;
82 if(number > el->number + el->r)
83 break;
84 else if(number < el->number + el->r)
85 totalscaledtime += (el->d * (el->r + 1));
86 else /* within repeat range */
87 totalscaledtime += el->d * (el->number + el->r - number);
88 }
89
90 return totalscaledtime;
91 }
92
getElementNumberByScaledPlaybackTime(stime_t scaled) const93 uint64_t SegmentTimeline::getElementNumberByScaledPlaybackTime(stime_t scaled) const
94 {
95 const Element *prevel = NULL;
96 std::list<Element *>::const_iterator it;
97
98 if(!elements.size())
99 return 0;
100
101 for(it = elements.begin(); it != elements.end(); ++it)
102 {
103 const Element *el = *it;
104 if(scaled >= el->t)
105 {
106 if((uint64_t)scaled < el->t + (el->d * el->r))
107 return el->number + (scaled - el->t) / el->d;
108 }
109 /* might have been discontinuity */
110 else
111 {
112 if(prevel) /* > prev but < current */
113 return prevel->number + prevel->r;
114 else /* << first of the list */
115 return el->number;
116 }
117 prevel = el;
118 }
119
120 /* time is >> any of the list */
121 return prevel->number + prevel->r;
122 }
123
getScaledPlaybackTimeDurationBySegmentNumber(uint64_t number,stime_t * time,stime_t * duration) const124 bool SegmentTimeline::getScaledPlaybackTimeDurationBySegmentNumber(uint64_t number,
125 stime_t *time, stime_t *duration) const
126 {
127 std::list<Element *>::const_iterator it;
128 for(it = elements.begin(); it != elements.end(); ++it)
129 {
130 const Element *el = *it;
131 if(number >= el->number)
132 {
133 if(number <= el->number + el->r)
134 {
135 *time = el->t + el->d * (number - el->number);
136 *duration = el->d;
137 return true;
138 }
139 }
140 }
141 return false;
142 }
143
getScaledPlaybackTimeByElementNumber(uint64_t number) const144 stime_t SegmentTimeline::getScaledPlaybackTimeByElementNumber(uint64_t number) const
145 {
146 stime_t time = 0, duration = 0;
147 (void) getScaledPlaybackTimeDurationBySegmentNumber(number, &time, &duration);
148 return time;
149 }
150
getTotalLength() const151 stime_t SegmentTimeline::getTotalLength() const
152 {
153 return totalLength;
154 }
155
maxElementNumber() const156 uint64_t SegmentTimeline::maxElementNumber() const
157 {
158 if(elements.empty())
159 return 0;
160
161 const Element *e = elements.back();
162 return e->number + e->r;
163 }
164
minElementNumber() const165 uint64_t SegmentTimeline::minElementNumber() const
166 {
167 if(elements.empty())
168 return 0;
169 return elements.front()->number;
170 }
171
pruneByPlaybackTime(mtime_t time)172 void SegmentTimeline::pruneByPlaybackTime(mtime_t time)
173 {
174 const Timescale timescale = inheritTimescale();
175 uint64_t num = getElementNumberByScaledPlaybackTime(timescale.ToScaled(time));
176 pruneBySequenceNumber(num);
177 }
178
pruneBySequenceNumber(uint64_t number)179 size_t SegmentTimeline::pruneBySequenceNumber(uint64_t number)
180 {
181 size_t prunednow = 0;
182 while(elements.size())
183 {
184 Element *el = elements.front();
185 if(el->number >= number)
186 {
187 break;
188 }
189 else if(el->number + el->r >= number)
190 {
191 uint64_t count = number - el->number;
192 el->number += count;
193 el->t += count * el->d;
194 el->r -= count;
195 prunednow += count;
196 break;
197 }
198 else
199 {
200 prunednow += el->r + 1;
201 elements.pop_front();
202 totalLength -= (el->d * (el->r + 1));
203 delete el;
204 }
205 }
206
207 return prunednow;
208 }
209
updateWith(SegmentTimeline & other)210 void SegmentTimeline::updateWith(SegmentTimeline &other)
211 {
212 if(elements.empty())
213 {
214 while(other.elements.size())
215 {
216 elements.push_back(other.elements.front());
217 other.elements.pop_front();
218 }
219 return;
220 }
221
222 Element *last = elements.back();
223 while(other.elements.size())
224 {
225 Element *el = other.elements.front();
226 other.elements.pop_front();
227
228 if(last->contains(el->t)) /* Same element, but prev could have been middle of repeat */
229 {
230 const uint64_t count = (el->t - last->t) / last->d;
231 totalLength -= (last->d * (last->r + 1));
232 last->r = std::max(last->r, el->r + count);
233 totalLength += (last->d * (last->r + 1));
234 delete el;
235 }
236 else if(el->t < last->t)
237 {
238 delete el;
239 }
240 else /* Did not exist in previous list */
241 {
242 totalLength += (el->d * (el->r + 1));
243 elements.push_back(el);
244 el->number = last->number + last->r + 1;
245 last = el;
246 }
247 }
248 }
249
debug(vlc_object_t * obj,int indent) const250 void SegmentTimeline::debug(vlc_object_t *obj, int indent) const
251 {
252 std::stringstream ss;
253 ss << std::string(indent, ' ') << "Timeline";
254 msg_Dbg(obj, "%s", ss.str().c_str());
255
256 std::list<Element *>::const_iterator it;
257 for(it = elements.begin(); it != elements.end(); ++it)
258 (*it)->debug(obj, indent + 1);
259 }
260
Element(uint64_t number_,stime_t d_,uint64_t r_,stime_t t_)261 SegmentTimeline::Element::Element(uint64_t number_, stime_t d_, uint64_t r_, stime_t t_)
262 {
263 number = number_;
264 d = d_;
265 t = t_;
266 r = r_;
267 }
268
contains(stime_t time) const269 bool SegmentTimeline::Element::contains(stime_t time) const
270 {
271 if(time >= t && time < t + (stime_t)(r + 1) * d)
272 return true;
273 return false;
274 }
275
debug(vlc_object_t * obj,int indent) const276 void SegmentTimeline::Element::debug(vlc_object_t *obj, int indent) const
277 {
278 std::stringstream ss;
279 ss.imbue(std::locale("C"));
280 ss << std::string(indent + 1, ' ') << "Element #" << number
281 << " d=" << d << " r=" << r << " @t=" << t;
282 msg_Dbg(obj, "%s", ss.str().c_str());
283 }
284