]> git.sesse.net Git - vlc/blob - modules/demux/dash/dash.cpp
23431ddd82928e1c6a3bd4e2e29988500518017d
[vlc] / modules / demux / dash / dash.cpp
1 /*****************************************************************************
2  * dash.cpp: DASH module
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 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #define __STDC_CONSTANT_MACROS 1
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <stdint.h>
35
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
38 #include <vlc_demux.h>
39 #include <vlc_meta.h>
40
41 #include <errno.h>
42
43 #include "dash.hpp"
44 #include "xml/DOMParser.h"
45 #include "mpd/MPDFactory.h"
46
47 /*****************************************************************************
48  * Module descriptor
49  *****************************************************************************/
50 static int  Open    (vlc_object_t *);
51 static void Close   (vlc_object_t *);
52
53 #define DASH_WIDTH_TEXT N_("Preferred Width")
54 #define DASH_WIDTH_LONGTEXT N_("Preferred Width")
55
56 #define DASH_HEIGHT_TEXT N_("Preferred Height")
57 #define DASH_HEIGHT_LONGTEXT N_("Preferred Height")
58
59 #define DASH_BW_TEXT N_("Fixed Bandwidth in KiB/s")
60 #define DASH_BW_LONGTEXT N_("Preferred bandwidth for non adaptative streams")
61
62 #define DASH_LOGIC_TEXT N_("Adaptation Logic")
63
64 static const int pi_logics[] = {dash::logic::AbstractAdaptationLogic::RateBased,
65                                 dash::logic::AbstractAdaptationLogic::FixedRate,
66                                 dash::logic::AbstractAdaptationLogic::AlwaysLowest,
67                                 dash::logic::AbstractAdaptationLogic::AlwaysBest};
68
69 static const char *const ppsz_logics[] = { N_("Bandwidth Adaptive"),
70                                            N_("Fixed Bandwidth"),
71                                            N_("Lowest Bandwidth/Quality"),
72                                            N_("Highest Bandwith/Quality")};
73
74 vlc_module_begin ()
75         set_shortname( N_("DASH"))
76         set_description( N_("Dynamic Adaptive Streaming over HTTP") )
77         set_capability( "demux", 10 )
78         set_category( CAT_INPUT )
79         set_subcategory( SUBCAT_INPUT_DEMUX )
80         add_integer( "dash-logic",      dash::logic::AbstractAdaptationLogic::Default,
81                                              DASH_LOGIC_TEXT, NULL, false )
82             change_integer_list( pi_logics, ppsz_logics )
83         add_integer( "dash-prefwidth",  480, DASH_WIDTH_TEXT,  DASH_WIDTH_LONGTEXT,  true )
84         add_integer( "dash-prefheight", 360, DASH_HEIGHT_TEXT, DASH_HEIGHT_LONGTEXT, true )
85         add_integer( "dash-prefbw",     250, DASH_BW_TEXT,     DASH_BW_LONGTEXT,     false )
86         set_callbacks( Open, Close )
87 vlc_module_end ()
88
89 /*****************************************************************************
90  * Local prototypes
91  *****************************************************************************/
92
93 static int  Demux( demux_t * );
94 static int  Control         (demux_t *p_demux, int i_query, va_list args);
95
96 /*****************************************************************************
97  * Open:
98  *****************************************************************************/
99 static int Open(vlc_object_t *p_obj)
100 {
101     demux_t *p_demux = (demux_t*) p_obj;
102
103     bool b_mimematched = false;
104     char *psz_mime = stream_ContentType(p_demux->s);
105     if(psz_mime)
106     {
107         b_mimematched = !strcmp(psz_mime, "application/dash+xml");
108         free(psz_mime);
109     }
110
111     if(!b_mimematched && !dash::xml::DOMParser::isDash(p_demux->s))
112         return VLC_EGENERIC;
113
114     //Build a XML tree
115     dash::xml::DOMParser        parser(p_demux->s);
116     if( !parser.parse() )
117     {
118         msg_Err( p_demux, "Could not parse MPD" );
119         return VLC_EGENERIC;
120     }
121
122     //Begin the actual MPD parsing:
123     dash::mpd::MPD *mpd = dash::mpd::MPDFactory::create(parser.getRootNode(), p_demux->s, parser.getProfile());
124     if(mpd == NULL)
125     {
126         msg_Err( p_demux, "Cannot create/unknown MPD for profile");
127         return VLC_EGENERIC;
128     }
129
130     demux_sys_t        *p_sys = (demux_sys_t *) malloc(sizeof(demux_sys_t));
131     if (unlikely(p_sys == NULL))
132         return VLC_ENOMEM;
133
134     p_sys->p_mpd = mpd;
135     int logic = var_InheritInteger( p_obj, "dash-logic" );
136     dash::DASHManager*p_dashManager = new dash::DASHManager(p_sys->p_mpd,
137             static_cast<dash::logic::AbstractAdaptationLogic::LogicType>(logic),
138             p_demux->s);
139
140     dash::mpd::Period *period = mpd->getFirstPeriod();
141     if(period && !p_dashManager->start(p_demux))
142     {
143         delete p_dashManager;
144         free( p_sys );
145         return VLC_EGENERIC;
146     }
147     p_sys->p_dashManager    = p_dashManager;
148     p_demux->p_sys         = p_sys;
149     p_demux->pf_demux      = Demux;
150     p_demux->pf_control    = Control;
151
152     msg_Dbg(p_obj,"opening mpd file (%s)", p_demux->s->psz_path);
153
154     return VLC_SUCCESS;
155 }
156 /*****************************************************************************
157  * Close:
158  *****************************************************************************/
159 static void Close(vlc_object_t *p_obj)
160 {
161     demux_t                            *p_demux       = (demux_t*) p_obj;
162     demux_sys_t                        *p_sys          = (demux_sys_t *) p_demux->p_sys;
163     dash::DASHManager                   *p_dashManager  = p_sys->p_dashManager;
164
165     delete p_dashManager;
166     free(p_sys);
167 }
168 /*****************************************************************************
169  * Callbacks:
170  *****************************************************************************/
171 static int Demux(demux_t *p_demux)
172 {
173     demux_sys_t *p_sys = p_demux->p_sys;
174     if ( p_sys->p_dashManager->read() > 0 )
175     {
176         if ( p_sys->p_dashManager->esCount() )
177         {
178             mtime_t pcr = p_sys->p_dashManager->getPCR();
179             int group = p_sys->p_dashManager->getGroup();
180             if(group > 0)
181                 es_out_Control(p_demux->out, ES_OUT_SET_GROUP_PCR, group, pcr);
182             else
183                 es_out_Control(p_demux->out, ES_OUT_SET_PCR, pcr);
184         }
185         return VLC_DEMUXER_SUCCESS;
186     }
187     else
188         return VLC_DEMUXER_EOF;
189 }
190
191 static int  Control         (demux_t *p_demux, int i_query, va_list args)
192 {
193     demux_sys_t *p_sys = p_demux->p_sys;
194
195     switch (i_query)
196     {
197         case DEMUX_CAN_SEEK:
198             *(va_arg (args, bool *)) = false;
199             break;
200
201         case DEMUX_CAN_CONTROL_PACE:
202             *(va_arg (args, bool *)) = true;
203             break;
204
205         case DEMUX_CAN_PAUSE:
206             *(va_arg (args, bool *)) = p_sys->p_mpd->isLive();
207             break;
208
209         case DEMUX_GET_TIME:
210             *(va_arg (args, int64_t *)) = p_sys->p_dashManager->getPCR();
211             break;
212
213         case DEMUX_GET_LENGTH:
214             *(va_arg (args, int64_t *)) = p_sys->p_dashManager->getDuration();
215             break;
216
217         case DEMUX_GET_POSITION:
218             if(!p_sys->p_dashManager->getDuration())
219                 return VLC_EGENERIC;
220
221             *(va_arg (args, double *)) = (double) p_sys->p_dashManager->getPCR()
222                                          / p_sys->p_dashManager->getDuration();
223             break;
224
225         case DEMUX_GET_PTS_DELAY:
226             *va_arg (args, int64_t *) = INT64_C(1000) *
227                 var_InheritInteger(p_demux, "network-caching");
228              break;
229
230         case DEMUX_GET_META:
231         {
232             if(!p_sys->p_mpd->getProgramInformation())
233                 break;
234
235             vlc_meta_t *p_meta = (vlc_meta_t *) va_arg (args, vlc_meta_t*);
236             vlc_meta_t *meta = vlc_meta_New();
237             if (meta == NULL)
238                 return VLC_EGENERIC;
239
240             if(!p_sys->p_mpd->getProgramInformation()->getTitle().empty())
241                 vlc_meta_SetTitle(meta, p_sys->p_mpd->getProgramInformation()->getTitle().c_str());
242
243             if(!p_sys->p_mpd->getProgramInformation()->getSource().empty())
244                 vlc_meta_SetPublisher(meta, p_sys->p_mpd->getProgramInformation()->getSource().c_str());
245
246             if(!p_sys->p_mpd->getProgramInformation()->getCopyright().empty())
247                 vlc_meta_SetCopyright(meta, p_sys->p_mpd->getProgramInformation()->getCopyright().c_str());
248
249             if(!p_sys->p_mpd->getProgramInformation()->getMoreInformationUrl().empty())
250                 vlc_meta_SetURL(meta, p_sys->p_mpd->getProgramInformation()->getMoreInformationUrl().c_str());
251
252             vlc_meta_Merge(p_meta, meta);
253             vlc_meta_Delete(meta);
254             break;
255         }
256
257         default:
258             return VLC_EGENERIC;
259     }
260     return VLC_SUCCESS;
261 }