]> git.sesse.net Git - vlc/blob - modules/demux/dash/DASHManager.cpp
demux: dash: include inttypes.h
[vlc] / modules / demux / dash / DASHManager.cpp
1 /*****************************************************************************
2  * DASHManager.cpp
3  *****************************************************************************
4  * Copyright © 2010 - 2011 Klagenfurt University
5  *
6  * Created on: Aug 10, 2010
7  * Authors: Christopher Mueller <christopher.mueller@itec.uni-klu.ac.at>
8  *          Christian Timmerer  <christian.timmerer@itec.uni-klu.ac.at>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 /* config.h may include inttypes.h, so make sure we define that option
26  * early enough. */
27 #define __STDC_FORMAT_MACROS 1
28 #define __STDC_CONSTANT_MACROS 1
29 #define __STDC_LIMIT_MACROS 1
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <inttypes.h>
36
37 #include "DASHManager.h"
38 #include "mpd/MPDFactory.h"
39 #include "mpd/SegmentTimeline.h"
40 #include "xml/DOMParser.h"
41 #include "adaptationlogic/AdaptationLogicFactory.h"
42 #include "SegmentTracker.hpp"
43 #include <vlc_stream.h>
44
45 using namespace dash;
46 using namespace dash::http;
47 using namespace dash::logic;
48 using namespace dash::mpd;
49
50 DASHManager::DASHManager    ( MPD *mpd,
51                               AbstractAdaptationLogic::LogicType type, stream_t *stream) :
52              conManager     ( NULL ),
53              logicType      ( type ),
54              mpd            ( mpd ),
55              stream         ( stream ),
56              nextMPDupdate  ( 0 )
57 {
58     for(int i=0; i<Streams::count; i++)
59         streams[i] = NULL;
60 }
61
62 DASHManager::~DASHManager   ()
63 {
64     delete conManager;
65     for(int i=0; i<Streams::count; i++)
66         delete streams[i];
67 }
68
69 bool DASHManager::start(demux_t *demux)
70 {
71     const Period *period = mpd->getFirstPeriod();
72     if(!period)
73         return false;
74
75     for(int i=0; i<Streams::count; i++)
76     {
77         Streams::Type type = static_cast<Streams::Type>(i);
78         const AdaptationSet *set = period->getAdaptationSet(type);
79         if(set)
80         {
81             streams[type] = new (std::nothrow) Streams::Stream(set->getMimeType());
82             if(!streams[type])
83                 continue;
84             AbstractAdaptationLogic *logic = AdaptationLogicFactory::create(logicType, mpd);
85             if(!logic)
86             {
87                 delete streams[type];
88                 streams[type] = NULL;
89                 continue;
90             }
91
92             SegmentTracker *tracker = new (std::nothrow) SegmentTracker(logic, mpd);
93             try
94             {
95                 if(!tracker)
96                     throw VLC_ENOMEM;
97                 streams[type]->create(demux, logic, tracker);
98             } catch (int) {
99                 delete streams[type];
100                 delete logic;
101                 delete tracker;
102                 streams[type] = NULL;
103             }
104         }
105     }
106
107     conManager = new (std::nothrow) HTTPConnectionManager(stream);
108     if(!conManager)
109         return false;
110
111     mpd->playbackStart.Set(time(NULL));
112     nextMPDupdate = mpd->playbackStart.Get();
113
114     return true;
115 }
116
117 size_t DASHManager::read()
118 {
119     size_t i_ret = 0;
120     for(int type=0; type<Streams::count; type++)
121     {
122         if(!streams[type])
123             continue;
124         i_ret += streams[type]->read(conManager);
125     }
126     return i_ret;
127 }
128
129 mtime_t DASHManager::getPCR() const
130 {
131     mtime_t pcr = VLC_TS_INVALID;
132     for(int type=0; type<Streams::count; type++)
133     {
134         if(!streams[type])
135             continue;
136         if(pcr == VLC_TS_INVALID || pcr > streams[type]->getPCR())
137             pcr = streams[type]->getPCR();
138     }
139     return pcr;
140 }
141
142 int DASHManager::getGroup() const
143 {
144     for(int type=0; type<Streams::count; type++)
145     {
146         if(!streams[type])
147             continue;
148         return streams[type]->getGroup();
149     }
150     return -1;
151 }
152
153 int DASHManager::esCount() const
154 {
155     int es = 0;
156     for(int type=0; type<Streams::count; type++)
157     {
158         if(!streams[type])
159             continue;
160         es += streams[type]->esCount();
161     }
162     return es;
163 }
164
165 mtime_t DASHManager::getDuration() const
166 {
167     if (mpd->isLive())
168         return 0;
169     else
170         return CLOCK_FREQ * mpd->duration.Get();
171 }
172
173 bool DASHManager::setPosition(mtime_t time)
174 {
175     bool ret = true;
176     for(int real = 0; real < 2; real++)
177     {
178         /* Always probe if we can seek first */
179         for(int type=0; type<Streams::count; type++)
180         {
181             if(!streams[type])
182                 continue;
183             ret &= streams[type]->setPosition(time, !real);
184         }
185         if(!ret)
186             break;
187     }
188     return ret;
189 }
190
191 bool DASHManager::seekAble() const
192 {
193     if(mpd->isLive())
194         return false;
195
196     for(int type=0; type<Streams::count; type++)
197     {
198         if(!streams[type])
199             continue;
200         if(!streams[type]->seekAble())
201             return false;
202     }
203     return true;
204 }
205
206 bool DASHManager::updateMPD()
207 {
208     if(!mpd->isLive() || !mpd->minUpdatePeriod.Get())
209         return true;
210
211     mtime_t now = time(NULL);
212     if(nextMPDupdate && now < nextMPDupdate)
213         return true;
214
215     /* do update */
216     if(nextMPDupdate)
217     {
218         std::string url(stream->psz_access);
219         url.append("://");
220         url.append(stream->psz_path);
221
222         stream_t *mpdstream = stream_UrlNew(stream, url.c_str());
223         if(!mpdstream)
224             return false;
225
226         xml::DOMParser parser(mpdstream);
227         if(!parser.parse())
228         {
229             stream_Delete(mpdstream);
230             return false;
231         }
232
233         mtime_t minsegmentTime = 0;
234         for(int type=0; type<Streams::count; type++)
235         {
236             if(!streams[type])
237                 continue;
238             mtime_t segmentTime = streams[type]->getPosition();
239             if(!minsegmentTime || segmentTime < minsegmentTime)
240                 minsegmentTime = segmentTime;
241         }
242
243         MPD *newmpd = MPDFactory::create(parser.getRootNode(), mpdstream, parser.getProfile());
244         if(newmpd)
245         {
246             mpd->mergeWith(newmpd, minsegmentTime);
247             delete newmpd;
248         }
249         stream_Delete(mpdstream);
250     }
251
252     /* Compute new MPD update time */
253     mtime_t mininterval = 0;
254     mtime_t maxinterval = 0;
255     mpd->getTimeLinesBoundaries(&mininterval, &maxinterval);
256     if(maxinterval > mininterval)
257         maxinterval = (maxinterval - mininterval) / CLOCK_FREQ;
258     else
259         maxinterval = 60;
260     maxinterval = std::max(maxinterval, (mtime_t)60);
261
262     mininterval = std::max(mpd->minUpdatePeriod.Get(),
263                            mpd->maxSegmentDuration.Get());
264
265     nextMPDupdate = now + (maxinterval - mininterval) / 2;
266
267     msg_Dbg(stream, "Updated MPD, next update in %"PRId64"s (%"PRId64"..%"PRId64")",
268             nextMPDupdate - now, mininterval, maxinterval );
269
270     return true;
271 }