dash.cpp 9.84 KB
Newer Older
Christopher Mueller's avatar
Christopher Mueller committed
1
2
3
/*****************************************************************************
 * dash.cpp: DASH module
 *****************************************************************************
4
 * Copyright © 2010 - 2011 Klagenfurt University
Christopher Mueller's avatar
Christopher Mueller committed
5
6
7
8
9
 *
 * Created on: Aug 10, 2010
 * Authors: Christopher Mueller <christopher.mueller@itec.uni-klu.ac.at>
 *          Christian Timmerer  <christian.timmerer@itec.uni-klu.ac.at>
 *
10
11
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
Christopher Mueller's avatar
Christopher Mueller committed
12
13
14
15
16
 * by the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * 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.
Christopher Mueller's avatar
Christopher Mueller committed
19
20
 *
 * You should have received a copy of the GNU Lesser General Public License
21
22
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Christopher Mueller's avatar
Christopher Mueller committed
23
24
25
26
27
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
28
29
#define __STDC_CONSTANT_MACROS 1

Christopher Mueller's avatar
Christopher Mueller committed
30
31
32
33
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

34
35
#include <stdint.h>

Christopher Mueller's avatar
Christopher Mueller committed
36
37
38
39
40
41
42
43
44
#include <vlc_common.h>
#include <vlc_plugin.h>

#include <errno.h>

#include "DASHManager.h"
#include "xml/DOMParser.h"
#include "http/HTTPConnectionManager.h"
#include "adaptationlogic/IAdaptationLogic.h"
45
#include "mpd/MPDFactory.h"
Christopher Mueller's avatar
Christopher Mueller committed
46
47
48
49
50
51
52
53
54

#define SEEK 0

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open    (vlc_object_t *);
static void Close   (vlc_object_t *);

55
56
57
58
59
60
#define DASH_WIDTH_TEXT N_("Preferred Width")
#define DASH_WIDTH_LONGTEXT N_("Preferred Width")

#define DASH_HEIGHT_TEXT N_("Preferred Height")
#define DASH_HEIGHT_LONGTEXT N_("Preferred Height")

61
62
63
#define DASH_BUFFER_TEXT N_("Buffer Size (Seconds)")
#define DASH_BUFFER_LONGTEXT N_("Buffer size in seconds")

Christopher Mueller's avatar
Christopher Mueller committed
64
65
66
67
68
69
vlc_module_begin ()
        set_shortname( N_("DASH"))
        set_description( N_("Dynamic Adaptive Streaming over HTTP") )
        set_capability( "stream_filter", 19 )
        set_category( CAT_INPUT )
        set_subcategory( SUBCAT_INPUT_STREAM_FILTER )
70
71
        add_integer( "dash-prefwidth",  480, DASH_WIDTH_TEXT,  DASH_WIDTH_LONGTEXT,  true )
        add_integer( "dash-prefheight", 360, DASH_HEIGHT_TEXT, DASH_HEIGHT_LONGTEXT, true )
72
        add_integer( "dash-buffersize", 30, DASH_BUFFER_TEXT, DASH_BUFFER_LONGTEXT, true )
Christopher Mueller's avatar
Christopher Mueller committed
73
74
        set_callbacks( Open, Close )
vlc_module_end ()
75

Christopher Mueller's avatar
Christopher Mueller committed
76
77
78
79
80
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
struct stream_sys_t
{
81
82
        dash::DASHManager   *p_dashManager;
        dash::mpd::MPD      *p_mpd;
Frédéric Yhuel's avatar
Frédéric Yhuel committed
83
        uint64_t                            position;
Christopher Mueller's avatar
Christopher Mueller committed
84
85
86
        bool                                isLive;
};

87
static int  Read            (stream_t *p_stream, void *p_ptr, unsigned int i_len);
Christopher Mueller's avatar
Christopher Mueller committed
88
89
static int  Peek            (stream_t *p_stream, const uint8_t **pp_peek, unsigned int i_peek);
static int  Control         (stream_t *p_stream, int i_query, va_list args);
90

Christopher Mueller's avatar
Christopher Mueller committed
91
92
93
/*****************************************************************************
 * Open:
 *****************************************************************************/
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
94
static int Open(vlc_object_t *p_obj)
Christopher Mueller's avatar
Christopher Mueller committed
95
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
96
    stream_t *p_stream = (stream_t*) p_obj;
Christopher Mueller's avatar
Christopher Mueller committed
97

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
98
    if(!dash::xml::DOMParser::isDash(p_stream->p_source))
