live555.cpp 82.9 KB
Newer Older
1
/*****************************************************************************
2
 * live555.cpp : LIVE555 Streaming Media support.
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2003-2007 VLC authors and VideoLAN
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
 *          Sébastien Escudier <sebastien-devel celeos eu>
11
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
12 13 14
 * 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 by
 * the Free Software Foundation; either version 2.1 of the License, or
15 16 17 18
 * (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
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
19 20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
21
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
22 23 24
 * You should have received a copy of the GNU Lesser 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.
25 26 27 28 29 30
 *****************************************************************************/

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

31 32 33 34
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

35 36
#include <inttypes.h>

37
#include <vlc_common.h>
38
#include <vlc_plugin.h>
39
#include <vlc_input.h>
40
#include <vlc_demux.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
41
#include <vlc_dialog.h>
42
#include <vlc_url.h>
43
#include <vlc_strings.h>
44
#include <vlc_interrupt.h>
45
#include <vlc_keystore.h>
46

47
#include <limits.h>
48
#include <assert.h>
49

50
#include <new>
51

52
#if defined( _WIN32 )
53 54 55
#   include <winsock2.h>
#endif

56 57 58 59
#include <UsageEnvironment.hh>
#include <BasicUsageEnvironment.hh>
#include <GroupsockHelper.hh>
#include <liveMedia.hh>
60
#include <liveMedia_version.hh>
61
#include <Base64.hh>
62

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

67 68 69
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
70 71
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );
72

73
#define KASENNA_TEXT N_( "Kasenna RTSP dialect")
JP Dinger's avatar
JP Dinger committed
74 75 76
#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." )
77

78
#define WMSERVER_TEXT N_("WMServer RTSP dialect")
79
#define WMSERVER_LONGTEXT N_("WMServer uses a nonstandard dialect " \
80 81 82
    "of RTSP. Selecting this parameter will tell VLC to assume some " \
    "options contrary to RFC 2326 guidelines.")

83
#define USER_TEXT N_("Username")
JP Dinger's avatar
JP Dinger committed
84 85
#define USER_LONGTEXT N_("Sets the username for the connection, " \
    "if no username or password are set in the url.")
86
#define PASS_TEXT N_("Password")
JP Dinger's avatar
JP Dinger committed
87 88
#define PASS_LONGTEXT N_("Sets the password for the connection, " \
    "if no username or password are set in the url.")
89 90 91 92
#define FRAME_BUFFER_SIZE_TEXT N_("RTSP frame buffer size")
#define FRAME_BUFFER_SIZE_LONGTEXT N_("RTSP start frame buffer size of the video " \
    "track, can be increased in case of broken pictures due " \
    "to too small buffer.")
93
#define DEFAULT_FRAME_BUFFER_SIZE 250000
94

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

    add_submodule ()
        set_description( N_("RTSP/RTP access and demux") )
106
        add_shortcut( "rtsp", "pnm", "live", "livedotcom" )
107 108
        set_capability( "access_demux", 0 )
        set_callbacks( Open, Close )
109
        add_bool( "rtsp-tcp", false,
110
                  N_("Use RTP over RTSP (TCP)"),
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
111
                  N_("Use RTP over RTSP (TCP)"), true )
112
            change_safe()
113
        add_integer( "rtp-client-port", -1,
114
                  N_("Client port"),
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
115
                  N_("Port to use for the RTP source of the session"), true )
116
        add_bool( "rtsp-mcast", false,
117
                  N_("Force multicast RTP via RTSP"),
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
118
                  N_("Force multicast RTP via RTSP"), true )
119
            change_safe()
120
        add_bool( "rtsp-http", false,
121
                  N_("Tunnel RTSP and RTP over HTTP"),
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
122
                  N_("Tunnel RTSP and RTP over HTTP"), true )
123
            change_safe()
124
        add_integer( "rtsp-http-port", 80,
125
                  N_("HTTP tunnel port"),
126
                  N_("Port to use for tunneling the RTSP/RTP over HTTP."),
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
127
                  true )
128
        add_bool(   "rtsp-kasenna", false, KASENNA_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
129
                    KASENNA_LONGTEXT, true )
Greg Farrell's avatar
Greg Farrell committed
130
            change_safe()
131
        add_bool(   "rtsp-wmserver", false, WMSERVER_TEXT,
132 133
                    WMSERVER_LONGTEXT, true)
            change_safe()
134
        add_string( "rtsp-user", NULL, USER_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
135
                    USER_LONGTEXT, true )
136
            change_safe()
137
        add_password( "rtsp-pwd", NULL, PASS_TEXT,
138
                      PASS_LONGTEXT, true )
139 140 141
        add_integer( "rtsp-frame-buffer-size", DEFAULT_FRAME_BUFFER_SIZE,
                     FRAME_BUFFER_SIZE_TEXT, FRAME_BUFFER_SIZE_LONGTEXT,
                     true )
142
vlc_module_end ()
143 144 145


/*****************************************************************************
146
 * Local prototypes
147
 *****************************************************************************/
148

149 150
typedef struct
{
151 152
    demux_t         *p_demux;
    MediaSubsession *sub;
153

154 155
    es_format_t     fmt;
    es_out_id_t     *p_es;
156

157 158 159 160 161 162 163 164
    enum
    {
        SINGLE_STREAM,
        MULTIPLEXED_STREAM,
        QUICKTIME_STREAM,
        ASF_STREAM
    } format;

165
    block_t         *p_asf_block;
166
    bool            b_discard_trunc;
167
    vlc_demux_chained_t *p_out_muxed;    /* for muxed stream */
168

169 170
    uint8_t         *p_buffer;
    unsigned int    i_buffer;
171

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
172
    bool            b_rtcp_sync;
173
    bool            b_flushing_discontinuity;
174
    int             i_next_block_flags;
175
    char            waiting;
176 177
    int64_t         i_lastpts;
    int64_t         i_pcr;
178
    double          f_npt;
179

180 181 182 183 184 185 186
    enum
    {
        STATE_NONE,
        STATE_SELECTED,
        STATE_IGNORED,
        STATE_TEARDOWN,
    } state;
187

188 189
} live_track_t;

