live555.cpp 67.6 KB
Newer Older
1
/*****************************************************************************
2
 * live555.cpp : LIVE555 Streaming Media support.
3
 *****************************************************************************
4
 * Copyright (C) 2003-2007 the VideoLAN team
Carlo Calabrò's avatar
Carlo Calabrò committed
5
 * $Id$
6
7
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8
9
 *          Derk-Jan Hartman <hartman at videolan. org>
 *          Derk-Jan Hartman <djhartman at m2x .dot. nl> for M2X
10
11
12
13
14
15
16
17
18
19
20
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
JP Dinger's avatar
JP Dinger committed
21
22
23
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24
25
26
27
28
29
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

30
31
32
33
34
/* For inttypes.h
 * Note: config.h may include inttypes.h, so make sure we define this option
 * early enough. */
#define __STDC_CONSTANT_MACROS 1

35
36
37
38
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

39
40
#include <inttypes.h>

41
#include <vlc_common.h>
42
#include <vlc_plugin.h>
43
#include <vlc_input.h>
zorglub's avatar
zorglub committed
44
#include <vlc_demux.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
45
#include <vlc_dialog.h>
46
#include <vlc_url.h>
47
#include <vlc_strings.h>
48
49

#include <iostream>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
50
#include <limits.h>
51
#include <assert.h>
52

53

gbazin's avatar
   
gbazin committed
54
55
56
57
#if defined( WIN32 )
#   include <winsock2.h>
#endif

58
59
60
61
#include <UsageEnvironment.hh>
#include <BasicUsageEnvironment.hh>
#include <GroupsockHelper.hh>
#include <liveMedia.hh>
62

63
64
65
66
extern "C" {
#include "../access/mms/asf.h"  /* Who said ugly ? */
}

67
68
69
70
71
using namespace std;

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
72
73
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );
74

hartman's avatar
hartman committed
75
#define CACHING_TEXT N_("Caching value (ms)")
Laurent Aimar's avatar
Laurent Aimar committed
76
#define CACHING_LONGTEXT N_( \
Carlo Calabrò's avatar
Carlo Calabrò committed
77
    "Allows you to modify the default caching value for RTSP streams. This " \
78
    "value should be set in millisecond units." )
Laurent Aimar's avatar
Laurent Aimar committed
79

80
#define KASENNA_TEXT N_( "Kasenna RTSP dialect")
JP Dinger's avatar
JP Dinger committed
81
82
83
#define KASENNA_LONGTEXT N_( "Kasenna servers use an old and nonstandard " \
    "dialect of RTSP. With this parameter VLC will try this dialect, but "\
    "then it cannot connect to normal RTSP servers." )
84

85
86
87
88
89
#define WMSERVER_TEXT N_("WMServer RTSP dialect")
#define WMSERVER_LONGTEXT N_("WMServer uses an unstandard dialect " \
    "of RTSP. Selecting this parameter will tell VLC to assume some " \
    "options contrary to RFC 2326 guidelines.")

90
#define USER_TEXT N_("RTSP user name")
JP Dinger's avatar
JP Dinger committed
91
92
#define USER_LONGTEXT N_("Sets the username for the connection, " \
    "if no username or password are set in the url.")
93
#define PASS_TEXT N_("RTSP password")
JP Dinger's avatar
JP Dinger committed
94
95
#define PASS_LONGTEXT N_("Sets the password for the connection, " \
    "if no username or password are set in the url.")
96

97
98
99
100
101
102
103
104
105
106
107
108
109
vlc_module_begin ()
    set_description( N_("RTP/RTSP/SDP demuxer (using Live555)" ) )
    set_capability( "demux", 50 )
    set_shortname( "RTP/RTSP")
    set_callbacks( Open, Close )
    add_shortcut( "live" )
    add_shortcut( "livedotcom" )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_DEMUX )

    add_submodule ()
        set_description( N_("RTSP/RTP access and demux") )
        add_shortcut( "rtsp" )
110
        add_shortcut( "pnm" )
111
        add_shortcut( "sdp" )
112
113
        add_shortcut( "live" )
        add_shortcut( "livedotcom" )
114
115
        set_capability( "access_demux", 0 )
        set_callbacks( Open, Close )
ivoire's avatar
ivoire committed
116
        add_bool( "rtsp-tcp", false, NULL,
Carlo Calabrò's avatar
Carlo Calabrò committed
117
                  N_("Use RTP over RTSP (TCP)"),
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
118
                  N_("Use RTP over RTSP (TCP)"), true )
119
            change_safe()
120
121
        add_integer( "rtp-client-port", -1, NULL,
                  N_("Client port"),
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
122
                  N_("Port to use for the RTP source of the session"), true )
123
124
        add_bool( "rtsp-mcast", false, NULL,
                  N_("Force multicast RTP via RTSP"),
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
125
                  N_("Force multicast RTP via RTSP"), true )
126
            change_safe()
ivoire's avatar
ivoire committed
127
        add_bool( "rtsp-http", false, NULL,
128
                  N_("Tunnel RTSP and RTP over HTTP"),
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
129
                  N_("Tunnel RTSP and RTP over HTTP"), true )
130
            change_safe()
131
132
        add_integer( "rtsp-http-port", 80, NULL,
                  N_("HTTP tunnel port"),
133
                  N_("Port to use for tunneling the RTSP/RTP over HTTP."),
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
134
                  true )