99
        return VLC_EGENERIC;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
100

101
102
103
    //Build a XML tree
    dash::xml::DOMParser        parser(p_stream->p_source);
    if( !parser.parse() )
Christopher Mueller's avatar
Christopher Mueller committed
104
    {
105
106
107
        msg_Dbg( p_stream, "Could not parse mpd file." );
        return VLC_EGENERIC;
    }
108

109
    //Begin the actual MPD parsing:
110
111
112
    dash::mpd::MPD *mpd = dash::mpd::MPDFactory::create(parser.getRootNode(), p_stream->p_source, parser.getProfile());

    if(mpd == NULL)
Christopher Mueller's avatar
Christopher Mueller committed
113
114
        return VLC_EGENERIC;

115
    stream_sys_t        *p_sys = (stream_sys_t *) malloc(sizeof(stream_sys_t));
Christopher Mueller's avatar
Christopher Mueller committed
116
117
118
    if (unlikely(p_sys == NULL))
        return VLC_ENOMEM;

119
    p_sys->p_mpd = mpd;
120
121
122
    dash::DASHManager*p_dashManager = new dash::DASHManager(p_sys->p_mpd,
                                          dash::logic::IAdaptationLogic::RateBased,
                                          p_stream);
Christopher Mueller's avatar
Christopher Mueller committed
123

124
    if(!p_dashManager->start())
125
126
127
128
129
    {
        delete p_dashManager;
        free( p_sys );
        return VLC_EGENERIC;
    }
Christopher Mueller's avatar
Christopher Mueller committed
130
131
    p_sys->p_dashManager    = p_dashManager;
    p_sys->position         = 0;
132
    p_sys->isLive           = p_dashManager->getMpdManager()->getMPD()->isLive();
Christopher Mueller's avatar
Christopher Mueller committed
133
134
135
136
137
    p_stream->p_sys         = p_sys;
    p_stream->pf_read       = Read;
    p_stream->pf_peek       = Peek;
    p_stream->pf_control    = Control;

138
    msg_Dbg(p_obj,"opening mpd file (%s)", p_stream->psz_path);
Christopher Mueller's avatar
Christopher Mueller committed
139
140
141
142
143
144

    return VLC_SUCCESS;
}
/*****************************************************************************
 * Close:
 *****************************************************************************/
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
145
static void Close(vlc_object_t *p_obj)
Christopher Mueller's avatar
Christopher Mueller committed
146
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
147
    stream_t                            *p_stream       = (stream_t*) p_obj;
Christopher Mueller's avatar
Christopher Mueller committed
148
149
150
151
152
153
154
155
156
    stream_sys_t                        *p_sys          = (stream_sys_t *) p_stream->p_sys;
    dash::DASHManager                   *p_dashManager  = p_sys->p_dashManager;

    delete(p_dashManager);
    free(p_sys);
}
/*****************************************************************************
 * Callbacks:
 *****************************************************************************/
Frédéric Yhuel's avatar
Frédéric Yhuel committed
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
static int  Seek            ( stream_t *p_stream, uint64_t pos )
{
    stream_sys_t        *p_sys          = (stream_sys_t *) p_stream->p_sys;
    dash::DASHManager   *p_dashManager  = p_sys->p_dashManager;
    int                 i_ret           = 0;
    unsigned            i_len           = 0;
    long                i_read          = 0;

    if( pos < p_sys->position )
    {
        if( p_sys->position - pos > UINT_MAX )
        {
            msg_Err( p_stream, "Cannot seek backward that far!" );
            return VLC_EGENERIC;
        }
        i_len = p_sys->position - pos;
        i_ret = p_dashManager->seekBackwards( i_len );
        if( i_ret == VLC_EGENERIC )
        {
            msg_Err( p_stream, "Cannot seek backward outside the current block :-/" );
            return VLC_EGENERIC;
        }
        else
            return VLC_SUCCESS;
    }

    /* Seek forward */
    if( pos - p_sys->position > UINT_MAX )
    {
        msg_Err( p_stream, "Cannot seek forward that far!" );
        return VLC_EGENERIC;
    }
    i_len = pos - p_sys->position;
    i_read = Read( p_stream, (void *)NULL, i_len );
    if( (unsigned)i_read == i_len )
        return VLC_SUCCESS;
    else
        return VLC_EGENERIC;
}