190 191
class RTSPClientVlc;

192
#define CAP_RATE_CONTROL        (1 << 1)
193 194
#define CAP_SUBSESSION_TEARDOWN (1 << 2)
#define CAP_SUBSESSION_PAUSE    (1 << 3)
195 196
#define CAPS_DEFAULT            CAP_RATE_CONTROL

197 198
struct demux_sys_t
{
199
    char            *p_sdp;    /* XXX mallocated */
200
    char            *psz_pl_url; /* password-less URL */
201
    vlc_url_t       url;
202 203 204 205

    MediaSession     *ms;
    TaskScheduler    *scheduler;
    UsageEnvironment *env ;
206
    RTSPClientVlc    *rtsp;
207
    int              capabilities; /* Server capabilities workaround */
208

209
    /* */
210
    int              i_track;
211
    live_track_t     **track;
212

213
    /* Weird formats */
214
    asf_header_t     asfh;
215
    vlc_demux_chained_t *p_out_asf;
216
    bool             b_real;
217 218

    /* */
219
    int64_t          i_pcr; /* The clock */
220
    bool             b_rtcp_sync; /* At least one track received sync */
221 222 223
    double           f_npt;
    double           f_npt_length;
    double           f_npt_start;
224

225
    /* timeout thread information */
226
    vlc_timer_t      timer;
227
    vlc_mutex_t      timeout_mutex; /* Serialise calls to live555 in timeout thread w.r.t. Demux()/Control() */
228

229
    /* */
230 231 232
    bool             b_force_mcast;
    bool             b_multicast;   /* if one of the tracks is multicasted */
    bool             b_no_data;     /* if we never received any data */
233 234
    int              i_no_data_ti;  /* consecutive number of TaskInterrupt */

235 236
    char             event_rtsp;
    char             event_data;
237 238

    bool             b_get_param;   /* Does the server support GET_PARAMETER */
239
    bool             b_paused;      /* Are we paused? */
240
    bool             b_error;
241
    int              i_live555_ret; /* live555 callback return code */
242 243

    float            f_seek_request;/* In case we receive a seek request while paused*/
244 245
};

246 247 248 249 250 251 252 253

class RTSPClientVlc : public RTSPClient
{
public:
    RTSPClientVlc( UsageEnvironment& env, char const* rtspURL, int verbosityLevel,
                   char const* applicationName, portNumBits tunnelOverHTTPPortNum,
                   demux_sys_t *p_sys) :
                   RTSPClient( env, rtspURL, verbosityLevel, applicationName,
254 255 256 257 258
                   tunnelOverHTTPPortNum
#if LIVEMEDIA_LIBRARY_VERSION_INT >= 1373932800
                   , -1
#endif
                   )
259 260 261 262 263 264
    {
        this->p_sys = p_sys;
    }
    demux_sys_t *p_sys;
};

265 266 267
static int Demux  ( demux_t * );
static int Control( demux_t *, int, va_list );

268 269 270 271 272
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 * );
273

274 275 276
static void StreamRead  ( void *, unsigned int, unsigned int,
                          struct timeval, unsigned int );
static void StreamClose ( void * );
277 278
static void TaskInterruptData( void * );
static void TaskInterruptRTSP( void * );
279

280
static void TimeoutPrevention( void * );
281

282
static unsigned char* parseH264ConfigStr( char const* configStr,
283
                                          unsigned int& configSize );
284 285
static unsigned char* parseVorbisConfigStr( char const* configStr,
                                            unsigned int& configSize );
286

287 288
static char *passwordLessURL( vlc_url_t *url );

289 290 291
#define PCR_OBS (CLOCK_FREQ / 4)
#define PCR_OFF PCR_OBS

292 293 294
/*****************************************************************************
 * DemuxOpen:
 *****************************************************************************/
