stream_output.c 27.4 KB
Newer Older
1 2 3
/*****************************************************************************
 * stream_output.c : stream output module
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2002-2007 VLC authors and VideoLAN
5
 * $Id$
6 7
 *
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8
 *          Laurent Aimar <fenrir@via.ecp.fr>
9
 *          Eric Petit <titer@videolan.org>
10
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
11 12 13
 * 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
14 15 16 17
 * (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
LGPL  
Jean-Baptiste Kempf committed
18 19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
20
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
21 22 23
 * 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.
24 25 26 27 28
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
29

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

34 35
#include <assert.h>

36
#include <vlc_common.h>
37

38 39
#include <stdlib.h>                                                /* free() */
#include <stdio.h>                                              /* sprintf() */
40
#include <string.h>
41

Clément Stenac's avatar
Clément Stenac committed
42
#include <vlc_sout.h>
43

Clément Stenac's avatar
Clément Stenac committed
44 45 46
#include "stream_output.h"

#include <vlc_meta.h>
47
#include <vlc_block.h>
48
#include <vlc_codec.h>
49
#include <vlc_modules.h>
Clément Stenac's avatar
Clément Stenac committed
50

51
#include "input/input_interface.h"
52

Laurent Aimar's avatar
Laurent Aimar committed
53 54
#define VLC_CODEC_NULL VLC_FOURCC( 'n', 'u', 'l', 'l' )

55
#undef DEBUG_BUFFER
56 57 58
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
59
static char *sout_stream_url_to_chain( bool, const char * );
60

61 62 63 64 65 66 67
/*
 * Generic MRL parser
 *
 */

typedef struct
{
68 69
    char *psz_access;
    char *psz_way;
70 71 72 73
    char *psz_name;
} mrl_t;

/* mrl_Parse: parse psz_mrl and fill p_mrl */
74
static int  mrl_Parse( mrl_t *p_mrl, const char *psz_mrl );
75 76 77
/* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
static void mrl_Clean( mrl_t *p_mrl );

78 79
#undef sout_NewInstance

80 81 82
/*****************************************************************************
 * sout_NewInstance: creates a new stream output instance
 *****************************************************************************/