197
static int  Read            (stream_t *p_stream, void *p_ptr, unsigned int i_len)
Christopher Mueller's avatar
Christopher Mueller committed
198
199
200
{
    stream_sys_t        *p_sys          = (stream_sys_t *) p_stream->p_sys;
    dash::DASHManager   *p_dashManager  = p_sys->p_dashManager;
201
    uint8_t             *p_buffer       = (uint8_t*)p_ptr;
Christopher Mueller's avatar
Christopher Mueller committed
202
    int                 i_ret           = 0;
203
    int                 i_read          = 0;
Christopher Mueller's avatar
Christopher Mueller committed
204

205
206
207
208
209
210
211
212
213
214
    while( i_len > 0 )
    {
        i_read = p_dashManager->read( p_buffer, i_len );
        if( i_read < 0 )
            break;
        p_buffer += i_read;
        i_ret += i_read;
        i_len -= i_read;
    }
    p_buffer -= i_ret;
Christopher Mueller's avatar
Christopher Mueller committed
215

216
    if (i_read < 0)
Christopher Mueller's avatar
Christopher Mueller committed
217
218
219
220
221
222
223
    {
        switch (errno)
        {
            case EINTR:
            case EAGAIN:
                break;
            default:
224
225
                msg_Dbg(p_stream, "DASH Read: failed to read (%s)",
                        vlc_strerror_c(errno));
Christopher Mueller's avatar
Christopher Mueller committed
226
227
228
229
230
231
232
233
234
                return 0;
        }
        return 0;
    }

    p_sys->position += i_ret;

    return i_ret;
}
235

Christopher Mueller's avatar
Christopher Mueller committed
236
237
238
239
240
static int  Peek            (stream_t *p_stream, const uint8_t **pp_peek, unsigned int i_peek)
{
    stream_sys_t        *p_sys          = (stream_sys_t *) p_stream->p_sys;
    dash::DASHManager   *p_dashManager  = p_sys->p_dashManager;

241
    return p_dashManager->peek( pp_peek, i_peek );
Christopher Mueller's avatar
Christopher Mueller committed
242
}
243

Christopher Mueller's avatar
Christopher Mueller committed
244
245
246
247
248
249
250
251
252
253
254
static int  Control         (stream_t *p_stream, int i_query, va_list args)
{
    stream_sys_t *p_sys = p_stream->p_sys;

    switch (i_query)
    {
        case STREAM_CAN_SEEK:
        case STREAM_CAN_FASTSEEK:
            /*TODO Support Seek */
            *(va_arg (args, bool *)) = SEEK;
            break;
255
256
257
258
259
        case STREAM_CAN_PAUSE:
        case STREAM_CAN_CONTROL_PACE:
            *(va_arg (args, bool *)) = false; /* TODO */
            break;

Christopher Mueller's avatar
Christopher Mueller committed
260
261
262
263
        case STREAM_GET_POSITION:
            *(va_arg (args, uint64_t *)) = p_sys->position;
            break;
        case STREAM_SET_POSITION:
Frédéric Yhuel's avatar
Frédéric Yhuel committed
264
265
266
267
268
269
270
271
272
273
        {
            uint64_t pos = (uint64_t)va_arg(args, uint64_t);
            if(Seek(p_stream, pos) == VLC_SUCCESS)
            {
                p_sys->position = pos;
                break;
            }
            else
                return VLC_EGENERIC;
        }
Christopher Mueller's avatar
Christopher Mueller committed
274
        case STREAM_GET_SIZE:
275
276
        {
            uint64_t*   res = (va_arg (args, uint64_t *));
Christopher Mueller's avatar
Christopher Mueller committed
277
            if(p_sys->isLive)
278
279
280
281
282
283
284
                *res = 0;
            else
            {
                const dash::mpd::Representation *rep = p_sys->p_dashManager->getAdaptionLogic()->getCurrentRepresentation();
                if ( rep == NULL )
                    *res = 0;
                else
285
                    *res = p_sys->p_mpd->getDuration() * rep->getBandwidth() / 8;
286
            }
Christopher Mueller's avatar
Christopher Mueller committed
287
            break;
288
        }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
289
        case STREAM_GET_PTS_DELAY:
290
            *va_arg (args, int64_t *) = INT64_C(1000) *
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
291
292
293
                var_InheritInteger(p_stream, "network-caching");
             break;

Christopher Mueller's avatar
Christopher Mueller committed
294
295
296
297
298
        default:
            return VLC_EGENERIC;
    }
    return VLC_SUCCESS;
}