hartman's avatar
hartman committed
135
        add_integer("rtsp-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
136
                    CACHING_TEXT, CACHING_LONGTEXT, true )
137
            change_safe()
138
        add_bool(   "rtsp-kasenna", false, NULL, KASENNA_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
139
                    KASENNA_LONGTEXT, true )
140
141
142
        add_bool(   "rtsp-wmserver", false, NULL, WMSERVER_TEXT,
                    WMSERVER_LONGTEXT, true)
            change_safe()
143
        add_string( "rtsp-user", NULL, NULL, USER_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
144
                    USER_LONGTEXT, true )
145
            change_safe()
146
147
        add_password( "rtsp-pwd", NULL, NULL, PASS_TEXT,
                      PASS_LONGTEXT, true )
148
            change_safe()
149
vlc_module_end ()
150
151
152


/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
153
 * Local prototypes
154
 *****************************************************************************/
155

156
157
typedef struct
{
158
159
    demux_t         *p_demux;
    MediaSubsession *sub;
160

161
162
    es_format_t     fmt;
    es_out_id_t     *p_es;
163

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
164
165
166
    bool            b_muxed;
    bool            b_quicktime;
    bool            b_asf;
167
    block_t         *p_asf_block;
168
    bool            b_discard_trunc;
169
    stream_t        *p_out_muxed;    /* for muxed stream */
170

171
172
    uint8_t         *p_buffer;
    unsigned int    i_buffer;
173

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
174
    bool            b_rtcp_sync;
175
176
    char            waiting;
    int64_t         i_pts;
177
    float           i_npt;
178

179
180
} live_track_t;

181
182
183
struct timeout_thread_t
{
    demux_sys_t  *p_sys;
184
185
    vlc_thread_t handle;
    bool         b_handle_keep_alive;
186
187
};

188
189
struct demux_sys_t
{
hartman's avatar
hartman committed
190
191
    char            *p_sdp;    /* XXX mallocated */
    char            *psz_path; /* URL-encoded path */
192
    vlc_url_t       url;
193
194
195
196
197
198

    MediaSession     *ms;
    TaskScheduler    *scheduler;
    UsageEnvironment *env ;
    RTSPClient       *rtsp;

199
    /* */
200
201
202
    int              i_track;
    live_track_t     **track;   /* XXX mallocated */

203
    /* Weird formats */
204
205
    asf_header_t     asfh;
    stream_t         *p_out_asf;
hartman's avatar
hartman committed
206
    bool             b_real;
207
208

    /* */
209
    int64_t          i_pcr; /* The clock */
210
    float            i_npt;
211
212
    float            i_npt_length;
    float            i_npt_start;
213

214
215
    /* timeout thread information */
    int              i_timeout;     /* session timeout value in seconds */
hartman's avatar
hartman committed
216
    bool             b_timeout_call;/* mark to send an RTSP call to prevent server timeout */
217
218
    timeout_thread_t *p_timeout;    /* the actual thread that makes sure we don't timeout */

219
    /* */
220
221
222
    bool             b_force_mcast;
    bool             b_multicast;   /* if one of the tracks is multicasted */
    bool             b_no_data;     /* if we never received any data */
223
224
    int              i_no_data_ti;  /* consecutive number of TaskInterrupt */

225
    char             event;
226
227

    bool             b_get_param;   /* Does the server support GET_PARAMETER */
228
    bool             b_paused;      /* Are we paused? */
229
    bool             b_error;
230
231

    float            f_seek_request;/* In case we receive a seek request while paused*/
232
233
234
235
236
};

static int Demux  ( demux_t * );
static int Control( demux_t *, int, va_list );

hartman's avatar
hartman committed
237
238
239
240
241
static int Connect      ( demux_t * );
static int SessionsSetup( demux_t * );
static int Play         ( demux_t *);
static int ParseASF     ( demux_t * );
static int RollOverTcp  ( demux_t * );
242

hartman's avatar
hartman committed
243
244
245
static void StreamRead  ( void *, unsigned int, unsigned int,
                          struct timeval, unsigned int );
static void StreamClose ( void * );
246
static void TaskInterrupt( void * );
247

248
static void* TimeoutPrevention( void * );
249

250
static unsigned char* parseH264ConfigStr( char const* configStr,
251
                                          unsigned int& configSize );
252

253
254
255
/*****************************************************************************
 * DemuxOpen:
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
256
static int  Open ( vlc_object_t *p_this )
257
{
258
    demux_t     *p_demux = (demux_t*)p_this;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
259
    demux_sys_t *p_sys = NULL;
260

ivoire's avatar
ivoire committed
261
    int i_return;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
262
    int i_error = VLC_EGENERIC;
263

Laurent Aimar's avatar
Laurent Aimar committed
264
    if( p_demux->s )
265
    {
Laurent Aimar's avatar
Laurent Aimar committed
266
267
        /* See if it looks like a SDP
           v, o, s fields are mandatory and in this order */
268
        const uint8_t *p_peek;
269
270
        if( stream_Peek( p_demux->s, &p_peek, 7 ) < 7 ) return VLC_EGENERIC;

