~ubuntu-branches/ubuntu/maverick/vlc/maverick

« back to all changes in this revision

Viewing changes to src/stream_output/stream_output.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2008-09-17 21:56:14 UTC
  • mfrom: (1.1.17 upstream)
  • Revision ID: james.westby@ubuntu.com-20080917215614-tj0vx8xzd57e52t8
Tags: 0.9.2-1ubuntu1
* New Upstream Release, exception granted by
    - dktrkranz, norsetto, Hobbsee (via irc). LP: #270404

Changes done in ubuntu:

* add libxul-dev to build-depends
* make sure that vlc is build against libxul in configure. This doesn't
  change anything in the package, but makes it more robust if building
  in an 'unclean' chroot or when modifying the package.
* debian/control: make Vcs-* fields point to the motumedia branch
* add libx264-dev and libass-dev to build-depends
  LP: #210354, #199870
* actually enable libass support by passing --enable-libass to configure
* enable libdca: add libdca-dev to build depends and --enable-libdca
* install the x264 plugin.

Changes already in the pkg-multimedia branch in debian:

* don't install usr/share/vlc/mozilla in debian/mozilla-plugin-vlc.install  
* new upstream .desktop file now registers flash video mimetype LP: #261567
* add Xb-Npp-Applications to mozilla-plugin-vlc
* remove duplicate entries in debian/vlc-nox.install

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*****************************************************************************
2
2
 * stream_output.c : stream output module
3
3
 *****************************************************************************
4
 
 * Copyright (C) 2002-2004 the VideoLAN team
5
 
 * $Id: e0072f910c8d913573adc7836a2b893d66ae9c27 $
 
4
 * Copyright (C) 2002-2007 the VideoLAN team
 
5
 * $Id: 8f205c8d1fc49adba484a94c6a67a6521eca0da8 $
6
6
 *
7
7
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8
8
 *          Laurent Aimar <fenrir@via.ecp.fr>
26
26
/*****************************************************************************
27
27
 * Preamble
28
28
 *****************************************************************************/
 
29
 
 
30
#ifdef HAVE_CONFIG_H
 
31
# include "config.h"
 
32
#endif
 
33
 
 
34
#include <vlc_common.h>
 
35
 
29
36
#include <stdlib.h>                                                /* free() */
30
37
#include <stdio.h>                                              /* sprintf() */
31
 
#include <string.h>                                            /* strerror() */
32
 
 
33
 
#include <vlc/vlc.h>
34
 
#include <vlc/sout.h>
35
 
#include <vlc/input.h>
36
 
 
37
 
#include "vlc_meta.h"
 
38
#include <string.h>
 
39
 
 
40
#include <vlc_sout.h>
 
41
 
 
42
#include "stream_output.h"
 
43
 
 
44
#include <vlc_meta.h>
 
45
 
 
46
#include "input/input_internal.h"
38
47
 
39
48
#undef DEBUG_BUFFER
40
49
/*****************************************************************************
41
50
 * Local prototypes
42
51
 *****************************************************************************/
43
 
static void sout_CfgDestroy( sout_cfg_t * );
44
 
 
45
52
#define sout_stream_url_to_chain( p, s ) \
46
53
    _sout_stream_url_to_chain( VLC_OBJECT(p), s )
47
 
static char *_sout_stream_url_to_chain( vlc_object_t *, char * );
 
54
static char *_sout_stream_url_to_chain( vlc_object_t *, const char * );
48
55
 
49
56
/*
50
57
 * Generic MRL parser
59
66
} mrl_t;
60
67
 
61
68
/* mrl_Parse: parse psz_mrl and fill p_mrl */
62
 
static int  mrl_Parse( mrl_t *p_mrl, char *psz_mrl );
 
69
static int  mrl_Parse( mrl_t *p_mrl, const char *psz_mrl );
63
70
/* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
64
71
static void mrl_Clean( mrl_t *p_mrl );
65
72
 
66
 
#define FREE( p ) if( p ) { free( p ); (p) = NULL; }
67
 
 
68
73
/*****************************************************************************
69
74
 * sout_NewInstance: creates a new stream output instance
70
75
 *****************************************************************************/