83
sout_instance_t *sout_NewInstance( vlc_object_t *p_parent, const char *psz_dest )
84
{
85
    sout_instance_t *p_sout;
86
    char *psz_chain;
87 88 89 90

    assert( psz_dest != NULL );

    if( psz_dest[0] == '#' )
91 92 93 94 95 96
    {
        psz_chain = strdup( &psz_dest[1] );
    }
    else
    {
        psz_chain = sout_stream_url_to_chain(
97
            var_InheritBool(p_parent, "sout-display"), psz_dest );
98 99 100 101
    }
    if(!psz_chain)
        return NULL;

102
    /* *** Allocate descriptor *** */
103
    p_sout = vlc_custom_create( p_parent, sizeof( *p_sout ), "stream output" );
104
    if( p_sout == NULL )
Rémi Duraffort's avatar
Rémi Duraffort committed
105 106
    {
        free( psz_chain );
107
        return NULL;
Rémi Duraffort's avatar
Rémi Duraffort committed
108
    }
109

110 111
    msg_Dbg( p_sout, "using sout chain=`%s'", psz_chain );

112 113
    /* *** init descriptor *** */
    p_sout->psz_sout    = strdup( psz_dest );
114
    p_sout->i_out_pace_nocontrol = 0;
115

116
    vlc_mutex_init( &p_sout->lock );
117 118
    p_sout->p_stream = NULL;

119
    var_Create( p_sout, "sout-mux-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
120

121 122
    p_sout->p_stream = sout_StreamChainNew( p_sout, psz_chain, NULL, NULL );
    if( p_sout->p_stream )
123
    {
124 125 126
        free( psz_chain );
        return p_sout;
    }
127

128
    msg_Err( p_sout, "stream chain failed for `%s'", psz_chain );
129
    free( psz_chain );
130

131
    FREENULL( p_sout->psz_sout );
132

133
    vlc_mutex_destroy( &p_sout->lock );
134 135
    vlc_object_release( p_sout );
    return NULL;
136
}
Jean-Paul Saman's avatar
Jean-Paul Saman committed
137

138 139 140 141 142
/*****************************************************************************
 * sout_DeleteInstance: delete a previously allocated instance
 *****************************************************************************/
void sout_DeleteInstance( sout_instance_t * p_sout )
{
143
    /* remove the stream out chain */
144
    sout_StreamChainDelete( p_sout->p_stream, NULL );
145

146
    /* *** free all string *** */
147
    FREENULL( p_sout->psz_sout );
148 149 150

    vlc_mutex_destroy( &p_sout->lock );

151
    /* *** free structure *** */
152
    vlc_object_release( p_sout );
153 154
}

155
/*****************************************************************************
156
 * Packetizer/Input
157
 *****************************************************************************/
158 159
sout_packetizer_input_t *sout_InputNew( sout_instance_t *p_sout,
                                        es_format_t *p_fmt )
160
{
161
    sout_packetizer_input_t *p_input;
162

163 164
    /* *** create a packetizer input *** */
    p_input         = malloc( sizeof( sout_packetizer_input_t ) );
Rafaël Carré's avatar
Rafaël Carré committed
165
    if( !p_input )  return NULL;
166 167
    p_input->p_sout = p_sout;
    p_input->p_fmt  = p_fmt;
168

169 170
    msg_Dbg( p_sout, "adding a new sout input (sout_input: %p)",
             (void *)p_input );
171

Laurent Aimar's avatar
Laurent Aimar committed
172
    if( p_fmt->i_codec == VLC_CODEC_NULL )
173 174 175
    {
        vlc_object_release( p_sout );
        return p_input;
176 177
    }

178
    /* *** add it to the stream chain */
179
    vlc_mutex_lock( &p_sout->lock );
180
    p_input->id = p_sout->p_stream->pf_add( p_sout->p_stream, p_fmt );
181
    vlc_mutex_unlock( &p_sout->lock );
182

183
    if( p_input->id == NULL )
184
    {
185
        free( p_input );
186
        return NULL;
187
    }
188

189
    return( p_input );
190
}
191

192 193 194
/*****************************************************************************
 *
 *****************************************************************************/
195
int sout_InputDelete( sout_packetizer_input_t *p_input )
196
{
197 198
    sout_instance_t     *p_sout = p_input->p_sout;

199 200
    msg_Dbg( p_sout, "removing a sout input (sout_input: %p)",
             (void *)p_input );
201

Laurent Aimar's avatar
Laurent Aimar committed
202
    if( p_input->p_fmt->i_codec != VLC_CODEC_NULL )
203
    {
204 205 206
        vlc_mutex_lock( &p_sout->lock );
        p_sout->p_stream->pf_del( p_sout->p_stream, p_input->id );
        vlc_mutex_unlock( &p_sout->lock );
207
    }
208

209
    free( p_input );
210

211 212
    return( VLC_SUCCESS);
}
213

214 215 216 217 218 219 220 221 222 223 224 225
bool sout_InputIsEmpty( sout_packetizer_input_t *p_input )
{
    sout_instance_t *p_sout = p_input->p_sout;
    bool b;

    vlc_mutex_lock( &p_sout->lock );
    if( sout_StreamControl( p_sout->p_stream, SOUT_STREAM_EMPTY, &b ) != VLC_SUCCESS )
        b = true;
    vlc_mutex_unlock( &p_sout->lock );
    return b;
}

226 227 228 229 230 231 232 233 234
void sout_InputFlush( sout_packetizer_input_t *p_input )
{
    sout_instance_t     *p_sout = p_input->p_sout;

    vlc_mutex_lock( &p_sout->lock );
    sout_StreamFlush( p_sout->p_stream, p_input->id );
    vlc_mutex_unlock( &p_sout->lock );
}

235 236 237
/*****************************************************************************
 *
 *****************************************************************************/
238
int sout_InputSendBuffer( sout_packetizer_input_t *p_input,
239
                          block_t *p_buffer )
240 241
{
    sout_instance_t     *p_sout = p_input->p_sout;
242
    int                 i_ret;
243

Laurent Aimar's avatar
Laurent Aimar committed
244
    if( p_input->p_fmt->i_codec == VLC_CODEC_NULL )
245
    {
246
        block_Release( p_buffer );
247 248 249
        return VLC_SUCCESS;
    }

250
    vlc_mutex_lock( &p_sout->lock );
251 252
    i_ret = p_sout->p_stream->pf_send( p_sout->p_stream,
                                       p_input->id, p_buffer );
253
    vlc_mutex_unlock( &p_sout->lock );
254

255
    return i_ret;
256
}
257

258
#undef sout_AccessOutNew
259 260 261
/*****************************************************************************
 * sout_AccessOutNew: allocate a new access out
 *****************************************************************************/
262
sout_access_out_t *sout_AccessOutNew( vlc_object_t *p_sout,
263
                                      const char *psz_access, const char *psz_name )
264 265
{
    sout_access_out_t *p_access;
266
    char              *psz_next;
267

268
    p_access = vlc_custom_create( p_sout, sizeof( *p_access ), "access out" );
269
    if( !p_access )
270
        return NULL;
271

272 273
    psz_next = config_ChainCreate( &p_access->psz_access, &p_access->p_cfg,
                                   psz_access );
274
    free( psz_next );
275
    p_access->psz_path   = strdup( psz_name ? psz_name : "" );
276
    p_access->p_sys      = NULL;
277
    p_access->pf_seek    = NULL;
278
    p_access->pf_read    = NULL;
279
    p_access->pf_write   = NULL;
280
    p_access->pf_control = NULL;
281
    p_access->p_module   = NULL;
282

283
    p_access->p_module   =
284
        module_need( p_access, "sout access", p_access->psz_access, true );
285 286 287

    if( !p_access->p_module )
    {
288
        free( p_access->psz_access );
289
        free( p_access->psz_path );
290
        vlc_object_release( p_access );
291
        return( NULL );
292 293 294 295 296 297 298
    }

    return p_access;
}
/*****************************************************************************
 * sout_AccessDelete: delete an access out
 *****************************************************************************/
299
void sout_AccessOutDelete( sout_access_out_t *p_access )
300 301 302
{
    if( p_access->p_module )
    {
303
        module_unneed( p_access, p_access->p_module );
304 305
    }
    free( p_access->psz_access );
306

307
    config_ChainDestroy( p_access->p_cfg );
308

309
    free( p_access->psz_path );
310

311
    vlc_object_release( p_access );
312 313 314 315 316
}

/*****************************************************************************
 * sout_AccessSeek:
 *****************************************************************************/
317
int sout_AccessOutSeek( sout_access_out_t *p_access, off_t i_pos )
318
{
319
    return p_access->pf_seek( p_access, i_pos );
320 321 322
}

/*****************************************************************************
323
 * sout_AccessRead:
324
 *****************************************************************************/
325
ssize_t sout_AccessOutRead( sout_access_out_t *p_access, block_t *p_buffer )
326
{
327 328
    return( p_access->pf_read ?
            p_access->pf_read( p_access, p_buffer ) : VLC_EGENERIC );
329 330
}

331 332 333
/*****************************************************************************
 * sout_AccessWrite:
 *****************************************************************************/
334
ssize_t sout_AccessOutWrite( sout_access_out_t *p_access, block_t *p_buffer )
335 336 337
{
    return p_access->pf_write( p_access, p_buffer );
}
338

339 340 341
/**
 * sout_AccessOutControl
 */
342
int sout_AccessOutControl (sout_access_out_t *access, int query, ...)
343
{
344 345 346 347 348 349 350 351 352 353
    va_list ap;
    int ret;

    va_start (ap, query);
    if (access->pf_control)
        ret = access->pf_control (access, query, ap);
    else
        ret = VLC_EGENERIC;
    va_end (ap);
    return ret;
354 355
}

356
/*****************************************************************************
357
 * sout_MuxNew: create a new mux
358
 *****************************************************************************/
Rémi Duraffort's avatar
Rémi Duraffort committed
359
sout_mux_t * sout_MuxNew( sout_instance_t *p_sout, const char *psz_mux,
360
                          sout_access_out_t *p_access )
361 362
{
    sout_mux_t *p_mux;
363
    char       *psz_next;
364

365
    p_mux = vlc_custom_create( p_sout, sizeof( *p_mux ), "mux" );
366 367 368
    if( p_mux == NULL )
        return NULL;

369
    p_mux->p_sout = p_sout;
370
    psz_next = config_ChainCreate( &p_mux->psz_mux, &p_mux->p_cfg, psz_mux );
371
    free( psz_next );
372

373
    p_mux->p_access     = p_access;
374
    p_mux->pf_control   = NULL;
375 376 377 378 379 380 381
    p_mux->pf_addstream = NULL;
    p_mux->pf_delstream = NULL;
    p_mux->pf_mux       = NULL;
    p_mux->i_nb_inputs  = 0;
    p_mux->pp_inputs    = NULL;

    p_mux->p_sys        = NULL;
382 383
    p_mux->p_module     = NULL;

384 385
    p_mux->b_add_stream_any_time = false;
    p_mux->b_waiting_stream = true;
386
    p_mux->i_add_stream_start = -1;
387

388
    p_mux->p_module =
389
        module_need( p_mux, "sout mux", p_mux->psz_mux, true );
390

391 392
    if( p_mux->p_module == NULL )
    {
393
        FREENULL( p_mux->psz_mux );
394

395
        vlc_object_release( p_mux );
396 397 398 399
        return NULL;
    }

    /* *** probe mux capacity *** */
400
    if( p_mux->pf_control )
401
    {
402
        int b_answer = false;
403 404 405

        if( sout_MuxControl( p_mux, MUX_CAN_ADD_STREAM_WHILE_MUXING,
                             &b_answer ) )
406
        {
407
            b_answer = false;
408
        }
409

410 411 412
        if( b_answer )
        {
            msg_Dbg( p_sout, "muxer support adding stream at any time" );
413 414
            p_mux->b_add_stream_any_time = true;
            p_mux->b_waiting_stream = false;
415

416 417 418 419
            /* If we control the output pace then it's better to wait before
             * starting muxing (generates better streams/files). */
            if( !p_sout->i_out_pace_nocontrol )
            {
420
                b_answer = true;
421 422 423
            }
            else if( sout_MuxControl( p_mux, MUX_GET_ADD_STREAM_WAIT,
                                      &b_answer ) )
424
            {
425
                b_answer = false;
426
            }
427

428 429
            if( b_answer )
            {
430 431
                msg_Dbg( p_sout, "muxer prefers to wait for all ES before "
                         "starting to mux" );
432
                p_mux->b_waiting_stream = true;
433
            }
434 435 436 437 438 439
        }
    }

    return p_mux;
}

440 441 442
/*****************************************************************************
 * sout_MuxDelete:
 *****************************************************************************/
443
void sout_MuxDelete( sout_mux_t *p_mux )
444 445 446
{
    if( p_mux->p_module )
    {
447
        module_unneed( p_mux, p_mux->p_module );
448 449 450
    }
    free( p_mux->psz_mux );

451
    config_ChainDestroy( p_mux->p_cfg );
452

453
    vlc_object_release( p_mux );
454 455
}

456 457 458
/*****************************************************************************
 * sout_MuxAddStream:
 *****************************************************************************/
459
sout_input_t *sout_MuxAddStream( sout_mux_t *p_mux, const es_format_t *p_fmt )
460 461 462
{
    sout_input_t *p_input;

463
    if( !p_mux->b_add_stream_any_time && !p_mux->b_waiting_stream )
464
    {
465
        msg_Err( p_mux, "cannot add a new stream (unsupported while muxing "
466
                        "to this format). You can try increasing sout-mux-caching value" );
467 468 469 470
        return NULL;
    }

    msg_Dbg( p_mux, "adding a new input" );
471

472
    /* create a new sout input */
473
    p_input = malloc( sizeof( sout_input_t ) );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
474 475
    if( !p_input )
        return NULL;
476 477 478 479 480

    // FIXME: remove either fmt or p_fmt...
    es_format_Copy( &p_input->fmt, p_fmt );
    p_input->p_fmt = &p_input->fmt;

481
    p_input->p_fifo = block_FifoNew();
482
    p_input->p_sys  = NULL;
483 484 485 486

    TAB_APPEND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
    if( p_mux->pf_addstream( p_mux, p_input ) < 0 )
    {
487 488 489 490 491
        msg_Err( p_mux, "cannot add this stream" );
        TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
        block_FifoRelease( p_input->p_fifo );
        free( p_input );
        return NULL;
492 493
    }

494
    return p_input;
495 496
}

497 498 499 500
/*****************************************************************************
 * sout_MuxDeleteStream:
 *****************************************************************************/
void sout_MuxDeleteStream( sout_mux_t *p_mux, sout_input_t *p_input )
501 502 503
{
    int i_index;

504 505
    if( p_mux->b_waiting_stream
     && block_FifoCount( p_input->p_fifo ) > 0 )
506 507 508
    {
        /* We stop waiting, and call the muxer for taking care of the data
         * before we remove this es */
509
        p_mux->b_waiting_stream = false;
510 511 512
        p_mux->pf_mux( p_mux );
    }

513 514 515
    TAB_FIND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input, i_index );
    if( i_index >= 0 )
    {
516
        p_mux->pf_delstream( p_mux, p_input );
517 518 519 520 521 522

        /* remove the entry */
        TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );

        if( p_mux->i_nb_inputs == 0 )
        {
523
            msg_Warn( p_mux, "no more input streams for this mux" );
524 525
        }

526
        block_FifoRelease( p_input->p_fifo );
527
        es_format_Clean( &p_input->fmt );
528
        free( p_input );
529 530 531
    }
}