271
272
        if( memcmp( p_peek, "v=0\r\n", 5 ) &&
            memcmp( p_peek, "v=0\n", 4 ) &&
Laurent Aimar's avatar
Laurent Aimar committed
273
274
275
276
            ( p_peek[0] < 'a' || p_peek[0] > 'z' || p_peek[1] != '=' ) )
        {
            return VLC_EGENERIC;
        }
277
    }
278
    var_Create( p_demux, "rtsp-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
279

280
281
282
    p_demux->pf_demux  = Demux;
    p_demux->pf_control= Control;
    p_demux->p_sys     = p_sys = (demux_sys_t*)malloc( sizeof( demux_sys_t ) );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
283
284
    if( !p_sys ) return VLC_ENOMEM;

285
286
287
288
289
290
291
    p_sys->p_sdp = NULL;
    p_sys->scheduler = NULL;
    p_sys->env = NULL;
    p_sys->ms = NULL;
    p_sys->rtsp = NULL;
    p_sys->i_track = 0;
    p_sys->track   = NULL;
292
    p_sys->i_pcr = 0;
293
294
295
    p_sys->i_npt = 0.;
    p_sys->i_npt_start = 0.;
    p_sys->i_npt_length = 0.;
296
    p_sys->p_out_asf = NULL;
297
    p_sys->b_no_data = true;
298
    p_sys->i_no_data_ti = 0;
299
300
    p_sys->p_timeout = NULL;
    p_sys->i_timeout = 0;
301
302
303
    p_sys->b_timeout_call = false;
    p_sys->b_multicast = false;
    p_sys->b_real = false;
hartman's avatar
hartman committed
304
    p_sys->psz_path = strdup( p_demux->psz_path );
305
    p_sys->b_force_mcast = var_CreateGetBool( p_demux, "rtsp-mcast" );
306
    p_sys->b_get_param = false;
307
    p_sys->b_paused = false;
308
    p_sys->f_seek_request = -1;
309
    p_sys->b_error = false;
310

311
312
313
    /* parse URL for rtsp://[user:[passwd]@]serverip:port/options */
    vlc_UrlParse( &p_sys->url, p_sys->psz_path, 0 );

314
315
    if( ( p_sys->scheduler = BasicTaskScheduler::createNew() ) == NULL )
    {
316
        msg_Err( p_demux, "BasicTaskScheduler::createNew failed" );
317
318
        goto error;
    }
319
    if( !( p_sys->env = BasicUsageEnvironment::createNew(*p_sys->scheduler) ) )
320
    {
321
        msg_Err( p_demux, "BasicUsageEnvironment::createNew failed" );
322
323
        goto error;
    }
Laurent Aimar's avatar
Laurent Aimar committed
324

325
    if( strcasecmp( p_demux->psz_access, "sdp" ) )
326
    {
327
        char *p = p_sys->psz_path;
328
        while( (p = strchr( p, ' ' )) != NULL ) *p = '+';
329
330
    }

hartman's avatar
hartman committed
331
    if( p_demux->s != NULL )
Laurent Aimar's avatar
Laurent Aimar committed
332
333
    {
        /* Gather the complete sdp file */
hartman's avatar
hartman committed
334
335
336
        int     i_sdp       = 0;
        int     i_sdp_max   = 1000;
        uint8_t *p_sdp      = (uint8_t*) malloc( i_sdp_max );
337

Jean-Paul Saman's avatar
Jean-Paul Saman committed
338
339
340
341
342
343
        if( !p_sdp )
        {
            i_error = VLC_ENOMEM;
            goto error;
        }

Laurent Aimar's avatar
Laurent Aimar committed
344
345
        for( ;; )
        {
346
347
            int i_read = stream_Read( p_demux->s, &p_sdp[i_sdp],
                                      i_sdp_max - i_sdp - 1 );
Laurent Aimar's avatar
Laurent Aimar committed
348

349
            if( !vlc_object_alive (p_demux) )
350
351
            {
                free( p_sdp );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
352
                goto error;
353
            }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
354

Laurent Aimar's avatar
Laurent Aimar committed
355
356
357
            if( i_read < 0 )
            {
                msg_Err( p_demux, "failed to read SDP" );
358
                free( p_sdp );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
359
                goto error;
Laurent Aimar's avatar
Laurent Aimar committed
360
361
362
363
364
365
366
367
368
369
370
            }

            i_sdp += i_read;

            if( i_read < i_sdp_max - i_sdp - 1 )
            {
                p_sdp[i_sdp] = '\0';
                break;
            }

            i_sdp_max += 1000;
371
            p_sdp = (uint8_t*)xrealloc( p_sdp, i_sdp_max );
Laurent Aimar's avatar
Laurent Aimar committed
372
373
        }
        p_sys->p_sdp = (char*)p_sdp;
374
    }
375
376
    else if( ( p_demux->s == NULL ) &&
             !strcasecmp( p_demux->psz_access, "sdp" ) )
hartman's avatar
hartman committed
377
378
379
380
381
    {
        /* sdp:// link from SAP */
        p_sys->p_sdp = strdup( p_sys->psz_path );
    }
    else if( ( i_return = Connect( p_demux ) ) != VLC_SUCCESS )
382
    {
hartman's avatar
hartman committed
383
        msg_Err( p_demux, "Failed to connect with rtsp://%s", p_sys->psz_path );
384
385
        goto error;
    }
386

hartman's avatar
hartman committed
387
    if( p_sys->p_sdp == NULL )
388
    {
hartman's avatar
hartman committed
389
        msg_Err( p_demux, "Failed to retrieve the RTSP Session Description" );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
390
        i_error = VLC_ENOMEM;
hartman's avatar
hartman committed
391
        goto error;
392
393
    }

hartman's avatar
hartman committed
394
395
396
397
398
    if( ( i_return = SessionsSetup( p_demux ) ) != VLC_SUCCESS )
    {
        msg_Err( p_demux, "Nothing to play for rtsp://%s", p_sys->psz_path );
        goto error;
    }
399

400
    if( p_sys->b_real ) goto error;
401

hartman's avatar
hartman committed
402
403
    if( ( i_return = Play( p_demux ) ) != VLC_SUCCESS )
        goto error;
404

405
406
407
408
409
410
411
    if( p_sys->p_out_asf && ParseASF( p_demux ) )
    {
        msg_Err( p_demux, "cannot find a usable asf header" );
        /* TODO Clean tracks */
        goto error;
    }

Laurent Aimar's avatar
Laurent Aimar committed
412
413
414
    if( p_sys->i_track <= 0 )
        goto error;

415
416
417
    return VLC_SUCCESS;

error:
ivoire's avatar
ivoire committed
418
    Close( p_this );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
419
    return i_error;
420
421
422
423
424
}

