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