295
static int  Open ( vlc_object_t *p_this )
296
{
297
    demux_t     *p_demux = (demux_t*)p_this;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
298
    demux_sys_t *p_sys = NULL;
299

300
    char *psz_url;
Rémi Duraffort's avatar
Rémi Duraffort committed
301
    int i_return;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
302
    int i_error = VLC_EGENERIC;
303

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
    /* if the rtsp URL may contain a sat.ip fake DNS, bail-out early and 
     * let the SAT>IP module handle that */
    if( !strncmp(p_demux->psz_location, "sat.ip", 6) )
    {
        msg_Err( p_demux, "SAT>IP server, bailing out");
        return VLC_EGENERIC;
    }
    /* If satip-host is set on the item, we shall assume it is a rtsp for the
     * SAT>IP module and bail-out early. */
    char *psz_host = var_InheritString(p_demux, "satip-host");
    if (psz_host != NULL) {
        msg_Err( p_demux, "URL is for SAT>IP, bailing out");
        free(psz_host);
        return VLC_EGENERIC;
    }

320
    if( p_demux->s )
321
    {
322 323
        /* See if it looks like a SDP
           v, o, s fields are mandatory and in this order */
324
        const uint8_t *p_peek;
325
        if( vlc_stream_Peek( p_demux->s, &p_peek, 7 ) < 7 ) return VLC_EGENERIC;
326

327 328
        if( memcmp( p_peek, "v=0\r\n", 5 ) &&
            memcmp( p_peek, "v=0\n", 4 ) &&
329 330 331 332
            ( p_peek[0] < 'a' || p_peek[0] > 'z' || p_peek[1] != '=' ) )
        {
            return VLC_EGENERIC;
        }
333 334
    }

335 336
    p_demux->pf_demux  = Demux;
    p_demux->pf_control= Control;
337
    p_demux->p_sys     = p_sys = (demux_sys_t*)calloc( 1, sizeof( demux_sys_t ) );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
338 339
    if( !p_sys ) return VLC_ENOMEM;

340 341 342 343 344 345
    if( vlc_timer_create(&p_sys->timer, TimeoutPrevention, p_demux) )
    {
        free( p_sys );
        return VLC_ENOMEM;
    }

346
    msg_Dbg( p_demux, "version " LIVEMEDIA_LIBRARY_VERSION_STRING );
347

348 349 350 351 352 353 354
    p_sys->capabilities = CAPS_DEFAULT;
    if( var_GetBool( p_demux, "rtsp-kasenna" ) ||
        var_GetBool( p_demux, "rtsp-wmserver" ) )
    {
        p_sys->capabilities &= ~CAP_RATE_CONTROL;
    }

355
    TAB_INIT( p_sys->i_track, p_sys->track );
356
    p_sys->b_no_data = true;
357
    p_sys->b_force_mcast = var_InheritBool( p_demux, "rtsp-mcast" );
358
    p_sys->f_seek_request = -1;
359
    vlc_mutex_init(&p_sys->timeout_mutex);
360

361
    /* parse URL for rtsp://[user:[passwd]@]serverip:port/options */
362 363 364 365 366 367 368 369 370 371 372 373 374
    if( asprintf( &psz_url, "%s://%s", p_demux->psz_access, p_demux->psz_location ) == -1 )
    {
        i_error = VLC_ENOMEM;
        goto error;
    }
    vlc_UrlParse( &p_sys->url, psz_url );
    free( psz_url );

    if( ( p_sys->psz_pl_url = passwordLessURL( &p_sys->url ) ) == NULL )
    {
        i_error = VLC_ENOMEM;
        goto error;
    }
375

376 377
    if( ( p_sys->scheduler = BasicTaskScheduler::createNew() ) == NULL )
    {
378
        msg_Err( p_demux, "BasicTaskScheduler::createNew failed" );
379 380
        goto error;
    }
381
    if( !( p_sys->env = BasicUsageEnvironment::createNew(*p_sys->scheduler) ) )
382
    {
383
        msg_Err( p_demux, "BasicUsageEnvironment::createNew failed" );
384 385
        goto error;
    }
386

387
    if( strcasecmp( p_demux->psz_access, "sdp" ) )
388
    {
389
        char *p = p_sys->psz_pl_url;
390
        while( (p = strchr( p, ' ' )) != NULL ) *p = '+';
391 392
    }

393
    if( p_demux->s != NULL )
394 395
    {
        /* Gather the complete sdp file */
396 397 398
        int     i_sdp       = 0;
        int     i_sdp_max   = 1000;
        uint8_t *p_sdp      = (uint8_t*) malloc( i_sdp_max );
399

Jean-Paul Saman's avatar
Jean-Paul Saman committed
400 401 402 403 404 405
        if( !p_sdp )
        {
            i_error = VLC_ENOMEM;
            goto error;
        }

406 407
        for( ;; )
        {
408
            int i_read = vlc_stream_Read( p_demux->s, &p_sdp[i_sdp],
409
                                      i_sdp_max - i_sdp - 1 );
410 411 412
            if( i_read < 0 )
            {
                msg_Err( p_demux, "failed to read SDP" );
413
                free( p_sdp );
414
                goto error;
415 416 417 418 419 420 421 422 423 424 425
            }

            i_sdp += i_read;

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

            i_sdp_max += 1000;
426
            p_sdp = (uint8_t*)xrealloc( p_sdp, i_sdp_max );
427 428
        }
        p_sys->p_sdp = (char*)p_sdp;
429
    }
430
    else if( ( i_return = Connect( p_demux ) ) != VLC_SUCCESS )
431
    {
432
        msg_Err( p_demux, "Failed to connect with %s", p_sys->psz_pl_url );
433 434
        goto error;
    }
435

436
    if( p_sys->p_sdp == NULL )
437
    {
438
        msg_Err( p_demux, "Failed to retrieve the RTSP Session Description" );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
439
        i_error = VLC_ENOMEM;
440
        goto error;
441 442
    }

443 444
    if( ( i_return = SessionsSetup( p_demux ) ) != VLC_SUCCESS )
    {
445
        msg_Err( p_demux, "Nothing to play for %s", p_sys->psz_pl_url );
446 447
        goto error;
    }
448

449
    if( p_sys->b_real ) goto error;
450

451 452
    if( ( i_return = Play( p_demux ) ) != VLC_SUCCESS )
        goto error;
453

454 455 456 457 458 459 460
    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
461 462 463
    if( p_sys->i_track <= 0 )
        goto error;

464 465 466
    return VLC_SUCCESS;

error:
Rémi Duraffort's avatar
Rémi Duraffort committed
467
    Close( p_this );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
468
    return i_error;
469 470 471 472 473
}

/*****************************************************************************
 * DemuxClose:
 *****************************************************************************/
474
static void Close( vlc_object_t *p_this )
475
{
476
    demux_t *p_demux = (demux_t*)p_this;
477
    demux_sys_t *p_sys = p_demux->p_sys;
478

479
    vlc_timer_destroy(p_sys->timer);
480

481
    if( p_sys->rtsp && p_sys->ms ) p_sys->rtsp->sendTeardownCommand( *p_sys->ms, NULL );
482 483 484 485 486
    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();

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

490 491
        if( tk->p_out_muxed )
            vlc_demux_chained_Delete( tk->p_out_muxed );
492
        es_format_Clean( &tk->fmt );
493
        free( tk->p_buffer );
494 495
        free( tk );
    }