532 533 534
/*****************************************************************************
 * sout_MuxSendBuffer:
 *****************************************************************************/
535
int sout_MuxSendBuffer( sout_mux_t *p_mux, sout_input_t *p_input,
536
                         block_t *p_buffer )
537
{
538
    mtime_t i_dts = p_buffer->i_dts;
539
    block_FifoPut( p_input->p_fifo, p_buffer );
540

541 542 543
    if( p_mux->p_sout->i_out_pace_nocontrol )
    {
        mtime_t current_date = mdate();
544
        if ( current_date > i_dts )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
545
            msg_Warn( p_mux, "late buffer for mux input (%"PRId64")",
546
                      current_date - i_dts );
547 548
    }

549 550
    if( p_mux->b_waiting_stream )
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
551
        const int64_t i_caching = var_GetInteger( p_mux->p_sout, "sout-mux-caching" ) * INT64_C(1000);
552

553
        if( p_mux->i_add_stream_start < 0 )
554
            p_mux->i_add_stream_start = i_dts;
555

Steve Lhomme's avatar
Steve Lhomme committed
556
        /* Wait until we have enough data before muxing */
557
        if( p_mux->i_add_stream_start < 0 ||
558
            i_dts < p_mux->i_add_stream_start + i_caching )
559
            return VLC_SUCCESS;
560
        p_mux->b_waiting_stream = false;
561
    }