71
76
sout_instance_t *__sout_NewInstance( vlc_object_t *p_parent, char * psz_dest )
72
77
{
 
78
    static const char typename[] = "stream output";
73
79
    sout_instance_t *p_sout;
74
 
    vlc_value_t keep;
75
 
    counter_t *p_counter;
76
 
 
77
 
    if( var_Get( p_parent, "sout-keep", &keep ) < 0 )
78
 
    {
79
 
        msg_Warn( p_parent, "cannot get sout-keep value" );
80
 
        keep.b_bool = VLC_FALSE;
81
 
    }
82
 
    if( keep.b_bool )
83
 
    {
84
 
        if( ( p_sout = vlc_object_find( p_parent, VLC_OBJECT_SOUT,
85
 
                                        FIND_ANYWHERE ) ) != NULL )
86
 
        {
87
 
            if( !strcmp( p_sout->psz_sout, psz_dest ) )
88
 
            {
89
 
                msg_Dbg( p_parent, "sout keep: reusing sout" );
90
 
                msg_Dbg( p_parent, "sout keep: you probably want to use "
91
 
                          "gather stream_out" );
92
 
                vlc_object_detach( p_sout );
93
 
                vlc_object_attach( p_sout, p_parent );
94
 
                vlc_object_release( p_sout );
95
 
                return p_sout;
96
 
            }
97
 
            else
98
 
            {
99
 
                msg_Dbg( p_parent, "sout keep: destroying unusable sout" );
100
 
                vlc_object_release( p_sout );
101
 
                sout_DeleteInstance( p_sout );
102
 
            }
103
 
        }
104
 
    }
105
 
    else if( !keep.b_bool )
106
 
    {
107
 
        while( ( p_sout = vlc_object_find( p_parent, VLC_OBJECT_SOUT,
108
 
                                           FIND_PARENT ) ) != NULL )
109
 
        {
110
 
            msg_Dbg( p_parent, "sout keep: destroying old sout" );
111
 
            vlc_object_release( p_sout );
112
 
            sout_DeleteInstance( p_sout );
113
 
        }
114
 
    }
115
80
 
116
81
    /* *** Allocate descriptor *** */
117
 
    p_sout = vlc_object_create( p_parent, VLC_OBJECT_SOUT );
 
82
    p_sout = vlc_custom_create( p_parent, sizeof( *p_sout ),
 
83
                                VLC_OBJECT_GENERIC, typename );
118
84
    if( p_sout == NULL )
119
 
    {
120
 
        msg_Err( p_parent, "out of memory" );
121
85
        return NULL;
122
 
    }
123
86
 
124
87
    /* *** init descriptor *** */
125
88
    p_sout->psz_sout    = strdup( psz_dest );
127
90
    p_sout->i_out_pace_nocontrol = 0;
128
91
    p_sout->p_sys       = NULL;
129
92
 
130
 
    vlc_mutex_init( p_sout, &p_sout->lock );
 
93
    vlc_mutex_init( &p_sout->lock );
131
94
    if( psz_dest && psz_dest[0] == '#' )
132
95
    {
133
96
        p_sout->psz_chain = strdup( &psz_dest[1] );
142
105
    /* attach it for inherit */
143
106
    vlc_object_attach( p_sout, p_parent );
144
107
 
145
 
    /* Create statistics */
146
 
    stats_Create( p_parent, "sout_sent_packets", STATS_SOUT_SENT_PACKETS,
147
 
                  VLC_VAR_INTEGER, STATS_COUNTER );
148
 
    stats_Create( p_parent, "sout_sent_bytes", STATS_SOUT_SENT_BYTES,
149
 
                  VLC_VAR_INTEGER, STATS_COUNTER );
150
 
    stats_Create( p_parent, "sout_send_bitrate", STATS_SOUT_SEND_BITRATE,
151
 
                  VLC_VAR_FLOAT, STATS_DERIVATIVE );
152
 
    p_counter = stats_CounterGet( p_parent, p_parent->i_object_id,
153
 
                                  STATS_SOUT_SEND_BITRATE );
154
 
    if( p_counter) p_counter->update_interval = 1000000;
 
108
    /* */
 
109
    var_Create( p_sout, "sout-mux-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
155
110
 
 
111
    /* */
156
112
    p_sout->p_stream = sout_StreamNew( p_sout, p_sout->psz_chain );
157
 
 
158
113
    if( p_sout->p_stream == NULL )
159
114
    {
160
115
        msg_Err( p_sout, "stream chain failed for `%s'", p_sout->psz_chain );
161
116
 
162
 
        FREE( p_sout->psz_sout );
163
 
        FREE( p_sout->psz_chain );
 
117
        FREENULL( p_sout->psz_sout );
 
118
        FREENULL( p_sout->psz_chain );
164
119
 
165
120
        vlc_object_detach( p_sout );
166
 
        vlc_object_destroy( p_sout );
 
121
        vlc_object_release( p_sout );
167
122
        return NULL;
168
123
    }
169
124
 
175
130
 *****************************************************************************/
176
131
void sout_DeleteInstance( sout_instance_t * p_sout )
177
132
{
178
 
    /* Unlink object */
179
 
    vlc_object_detach( p_sout );
180
 
 
181
133
    /* remove the stream out chain */
182
134
    sout_StreamDelete( p_sout->p_stream );
183
135
 
184
136
    /* *** free all string *** */
185
 
    FREE( p_sout->psz_sout );
186
 
    FREE( p_sout->psz_chain );
 
137
    FREENULL( p_sout->psz_sout );
 
138
    FREENULL( p_sout->psz_chain );
187
139
 
188
140
    /* delete meta */
189
141
    if( p_sout->p_meta )
194
146
    vlc_mutex_destroy( &p_sout->lock );
195
147
 
196
148
    /* *** free structure *** */
197
 
    vlc_object_destroy( p_sout );
198
 
}
199
 
 
 
149
    vlc_object_release( p_sout );
 
150
}
 
151
 
 
152
/*****************************************************************************
 
153
 * 
 
154
 *****************************************************************************/
 
155
void sout_UpdateStatistic( sout_instance_t *p_sout, sout_statistic_t i_type, int i_delta )
 
156
{
 
157
    input_thread_t *p_input;
 
158
    int i_bytes; /* That's pretty stupid to define it as an integer, it will overflow
 
159
                    really fast ... */
 
160
 
 
161
    if( !libvlc_stats (p_sout) )
 
162
        return;
 
163
 
 
164
    /* FIXME that's ugly
 
165
     * TODO add a private (ie not VLC_EXPORTed) input_UpdateStatistic for that */
 
166
    p_input = vlc_object_find( p_sout, VLC_OBJECT_INPUT, FIND_PARENT );
 
167
    if( !p_input || p_input->i_state == INIT_S || p_input->i_state == ERROR_S )
 
168
        return;
 
169
 
 
170
    switch( i_type )
 
171
    {
 
172
#define I(c) stats_UpdateInteger( p_input, p_input->p->counters.c, i_delta, NULL )
 
173
    case SOUT_STATISTIC_DECODED_VIDEO:
 
174
        I(p_decoded_video);
 
175
        break;
 
176
    case SOUT_STATISTIC_DECODED_AUDIO:
 
177
        I(p_decoded_audio);
 
178
        break;
 
179
    case SOUT_STATISTIC_DECODED_SUBTITLE:
 
180
        I(p_decoded_sub);
 
181
        break;
 
182
#if 0
 
183
    case SOUT_STATISTIC_ENCODED_VIDEO:
 
184
    case SOUT_STATISTIC_ENCODED_AUDIO:
 
185
    case SOUT_STATISTIC_ENCODED_SUBTITLE:
 
186
        msg_Warn( p_sout, "Not yet supported statistic type %d", i_type );
 
187
        break;
 
188
#endif
 
189
 
 
190
    case SOUT_STATISTIC_SENT_PACKET:
 
191
        I(p_sout_sent_packets);
 
192
        break;
 
193
#undef I
 
194
    case SOUT_STATISTIC_SENT_BYTE:
 
195
        if( !stats_UpdateInteger( p_input, p_input->p->counters.p_sout_sent_bytes, i_delta, &i_bytes ) )
 
196
            stats_UpdateFloat( p_input, p_input->p->counters.p_sout_send_bitrate, i_bytes, NULL );
 
197
        break;
 
198
 
 
199
    default:
 
200
        msg_Err( p_sout, "Invalid statistic type %d (internal error)", i_type );
 
201
        break;
 
202
    }
 
203
    vlc_object_release( p_input );
 
204
}
200
205
/*****************************************************************************
201
206
 * Packetizer/Input
202
207
 *****************************************************************************/
205
210
{
206
211
    sout_packetizer_input_t *p_input;
207
212
 
208
 
    msg_Dbg( p_sout, "adding a new input" );
209
 
 
210
213
    /* *** create a packetizer input *** */
211
214
    p_input         = malloc( sizeof( sout_packetizer_input_t ) );
212
215
    if( !p_input )  return NULL;
213
216
    p_input->p_sout = p_sout;
214
217
    p_input->p_fmt  = p_fmt;
215
218
 
 
219
    msg_Dbg( p_sout, "adding a new sout input (sout_input:%p)", p_input );
 
220
 
216
221
    if( p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
217
222
    {
218
223
        vlc_object_release( p_sout );
240
245
{
241
246
    sout_instance_t     *p_sout = p_input->p_sout;
242
247
 
243
 
    msg_Dbg( p_sout, "removing an input" );
 
248
    msg_Dbg( p_sout, "removing a sout input (sout_input:%p)", p_input );
244
249
 
245
250
    if( p_input->p_fmt->i_codec != VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
246
251
    {
287
292
 * sout_AccessOutNew: allocate a new access out
288
293
 *****************************************************************************/
289
294
sout_access_out_t *sout_AccessOutNew( sout_instance_t *p_sout,
290
 
                                      char *psz_access, char *psz_name )
 
295
                                      const char *psz_access, const char *psz_name )
291
296
{
 
297
    static const char typename[] = "access out";
292
298
    sout_access_out_t *p_access;
293
299
    char              *psz_next;
294
300
 
295
 
    if( !( p_access = vlc_object_create( p_sout,
296
 
                                         sizeof( sout_access_out_t ) ) ) )
297
 
    {
298
 
        msg_Err( p_sout, "out of memory" );
 
301
    p_access = vlc_custom_create( p_sout, sizeof( *p_access ),
 
302
                                  VLC_OBJECT_GENERIC, typename );
 
303
    if( !p_access )
299
304
        return NULL;
300
 
    }
301
305
 
302
 
    psz_next = sout_CfgCreate( &p_access->psz_access, &p_access->p_cfg,
303
 
                                psz_access );
304
 
    if( psz_next )
305
 
    {
306
 
        free( psz_next );
307
 
    }
308
 
    p_access->psz_name   = strdup( psz_name ? psz_name : "" );
 
306
    psz_next = config_ChainCreate( &p_access->psz_access, &p_access->p_cfg,
 
307
                                   psz_access );
 
308
    free( psz_next );
 
309
    p_access->psz_path   = strdup( psz_name ? psz_name : "" );
309
310
    p_access->p_sout     = p_sout;
310
 
    p_access->p_sys = NULL;
 
311
    p_access->p_sys      = NULL;
311
312
    p_access->pf_seek    = NULL;
312
313
    p_access->pf_read    = NULL;
313
314
    p_access->pf_write   = NULL;
 
315
    p_access->pf_control = NULL;
314
316
    p_access->p_module   = NULL;
315
317
 
316
318
    p_access->i_writes = 0;
319
321
    vlc_object_attach( p_access, p_sout );
320
322
 
321
323
    p_access->p_module   =
322
 
        module_Need( p_access, "sout access", p_access->psz_access, VLC_TRUE );
 
324
        module_Need( p_access, "sout access", p_access->psz_access, true );
323
325
 
324
326
    if( !p_access->p_module )
325
327
    {
326
328
        free( p_access->psz_access );
327
 
        free( p_access->psz_name );
 
329
        free( p_access->psz_path );
328
330
        vlc_object_detach( p_access );
329
 
        vlc_object_destroy( p_access );
 
331
        vlc_object_release( p_access );
330
332
        return( NULL );
331
333
    }
332
334
 
344
346
    }
345
347
    free( p_access->psz_access );
346
348
 
347
 
    sout_CfgDestroy( p_access->p_cfg );
348
 
 
349
 
    free( p_access->psz_name );
350
 
 
351
 
    vlc_object_destroy( p_access );
 
349
    config_ChainDestroy( p_access->p_cfg );
 
350
 
 
351
    free( p_access->psz_path );
 
352
 
 
353
    vlc_object_release( p_access );
352
354
}
353
355
 
354
356
/*****************************************************************************
362
364
/*****************************************************************************
363
365
 * sout_AccessRead:
364
366
 *****************************************************************************/
365
 
int sout_AccessOutRead( sout_access_out_t *p_access, block_t *p_buffer )
 
367
ssize_t sout_AccessOutRead( sout_access_out_t *p_access, block_t *p_buffer )
366
368
{
367
369
    return( p_access->pf_read ?
368
370
            p_access->pf_read( p_access, p_buffer ) : VLC_EGENERIC );
371
373
/*****************************************************************************
372
374
 * sout_AccessWrite:
373
375
 *****************************************************************************/
374
 
int sout_AccessOutWrite( sout_access_out_t *p_access, block_t *p_buffer )
 
376
ssize_t sout_AccessOutWrite( sout_access_out_t *p_access, block_t *p_buffer )
375
377
{
376
 
    int i_total;
 
378
    const unsigned i_packets_gather = 30;
377
379
    p_access->i_writes++;
378
380
    p_access->i_sent_bytes += p_buffer->i_buffer;
379
 
    if( p_access->p_libvlc->b_stats && p_access->i_writes % 30 == 0 )
 
381
    if( (p_access->i_writes % i_packets_gather) == 0 )
380
382
    {
381
 
        /* Access_out -> sout_instance -> input_thread_t */
382
 
        input_thread_t *p_input =
383
 
            (input_thread_t *)vlc_object_find( p_access, VLC_OBJECT_INPUT,
384
 
                                               FIND_PARENT );
385
 
        if( p_input )
386
 
        {
387
 
            stats_UpdateInteger( p_input, STATS_SOUT_SENT_PACKETS, 30, NULL );
388
 
            stats_UpdateInteger( p_input, STATS_SOUT_SENT_BYTES,
389
 
                                 p_access->i_sent_bytes, &i_total );
390
 
            stats_UpdateFloat( p_input, STATS_SOUT_SEND_BITRATE, (float)i_total,
391
 
                               NULL );
392
 
            p_access->i_sent_bytes = 0;
393
 
            vlc_object_release( p_input );
394
 
        }
 
383
        sout_UpdateStatistic( p_access->p_sout, SOUT_STATISTIC_SENT_PACKET, i_packets_gather );
 
384
        sout_UpdateStatistic( p_access->p_sout, SOUT_STATISTIC_SENT_BYTE, p_access->i_sent_bytes );
 
385
        p_access->i_sent_bytes = 0;
395
386
    }
396
387
    return p_access->pf_write( p_access, p_buffer );
397
388
}
398
389
 
 
390
/**
 
391
 * sout_AccessOutControl
 
392
 */
 
393
int sout_AccessOutControl (sout_access_out_t *access, int query, va_list args)
 
394
{
 
395
    return (access->pf_control) ? access->pf_control (access, query, args)
 
396
                                : VLC_EGENERIC;
 
397
}
 
398
 
399
399
/*****************************************************************************
400
400
 * sout_MuxNew: create a new mux
401
401
 *****************************************************************************/
402
402
sout_mux_t * sout_MuxNew( sout_instance_t *p_sout, char *psz_mux,
403
403
                          sout_access_out_t *p_access )
404
404
{
 
405
    static const char typename[] = "mux";
405
406
    sout_mux_t *p_mux;
406
407
    char       *psz_next;
407
408
 
408
 
    p_mux = vlc_object_create( p_sout, sizeof( sout_mux_t ) );
 
409
    p_mux = vlc_custom_create( p_sout, sizeof( *p_mux ), VLC_OBJECT_GENERIC,
 
410
                               typename);
409
411
    if( p_mux == NULL )
410
 
    {
411
 
        msg_Err( p_sout, "out of memory" );
412
412
        return NULL;
413
 
    }
414
413
 
415
414
    p_mux->p_sout = p_sout;
416
 
    psz_next = sout_CfgCreate( &p_mux->psz_mux, &p_mux->p_cfg, psz_mux );
417
 
    if( psz_next ) free( psz_next );
 
415
    psz_next = config_ChainCreate( &p_mux->psz_mux, &p_mux->p_cfg, psz_mux );
 
416
    free( psz_next );
418
417
 
419
418
    p_mux->p_access     = p_access;
420
419
    p_mux->pf_control   = NULL;
427
426
    p_mux->p_sys        = NULL;
428
427
    p_mux->p_module     = NULL;
429
428
 
430
 
    p_mux->b_add_stream_any_time = VLC_FALSE;
431
 
    p_mux->b_waiting_stream = VLC_TRUE;
 
429
    p_mux->b_add_stream_any_time = false;
 
430
    p_mux->b_waiting_stream = true;
432
431
    p_mux->i_add_stream_start = -1;
433
432
 
434
433
    vlc_object_attach( p_mux, p_sout );
435
434
 
436
435
    p_mux->p_module =
437
 
        module_Need( p_mux, "sout mux", p_mux->psz_mux, VLC_TRUE );
 
436
        module_Need( p_mux, "sout mux", p_mux->psz_mux, true );
438
437
 
439
438
    if( p_mux->p_module == NULL )
440
439
    {
441
 
        FREE( p_mux->psz_mux );
 
440
        FREENULL( p_mux->psz_mux );
442
441
 
443
442
        vlc_object_detach( p_mux );
444
 
        vlc_object_destroy( p_mux );
 
443
        vlc_object_release( p_mux );
445
444
        return NULL;
446
445
    }
447
446
 
448
447
    /* *** probe mux capacity *** */
449
448
    if( p_mux->pf_control )
450
449
    {
451
 
        int b_answer = VLC_FALSE;
 
450
        int b_answer = false;
452
451
 
453
452
        if( sout_MuxControl( p_mux, MUX_CAN_ADD_STREAM_WHILE_MUXING,
454
453
                             &b_answer ) )
455
454
        {
456
 
            b_answer = VLC_FALSE;
 
455
            b_answer = false;
457
456
        }
458
457
 
459
458
        if( b_answer )
460
459
        {
461
460
            msg_Dbg( p_sout, "muxer support adding stream at any time" );
462
 
            p_mux->b_add_stream_any_time = VLC_TRUE;
463
 
            p_mux->b_waiting_stream = VLC_FALSE;
 
461
            p_mux->b_add_stream_any_time = true;
 
462
            p_mux->b_waiting_stream = false;
464
463
 
465
464
            /* If we control the output pace then it's better to wait before
466
465
             * starting muxing (generates better streams/files). */
467
466
            if( !p_sout->i_out_pace_nocontrol )
468
467
            {
469
 
                b_answer = VLC_TRUE;
 
468
                b_answer = true;
470
469
            }
471
470
            else if( sout_MuxControl( p_mux, MUX_GET_ADD_STREAM_WAIT,
472
471
                                      &b_answer ) )
473
472
            {
474
 
                b_answer = VLC_FALSE;
 
473
                b_answer = false;
475
474
            }
476
475
 
477
476
            if( b_answer )
478
477
            {
479
478
                msg_Dbg( p_sout, "muxer prefers to wait for all ES before "
480
479
                         "starting to mux" );
481
 
                p_mux->b_waiting_stream = VLC_TRUE;
 
480
                p_mux->b_waiting_stream = true;
482
481
            }
483
482
        }
484
483
    }
498
497
    }
499
498
    free( p_mux->psz_mux );
500
499
 
501
 
    sout_CfgDestroy( p_mux->p_cfg );
 
500
    config_ChainDestroy( p_mux->p_cfg );
502
501
 
503
 
    vlc_object_destroy( p_mux );
 
502
    vlc_object_release( p_mux );
504
503
}
505
504
 
506
505
/*****************************************************************************
513
512
    if( !p_mux->b_add_stream_any_time && !p_mux->b_waiting_stream )
514
513
    {
515
514
        msg_Err( p_mux, "cannot add a new stream (unsupported while muxing "
516
 
                        "to this format)" );
 
515
                        "to this format). You can try increasing sout-mux-caching value" );
517
516
        return NULL;
518
517
    }
519
518
 
521
520
 
522
521
    /* create a new sout input */
523
522
    p_input = malloc( sizeof( sout_input_t ) );
 
523
    if( !p_input )
 
524
        return NULL;
524
525
    p_input->p_sout = p_mux->p_sout;
525
526
    p_input->p_fmt  = p_fmt;
526
 
    p_input->p_fifo = block_FifoNew( p_mux->p_sout );
 
527
    p_input->p_fifo = block_FifoNew();
527
528
    p_input->p_sys  = NULL;
528
529
 
529
530
    TAB_APPEND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
530
531
    if( p_mux->pf_addstream( p_mux, p_input ) < 0 )
531
532
    {
532
 
            msg_Err( p_mux, "cannot add this stream" );
533
 
            TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
534
 
            block_FifoRelease( p_input->p_fifo );
535
 
            free( p_input );
536
 
            return NULL;
 
533
        msg_Err( p_mux, "cannot add this stream" );
 
534
        TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
 
535
        block_FifoRelease( p_input->p_fifo );
 
536
        free( p_input );
 
537
        return NULL;
537
538
    }
538
539
 
539
540
    return p_input;
546
547
{
547
548
    int i_index;
548
549
 
549
 
    if( p_mux->b_waiting_stream && p_input->p_fifo->i_depth > 0 )
 
550
    if( p_mux->b_waiting_stream
 
551
     && block_FifoCount( p_input->p_fifo ) > 0 )
550
552
    {
551
553
        /* We stop waiting, and call the muxer for taking care of the data
552
554
         * before we remove this es */
553
 
        p_mux->b_waiting_stream = VLC_FALSE;
 
555
        p_mux->b_waiting_stream = false;
554
556
        p_mux->pf_mux( p_mux );
555
557
    }
556
558
 
587
589
    {
588
590
        mtime_t current_date = mdate();
589
591
        if ( current_date > p_buffer->i_dts )
590
 
            msg_Warn( p_mux, "late buffer for mux input ("I64Fd")",
 
592
            msg_Warn( p_mux, "late buffer for mux input (%"PRId64")",
591
593
                      current_date - p_buffer->i_dts );
592
594
    }
593
595
 
594
596
    if( p_mux->b_waiting_stream )
595
597
    {
 
598
        const int64_t i_caching = var_GetInteger( p_mux->p_sout, "sout-mux-caching" ) * INT64_C(1000);
 
599
 
596
600
        if( p_mux->i_add_stream_start < 0 )
597
 
        {
598
601
            p_mux->i_add_stream_start = p_buffer->i_dts;
599
 
        }
600
602
 
601
 
        if( p_mux->i_add_stream_start >= 0 &&
602
 
            p_mux->i_add_stream_start + I64C(1500000) < p_buffer->i_dts )
603
 
        {
604
 
            /* Wait until we have more than 1.5 seconds worth of data
605
 
             * before start muxing */
606
 
            p_mux->b_waiting_stream = VLC_FALSE;
607
 
        }
608
 
        else
609
 
        {
 
603
        /* Wait until we have enought data before muxing */
 
604
        if( p_mux->i_add_stream_start < 0 ||
 
605
            p_buffer->i_dts < p_mux->i_add_stream_start + i_caching )
610
606
            return;
611
 
        }
 
607
        p_mux->b_waiting_stream = false;
612
608
    }
613
609
    p_mux->pf_mux( p_mux );
614
610
}
616
612
/*****************************************************************************
617
613
 *
618
614
 *****************************************************************************/
619
 
static int mrl_Parse( mrl_t *p_mrl, char *psz_mrl )
 
615
static int mrl_Parse( mrl_t *p_mrl, const char *psz_mrl )
620
616
{
621
617
    char * psz_dup = strdup( psz_mrl );
622
618
    char * psz_parser = psz_dup;
623
 
    char * psz_access = "";
624
 
    char * psz_way = "";
625
 
    char * psz_name = "";
 
619
    const char * psz_access;
 
620
    const char * psz_way;
 
621
    char * psz_name;
626
622
 
627
623
    /* *** first parse psz_dest */
628
624
    while( *psz_parser && *psz_parser != ':' )
735
731
/* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
736
732
static void mrl_Clean( mrl_t *p_mrl )
737
733
{
738
 
    FREE( p_mrl->psz_access );
739
 
    FREE( p_mrl->psz_way );
740
 
    FREE( p_mrl->psz_name );
 
734
    FREENULL( p_mrl->psz_access );
 
735
    FREENULL( p_mrl->psz_way );
 
736
    FREENULL( p_mrl->psz_name );
741
737
}
742
738
 
743
739
 
759
755
 *  return a pointer on the rest
760
756
 *  XXX: psz_chain is modified
761
757
 */
762
 
#define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; }
763
 
#define SKIPTRAILINGSPACE( p, e ) \
764
 
    { while( e > p && ( *(e-1) == ' ' || *(e-1) == '\t' ) ) e--; }
765
 
 
766
 
/* go accross " " and { } */
767
 
static char *_get_chain_end( char *str )
768
 
{
769
 
    char c, *p = str;
770
 
 
771
 
    SKIPSPACE( p );
772
 
 
773
 
    for( ;; )
774
 
    {
775
 
        if( !*p || *p == ',' || *p == '}' ) return p;
776
 
 
777
 
        if( *p != '{' && *p != '"' && *p != '\'' )
778
 
        {
779
 
            p++;
780
 
            continue;
781
 
        }
782
 
 
783
 
        if( *p == '{' ) c = '}';
784
 
        else c = *p;
785
 
        p++;
786
 
 
787
 
        for( ;; )
788
 
        {
789
 
            if( !*p ) return p;
790
 
 
791
 
            if( *p == c ) return ++p;
792
 
            else if( *p == '{' && c == '}' ) p = _get_chain_end( p );
793
 
            else p++;
794
 
        }
795
 
    }
796
 
}
797
 
 
798
 
char *sout_CfgCreate( char **ppsz_name, sout_cfg_t **pp_cfg, char *psz_chain )
799
 
{
800
 
    sout_cfg_t *p_cfg = NULL;
801
 
    char       *p = psz_chain;
802
 
 
803
 
    *ppsz_name = NULL;
804
 
    *pp_cfg    = NULL;
805
 
 
806
 
    if( !p ) return NULL;
807
 
 
808
 
    SKIPSPACE( p );
809
 
 
810
 
    while( *p && *p != '{' && *p != ':' && *p != ' ' && *p != '\t' ) p++;
811
 
 
812
 
    if( p == psz_chain ) return NULL;
813
 
 
814
 
    *ppsz_name = strndup( psz_chain, p - psz_chain );
815
 
 
816
 
    SKIPSPACE( p );
817
 
 
818
 
    if( *p == '{' )
819
 
    {
820
 
        char *psz_name;
821
 
 
822
 
        p++;
823
 
 
824
 
        for( ;; )
825
 
        {
826
 
            sout_cfg_t cfg;
827
 
 
828
 
            SKIPSPACE( p );
829
 
 
830
 
            psz_name = p;
831
 
 
832
 
            while( *p && *p != '=' && *p != ',' && *p != '{' && *p != '}' &&
833
 
                   *p != ' ' && *p != '\t' ) p++;
834
 
 
835
 
            /* fprintf( stderr, "name=%s - rest=%s\n", psz_name, p ); */
836
 
            if( p == psz_name )
837
 
            {
838
 
                fprintf( stderr, "invalid options (empty)" );
839
 
                break;
840
 
            }
841
 
 
842
 
            cfg.psz_name = strndup( psz_name, p - psz_name );
843
 
 
844
 
            SKIPSPACE( p );
845
 
 
846
 
            if( *p == '=' || *p == '{' )
847
 
            {
848
 
                char *end;
849
 
                vlc_bool_t b_keep_brackets = (*p == '{');
850
 
 
851
 
                if( *p == '=' ) p++;
852
 
 
853
 
                end = _get_chain_end( p );
854
 
                if( end <= p )
855
 
                {
856
 
                    cfg.psz_value = NULL;
857
 
                }
858
 
                else
859
 
                {
860
 
                    /* Skip heading and trailing spaces.
861
 
                     * This ain't necessary but will avoid simple
862
 
                     * user mistakes. */
863
 
                    SKIPSPACE( p );
864
 
                }
865
 
 
866
 
                if( end <= p )
867
 
                {
868
 
                    cfg.psz_value = NULL;
869
 
                }
870
 
                else
871
 
                {
872
 
                    if( *p == '\'' || *p == '"' ||
873
 
                        ( !b_keep_brackets && *p == '{' ) )
874
 
                    {
875
 
                        p++;
876
 
 
877
 
                        if( *(end-1) != '\'' && *(end-1) == '"' )
878
 
                            SKIPTRAILINGSPACE( p, end );
879
 
 
880
 
                        if( end - 1 <= p ) cfg.psz_value = NULL;
881
 
                        else cfg.psz_value = strndup( p, end -1 - p );
882
 
                    }
883
 
                    else
884
 
                    {
885
 
                        SKIPTRAILINGSPACE( p, end );
886
 
                        if( end <= p ) cfg.psz_value = NULL;
887
 
                        else cfg.psz_value = strndup( p, end - p );
888
 
                    }
889
 
                }
890
 
 
891
 
                p = end;
892
 
                SKIPSPACE( p );
893
 
            }
894
 
            else
895
 
            {
896
 
                cfg.psz_value = NULL;
897
 
            }
898
 
 
899
 
            cfg.p_next = NULL;
900
 
            if( p_cfg )
901
 
            {
902
 
                p_cfg->p_next = malloc( sizeof( sout_cfg_t ) );
903
 
                memcpy( p_cfg->p_next, &cfg, sizeof( sout_cfg_t ) );
904
 
 
905
 
                p_cfg = p_cfg->p_next;
906
 
            }
907
 
            else
908
 
            {
909
 
                p_cfg = malloc( sizeof( sout_cfg_t ) );
910
 
                memcpy( p_cfg, &cfg, sizeof( sout_cfg_t ) );
911
 
 
912
 
                *pp_cfg = p_cfg;
913
 
            }
914
 
 
915
 
            if( *p == ',' ) p++;
916
 
 
917
 
            if( *p == '}' )
918
 
            {
919
 
                p++;
920
 
                break;
921
 
            }
922
 
        }
923
 
    }
924
 
 
925
 
    if( *p == ':' ) return( strdup( p + 1 ) );
926
 
 
927
 
    return NULL;
928
 
}
929
 
 
930
 
static void sout_CfgDestroy( sout_cfg_t *p_cfg )
931
 
{
932
 
    while( p_cfg != NULL )
933
 
    {
934
 
        sout_cfg_t *p_next;
935
 
 
936
 
        p_next = p_cfg->p_next;
937
 
 
938
 
        FREE( p_cfg->psz_name );
939
 
        FREE( p_cfg->psz_value );
940
 
        free( p_cfg );
941
 
 
942
 
        p_cfg = p_next;
943
 
    }
944
 
}
945
 
 
946
 
void __sout_CfgParse( vlc_object_t *p_this, char *psz_prefix,
947
 
                      const char **ppsz_options, sout_cfg_t *cfg )
948
 
{
949
 
    char *psz_name;
950
 
    int  i_type;
951
 
    int  i;
952
 
 
953
 
    /* First, var_Create all variables */
954
 
    for( i = 0; ppsz_options[i] != NULL; i++ )
955
 
    {
956
 
        asprintf( &psz_name, "%s%s", psz_prefix,
957
 
                  *ppsz_options[i] == '*' ? &ppsz_options[i][1] : ppsz_options[i] );
958
 
 
959
 
        i_type = config_GetType( p_this, psz_name );
960
 
 
961
 
        var_Create( p_this, psz_name, i_type | VLC_VAR_DOINHERIT );
962
 
        free( psz_name );
963
 
    }
964
 
 
965
 
    /* Now parse options and set value */
966
 
    if( psz_prefix == NULL ) psz_prefix = "";
967
 
 
968
 
    while( cfg )
969
 
    {
970
 
        vlc_value_t val;
971
 
        vlc_bool_t b_yes = VLC_TRUE;
972
 
        vlc_bool_t b_once = VLC_FALSE;
973
 
        module_config_t *p_conf;
974
 
 
975
 
        if( cfg->psz_name == NULL || *cfg->psz_name == '\0' )
976
 
        {
977
 
            cfg = cfg->p_next;
978
 
            continue;
979
 
        }
980
 
        for( i = 0; ppsz_options[i] != NULL; i++ )
981
 
        {
982
 
            if( !strcmp( ppsz_options[i], cfg->psz_name ) )
983
 
            {
984
 
                break;
985
 
            }
986
 
            if( ( !strncmp( cfg->psz_name, "no-", 3 ) &&
987
 
                  !strcmp( ppsz_options[i], cfg->psz_name + 3 ) ) ||
988
 
                ( !strncmp( cfg->psz_name, "no", 2 ) &&
989
 
                  !strcmp( ppsz_options[i], cfg->psz_name + 2 ) ) )
990
 
            {
991
 
                b_yes = VLC_FALSE;
992
 
                break;
993
 
            }
994
 
 
995
 
            if( *ppsz_options[i] == '*' &&
996
 
                !strcmp( &ppsz_options[i][1], cfg->psz_name ) )
997
 
            {
998
 
                b_once = VLC_TRUE;
999
 
                break;
1000
 
            }
1001
 
 
1002
 
        }
1003
 
        if( ppsz_options[i] == NULL )
1004
 
        {
1005
 
            msg_Warn( p_this, "option %s is unknown", cfg->psz_name );
1006
 
            cfg = cfg->p_next;
1007
 
            continue;
1008
 
        }
1009
 
 
1010
 
        /* create name */
1011
 
        asprintf( &psz_name, "%s%s", psz_prefix, b_once ? &ppsz_options[i][1] : ppsz_options[i] );
1012
 
 
1013
 
        /* Check if the option is deprecated */
1014
 
        p_conf = config_FindConfig( p_this, psz_name );
1015
 
 
1016
 
        /* This is basically cut and paste from src/misc/configuration.c
1017
 
         * with slight changes */
1018
 
        if( p_conf && p_conf->psz_current )
1019
 
        {
1020
 
            if( !strcmp( p_conf->psz_current, "SUPPRESSED" ) )
1021
 
            {
1022
 
                msg_Err( p_this, "Option %s is no longer used.",
1023
 
                         p_conf->psz_name );
1024
 
                goto next;
1025
 
            }
1026
 
            else if( p_conf->b_strict )
1027
 
            {
1028
 
                msg_Err( p_this, "Option %s is deprecated. Use %s instead.",
1029
 
                         p_conf->psz_name, p_conf->psz_current );
1030
 
                /* TODO: this should return an error and end option parsing
1031
 
                 * ... but doing this would change the VLC API and all the
1032
 
                 * modules so i'll do it later */
1033
 
                goto next;
1034
 
            }
1035
 
            else
1036
 
            {
1037
 
                msg_Warn( p_this, "Option %s is deprecated. You should use "
1038
 
                        "%s instead.", p_conf->psz_name, p_conf->psz_current );
1039
 
                free( psz_name );
1040
 
                psz_name = strdup( p_conf->psz_current );
1041
 
            }
1042
 
        }
1043
 
        /* </Check if the option is deprecated> */
1044
 
 
1045
 
        /* get the type of the variable */
1046
 
        i_type = config_GetType( p_this, psz_name );
1047
 
        if( !i_type )
1048
 
        {
1049
 
            msg_Warn( p_this, "unknown option %s (value=%s)",
1050
 
                      cfg->psz_name, cfg->psz_value );
1051
 
            goto next;
1052
 
        }
1053
 
        if( i_type != VLC_VAR_BOOL && cfg->psz_value == NULL )
1054
 
        {
1055
 
            msg_Warn( p_this, "missing value for option %s", cfg->psz_name );
1056
 
            goto next;
1057
 
        }
1058
 
        if( i_type != VLC_VAR_STRING && b_once )
1059
 
        {
1060
 
            msg_Warn( p_this, "*option_name need to be a string option" );
1061
 
            goto next;
1062
 
        }
1063
 
 
1064
 
        switch( i_type )
1065
 
        {
1066
 
            case VLC_VAR_BOOL:
1067
 
                val.b_bool = b_yes;
1068
 
                break;
1069
 
            case VLC_VAR_INTEGER:
1070
 
                val.i_int = strtol( cfg->psz_value ? cfg->psz_value : "0",
1071
 
                                    NULL, 0 );
1072
 
                break;
1073
 
            case VLC_VAR_FLOAT:
1074
 
                val.f_float = atof( cfg->psz_value ? cfg->psz_value : "0" );
1075
 
                break;
1076
 
            case VLC_VAR_STRING:
1077
 
            case VLC_VAR_MODULE:
1078
 
                val.psz_string = cfg->psz_value;
1079
 
                break;
1080
 
            default:
1081
 
                msg_Warn( p_this, "unhandled config var type" );
1082
 
                memset( &val, 0, sizeof( vlc_value_t ) );
1083
 
                break;
1084
 
        }
1085
 
        if( b_once )
1086
 
        {
1087
 
            vlc_value_t val2;
1088
 
 
1089
 
            var_Get( p_this, psz_name, &val2 );
1090
 
            if( *val2.psz_string )
1091
 
            {
1092
 
                free( val2.psz_string );
1093
 
                msg_Dbg( p_this, "ignoring option %s (not first occurrence)", psz_name );
1094
 
                goto next;
1095
 
            }
1096
 
            free( val2.psz_string );
1097
 
        }
1098
 
        var_Set( p_this, psz_name, val );
1099
 
        msg_Dbg( p_this, "set sout option: %s to %s", psz_name, cfg->psz_value );
1100
 
 
1101
 
    next:
1102
 
        free( psz_name );
1103
 
        cfg = cfg->p_next;
1104
 
    }
1105
 
}
1106
 
 
1107
758
 
1108
759
/*
1109
760
 * XXX name and p_cfg are used (-> do NOT free them)
1110
761
 */
1111
762
sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_chain )
1112
763
{
 
764
    static const char typename[] = "stream out";
1113
765
    sout_stream_t *p_stream;
1114
766
 
1115
767
    if( !psz_chain )
1118
770
        return NULL;
1119
771
    }
1120
772
 
1121
 
    p_stream = vlc_object_create( p_sout, sizeof( sout_stream_t ) );
1122
 
 
 
773
    p_stream = vlc_custom_create( p_sout, sizeof( *p_stream ),
 
774
                                  VLC_OBJECT_GENERIC, typename );
1123
775
    if( !p_stream )
1124
 
    {
1125
 
        msg_Err( p_sout, "out of memory" );
1126
776
        return NULL;
1127
 
    }
1128
777
 
1129
778
    p_stream->p_sout   = p_sout;
1130
779
    p_stream->p_sys    = NULL;
1131
780
 
1132
781
    p_stream->psz_next =
1133
 
        sout_CfgCreate( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
 
782
        config_ChainCreate( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
1134
783
 
1135
784
    msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );
1136
785
 
1137
786
    vlc_object_attach( p_stream, p_sout );
1138
787
 
1139
788
    p_stream->p_module =
1140
 
        module_Need( p_stream, "sout stream", p_stream->psz_name, VLC_TRUE );
 
789
        module_Need( p_stream, "sout stream", p_stream->psz_name, true );
1141
790
 
1142
791
    if( !p_stream->p_module )
1143
792
    {
1155
804
    vlc_object_detach( p_stream );
1156
805
    if( p_stream->p_module ) module_Unneed( p_stream, p_stream->p_module );
1157
806
 
1158
 
    FREE( p_stream->psz_name );
1159
 
    FREE( p_stream->psz_next );
 
807
    FREENULL( p_stream->psz_name );
 
808
    FREENULL( p_stream->psz_next );
1160
809
 
1161
 
    sout_CfgDestroy( p_stream->p_cfg );
 
810
    config_ChainDestroy( p_stream->p_cfg );
1162
811
 
1163
812
    msg_Dbg( p_stream, "destroying chain done" );
1164
 
    vlc_object_destroy( p_stream );
 
813
    vlc_object_release( p_stream );
1165
814
}
1166
815
 
1167
 
static char *_sout_stream_url_to_chain( vlc_object_t *p_this, char *psz_url )
 
816
static char *_sout_stream_url_to_chain( vlc_object_t *p_this,
 
817
                                        const char *psz_url )
1168
818
{
1169
819
    mrl_t       mrl;
1170
 
    char        *psz_chain, *p;
 
820
    char        *psz_chain;
1171
821
 
1172
822
    mrl_Parse( &mrl, psz_url );
1173
 
    p = psz_chain = malloc( 500 + strlen( mrl.psz_way ) +
1174
 
                                  strlen( mrl.psz_access ) +
1175
 
                                  strlen( mrl.psz_name ) );
1176
 
 
1177
 
 
1178
 
    if( config_GetInt( p_this, "sout-display" ) )
 
823
 
 
824
    /* Check if the URLs goes to #rtp - otherwise we'll use #standard */
 
825
    static const char rtplist[] = "dccp\0sctp\0tcp\0udplite\0";
 
826
    for (const char *a = rtplist; *a; a += strlen (a) + 1)
 
827
        if (strcmp (a, mrl.psz_access) == 0)
 
828
            goto rtp;
 
829
 
 
830
    if (strcmp (mrl.psz_access, "rtp") == 0)
1179
831
    {
1180
 
        p += sprintf( p, "duplicate{dst=display,dst=std{mux=\"%s\","
1181
 
                      "access=\"%s\",dst=\"%s\"}}",
1182
 
                      mrl.psz_way, mrl.psz_access, mrl.psz_name );
 
832
        char *port;
 
833
        /* For historical reasons, rtp:// means RTP over UDP */
 
834
        strcpy (mrl.psz_access, "udp");
 
835
rtp:
 
836
        if (mrl.psz_name[0] == '[')
 
837
        {
 
838
            port = strstr (mrl.psz_name, "]:");
 
839
            if (port != NULL)
 
840
                port++;
 
841
        }
 
842
        else
 
843
            port = strchr (mrl.psz_name, ':');
 
844
        if (port != NULL)
 
845
            *port++ = '\0'; /* erase ':' */
 
846
 
 
847
        if (asprintf (&psz_chain,
 
848
                      "rtp{mux=\"%s\",proto=\"%s\",dst=\"%s%s%s\"}",
 
849
                      mrl.psz_way, mrl.psz_access, mrl.psz_name,
 
850
                      port ? "\",port=\"" : "", port ? port : "") == -1)
 
851
            psz_chain = NULL;
1183
852
    }
1184
853
    else
1185
854
    {
1186
 
        p += sprintf( p, "std{mux=\"%s\",access=\"%s\",dst=\"%s\"}",
1187
 
                      mrl.psz_way, mrl.psz_access, mrl.psz_name );
 
855
        /* Convert the URL to a basic standard sout chain */
 
856
        if (asprintf (&psz_chain,
 
857
                      "standard{mux=\"%s\",access=\"%s\",dst=\"%s\"}",
 
858
                      mrl.psz_way, mrl.psz_access, mrl.psz_name) == -1)
 
859
            psz_chain = NULL;
 
860
    }
 
861
 
 
862
    /* Duplicate and wrap if sout-display is on */
 
863
    if (psz_chain && (config_GetInt( p_this, "sout-display" ) > 0))
 
864
    {
 
865
        char *tmp;
 
866
        if (asprintf (&tmp, "duplicate{dst=display,dst=%s}", tmp) == -1)
 
867
            tmp = NULL;
 
868
        free (psz_chain);
 
869
        psz_chain = tmp;
1188
870
    }
1189
871
 
1190
872
    mrl_Clean( &mrl );
1191
 
    return( psz_chain );
 
873
    return psz_chain;
1192
874
}