496
    TAB_CLEAN( p_sys->i_track, p_sys->track );
497 498
    if( p_sys->p_out_asf )
        vlc_demux_chained_Delete( p_sys->p_out_asf );
499 500
    delete p_sys->scheduler;
    free( p_sys->p_sdp );
501
    free( p_sys->psz_pl_url );
502

503
    vlc_UrlClean( &p_sys->url );
504
    vlc_mutex_destroy(&p_sys->timeout_mutex);
505

506 507 508
    free( p_sys );
}

509 510
static inline Boolean toBool( bool b ) { return b?True:False; } // silly, no?

511 512 513 514 515 516 517
static void default_live555_callback( RTSPClient* client, int result_code, char* result_string )
{
    RTSPClientVlc *client_vlc = static_cast<RTSPClientVlc *> ( client );
    demux_sys_t *p_sys = client_vlc->p_sys;
    delete []result_string;
    p_sys->i_live555_ret = result_code;
    p_sys->b_error = p_sys->i_live555_ret != 0;
518
    p_sys->event_rtsp = 1;
519 520 521 522 523 524 525
}

/* return true if the RTSP command succeeded */
static bool wait_Live555_response( demux_t *p_demux, int i_timeout = 0 /* ms */ )
{
    TaskToken task;
    demux_sys_t * p_sys = p_demux->p_sys;
526
    p_sys->event_rtsp = 0;
527 528 529
    if( i_timeout > 0 )
    {
        /* Create a task that will be called if we wait more than timeout ms */
530 531
        task = p_sys->scheduler->scheduleDelayedTask( i_timeout*1000,
                                                      TaskInterruptRTSP,
532 533
                                                      p_demux );
    }
534
    p_sys->event_rtsp = 0;
535 536
    p_sys->b_error = true;
    p_sys->i_live555_ret = 0;
537
    p_sys->scheduler->doEventLoop( &p_sys->event_rtsp );
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
    //here, if b_error is true and i_live555_ret = 0 we didn't receive a response
    if( i_timeout > 0 )
    {
        /* remove the task */
        p_sys->scheduler->unscheduleDelayedTask( task );
    }
    return !p_sys->b_error;
}

static void continueAfterDESCRIBE( RTSPClient* client, int result_code,
                                   char* result_string )
{
    RTSPClientVlc *client_vlc = static_cast<RTSPClientVlc *> ( client );
    demux_sys_t *p_sys = client_vlc->p_sys;
    p_sys->i_live555_ret = result_code;
553
    if ( result_code == 0 )
554
    {
555 556 557 558 559 560 561 562
        char* sdpDescription = result_string;
        free( p_sys->p_sdp );
        p_sys->p_sdp = NULL;
        if( sdpDescription )
        {
            p_sys->p_sdp = strdup( sdpDescription );
            p_sys->b_error = false;
        }
563
    }
564 565 566
    else
        p_sys->b_error = true;
    delete[] result_string;
567
    p_sys->event_rtsp = 1;
568 569 570 571 572 573
#ifdef VLC_PATCH_RTSPCLIENT_SERVERSTRING
    if( client_vlc->serverString() )
    {
        if( !strncmp(client_vlc->serverString(), "Kasenna", 7) ||
            !strncmp(client_vlc->serverString(), "WMServer", 8) )
            p_sys->capabilities &= ~CAP_RATE_CONTROL;
574 575
        if( !strncmp(client_vlc->serverString(), "VLC/", 4) )
            p_sys->capabilities |= (CAP_SUBSESSION_TEARDOWN|CAP_SUBSESSION_PAUSE);
576 577
    }
#endif
578 579 580 581 582 583 584
}

static void continueAfterOPTIONS( RTSPClient* client, int result_code,
                                  char* result_string )
{
    RTSPClientVlc *client_vlc = static_cast<RTSPClientVlc *> (client);
    demux_sys_t *p_sys = client_vlc->p_sys;
585 586 587 588
    p_sys->b_get_param =
      // If OPTIONS fails, assume GET_PARAMETER is not supported but
      // still continue on with the stream.  Some servers (foscam)
      // return 501/not implemented for OPTIONS.
589
      result_code == 0
590 591
      && result_string != NULL
      && strstr( result_string, "GET_PARAMETER" ) != NULL;
592
    client->sendDescribeCommand( continueAfterDESCRIBE );
593 594 595
    delete[] result_string;
}

596 597 598 599 600 601 602
/*****************************************************************************
 * 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;
603 604 605
    vlc_credential credential;
    const char *psz_user = NULL;
    const char *psz_pwd  = NULL;
606 607
    int  i_http_port  = 0;
    int  i_ret        = VLC_SUCCESS;
608
    const int i_timeout = var_InheritInteger( p_demux, "ipv4-timeout" );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
609

610
    vlc_credential_init( &credential, &p_sys->url );
611

612 613 614 615 616 617
    /* Credentials can be NULL since they may not be needed */
    if( vlc_credential_get( &credential, p_demux, "rtsp-user", "rtsp-pwd",
                            NULL, NULL) )
    {
        psz_user = credential.psz_username;
        psz_pwd = credential.psz_password;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
618 619
    }

620
createnew:
621 622 623
    /* FIXME: This is naive and incorrect; it does not prevent the thread
     * getting stuck in blocking socket operations. */
    if( vlc_killed() )