562
    return p_mux->pf_mux( p_mux );
563 564
}

565 566 567 568

/*****************************************************************************
 * sout_MuxGetStream: find stream to be muxed
 *****************************************************************************/
569
int sout_MuxGetStream( sout_mux_t *p_mux, unsigned i_blocks, mtime_t *pi_dts )
570 571 572 573
{
    mtime_t i_dts = 0;
    int     i_stream = -1;

574 575
    assert( i_blocks > 0 );

576 577 578 579 580
    for( int i = 0; i < p_mux->i_nb_inputs; i++ )
    {
        sout_input_t *p_input = p_mux->pp_inputs[i];
        block_t *p_data;

581
        if( block_FifoCount( p_input->p_fifo ) < i_blocks )
582
        {
583 584
            if( (!p_mux->b_add_stream_any_time) &&
                (p_input->p_fmt->i_cat != SPU_ES ) )
585 586 587 588
            {
                return -1;
            }
            /* FIXME: SPU muxing */
589
            continue;
590
        }
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605

        p_data = block_FifoShow( p_input->p_fifo );
        if( i_stream < 0 || p_data->i_dts < i_dts )
        {
            i_stream = i;
            i_dts    = p_data->i_dts;
        }
    }

    if( pi_dts ) *pi_dts = i_dts;

    return i_stream;
}


