Update translations from 2.2.x branch
[vlc.git] / modules / demux / adaptive / SegmentTracker.cpp
blobce5db8874f805fdd4a4d1f2011012f6fa327b0b0
1 /*
2 * SegmentTracker.cpp
3 *****************************************************************************
4 * Copyright (C) 2014 - VideoLAN and VLC authors
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.
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.
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 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include "SegmentTracker.hpp"
26 #include "playlist/AbstractPlaylist.hpp"
27 #include "playlist/BaseRepresentation.h"
28 #include "playlist/BaseAdaptationSet.h"
29 #include "playlist/Segment.h"
30 #include "playlist/SegmentChunk.hpp"
31 #include "logic/AbstractAdaptationLogic.h"
33 using namespace adaptive;
34 using namespace adaptive::logic;
35 using namespace adaptive::playlist;
37 SegmentTrackerEvent::SegmentTrackerEvent(SegmentChunk *s)
39 type = DISCONTINUITY;
40 u.discontinuity.sc = s;
43 SegmentTrackerEvent::SegmentTrackerEvent(BaseRepresentation *prev, BaseRepresentation *next)
45 type = SWITCHING;
46 u.switching.prev = prev;
47 u.switching.next = next;
50 SegmentTrackerEvent::SegmentTrackerEvent(const StreamFormat *fmt)
52 type = FORMATCHANGE;
53 u.format.f = fmt;
56 SegmentTrackerEvent::SegmentTrackerEvent(const ID &id, bool enabled)
58 type = BUFFERING_STATE;
59 u.buffering.enabled = enabled;
60 u.buffering.id = &id;
63 SegmentTrackerEvent::SegmentTrackerEvent(const ID &id, mtime_t min, mtime_t current, mtime_t target)
65 type = BUFFERING_LEVEL_CHANGE;
66 u.buffering_level.minimum = min;
67 u.buffering_level.current = current;
68 u.buffering_level.target = target;
69 u.buffering.id = &id;
72 SegmentTrackerEvent::SegmentTrackerEvent(const ID &id, mtime_t duration)
74 type = SEGMENT_CHANGE;
75 u.segment.duration = duration;
76 u.segment.id = &id;
79 SegmentTracker::SegmentTracker(AbstractAdaptationLogic *logic_, BaseAdaptationSet *adaptSet)
81 first = true;
82 curNumber = next = 0;
83 initializing = true;
84 index_sent = false;
85 init_sent = false;
86 curRepresentation = NULL;
87 setAdaptationLogic(logic_);
88 adaptationSet = adaptSet;
89 format = StreamFormat::UNSUPPORTED;
92 SegmentTracker::~SegmentTracker()
94 reset();
97 void SegmentTracker::setAdaptationLogic(AbstractAdaptationLogic *logic_)
99 logic = logic_;
100 registerListener(logic);
103 StreamFormat SegmentTracker::getCurrentFormat() const
105 BaseRepresentation *rep = curRepresentation;
106 if(!rep)
107 rep = logic->getNextRepresentation(adaptationSet, NULL);
108 if(rep)
110 /* Ensure ephemere content is updated/loaded */
111 if(rep->needsUpdate())
112 (void) rep->runLocalUpdates(0, curNumber, false);
113 return rep->getStreamFormat();
115 return StreamFormat();
118 bool SegmentTracker::segmentsListReady() const
120 BaseRepresentation *rep = curRepresentation;
121 if(!rep)
122 rep = logic->getNextRepresentation(adaptationSet, NULL);
123 if(rep && rep->getPlaylist()->isLive())
124 return rep->getMinAheadTime(curNumber) > 0;
125 return true;
128 void SegmentTracker::reset()
130 notify(SegmentTrackerEvent(curRepresentation, NULL));
131 curRepresentation = NULL;
132 init_sent = false;
133 index_sent = false;
134 initializing = true;
135 format = StreamFormat::UNSUPPORTED;
138 SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed,
139 AbstractConnectionManager *connManager)
141 BaseRepresentation *rep = NULL, *prevRep = NULL;
142 ISegment *segment;
144 if(!adaptationSet)
145 return NULL;
147 /* Ensure we don't keep chaining init/index without data */
148 if( initializing )
150 if( curRepresentation )
151 switch_allowed = false;
152 else
153 switch_allowed = true;
156 if( !switch_allowed ||
157 (curRepresentation && curRepresentation->getSwitchPolicy() == SegmentInformation::SWITCH_UNAVAILABLE) )
158 rep = curRepresentation;
159 else
160 rep = logic->getNextRepresentation(adaptationSet, curRepresentation);
162 if ( rep == NULL )
163 return NULL;
166 if(rep != curRepresentation)
168 notify(SegmentTrackerEvent(curRepresentation, rep));
169 prevRep = curRepresentation;
170 curRepresentation = rep;
171 init_sent = false;
172 index_sent = false;
173 initializing = true;
176 bool b_updated = false;
177 /* Ensure ephemere content is updated/loaded */
178 if(rep->needsUpdate())
179 b_updated = rep->runLocalUpdates(getPlaybackTime(), curNumber, false);
181 if(prevRep && !rep->consistentSegmentNumber())
183 /* Convert our segment number */
184 next = rep->translateSegmentNumber(next, prevRep);
186 else if(first && rep->getPlaylist()->isLive())
188 next = rep->getLiveStartSegmentNumber(next);
189 first = false;
192 if(b_updated)
194 if(!rep->consistentSegmentNumber())
195 curRepresentation->pruneBySegmentNumber(curNumber);
196 curRepresentation->scheduleNextUpdate(next);
199 if(rep->getStreamFormat() != format)
201 /* Initial format ? */
202 if(format == StreamFormat(StreamFormat::UNSUPPORTED))
204 format = rep->getStreamFormat();
206 else
208 format = rep->getStreamFormat();
209 notify(SegmentTrackerEvent(&format)); /* Notify new demux format */
210 return NULL; /* Force current demux to end */
214 if(format == StreamFormat(StreamFormat::UNSUPPORTED))
216 return NULL; /* Can't return chunk because no demux will be created */
219 if(!init_sent)
221 init_sent = true;
222 segment = rep->getSegment(BaseRepresentation::INFOTYPE_INIT);
223 if(segment)
224 return segment->toChunk(next, rep, connManager);
227 if(!index_sent)
229 index_sent = true;
230 segment = rep->getSegment(BaseRepresentation::INFOTYPE_INDEX);
231 if(segment)
232 return segment->toChunk(next, rep, connManager);
235 bool b_gap = false;
236 segment = rep->getNextSegment(BaseRepresentation::INFOTYPE_MEDIA, next, &next, &b_gap);
237 if(!segment)
239 return NULL;
242 if(initializing)
244 b_gap = false;
245 /* stop initializing after 1st chunk */
246 initializing = false;
249 SegmentChunk *chunk = segment->toChunk(next, rep, connManager);
251 /* Notify new segment length for stats / logic */
252 if(chunk)
254 const Timescale timescale = rep->inheritTimescale();
255 notify(SegmentTrackerEvent(rep->getAdaptationSet()->getID(),
256 timescale.ToTime(segment->duration.Get())));
259 /* We need to check segment/chunk format changes, as we can't rely on representation's (HLS)*/
260 if(chunk && format != chunk->getStreamFormat())
262 format = chunk->getStreamFormat();
263 notify(SegmentTrackerEvent(&format));
266 /* Handle both implicit and explicit discontinuities */
267 if( (b_gap && next) || (chunk && chunk->discontinuity) )
269 notify(SegmentTrackerEvent(chunk));
272 if(chunk)
274 curNumber = next;
275 next++;
278 return chunk;
281 bool SegmentTracker::setPositionByTime(mtime_t time, bool restarted, bool tryonly)
283 uint64_t segnumber;
284 BaseRepresentation *rep = curRepresentation;
285 if(!rep)
286 rep = logic->getNextRepresentation(adaptationSet, NULL);
288 if(rep &&
289 rep->getSegmentNumberByTime(time, &segnumber))
291 if(!tryonly)
292 setPositionByNumber(segnumber, restarted);
293 return true;
295 return false;
298 void SegmentTracker::setPositionByNumber(uint64_t segnumber, bool restarted)
300 if(restarted)
302 initializing = true;
303 index_sent = false;
304 init_sent = false;
306 curNumber = next = segnumber;
309 mtime_t SegmentTracker::getPlaybackTime() const
311 mtime_t time, duration;
313 BaseRepresentation *rep = curRepresentation;
314 if(!rep)
315 rep = logic->getNextRepresentation(adaptationSet, NULL);
317 if(rep &&
318 rep->getPlaybackTimeDurationBySegmentNumber(next, &time, &duration))
320 return time;
322 return 0;
325 mtime_t SegmentTracker::getMinAheadTime() const
327 BaseRepresentation *rep = curRepresentation;
328 if(!rep)
329 rep = logic->getNextRepresentation(adaptationSet, NULL);
330 if(rep)
331 return rep->getMinAheadTime(curNumber);
332 return 0;
335 void SegmentTracker::notifyBufferingState(bool enabled) const
337 notify(SegmentTrackerEvent(adaptationSet->getID(), enabled));
340 void SegmentTracker::notifyBufferingLevel(mtime_t min, mtime_t current, mtime_t target) const
342 notify(SegmentTrackerEvent(adaptationSet->getID(), min, current, target));
345 void SegmentTracker::registerListener(SegmentTrackerListenerInterface *listener)
347 listeners.push_back(listener);
350 void SegmentTracker::updateSelected()
352 if(curRepresentation && curRepresentation->needsUpdate())
354 curRepresentation->runLocalUpdates(getPlaybackTime(), curNumber, true);
355 curRepresentation->scheduleNextUpdate(curNumber);
359 void SegmentTracker::notify(const SegmentTrackerEvent &event) const
361 std::list<SegmentTrackerListenerInterface *>::const_iterator it;
362 for(it=listeners.begin();it != listeners.end(); ++it)
363 (*it)->trackerEvent(event);