624
    {
625 626
        i_ret = VLC_EGENERIC;
        goto bailout;
627 628
    }

629
    if( var_CreateGetBool( p_demux, "rtsp-http" ) )
630
        i_http_port = var_InheritInteger( p_demux, "rtsp-http-port" );
631

632
    p_sys->rtsp = new (std::nothrow) RTSPClientVlc( *p_sys->env, p_sys->psz_pl_url,
633
                                     var_InheritInteger( p_demux, "verbose" ) > 1 ? 1 : 0,
634
                                     "LibVLC/" VERSION, i_http_port, p_sys );
635
    if( !p_sys->rtsp )
636 637 638
    {
        msg_Err( p_demux, "RTSPClient::createNew failed (%s)",
                 p_sys->env->getResultMsg() );
639 640
        i_ret = VLC_EGENERIC;
        goto bailout;
641
    }
642

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
643 644 645 646
    /* 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
647 648 649
     * to spaces in the string or the string being too long. Here we override
     * the default string with a more compact version.
     */
650
    if( var_InheritBool( p_demux, "rtsp-kasenna" ))
651 652 653 654
    {
        p_sys->rtsp->setUserAgentString( "VLC_MEDIA_PLAYER_KA" );
    }

655
describe:
Rémi Duraffort's avatar
Rémi Duraffort committed
656
    authenticator.setUsernameAndPassword( psz_user, psz_pwd );
657

658
    p_sys->rtsp->sendOptionsCommand( &continueAfterOPTIONS, &authenticator );
659

660
    if( !wait_Live555_response( p_demux, i_timeout ) )
661
    {
662
        int i_code = p_sys->i_live555_ret;
663 664 665 666
        if( i_code == 401 )
        {
            msg_Dbg( p_demux, "authentication failed" );

667 668 669
            if( vlc_credential_get( &credential, p_demux, "rtsp-user", "rtsp-pwd",
                                    _("RTSP authentication"),
                                    _("Please enter a valid login name and a password.") ) )
670
            {
671 672
                psz_user = credential.psz_username;
                psz_pwd = credential.psz_password;
673
                msg_Dbg( p_demux, "retrying with user=%s", psz_user );
674
                goto describe;
675 676
            }
        }
677
        else if( i_code > 0 && i_code != 404 && !var_GetBool( p_demux, "rtsp-http" ) )
678 679 680
        {
            /* Perhaps a firewall is being annoying. Try HTTP tunneling mode */
            msg_Dbg( p_demux, "we will now try HTTP tunneling mode" );
Rémi Duraffort's avatar
Rémi Duraffort committed
681
            var_SetBool( p_demux, "rtsp-http", true );
682
            if( p_sys->rtsp ) RTSPClient::close( p_sys->rtsp );
683
            p_sys->rtsp = NULL;
684 685
            goto createnew;
        }
686 687
        else
        {
688 689
            if( i_code == 0 )
                msg_Dbg( p_demux, "connection timeout" );
690
            else
691
            {
692
                msg_Dbg( p_demux, "connection error %d", i_code );
693
                if( i_code == 403 )
Thomas Guillem's avatar
Thomas Guillem committed
694 695
                    vlc_dialog_display_error( p_demux, _("RTSP connection failed"),
                        _("Access to the stream is denied by the server configuration.") );
696
            }
697
            if( p_sys->rtsp ) RTSPClient::close( p_sys->rtsp );
698
            p_sys->rtsp = NULL;
699
        }
700 701
        i_ret = VLC_EGENERIC;
    }
702
    else
703
        vlc_credential_store( &credential, p_demux );
704

705
bailout:
706
    vlc_credential_clean( &credential );
707

708 709 710 711
    return i_ret;
}

/*****************************************************************************
712
 * SessionsSetup: prepares the subsessions and does the SETUP
713 714 715 716 717 718 719
 *****************************************************************************/