606 607 608
/*****************************************************************************
 *
 *****************************************************************************/
609
static int mrl_Parse( mrl_t *p_mrl, const char *psz_mrl )
610
{
Laurent Aimar's avatar
Laurent Aimar committed
611
    char * psz_dup = strdup( psz_mrl );
612
    char * psz_parser = psz_dup;
613 614
    const char * psz_access;
    const char * psz_way;
615
    char * psz_name;
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635

    /* *** first parse psz_dest */
    while( *psz_parser && *psz_parser != ':' )
    {
        if( *psz_parser == '{' )
        {
            while( *psz_parser && *psz_parser != '}' )
            {
                psz_parser++;
            }
            if( *psz_parser )
            {
                psz_parser++;
            }
        }
        else
        {
            psz_parser++;
        }
    }
636
#if defined( _WIN32 ) || defined( __OS2__ )
637 638
    if( psz_parser - psz_dup == 1 )
    {
639 640
        /* msg_Warn( p_sout, "drive letter %c: found in source string",
                          *psz_dup ) ; */
641
        *psz_parser = '\0';
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
    }
#endif

    if( !*psz_parser )
    {
        psz_access = psz_way = "";
        psz_name = psz_dup;
    }
    else
    {
        *psz_parser++ = '\0';

        /* let's skip '//' */
        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
        {
            psz_parser += 2 ;
        }

        psz_name = psz_parser ;

        /* Come back to parse the access and mux plug-ins */
        psz_parser = psz_dup;

        if( !*psz_parser )
        {
            /* No access */
            psz_access = "";
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
            psz_access = "";
            psz_parser++;
        }
        else
        {
            psz_access = psz_parser;

            while( *psz_parser && *psz_parser != '/' )
            {
                if( *psz_parser == '{' )
                {
                    while( *psz_parser && *psz_parser != '}' )
                    {
                        psz_parser++;
                    }
                    if( *psz_parser )
                    {
                        psz_parser++;
                    }
                }
                else
                {
                    psz_parser++;
                }
            }

            if( *psz_parser == '/' )
            {
                *psz_parser++ = '\0';
            }
        }

        if( !*psz_parser )
        {
            /* No mux */
            psz_way = "";
        }
        else
        {
            psz_way = psz_parser;
        }
    }

    p_mrl->psz_access = strdup( psz_access );
    p_mrl->psz_way    = strdup( psz_way );
    p_mrl->psz_name   = strdup( psz_name );

Laurent Aimar's avatar
Laurent Aimar committed
720
    free( psz_dup );
721 722 723 724 725 726 727
    return( VLC_SUCCESS );
}


/* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
static void mrl_Clean( mrl_t *p_mrl )
{
728 729 730
    FREENULL( p_mrl->psz_access );
    FREENULL( p_mrl->psz_way );
    FREENULL( p_mrl->psz_name );
731 732 733
}


734 735 736 737 738 739 740 741
/****************************************************************************
 ****************************************************************************
 **
 **
 **
 ****************************************************************************
 ****************************************************************************/

742 743 744
/* Destroy a "stream_out" module */
static void sout_StreamDelete( sout_stream_t *p_stream )
{
745 746
    sout_instance_t *p_sout = (sout_instance_t *)(p_stream->p_parent);

747
    msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
748

749 750 751 752
    p_sout->i_out_pace_nocontrol -= p_stream->pace_nocontrol;

    if( p_stream->p_module != NULL )
        module_unneed( p_stream, p_stream->p_module );
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767

    FREENULL( p_stream->psz_name );

    config_ChainDestroy( p_stream->p_cfg );

    msg_Dbg( p_stream, "destroying chain done" );
    vlc_object_release( p_stream );
}

/* Destroy a "stream_out" modules chain
 *
 * p_first is the first module to be destroyed in the chain
 * p_last is the last module to be destroyed
 *  if NULL, all modules are destroyed
 *  if not NULL, modules following it must be destroyed separately
768
 */
