]> git.sesse.net Git - vlc/blob - modules/stream_filter/dash/dash.cpp
stream_filter: dash: add segment chunk class
[vlc] / modules / stream_filter / 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
39 #include <errno.h>
40
41 #include "dash.hpp"
42 #include "xml/DOMParser.h"
43 #include "mpd/MPDFactory.h"
44
45 #define SEEK 0
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_BUFFER_TEXT N_("Buffer Size (Seconds)")
60 #define DASH_BUFFER_LONGTEXT N_("Buffer size in seconds")
61
62 vlc_module_begin ()
63         set_shortname( N_("DASH"))
64         set_description( N_("Dynamic Adaptive Streaming over HTTP") )
65         set_capability( "stream_filter", 19 )
66         set_category( CAT_INPUT )
67         set_subcategory( SUBCAT_INPUT_STREAM_FILTER )
68         add_integer( "dash-prefwidth",  480, DASH_WIDTH_TEXT,  DASH_WIDTH_LONGTEXT,  true )
69         add_integer( "dash-prefheight", 360, DASH_HEIGHT_TEXT, DASH_HEIGHT_LONGTEXT, true )
70         add_integer( "dash-buffersize", 30, DASH_BUFFER_TEXT, DASH_BUFFER_LONGTEXT, true )
71         set_callbacks( Open, Close )
72 vlc_module_end ()
73
74 /*****************************************************************************
75  * Local prototypes
76  *****************************************************************************/
77
78 static int  Read            (stream_t *p_stream, void *p_ptr, unsigned int i_len);
79 static int  Peek            (stream_t *p_stream, const uint8_t **pp_peek, unsigned int i_peek);
80 static int  Control         (stream_t *p_stream, int i_query, va_list args);
81
82 /*****************************************************************************
83  * Open:
84  *****************************************************************************/
85 static int Open(vlc_object_t *p_obj)
86 {
87     stream_t *p_stream = (stream_t*) p_obj;
88
89     if(!dash::xml::DOMParser::isDash(p_stream->p_source))
90         return VLC_EGENERIC;
91
92     //Build a XML tree
93     dash::xml::DOMParser        parser(p_stream->p_source);
94     if( !parser.parse() )
95     {
96         msg_Dbg( p_stream, "Could not parse mpd file." );
97         return VLC_EGENERIC;
98     }
99
100     //Begin the actual MPD parsing:
101     dash::mpd::MPD *mpd = dash::mpd::MPDFactory::create(parser.getRootNode(), p_stream->p_source, parser.getProfile());
102
103     if(mpd == NULL)
104         return VLC_EGENERIC;
105
106     stream_sys_t        *p_sys = (stream_sys_t *) malloc(sizeof(stream_sys_t));
107     if (unlikely(p_sys == NULL))
108         return VLC_ENOMEM;
109
110     p_sys->psz_useragent = var_InheritString(p_stream, "http-user-agent");
111
112     p_sys->p_mpd = mpd;
113     dash::DASHManager*p_dashManager = new dash::DASHManager(p_sys->p_mpd,
114                                           dash::logic::IAdaptationLogic::RateBased,
115                                           p_stream);
116
117     if(!p_dashManager->start())
118     {
119         delete p_dashManager;
120         free( p_sys );
121         free( p_sys->psz_useragent );
122         return VLC_EGENERIC;
123     }
124     p_sys->p_dashManager    = p_dashManager;
125     p_sys->position         = 0;
126     p_stream->p_sys         = p_sys;
127     p_stream->pf_read       = Read;
128     p_stream->pf_peek       = Peek;
129     p_stream->pf_control    = Control;
130
131     msg_Dbg(p_obj,"opening mpd file (%s)", p_stream->psz_path);
132
133     return VLC_SUCCESS;
134 }
135 /*****************************************************************************
136  * Close:
137  *****************************************************************************/
138 static void Close(vlc_object_t *p_obj)
139 {
140     stream_t                            *p_stream       = (stream_t*) p_obj;
141     stream_sys_t                        *p_sys          = (stream_sys_t *) p_stream->p_sys;
142     dash::DASHManager                   *p_dashManager  = p_sys->p_dashManager;
143
144     delete(p_dashManager);
145     free(p_sys->psz_useragent);
146     free(p_sys);
147 }
148 /*****************************************************************************
149  * Callbacks:
150  *****************************************************************************/
151 static int  Seek            ( stream_t *p_stream, uint64_t pos )
152 {
153     stream_sys_t        *p_sys          = (stream_sys_t *) p_stream->p_sys;
154     dash::DASHManager   *p_dashManager  = p_sys->p_dashManager;
155     int                 i_ret           = 0;
156     unsigned            i_len           = 0;
157     long                i_read          = 0;
158
159     if( pos < p_sys->position )
160     {
161         if( p_sys->position - pos > UINT_MAX )
162         {
163             msg_Err( p_stream, "Cannot seek backward that far!" );
164             return VLC_EGENERIC;
165         }
166         i_len = p_sys->position - pos;
167         i_ret = p_dashManager->seekBackwards( i_len );
168         if( i_ret == VLC_EGENERIC )
169         {
170             msg_Err( p_stream, "Cannot seek backward outside the current block :-/" );
171             return VLC_EGENERIC;
172         }
173         else
174             return VLC_SUCCESS;
175     }
176
177     /* Seek forward */
178     if( pos - p_sys->position > UINT_MAX )
179     {
180         msg_Err( p_stream, "Cannot seek forward that far!" );
181         return VLC_EGENERIC;
182     }
183     i_len = pos - p_sys->position;
184     i_read = Read( p_stream, (void *)NULL, i_len );
185     if( (unsigned)i_read == i_len )
186         return VLC_SUCCESS;
187     else
188         return VLC_EGENERIC;
189 }
190
191 static int  Read            (stream_t *p_stream, void *p_ptr, unsigned int i_len)
192 {
193     stream_sys_t        *p_sys          = (stream_sys_t *) p_stream->p_sys;
194     dash::DASHManager   *p_dashManager  = p_sys->p_dashManager;
195     uint8_t             *p_buffer       = (uint8_t*)p_ptr;
196     int                 i_ret           = 0;
197     int                 i_read          = 0;
198
199     while( i_len > 0 )
200     {
201         i_read = p_dashManager->read( p_buffer, i_len );
202         if( i_read < 0 )
203             break;
204         p_buffer += i_read;
205         i_ret += i_read;
206         i_len -= i_read;
207     }
208     p_buffer -= i_ret;
209
210     if (i_read < 0)
211     {
212         switch (errno)
213         {
214             case EINTR:
215             case EAGAIN:
216                 break;
217             default:
218                 msg_Dbg(p_stream, "DASH Read: failed to read (%s)",
219                         vlc_strerror_c(errno));
220                 return 0;
221         }
222         return 0;
223     }
224
225     p_sys->position += i_ret;
226
227     return i_ret;
228 }
229
230 static int  Peek            (stream_t *p_stream, const uint8_t **pp_peek, unsigned int i_peek)
231 {
232     stream_sys_t        *p_sys          = (stream_sys_t *) p_stream->p_sys;
233     dash::DASHManager   *p_dashManager  = p_sys->p_dashManager;
234
235     return p_dashManager->peek( pp_peek, i_peek );
236 }
237
238 static int  Control         (stream_t *p_stream, int i_query, va_list args)
239 {
240     stream_sys_t *p_sys = p_stream->p_sys;
241
242     switch (i_query)
243     {
244         case STREAM_CAN_SEEK:
245         case STREAM_CAN_FASTSEEK:
246             /*TODO Support Seek */
247             *(va_arg (args, bool *)) = SEEK;
248             break;
249         case STREAM_CAN_CONTROL_PACE:
250             *(va_arg (args, bool *)) = true;
251             break;
252         case STREAM_CAN_PAUSE:
253             *(va_arg (args, bool *)) = false; /* TODO */
254             break;
255
256         case STREAM_GET_POSITION:
257             *(va_arg (args, uint64_t *)) = p_sys->position;
258             break;
259         case STREAM_SET_POSITION:
260         {
261             uint64_t pos = (uint64_t)va_arg(args, uint64_t);
262             if(Seek(p_stream, pos) == VLC_SUCCESS)
263             {
264                 p_sys->position = pos;
265                 break;
266             }
267             else
268                 return VLC_EGENERIC;
269         }
270         case STREAM_GET_SIZE:
271         {
272             uint64_t*   res = (va_arg (args, uint64_t *));
273             *res = p_sys->p_dashManager->getDuration();
274             break;
275         }
276         case STREAM_GET_PTS_DELAY:
277             *va_arg (args, int64_t *) = INT64_C(1000) *
278                 var_InheritInteger(p_stream, "network-caching");
279              break;
280
281         default:
282             return VLC_EGENERIC;
283     }
284     return VLC_SUCCESS;
285 }