/*****************************************************************************
 * DemuxClose:
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
425
static void Close( vlc_object_t *p_this )
426
{
427
    demux_t *p_demux = (demux_t*)p_this;
428
429
    demux_sys_t *p_sys = p_demux->p_sys;
    int i;
430
431
432
433
434

    for( i = 0; i < p_sys->i_track; i++ )
    {
        live_track_t *tk = p_sys->track[i];

435
        if( tk->b_muxed ) stream_Delete( tk->p_out_muxed );
436
        es_format_Clean( &tk->fmt );
437
        free( tk->p_buffer );
438
439
        free( tk );
    }
440
441

    if( p_sys->i_track ) free( p_sys->track );
442
    if( p_sys->p_out_asf ) stream_Delete( p_sys->p_out_asf );
443
    if( p_sys->rtsp && p_sys->ms ) p_sys->rtsp->teardownMediaSession( *p_sys->ms );
444
445
    if( p_sys->p_timeout )
    {
446
447
448
        vlc_cancel( p_sys->p_timeout->handle );
        vlc_join( p_sys->p_timeout->handle, NULL );
        free( p_sys->p_timeout );
449
    }
450
451
452
    if( p_sys->ms ) Medium::close( p_sys->ms );
    if( p_sys->rtsp ) RTSPClient::close( p_sys->rtsp );
    if( p_sys->env ) p_sys->env->reclaim();
453
454
455
    delete p_sys->scheduler;
    free( p_sys->p_sdp );
    free( p_sys->psz_path );
456

457
458
    vlc_UrlClean( &p_sys->url );

459
460
461
    free( p_sys );
}

462
463
464
static inline const char *strempty( const char *s ) { return s?s:""; }
static inline Boolean toBool( bool b ) { return b?True:False; } // silly, no?

hartman's avatar
hartman committed
465
466
467
468
469
470
471
472
473
474
475
476
477
478
/*****************************************************************************
 * Connect: connects to the RTSP server to setup the session DESCRIBE
 *****************************************************************************/