769 770
void sout_StreamChainDelete(sout_stream_t *p_first, sout_stream_t *p_last)
{
771 772 773
    while(p_first != NULL)
    {
        sout_stream_t *p_next = p_first->p_next;
774

775 776 777 778 779
        sout_StreamDelete(p_first);
        if(p_first == p_last)
           break;
        p_first = p_next;
    }
780
}
781

782
/* Create a "stream_out" module, which may forward its ES to p_next module */
783 784 785
/*
 * XXX name and p_cfg are used (-> do NOT free them)
 */
786 787
static sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_name,
                               config_chain_t *p_cfg, sout_stream_t *p_next)
788 789 790
{
    sout_stream_t *p_stream;

791
    assert(psz_name);
792

793
    p_stream = vlc_custom_create( p_sout, sizeof( *p_stream ), "stream out" );
794 795 796 797
    if( !p_stream )
        return NULL;

    p_stream->p_sout   = p_sout;
798 799 800
    p_stream->psz_name = psz_name;
    p_stream->p_cfg    = p_cfg;
    p_stream->p_next   = p_next;
801
    p_stream->pf_flush = NULL;
802
    p_stream->pf_control = NULL;
803 804
    p_stream->pace_nocontrol = false;
    p_stream->p_sys = NULL;
805

806 807 808
    msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );

    p_stream->p_module =
809
        module_need( p_stream, "sout stream", p_stream->psz_name, true );
810 811 812

    if( !p_stream->p_module )
    {
813 814 815 816
        /* those must be freed by the caller if creation failed */
        p_stream->psz_name = NULL;
        p_stream->p_cfg = NULL;

817
        sout_StreamDelete( p_stream );
818 819 820
        return NULL;
    }

821
    p_sout->i_out_pace_nocontrol += p_stream->pace_nocontrol;
822 823 824
    return p_stream;
}

825 826 827 828 829 830 831 832 833 834 835
/* Creates a complete "stream_out" modules chain
 *
 *  chain format: module1{option=*:option=*}[:module2{option=*:...}]
 *
 *  The modules are created starting from the last one and linked together
 *  A pointer to the last module created is stored if pp_last isn't NULL, to
 *  make sure sout_StreamChainDelete doesn't delete modules created in another
 *  place.
 *
 *  Returns a pointer to the first module.
 */
836
sout_stream_t *sout_StreamChainNew(sout_instance_t *p_sout, const char *psz_chain,
837
                                sout_stream_t *p_next, sout_stream_t **pp_last)