static int SessionsSetup( demux_t *p_demux )
{
    demux_sys_t             *p_sys  = p_demux->p_sys;
    MediaSubsessionIterator *iter   = NULL;
    MediaSubsession         *sub    = NULL;

720
    bool           b_rtsp_tcp;
721 722
    int            i_client_port;
    int            i_return = VLC_SUCCESS;
723 724
    unsigned int   i_receive_buffer = 0;
    int            i_frame_buffer = DEFAULT_FRAME_BUFFER_SIZE;
725
    unsigned const thresh = 200000; /* RTP reorder threshold .2 second (default .1) */
726 727
    const char     *p_sess_lang = NULL;
    const char     *p_lang;
728

729
    b_rtsp_tcp    = var_CreateGetBool( p_demux, "rtsp-tcp" ) ||
730
                    var_GetBool( p_demux, "rtsp-http" );
731
    i_client_port = var_InheritInteger( p_demux, "rtp-client-port" );
732

733

734 735 736 737 738 739 740 741
    /* 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;
    }

742 743 744 745 746 747 748 749 750 751 752 753 754 755
    if( strcmp( p_sys->p_sdp, "m=" ) != 0 )
    {
        const char *p_sess_attr_end;

        p_sess_attr_end = strstr( p_sys->p_sdp, "\nm=" );
        if( !p_sess_attr_end )
            p_sess_attr_end = strstr( p_sys->p_sdp, "\rm=" );

        p_sess_lang = p_sess_attr_end ? strstr( p_sys->p_sdp, "a=lang:" ) : NULL;
        if( p_sess_lang &&
            p_sess_lang - p_sys->p_sdp > p_sess_attr_end - p_sys->p_sdp )
            p_sess_lang = NULL;
    }

756 757 758 759 760
    /* Initialise each media subsession */
    iter = new MediaSubsessionIterator( *p_sys->ms );
    while( ( sub = iter->next() ) != NULL )
    {
        Boolean bInit;
761
        live_track_t *tk;
762 763 764

        /* Value taken from mplayer */
        if( !strcmp( sub->mediumName(), "audio" ) )
765
            i_receive_buffer = 100000;
766
        else if( !strcmp( sub->mediumName(), "video" ) )
767 768 769 770 771 772
        {
            int i_var_buf_size = var_InheritInteger( p_demux, "rtsp-frame-buffer-size" );
            if( i_var_buf_size > 0 )
                i_frame_buffer = i_var_buf_size;
            i_receive_buffer = 2000000;
        }
773 774
        else if( !strcmp( sub->mediumName(), "text" ) )
            ;
775 776 777 778 779
        else continue;

        if( strcasestr( sub->codecName(), "REAL" ) )
        {
            msg_Info( p_demux, "real codec detected, using real-RTSP instead" );
780
            p_sys->b_real = true; /* This is a problem, we'll handle it later */
781
            continue;
782 783
        }

784 785 786 787 788 789
        if( p_sys->rtsp && i_client_port != -1 )
        {
            sub->setClientPortNum( i_client_port );
            i_client_port += 2;
        }

790
        if( !strcmp( sub->codecName(), "X-ASF-PF" ) )
791
            bInit = sub->initiate( 0 );
792 793
        else
            bInit = sub->initiate();
794

795 796 797 798 799 800 801 802 803 804 805
        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();
806

807
                /* Increase the buffer size */
808 809
                if( i_receive_buffer > 0 )
                    increaseReceiveBufferTo( *p_sys->env, fd, i_receive_buffer );
810

811 812 813 814 815 816 817 818 819
                /* 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 )
            {
820 821 822 823
                p_sys->rtsp->sendSetupCommand( *sub, default_live555_callback, False,
                                               toBool( b_rtsp_tcp ),
                                               toBool( p_sys->b_force_mcast && !b_rtsp_tcp ) );
                if( !wait_Live555_response( p_demux ) )
824
                {
825 826
                    /* if we get an unsupported transport error, toggle TCP
                     * use and try again */
827 828
                    if( p_sys->i_live555_ret == 461 )
                        p_sys->rtsp->sendSetupCommand( *sub, default_live555_callback, False,
829
                                                       !toBool( b_rtsp_tcp ), False );
830
                    if( p_sys->i_live555_ret != 461 || !wait_Live555_response( p_demux ) )
831
                    {
832 833 834
                        msg_Err( p_demux, "SETUP of'%s/%s' failed %s",
                                 sub->mediumName(), sub->codecName(),
                                 p_sys->env->getResultMsg() );
835 836
                        continue;
                    }
837 838 839 840 841
                    else
                    {
                        var_SetBool( p_demux, "rtsp-tcp", true );
                        b_rtsp_tcp = true;
                    }
842
                }
843
            }
844

845 846
            /* Check if we will receive data from this subsession for
             * this track */
847
            if( sub->readSource() == NULL ) continue;
848 849
            if( !p_sys->b_multicast )
            {
850
                /* We need different rollover behaviour for multicast */
851 852
                p_sys->b_multicast = IsMulticastAddress( sub->connectionEndpointAddress() );
            }
853 854

            tk = (live_track_t*)malloc( sizeof( live_track_t ) );
855 856 857 858 859
            if( !tk )
            {
                delete iter;
                return VLC_ENOMEM;
            }
860 861 862
            tk->p_demux     = p_demux;
            tk->sub         = sub;
            tk->p_es        = NULL;
863
            tk->format      = live_track_t::SINGLE_STREAM;
864
            tk->p_asf_block = NULL;
865
            tk->b_discard_trunc = false;
866 867
            tk->p_out_muxed = NULL;
            tk->waiting     = 0;
868
            tk->b_rtcp_sync = false;
869
            tk->b_flushing_discontinuity = false;
870
            tk->i_next_block_flags = 0;
871 872
            tk->i_lastpts   = VLC_TS_INVALID;
            tk->i_pcr       = VLC_TS_INVALID;
873
            tk->f_npt       = 0.;
874
            tk->state       = live_track_t::STATE_SELECTED;
875 876 877
            tk->i_buffer    = i_frame_buffer;
            tk->p_buffer    = (uint8_t *)malloc( i_frame_buffer );

878 879
            if( !tk->p_buffer )
            {
Christophe Mutricy's avatar
Christophe Mutricy committed
880
                free( tk );
881 882 883
                delete iter;
                return VLC_ENOMEM;
            }