static int Connect( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    Authenticator authenticator;
    char *psz_user    = NULL;
    char *psz_pwd     = NULL;
    char *psz_url     = NULL;
    char *psz_options = NULL;
    char *p_sdp       = NULL;
    int  i_http_port  = 0;
    int  i_ret        = VLC_SUCCESS;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
479

480
481
    /* Get the user name and password */
    if( p_sys->url.psz_username || p_sys->url.psz_password )
Jean-Paul Saman's avatar
Jean-Paul Saman committed
482
    {
483
484
485
486
487
        /* Create the URL by stripping away the username/password part */
        if( p_sys->url.i_port == 0 )
            p_sys->url.i_port = 554;
        if( asprintf( &psz_url, "rtsp://%s:%d%s",
                      strempty( p_sys->url.psz_host ),
488
489
                      p_sys->url.i_port,
                      strempty( p_sys->url.psz_path ) ) == -1 )
490
            return VLC_ENOMEM;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
491

492
493
        psz_user = strdup( strempty( p_sys->url.psz_username ) );
        psz_pwd  = strdup( strempty( p_sys->url.psz_password ) );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
494
495
496
    }
    else
    {
497
498
499
        if( asprintf( &psz_url, "rtsp://%s", p_sys->psz_path ) == -1 )
            return VLC_ENOMEM;

Jean-Paul Saman's avatar
Jean-Paul Saman committed
500
501
502
503
        psz_user = var_CreateGetString( p_demux, "rtsp-user" );
        psz_pwd  = var_CreateGetString( p_demux, "rtsp-pwd" );
    }

hartman's avatar
hartman committed
504
createnew:
505
    if( !vlc_object_alive (p_demux) )
506
    {
507
508
        i_ret = VLC_EGENERIC;
        goto bailout;
509
510
    }

hartman's avatar
hartman committed
511
512
513
    if( var_CreateGetBool( p_demux, "rtsp-http" ) )
        i_http_port = var_CreateGetInteger( p_demux, "rtsp-http-port" );

514
    if( ( p_sys->rtsp = RTSPClient::createNew( *p_sys->env,
515
          var_CreateGetInteger( p_demux, "verbose" ) > 1,
hartman's avatar
hartman committed
516
517
518
519
          "VLC media player", i_http_port ) ) == NULL )
    {
        msg_Err( p_demux, "RTSPClient::createNew failed (%s)",
                 p_sys->env->getResultMsg() );
520
521
        i_ret = VLC_EGENERIC;
        goto bailout;
hartman's avatar
hartman committed
522
    }
523

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
524
525
526
527
    /* Kasenna enables KeepAlive by analysing the User-Agent string.
     * Appending _KA to the string should be enough to enable this feature,
     * however, there is a bug where the _KA doesn't get parsed from the
     * default User-Agent as created by VLC/Live555 code. This is probably due
528
529
530
531
532
533
534
535
     * to spaces in the string or the string being too long. Here we override
     * the default string with a more compact version.
     */
    if( var_CreateGetBool( p_demux, "rtsp-kasenna" ))
    {
        p_sys->rtsp->setUserAgentString( "VLC_MEDIA_PLAYER_KA" );
    }

536
describe:
ivoire's avatar
ivoire committed
537
    authenticator.setUsernameAndPassword( psz_user, psz_pwd );
538

539
    /* */
540
    { /* i_timeout hack scope */
541
#if LIVEMEDIA_LIBRARY_VERSION_INT >= 1223337600
ivoire's avatar
ivoire committed
542
    const int i_timeout = var_CreateGetInteger(p_demux, "ipv4-timeout") / 1000;
543
    psz_options = p_sys->rtsp->sendOptionsCmd( psz_url, psz_user, psz_pwd,
544
                                               &authenticator, i_timeout );
545
#else
546
547
    psz_options = p_sys->rtsp->sendOptionsCmd( psz_url, psz_user, psz_pwd,
                                               &authenticator );
548
#endif
549
550
551
552
553
    if( psz_options == NULL && authenticator.realm() != NULL )
    {
        // try again, with the realm set this time
#if LIVEMEDIA_LIBRARY_VERSION_INT >= 1223337600
        psz_options = p_sys->rtsp->sendOptionsCmd( psz_url, psz_user, psz_pwd,
554
                                               &authenticator, i_timeout );
555
556
557
558
559
#else
        psz_options = p_sys->rtsp->sendOptionsCmd( psz_url, psz_user, psz_pwd,
                                               &authenticator );
#endif
    }
560
    if( psz_options )
561
        p_sys->b_get_param = (bool)strstr( psz_options, "GET_PARAMETER" );
562
563
    delete [] psz_options;

564
565
566
    if( var_CreateGetBool( p_demux, "rtsp-wmserver" ) )
       p_sys->b_get_param = true;

567
#if LIVEMEDIA_LIBRARY_VERSION_INT >= 1223337600
568
569
    p_sdp = p_sys->rtsp->describeWithPassword( psz_url, psz_user, psz_pwd,
                          var_GetBool( p_demux, "rtsp-kasenna" ), i_timeout );
570
#else
571
572
    p_sdp = p_sys->rtsp->describeWithPassword( psz_url, psz_user, psz_pwd,
                                     var_GetBool( p_demux, "rtsp-kasenna" ) );
573
#endif
574
    } /* i_timeout scope end */
575

hartman's avatar
hartman committed
576
577
    if( p_sdp == NULL )
    {
578
        /* failure occurred */
hartman's avatar
hartman committed
579
580
        int i_code = 0;
        const char *psz_error = p_sys->env->getResultMsg();
581

582
        if( var_GetBool( p_demux, "rtsp-http" ) )
Jean-Paul Saman's avatar
Jean-Paul Saman committed
583
584
            sscanf( psz_error, "%*s %*s HTTP GET %*s HTTP/%*u.%*u %3u %*s",
                    &i_code );
585
586
587
        else
        {
            const char *psz_tmp = strstr( psz_error, "RTSP" );
588
589
590
591
            if( psz_tmp )
                sscanf( psz_tmp, "RTSP/%*s%3u", &i_code );
            else
                i_code = 0;
592
        }
593
        msg_Dbg( p_demux, "DESCRIBE failed with %d: %s", i_code, psz_error );
594

hartman's avatar
hartman committed
595
596
597
598
        if( i_code == 401 )
        {
            msg_Dbg( p_demux, "authentication failed" );

599
600
            free( psz_user );
            free( psz_pwd );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
601
            dialog_Login( p_demux, &psz_user, &psz_pwd,
602
                          _("RTSP authentication"), "%s",
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
603
604
                        _("Please enter a valid login name and a password.") );
            if( psz_user != NULL && psz_pwd != NULL )
hartman's avatar
hartman committed
605
            {
ivoire's avatar
ivoire committed
606
                msg_Dbg( p_demux, "retrying with user=%s", psz_user );
607
                goto describe;
hartman's avatar
hartman committed
608
609
            }
        }
610
        else if( (i_code != 0) && !var_GetBool( p_demux, "rtsp-http" ) )
hartman's avatar
hartman committed
611
612
613
        {
            /* Perhaps a firewall is being annoying. Try HTTP tunneling mode */
            msg_Dbg( p_demux, "we will now try HTTP tunneling mode" );
ivoire's avatar
ivoire committed
614
            var_SetBool( p_demux, "rtsp-http", true );
hartman's avatar
hartman committed
615
            if( p_sys->rtsp ) RTSPClient::close( p_sys->rtsp );
616
            p_sys->rtsp = NULL;
hartman's avatar
hartman committed
617
618
            goto createnew;
        }
619
620
        else
        {
sebastien's avatar
sebastien committed
621
            msg_Dbg( p_demux, "connection timeout" );
622
            if( p_sys->rtsp ) RTSPClient::close( p_sys->rtsp );
623
            p_sys->rtsp = NULL;
624
        }
hartman's avatar
hartman committed
625
626
627
        i_ret = VLC_EGENERIC;
    }

628
    free( p_sys->p_sdp );
629
    p_sys->p_sdp = NULL;
hartman's avatar
hartman committed
630
    if( p_sdp ) p_sys->p_sdp = strdup( (char*)p_sdp );
hartman's avatar
hartman committed
631
632
    delete[] p_sdp;

633
634
635
636
637
638
bailout:
    /* malloc-ated copy */
    free( psz_url );
    free( psz_user );
    free( psz_pwd );

hartman's avatar
hartman committed
639
640
641
642
    return i_ret;
}