838
{
839 840 841 842 843
    if(!psz_chain || !*psz_chain)
    {
        if(pp_last) *pp_last = NULL;
        return p_next;
    }
844

845 846 847
    char *psz_parser = strdup(psz_chain);
    if(!psz_parser)
        return NULL;
848

849 850 851
    vlc_array_t cfg, name;
    vlc_array_init(&cfg);
    vlc_array_init(&name);
852

853 854 855 856 857
    /* parse chain */
    while(psz_parser)
    {
        config_chain_t *p_cfg;
        char *psz_name;
858
        char *psz_rest_chain = config_ChainCreate( &psz_name, &p_cfg, psz_parser );
859
        free( psz_parser );
860
        psz_parser = psz_rest_chain;
861

862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
        vlc_array_append(&cfg, p_cfg);
        vlc_array_append(&name, psz_name);
    }

    int i = vlc_array_count(&name);
    vlc_array_t module;
    vlc_array_init(&module);
    while(i--)
    {
        p_next = sout_StreamNew( p_sout, vlc_array_item_at_index(&name, i),
            vlc_array_item_at_index(&cfg, i), p_next);

        if(!p_next)
            goto error;

        if(i == vlc_array_count(&name) - 1 && pp_last)
            *pp_last = p_next;   /* last module created in the chain */

        vlc_array_append(&module, p_next);
    }

    vlc_array_clear(&name);
    vlc_array_clear(&cfg);
    vlc_array_clear(&module);

    return p_next;

error:

    i++;    /* last module couldn't be created */

    /* destroy all modules created, starting with the last one */
    int modules = vlc_array_count(&module);
    while(modules--)
        sout_StreamDelete(vlc_array_item_at_index(&module, modules));
    vlc_array_clear(&module);

    /* then destroy all names and config which weren't destroyed by
     * sout_StreamDelete */
    while(i--)
    {
        free(vlc_array_item_at_index(&name, i));
        config_ChainDestroy(vlc_array_item_at_index(&cfg, i));
    }
    vlc_array_clear(&name);
    vlc_array_clear(&cfg);

    return NULL;
910 911
}

912 913
static char *sout_stream_url_to_chain( bool b_sout_display,
                                       const char *psz_url )
914
{
915
    mrl_t       mrl;
916
    char        *psz_chain;
917 918

    mrl_Parse( &mrl, psz_url );
919

920 921 922 923 924 925
    /* Check if the URLs goes to #rtp - otherwise we'll use #standard */
    static const char rtplist[] = "dccp\0sctp\0tcp\0udplite\0";
    for (const char *a = rtplist; *a; a += strlen (a) + 1)
        if (strcmp (a, mrl.psz_access) == 0)
            goto rtp;

926
    if (strcmp (mrl.psz_access, "rtp") == 0)
927
    {
928
        char *port;
929 930
        /* For historical reasons, rtp:// means RTP over UDP */
        strcpy (mrl.psz_access, "udp");
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947
rtp:
        if (mrl.psz_name[0] == '[')
        {
            port = strstr (mrl.psz_name, "]:");
            if (port != NULL)
                port++;
        }
        else
            port = strchr (mrl.psz_name, ':');
        if (port != NULL)
            *port++ = '\0'; /* erase ':' */

        if (asprintf (&psz_chain,
                      "rtp{mux=\"%s\",proto=\"%s\",dst=\"%s%s%s\"}",
                      mrl.psz_way, mrl.psz_access, mrl.psz_name,
                      port ? "\",port=\"" : "", port ? port : "") == -1)
            psz_chain = NULL;
948 949 950
    }
    else
    {
951 952 953 954 955
        /* Convert the URL to a basic standard sout chain */
        if (asprintf (&psz_chain,
                      "standard{mux=\"%s\",access=\"%s\",dst=\"%s\"}",
                      mrl.psz_way, mrl.psz_access, mrl.psz_name) == -1)
            psz_chain = NULL;
956 957 958
    }

    /* Duplicate and wrap if sout-display is on */
959
    if (psz_chain && b_sout_display)
960 961
    {
        char *tmp;
Rémi Duraffort's avatar
Rémi Duraffort committed
962
        if (asprintf (&tmp, "duplicate{dst=display,dst=%s}", psz_chain) == -1)
963 964 965
            tmp = NULL;
        free (psz_chain);
        psz_chain = tmp;
966
    }
967

968
    mrl_Clean( &mrl );
969
    return psz_chain;
970
}
971 972 973 974

#undef sout_EncoderCreate
encoder_t *sout_EncoderCreate( vlc_object_t *p_this )
{
975
    return vlc_custom_create( p_this, sizeof( encoder_t ), "encoder" );
976
}