884 885 886 887

            /* Value taken from mplayer */
            if( !strcmp( sub->mediumName(), "audio" ) )
            {
888
                es_format_Init( &tk->fmt, AUDIO_ES, VLC_CODEC_UNKNOWN );
889 890 891 892 893 894 895
                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" ) )
                {
896
                    tk->fmt.i_codec = VLC_CODEC_MPGA;
897 898 899 900
                    tk->fmt.audio.i_rate = 0;
                }
                else if( !strcmp( sub->codecName(), "AC3" ) )
                {
901
                    tk->fmt.i_codec = VLC_CODEC_A52;
902 903 904 905
                    tk->fmt.audio.i_rate = 0;
                }
                else if( !strcmp( sub->codecName(), "L16" ) )
                {
906
                    tk->fmt.i_codec = VLC_CODEC_S16B;
907 908
                    tk->fmt.audio.i_bitspersample = 16;
                }
909 910 911 912 913
                else if( !strcmp( sub->codecName(), "L20" ) )
                {
                    tk->fmt.i_codec = VLC_CODEC_S20B;
                    tk->fmt.audio.i_bitspersample = 20;
                }
Sébastien Escudier's avatar
Sébastien Escudier committed
914
                else if( !strcmp( sub->codecName(), "L24" ) )
915 916 917 918
                {
                    tk->fmt.i_codec = VLC_CODEC_S24B;
                    tk->fmt.audio.i_bitspersample = 24;
                }
919 920
                else if( !strcmp( sub->codecName(), "L8" ) )
                {
921
                    tk->fmt.i_codec = VLC_CODEC_U8;
922 923
                    tk->fmt.audio.i_bitspersample = 8;
                }
924 925 926 927 928
                else if( !strcmp( sub->codecName(), "DAT12" ) )
                {
                    tk->fmt.i_codec = VLC_CODEC_DAT12;
                    tk->fmt.audio.i_bitspersample = 12;
                }
929 930
                else if( !strcmp( sub->codecName(), "PCMU" ) )
                {
931
                    tk->fmt.i_codec = VLC_CODEC_MULAW;
932
                    tk->fmt.audio.i_bitspersample = 8;
933 934 935
                }
                else if( !strcmp( sub->codecName(), "PCMA" ) )
                {
936
                    tk->fmt.i_codec = VLC_CODEC_ALAW;
937
                    tk->fmt.audio.i_bitspersample = 8;
938 939 940
                }
                else if( !strncmp( sub->codecName(), "G726", 4 ) )
                {
941
                    tk->fmt.i_codec = VLC_CODEC_ADPCM_G726;
942 943 944 945 946 947 948 949 950 951 952 953 954
                    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" ) )
                {
955
                    tk->fmt.i_codec = VLC_CODEC_AMR_NB;
956 957 958
                }
                else if( !strcmp( sub->codecName(), "AMR-WB" ) )
                {
959
                    tk->fmt.i_codec = VLC_CODEC_AMR_WB;
960 961 962 963 964 965
                }
                else if( !strcmp( sub->codecName(), "MP4A-LATM" ) )
                {
                    unsigned int i_extra;
                    uint8_t      *p_extra;

966
                    tk->fmt.i_codec = VLC_CODEC_MP4A;
967 968 969 970 971

                    if( ( p_extra = parseStreamMuxConfigStr( sub->fmtp_config(),
                                                             i_extra ) ) )
                    {
                        tk->fmt.i_extra = i_extra;
972
                        tk->fmt.p_extra = xmalloc( i_extra );
973 974 975
                        memcpy( tk->fmt.p_extra, p_extra, i_extra );
                        delete[] p_extra;
                    }
976 977
                    /* Because the "faad" decoder does not handle the LATM
                     * data length field at the start of each returned LATM
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
978
                     * frame, tell the RTP source to omit. */
979 980 981 982 983 984 985
                    ((MPEG4LATMAudioRTPSource*)sub->rtpSource())->omitLATMDataLengthField();
                }
                else if( !strcmp( sub->codecName(), "MPEG4-GENERIC" ) )
                {
                    unsigned int i_extra;
                    uint8_t      *p_extra;

986
                    tk->fmt.i_codec = VLC_CODEC_MP4A;
987 988 989 990 991

                    if( ( p_extra = parseGeneralConfigStr( sub->fmtp_config(),
                                                           i_extra ) ) )
                    {
                        tk->fmt.i_extra = i_extra;
992
                        tk->fmt.p_extra = xmalloc( i_extra );
993 994 995 996 997 998
                        memcpy( tk->fmt.p_extra, p_extra, i_extra );
                        delete[] p_extra;
                    }
                }
                else if( !strcmp( sub->codecName(), "X-ASF-PF" ) )
                {
999
                    tk->format = live_track_t::ASF_STREAM;
1000
                    if( p_sys->p_out_asf == NULL )
1001 1002 1003
                        p_sys->p_out_asf =
                            vlc_demux_chained_New( VLC_OBJECT(p_demux), "asf",
                                                   p_demux->out );
1004 1005 1006 1007
                }
                else if( !strcmp( sub->codecName(), "X-QT" ) ||
                         !strcmp( sub->codecName(), "X-QUICKTIME" ) )
                {
1008
                    tk->format = live_track_t::QUICKTIME_STREAM;
1009
                }
1010 1011
                else if( !strcmp( sub->codecName(), "SPEEX" ) )
                {
1012
                    tk->fmt.i_codec = VLC_FOURCC( 's', 'p', 'x', 'r' );
1013
                }
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
                else if( !strcmp( sub->codecName(), "VORBIS" ) )
                {
                    tk->fmt.i_codec = VLC_CODEC_VORBIS;
                    unsigned int i_extra;
                    unsigned char *p_extra;
                    if( ( p_extra=parseVorbisConfigStr( sub->fmtp_config(),
                                                        i_extra ) ) )
                    {
                        tk->fmt.i_extra = i_extra;
                        tk->fmt.p_extra = p_extra;
                    }
                    else
                        msg_Warn( p_demux,"Missing or unsupported vorbis header." );
                }
1028 1029 1030 1031
                else if( !strcmp( sub->codecName(), "OPUS" ) )
                {
                    tk->fmt.i_codec = VLC_CODEC_OPUS;
                }
1032 1033 1034
            }
            else if( !strcmp( sub->mediumName(), "video" ) )
            {
1035
                es_format_Init( &tk->fmt, VIDEO_ES, VLC_CODEC_UNKNOWN );
1036 1037
                if( !strcmp( sub->codecName(), "MPV" ) )
                {
1038
                    tk->fmt.i_codec = VLC_CODEC_MPGV;
1039
                    tk->fmt.b_packetized = false;
1040 1041 1042 1043 1044
                }
                else if( !strcmp( sub->codecName(), "H263" ) ||
                         !strcmp( sub->codecName(), "H263-1998" ) ||
                         !strcmp( sub->codecName(), "H263-2000" ) )
                {
1045
                    tk->fmt.i_codec = VLC_CODEC_H263;
1046 1047 1048
                }
                else if( !strcmp( sub->codecName(), "H261" ) )
                {
1049
                    tk->fmt.i_codec = VLC_CODEC_H261;
1050 1051 1052 1053 1054 1055
                }
                else if( !strcmp( sub->codecName(), "H264" ) )
                {
                    unsigned int i_extra = 0;
                    uint8_t      *p_extra = NULL;

1056
                    tk->fmt.i_codec = VLC_CODEC_H264;
1057
                    tk->fmt.b_packetized = false;
1058 1059 1060 1061 1062

                    if((p_extra=parseH264ConfigStr( sub->fmtp_spropparametersets(),
                                                    i_extra ) ) )
                    {
                        tk->fmt.i_extra = i_extra;
1063
                        tk->fmt.p_extra = xmalloc( i_extra );
1064 1065 1066 1067 1068
                        memcpy( tk->fmt.p_extra, p_extra, i_extra );

                        delete[] p_extra;
                    }
                }
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
#if LIVEMEDIA_LIBRARY_VERSION_INT >= 1393372800 // 2014.02.26
                else if( !strcmp( sub->codecName(), "H265" ) )
                {
                   unsigned int i_extra1 = 0, i_extra2 = 0, i_extra3 = 0, i_extraTot;
                    uint8_t      *p_extra1 = NULL, *p_extra2 = NULL, *p_extra3 = NULL;

                    tk->fmt.i_codec = VLC_CODEC_HEVC;
                    tk->fmt.b_packetized = false;

                    p_extra1 = parseH264ConfigStr( sub->fmtp_spropvps(), i_extra1 );
                    p_extra2 = parseH264ConfigStr( sub->fmtp_spropsps(), i_extra2 );
                    p_extra3 = parseH264ConfigStr( sub->fmtp_sproppps(), i_extra3 );
                   i_extraTot = i_extra1 + i_extra2 + i_extra3;
                   if( i_extraTot > 0 )
                    {
                        tk->fmt.i_extra = i_extraTot;
                        tk->fmt.p_extra = xmalloc( i_extraTot );
                       if( p_extra1 )
                       {
                            memcpy( tk->fmt.p_extra, p_extra1, i_extra1 );
                       }
                       if( p_extra2 )
                       {
                         memcpy( ((char*)tk->fmt.p_extra)+i_extra1, p_extra2, i_extra2 );
                       }
                       if( p_extra3 )
                       {
                         memcpy( ((char*)tk->fmt.p_extra)+i_extra1+i_extra2, p_extra3, i_extra3 );
                       }
1098 1099

                        delete[] p_extra1; delete[] p_extra2; delete[] p_extra3;
1100 1101 1102
                    }
                }
#endif
1103 1104
                else if( !strcmp( sub->codecName(), "JPEG" ) )
                {
1105
                    tk->fmt.i_codec = VLC_CODEC_MJPG;
1106 1107 1108 1109 1110 1111
                }
                else if( !strcmp( sub->codecName(), "MP4V-ES" ) )
                {
                    unsigned int i_extra;
                    uint8_t      *p_extra;

1112
                    tk->fmt.i_codec = VLC_CODEC_MP4V;
1113 1114 1115 1116 1117

                    if( ( p_extra = parseGeneralConfigStr( sub->fmtp_config(),
                                                           i_extra ) ) )
                    {
                        tk->fmt.i_extra = i_extra;
1118
                        tk->fmt.p_extra = xmalloc( i_extra );
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128
                        memcpy( tk->fmt.p_extra, p_extra, i_extra );
                        delete[] p_extra;
                    }
                }
                else if( !strcmp( sub->codecName(), "X-QT" ) ||
                         !strcmp( sub->codecName(), "X-QUICKTIME" ) ||
                         !strcmp( sub->codecName(), "X-QDM" ) ||
                         !strcmp( sub->codecName(), "X-SV3V-ES" )  ||
                         !strcmp( sub->codecName(), "X-SORENSONVIDEO" ) )
                {
1129
                    tk->format = live_track_t::QUICKTIME_STREAM;
1130 1131 1132
                }
                else if( !strcmp( sub->codecName(), "MP2T" ) )
                {
1133
                    tk->format = live_track_t::MULTIPLEXED_STREAM;
1134 1135 1136
                    tk->p_out_muxed =
                        vlc_demux_chained_New( VLC_OBJECT(p_demux), "ts",
                                               p_demux->out );
1137 1138 1139 1140
                }
                else if( !strcmp( sub->codecName(), "MP2P" ) ||
                         !strcmp( sub->codecName(), "MP1S" ) )
                {
1141
                    tk->format = live_track_t::MULTIPLEXED_STREAM;
1142 1143 1144
                    tk->p_out_muxed =
                        vlc_demux_chained_New( VLC_OBJECT(p_demux), "ps",
                                               p_demux->out );
1145 1146 1147
                }
                else if( !strcmp( sub->codecName(), "X-ASF-PF" ) )
                {
1148
                    tk->format = live_track_t::ASF_STREAM;
1149
                    if( p_sys->p_out_asf == NULL )
1150 1151 1152
                        p_sys->p_out_asf =
                            vlc_demux_chained_New( VLC_OBJECT(p_demux),
                                                   "asf", p_demux->out );
1153
                }
1154 1155
                else if( !strcmp( sub->codecName(), "DV" ) )
                {
1156
                    tk->format = live_track_t::MULTIPLEXED_STREAM;
1157
                    tk->b_discard_trunc = true;
1158 1159 1160
                    tk->p_out_mux