/*****************************************************************************
643
 * SessionsSetup: prepares the subsessions and does the SETUP
hartman's avatar
hartman committed
644
645
646
647
648
649
650
 *****************************************************************************/
static int SessionsSetup( demux_t *p_demux )
{
    demux_sys_t             *p_sys  = p_demux->p_sys;
    MediaSubsessionIterator *iter   = NULL;
    MediaSubsession         *sub    = NULL;

hartman's avatar
hartman committed
651
    bool           b_rtsp_tcp = false;
hartman's avatar
hartman committed
652
653
654
655
656
    int            i_client_port;
    int            i_return = VLC_SUCCESS;
    unsigned int   i_buffer = 0;
    unsigned const thresh = 200000; /* RTP reorder threshold .2 second (default .1) */

657
658
    b_rtsp_tcp    = var_CreateGetBool( p_demux, "rtsp-tcp" ) ||
                    var_GetBool( p_demux, "rtsp-http" );
hartman's avatar
hartman committed
659
660
    i_client_port = var_CreateGetInteger( p_demux, "rtp-client-port" );

661
662
663
664
665
666
667
668
    /* Create the session from the SDP */
    if( !( p_sys->ms = MediaSession::createNew( *p_sys->env, p_sys->p_sdp ) ) )
    {
        msg_Err( p_demux, "Could not create the RTSP Session: %s",
            p_sys->env->getResultMsg() );
        return VLC_EGENERIC;
    }

hartman's avatar
hartman committed
669
670
671
672
673
    /* Initialise each media subsession */
    iter = new MediaSubsessionIterator( *p_sys->ms );
    while( ( sub = iter->next() ) != NULL )
    {
        Boolean bInit;
674
        live_track_t *tk;
hartman's avatar
hartman committed
675

676
        if( !vlc_object_alive (p_demux) )
677
678
679
680
681
        {
            delete iter;
            return VLC_EGENERIC;
        }

hartman's avatar
hartman committed
682
683
684
685
686
        /* Value taken from mplayer */
        if( !strcmp( sub->mediumName(), "audio" ) )
            i_buffer = 100000;
        else if( !strcmp( sub->mediumName(), "video" ) )
            i_buffer = 2000000;
687
688
        else if( !strcmp( sub->mediumName(), "text" ) )
            ;
hartman's avatar
hartman committed
689
690
691
692
693
694
695
696
697
698
699
        else continue;

        if( i_client_port != -1 )
        {
            sub->setClientPortNum( i_client_port );
            i_client_port += 2;
        }

        if( strcasestr( sub->codecName(), "REAL" ) )
        {
            msg_Info( p_demux, "real codec detected, using real-RTSP instead" );
700
            p_sys->b_real = true; /* This is a problem, we'll handle it later */
701
            continue;
hartman's avatar
hartman committed
702
703
704
        }

        if( !strcmp( sub->codecName(), "X-ASF-PF" ) )
705
            bInit = sub->initiate( 0 );
hartman's avatar
hartman committed
706
707
        else
            bInit = sub->initiate();
708

hartman's avatar
hartman committed
709
710
711
712
713
714
715
716
717
718
719
        if( !bInit )
        {
            msg_Warn( p_demux, "RTP subsession '%s/%s' failed (%s)",
                      sub->mediumName(), sub->codecName(),
                      p_sys->env->getResultMsg() );
        }
        else
        {
            if( sub->rtpSource() != NULL )
            {
                int fd = sub->rtpSource()->RTPgs()->socketNum();
720

hartman's avatar
hartman committed
721
722
723
                /* Increase the buffer size */
                if( i_buffer > 0 )
                    increaseReceiveBufferTo( *p_sys->env, fd, i_buffer );
724

hartman's avatar
hartman committed
725
726
727
728
729
730
731
732
733
                /* Increase the RTP reorder timebuffer just a bit */
                sub->rtpSource()->setPacketReorderingThresholdTime(thresh);
            }
            msg_Dbg( p_demux, "RTP subsession '%s/%s'", sub->mediumName(),
                     sub->codecName() );

            /* Issue the SETUP */
            if( p_sys->rtsp )
            {
734
                if( !p_sys->rtsp->setupMediaSubsession( *sub, False,
735
736
                                                        toBool( b_rtsp_tcp ),
                             toBool( p_sys->b_force_mcast && !b_rtsp_tcp ) ) )
hartman's avatar
hartman committed
737
                {
738
739
740
741
742
743
                    /* if we get an unsupported transport error, toggle TCP
                     * use and try again */
                    if( !strstr(p_sys->env->getResultMsg(),
                                "461 Unsupported Transport")
                        || !p_sys->rtsp->setupMediaSubsession( *sub, False,
                                               toBool( b_rtsp_tcp ), False ) )
744
                    {
745
746
747
                        msg_Err( p_demux, "SETUP of'%s/%s' failed %s",
                                 sub->mediumName(), sub->codecName(),
                                 p_sys->env->getResultMsg() );
748
749
                        continue;
                    }
hartman's avatar
hartman committed
750
                }
751
            }
hartman's avatar
hartman committed
752

753
754
            /* Check if we will receive data from this subsession for
             * this track */
755
            if( sub->readSource() == NULL ) continue;
hartman's avatar
hartman committed
756
757
            if( !p_sys->b_multicast )
            {
758
                /* We need different rollover behaviour for multicast */
hartman's avatar
hartman committed
759
760
                p_sys->b_multicast = IsMulticastAddress( sub->connectionEndpointAddress() );
            }
761
762

            tk = (live_track_t*)malloc( sizeof( live_track_t ) );
763
764
765
766
767
            if( !tk )
            {
                delete iter;
                return VLC_ENOMEM;
            }
768
769
770
            tk->p_demux     = p_demux;
            tk->sub         = sub;
            tk->p_es        = NULL;
771
772
            tk->b_quicktime = false;
            tk->b_asf       = false;
773
            tk->p_asf_block = NULL;
774
            tk->b_muxed     = false;
775
            tk->b_discard_trunc = false;
776
777
            tk->p_out_muxed = NULL;
            tk->waiting     = 0;
778
            tk->b_rtcp_sync = false;
779
            tk->i_pts       = VLC_TS_INVALID;
780
            tk->i_npt       = 0.;
781
782
            tk->i_buffer    = 65536;
            tk->p_buffer    = (uint8_t *)malloc( 65536 );
783
784
            if( !tk->p_buffer )
            {
Christophe Mutricy's avatar
Christophe Mutricy committed
785
                free( tk );
786
787
788
                delete iter;
                return VLC_ENOMEM;
            }
789
790
791
792
793
794
795
796
797
798
799
800

            /* Value taken from mplayer */
            if( !strcmp( sub->mediumName(), "audio" ) )
            {
                es_format_Init( &tk->fmt, AUDIO_ES, VLC_FOURCC('u','n','d','f') );
                tk->fmt.audio.i_channels = sub->numChannels();
                tk->fmt.audio.i_rate = sub->rtpTimestampFrequency();

                if( !strcmp( sub->codecName(), "MPA" ) ||
                    !strcmp( sub->codecName(), "MPA-ROBUST" ) ||
                    !strcmp( sub->codecName(), "X-MP3-DRAFT-00" ) )
                {
801
                    tk->fmt.i_codec = VLC_CODEC_MPGA;
802
803
804
805
                    tk->fmt.audio.i_rate = 0;
                }
                else if( !strcmp( sub->codecName(), "AC3" ) )
                {
806
                    tk->fmt.i_codec = VLC_CODEC_A52;
807
808
809
810
811
812
813
814
815
816
817
818
819
820
                    tk->fmt.audio.i_rate = 0;
                }
                else if( !strcmp( sub->codecName(), "L16" ) )
                {
                    tk->fmt.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' );
                    tk->fmt.audio.i_bitspersample = 16;
                }
                else if( !strcmp( sub->codecName(), "L8" ) )
                {
                    tk->fmt.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' );
                    tk->fmt.audio.i_bitspersample = 8;
                }
                else if( !strcmp( sub->codecName(), "PCMU" ) )
                {
821
                    tk->fmt.i_codec = VLC_CODEC_MULAW;
822
823
824
                }
                else if( !strcmp( sub->codecName(), "PCMA" ) )
                {
825
                    tk->fmt.i_codec = VLC_CODEC_ALAW;
826
827
828
                }
                else if( !strncmp( sub->codecName(), "G726", 4 ) )
                {
829
                    tk->fmt.i_codec = VLC_CODEC_ADPCM_G726;
830
831
832
833
834
835
836
837
838
839
840
841
842
                    tk->fmt.audio.i_rate = 8000;
                    tk->fmt.audio.i_channels = 1;
                    if( !strcmp( sub->codecName()+5, "40" ) )
                        tk->fmt.i_bitrate = 40000;
                    else if( !strcmp( sub->codecName()+5, "32" ) )
                        tk->fmt.i_bitrate = 32000;
                    else if( !strcmp( sub->codecName()+5, "24" ) )
                        tk->fmt.i_bitrate = 24000;
                    else if( !strcmp( sub->codecName()+5, "16" ) )
                        tk->fmt.i_bitrate = 16000;
                }
                else if( !strcmp( sub->codecName(), "AMR" ) )
                {
843
                    tk->fmt.i_codec = VLC_CODEC_AMR_NB;
844
845
846
                }
                else if( !strcmp( sub->codecName(), "AMR-WB" ) )
                {
847
                    tk->fmt.i_codec = VLC_CODEC_AMR_WB;
848
849
850
851
852
853
                }
                else if( !strcmp( sub->codecName(), "MP4A-LATM" ) )
                {
                    unsigned int i_extra;
                    uint8_t      *p_extra;

854
                    tk->fmt.i_codec = VLC_CODEC_MP4A;
855
856
857
858
859

                    if( ( p_extra = parseStreamMuxConfigStr( sub->fmtp_config(),
                                                             i_extra ) ) )
                    {
                        tk->fmt.i_extra = i_extra;
860
                        tk->fmt.p_extra = xmalloc( i_extra );
861
862
863
                        memcpy( tk->fmt.p_extra, p_extra, i_extra );
                        delete[] p_extra;
                    }
864
865
866
                    /* Because the "faad" decoder does not handle the LATM
                     * data length field at the start of each returned LATM
                     * frame, tell the RTP source to omit it. */
867
868
869
870
871
872
873
                    ((MPEG4LATMAudioRTPSource*)sub->rtpSource())->omitLATMDataLengthField();
                }
                else if( !strcmp( sub->codecName(), "MPEG4-GENERIC" ) )
                {
                    unsigned int i_extra;
                    uint8_t      *p_extra;

874
                    tk->fmt.i_codec = VLC_CODEC_MP4A;
875
876
877
878
879

                    if( ( p_extra = parseGeneralConfigStr( sub->fmtp_config(),
                                                           i_extra ) ) )
                    {
                        tk->fmt.i_extra = i_extra;
880
                        tk->fmt.p_extra = xmalloc( i_extra );
881
882
883
884
885
886
                        memcpy( tk->fmt.p_extra, p_extra, i_extra );
                        delete[] p_extra;
                    }
                }
                else if( !strcmp( sub->codecName(), "X-ASF-PF" ) )
                {
887
                    tk->b_asf = true;
888
889
890
891
892
893
894
                    if( p_sys->p_out_asf == NULL )
                        p_sys->p_out_asf = stream_DemuxNew( p_demux, "asf",
                                                            p_demux->out );
                }
                else if( !strcmp( sub->codecName(), "X-QT" ) ||
                         !strcmp( sub->codecName(), "X-QUICKTIME" ) )
                {
895
                    tk->b_quicktime = true;
896
                }
897
898
                else if( !strcmp( sub->codecName(), "SPEEX" ) )
                {
899
                    tk->fmt.i_codec = VLC_FOURCC( 's', 'p', 'x', 'r' );
900
901
                    if ( sub->rtpTimestampFrequency() )
                        tk->fmt.audio.i_rate = sub->rtpTimestampFrequency();
902
                    else
903
904
905
906
                    {
                        msg_Warn( p_demux,"Using 8kHz as default sample rate." );
                        tk->fmt.audio.i_rate = 8000;
                    }
907
                }
908
909
910
911
912
913
            }
            else if( !strcmp( sub->mediumName(), "video" ) )
            {
                es_format_Init( &tk->fmt, VIDEO_ES, VLC_FOURCC('u','n','d','f') );
                if( !strcmp( sub->codecName(), "MPV" ) )
                {
914
                    tk->fmt.i_codec = VLC_CODEC_MPGV;
915
916
917
918
919
                }
                else if( !strcmp( sub->codecName(), "H263" ) ||
                         !strcmp( sub->codecName(), "H263-1998" ) ||
                         !strcmp( sub->codecName(), "H263-2000" ) )
                {
920
                    tk->fmt.i_codec = VLC_CODEC_H263;
921
922
923
                }
                else if( !strcmp( sub->codecName(), "H261" ) )
                {
924
                    tk->fmt.i_codec = VLC_CODEC_H261;
925
926
927
928
929
930
                }
                else if( !strcmp( sub->codecName(), "H264" ) )
                {
                    unsigned int i_extra = 0;
                    uint8_t      *p_extra = NULL;

931
                    tk->fmt.i_codec = VLC_CODEC_H264;
932
                    tk->fmt.b_packetized = false;
933
934
935
936
937

                    if((p_extra=parseH264ConfigStr( sub->fmtp_spropparametersets(),
                                                    i_extra ) ) )
                    {
                        tk->fmt.i_extra = i_extra;
938
                        tk->fmt.p_extra = xmalloc( i_extra );
939
940
941
942
943
944
945
                        memcpy( tk->fmt.p_extra, p_extra, i_extra );

                        delete[] p_extra;
                    }
                }
                else if( !strcmp( sub->codecName(), "JPEG" ) )
                {
946
                    tk->fmt.i_codec = VLC_CODEC_MJPG;
947
948
949
950
951
952
                }
                else if( !strcmp( sub->codecName(), "MP4V-ES" ) )
                {
                    unsigned int i_extra;
                    uint8_t      *p_extra;