root/modules/stream_out/bridge.c

Revision 09cffd8327bd7a6b6809f14e999df7732b2a875a, 23.3 kB (checked in by Antoine Cellerier <dionoea@videolan.org>, 3 days ago)

Fix placeholder mode. UDP streaming now works.

Make sure that we don't add the briged elementary streams to the next
stream output chain element when in placeholder mode. Maybe I should
split normal bridge-in and placeholder mode because the code is
begining to be filled with quite a few if( p_sys->b_placeholder ).

  • Property mode set to 100644
Line 
1 /*****************************************************************************
2  * bridge.c: bridge stream output module
3  *****************************************************************************
4  * Copyright (C) 2005-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *          Antoine Cellerier <dionoea at videolan dot org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_sout.h>
36 #include <vlc_block.h>
37
38 /*****************************************************************************
39  * Module descriptor
40  *****************************************************************************/
41 #define ID_TEXT N_("ID")
42 #define ID_LONGTEXT N_( \
43     "Integer identifier for this elementary stream. This will be used to " \
44     "\"find\" this stream later." )
45
46 #define DEST_TEXT N_( "Destination bridge-in name" )
47 #define DEST_LONGTEXT N_( \
48     "Name of the destination bridge-in. If you do not need more " \
49     "than one bridge-in at a time, you can discard this option." )
50
51 #define DELAY_TEXT N_("Delay")
52 #define DELAY_LONGTEXT N_("Pictures coming from the picture video outputs " \
53         "will be delayed according to this value (in milliseconds, should be "\
54         ">= 100 ms). For high values, you will need to raise caching values." )
55
56 #define ID_OFFSET_TEXT N_("ID Offset")
57 #define ID_OFFSET_LONGTEXT N_("Offset to add to the stream IDs specified in " \
58         "bridge_out to obtain the stream IDs bridge_in will register.")
59
60 #define NAME_TEXT N_( "Name of current instance" )
61 #define NAME_LONGTEXT N_( \
62     "Name of this bridge-in instance. If you do not need more " \
63     "than one bridge-in at a time, you can discard this option." )
64
65 #define PLACEHOLDER_TEXT N_( "Fallback to placeholder stream when out of data" )
66 #define PLACEHOLDER_LONGTEXT N_( \
67     "If set to true, the bridge will discard all input elementary streams " \
68     "except if it doesn't receive data from another bridge-in. This can " \
69     "be used to configure a place holder stream when the real source " \
70     "breaks. Source and placeholder streams should have the same format. " )
71
72 #define PLACEHOLDER_DELAY_TEXT N_( "Placeholder delay" )
73 #define PLACEHOLDER_DELAY_LONGTEXT N_( \
74     "Delay (in ms) before the placeholder kicks in." )
75
76 #define PLACEHOLDER_IFRAME_TEXT N_( "Wait for I frame before toggling placholder" )
77 #define PLACEHOLDER_IFRAME_LONGTEXT N_( \
78     "If enabled, switching between the placeholder and the normal stream " \
79     "will only occur on I frames. This will remove artifacts on stream " \
80     "switching at the expense of a slightly longer delay, depending on " \
81     "the frequence of I frames in the streams." )
82
83 static int  OpenOut ( vlc_object_t * );
84 static void CloseOut( vlc_object_t * );
85 static int  OpenIn  ( vlc_object_t * );
86 static void CloseIn ( vlc_object_t * );
87
88 #define SOUT_CFG_PREFIX_OUT "sout-bridge-out-"
89 #define SOUT_CFG_PREFIX_IN "sout-bridge-in-"
90
91 vlc_module_begin();
92     set_shortname( N_("Bridge"));
93     set_description( N_("Bridge stream output"));
94     add_submodule();
95     set_section( N_("Bridge out"), NULL );
96     set_capability( "sout stream", 50 );
97     add_shortcut( "bridge-out" );
98     /* Only usable with VLM. No category so not in gui preferences
99     set_category( CAT_SOUT );
100     set_subcategory( SUBCAT_SOUT_STREAM );*/
101     add_integer( SOUT_CFG_PREFIX_OUT "id", 0, NULL, ID_TEXT, ID_LONGTEXT,
102                  false );
103     add_string( SOUT_CFG_PREFIX_OUT "in-name", "default", NULL,
104                 DEST_TEXT, DEST_LONGTEXT, false );
105     set_callbacks( OpenOut, CloseOut );
106
107     add_submodule();
108     set_section( N_("Bridge in"), NULL );
109     set_capability( "sout stream", 50 );
110     add_shortcut( "bridge-in" );
111     /*set_category( CAT_SOUT );
112     set_subcategory( SUBCAT_SOUT_STREAM );*/
113     add_integer( SOUT_CFG_PREFIX_IN "delay", 0, NULL, DELAY_TEXT,
114                  DELAY_LONGTEXT, false );
115     add_integer( SOUT_CFG_PREFIX_IN "id-offset", 8192, NULL, ID_OFFSET_TEXT,
116                  ID_OFFSET_LONGTEXT, false );
117     add_string( SOUT_CFG_PREFIX_IN "name", "default", NULL,
118                 NAME_TEXT, NAME_LONGTEXT, false );
119     add_bool( SOUT_CFG_PREFIX_IN "placeholder", false, NULL,
120               PLACEHOLDER_TEXT, PLACEHOLDER_LONGTEXT, false );
121     add_integer( SOUT_CFG_PREFIX_IN "placeholder-delay", 200, NULL,
122                  PLACEHOLDER_DELAY_TEXT, PLACEHOLDER_DELAY_LONGTEXT, false );
123     add_bool( SOUT_CFG_PREFIX_IN "placeholder-switch-on-iframe", true, NULL,
124               PLACEHOLDER_IFRAME_TEXT, PLACEHOLDER_IFRAME_LONGTEXT, false );
125     set_callbacks( OpenIn, CloseIn );
126
127 vlc_module_end();
128
129
130 /*****************************************************************************
131  * Local prototypes
132  *****************************************************************************/
133 static const char *const ppsz_sout_options_out[] = {
134     "id", "in-name", NULL
135 };
136
137 static const char *const ppsz_sout_options_in[] = {
138     "delay", "id-offset", "name",
139     "placeholder", "placeholder-delay", "placeholder-switch-on-iframe",
140     NULL
141 };
142
143 static sout_stream_id_t *AddOut ( sout_stream_t *, es_format_t * );
144 static int               DelOut ( sout_stream_t *, sout_stream_id_t * );
145 static int               SendOut( sout_stream_t *, sout_stream_id_t *, block_t * );
146
147 static sout_stream_id_t *AddIn ( sout_stream_t *, es_format_t * );
148 static int               DelIn ( sout_stream_t *, sout_stream_id_t * );
149 static int               SendIn( sout_stream_t *, sout_stream_id_t *, block_t * );
150
151 typedef struct bridged_es_t
152 {
153     es_format_t fmt;
154     block_t *p_block;
155     block_t **pp_last;
156     bool b_empty;
157
158     /* bridge in part */
159     sout_stream_id_t *id;
160     mtime_t i_last;
161     bool b_changed;
162 } bridged_es_t;
163
164 typedef struct bridge_t
165 {
166     bridged_es_t **pp_es;
167     int i_es_num;
168 } bridge_t;
169
170 #define GetBridge(a,b) __GetBridge( VLC_OBJECT(a), b )
171 static bridge_t *__GetBridge( vlc_object_t *p_object, const char *psz_name )
172 {
173     bridge_t *p_bridge;
174     vlc_value_t val;
175
176     if( var_Get( p_object->p_libvlc, psz_name, &val ) )
177     {
178         p_bridge = NULL;
179     }
180     else
181     {
182         p_bridge = val.p_address;
183     }
184
185     return p_bridge;
186 }
187
188
189 /*
190  * Bridge out
191  */
192
193 typedef struct out_sout_stream_sys_t
194 {
195     vlc_mutex_t *p_lock;
196     bridged_es_t *p_es;
197     int i_id;
198     bool b_inited;
199
200     char *psz_name;
201 } out_sout_stream_sys_t;
202
203 /*****************************************************************************
204  * OpenOut:
205  *****************************************************************************/
206 static int OpenOut( vlc_object_t *p_this )
207 {
208     sout_stream_t     *p_stream = (sout_stream_t *)p_this;
209     out_sout_stream_sys_t *p_sys;
210     vlc_value_t val;
211
212     config_ChainParse( p_stream, SOUT_CFG_PREFIX_OUT, ppsz_sout_options_out,
213                    p_stream->p_cfg );
214
215     p_sys          = malloc( sizeof( out_sout_stream_sys_t ) );
216     p_sys->b_inited = false;
217
218     var_Create( p_this->p_libvlc, "bridge-lock", VLC_VAR_MUTEX );
219     var_Get( p_this->p_libvlc, "bridge-lock", &val );
220     p_sys->p_lock = val.p_address;
221
222     var_Get( p_stream, SOUT_CFG_PREFIX_OUT "id", &val );
223     p_sys->i_id = val.i_int;
224
225     var_Get( p_stream, SOUT_CFG_PREFIX_OUT "in-name", &val );
226     if( asprintf( &p_sys->psz_name, "bridge-struct-%s", val.psz_string )<0 )
227     {
228         free( val.psz_string );
229         free( p_sys );
230         return VLC_ENOMEM;
231     }
232     free( val.psz_string );
233
234     p_stream->pf_add    = AddOut;
235     p_stream->pf_del    = DelOut;
236     p_stream->pf_send   = SendOut;
237
238     p_stream->p_sys     = (sout_stream_sys_t *)p_sys;
239
240     p_stream->p_sout->i_out_pace_nocontrol++;
241
242     return VLC_SUCCESS;
243 }
244
245 /*****************************************************************************
246  * CloseOut:
247  *****************************************************************************/
248 static void CloseOut( vlc_object_t * p_this )
249 {
250     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
251     out_sout_stream_sys_t *p_sys = (out_sout_stream_sys_t *)p_stream->p_sys;
252
253     p_stream->p_sout->i_out_pace_nocontrol--;
254
255     free( p_sys->psz_name );
256     free( p_sys );
257 }
258
259 static sout_stream_id_t * AddOut( sout_stream_t *p_stream, es_format_t *p_fmt )
260 {
261     out_sout_stream_sys_t *p_sys = (out_sout_stream_sys_t *)p_stream->p_sys;
262     bridge_t *p_bridge;
263     bridged_es_t *p_es;
264     int i;
265
266     if ( p_sys->b_inited )
267     {
268         msg_Err( p_stream, "bridge-out can only handle 1 es at a time." );
269         return NULL;
270     }
271     p_sys->b_inited = true;
272
273     vlc_mutex_lock( p_sys->p_lock );
274
275     p_bridge = GetBridge( p_stream, p_sys->psz_name );
276     if ( p_bridge == NULL )
277     {
278         vlc_object_t *p_libvlc = VLC_OBJECT( p_stream->p_libvlc );
279         vlc_value_t val;
280
281         p_bridge = malloc( sizeof( bridge_t ) );
282
283         var_Create( p_libvlc, p_sys->psz_name, VLC_VAR_ADDRESS );
284         val.p_address = p_bridge;
285         var_Set( p_libvlc, p_sys->psz_name, val );
286
287         p_bridge->i_es_num = 0;
288         p_bridge->pp_es = NULL;
289     }
290
291     for ( i = 0; i < p_bridge->i_es_num; i++ )
292     {
293         if ( p_bridge->pp_es[i]->b_empty && !p_bridge->pp_es[i]->b_changed )
294             break;
295     }
296
297     if ( i == p_bridge->i_es_num )
298     {
299         p_bridge->pp_es = realloc( p_bridge->pp_es,
300                                    (p_bridge->i_es_num + 1)
301                                      * sizeof(bridged_es_t *) );
302         p_bridge->i_es_num++;
303         p_bridge->pp_es[i] = malloc( sizeof(bridged_es_t) );
304     }
305
306     p_sys->p_es = p_es = p_bridge->pp_es[i];
307
308     p_es->fmt = *p_fmt;
309     p_es->fmt.i_id = p_sys->i_id;
310     p_es->p_block = NULL;
311     p_es->pp_last = &p_es->p_block;
312     p_es->b_empty = false;
313
314     p_es->id = NULL;
315     p_es->i_last = 0;
316     p_es->b_changed = true;
317
318     msg_Dbg( p_stream, "bridging out input codec=%4.4s id=%d pos=%d",
319              (char*)&p_es->fmt.i_codec, p_es->fmt.i_id, i );
320
321     vlc_mutex_unlock( p_sys->p_lock );
322
323     return (sout_stream_id_t *)p_sys;
324 }
325
326 static int DelOut( sout_stream_t *p_stream, sout_stream_id_t *id )
327 {
328     VLC_UNUSED(id);
329     out_sout_stream_sys_t *p_sys = (out_sout_stream_sys_t *)p_stream->p_sys;
330     bridged_es_t *p_es;
331
332     if ( !p_sys->b_inited )
333     {
334         return VLC_SUCCESS;
335     }
336
337     vlc_mutex_lock( p_sys->p_lock );
338
339     p_es = p_sys->p_es;
340
341     p_es->b_empty = true;
342     block_ChainRelease( p_es->p_block );
343     p_es->p_block = false;
344
345     p_es->b_changed = true;
346     vlc_mutex_unlock( p_sys->p_lock );
347
348     p_sys->b_inited = false;
349
350     return VLC_SUCCESS;
351 }
352
353 static int SendOut( sout_stream_t *p_stream, sout_stream_id_t *id,
354                     block_t *p_buffer )
355 {
356     out_sout_stream_sys_t *p_sys = (out_sout_stream_sys_t *)p_stream->p_sys;
357     bridged_es_t *p_es;
358
359     if ( (out_sout_stream_sys_t *)id != p_sys )
360     {
361         block_ChainRelease( p_buffer );
362         return VLC_SUCCESS;
363     }
364
365     vlc_mutex_lock( p_sys->p_lock );
366
367     p_es = p_sys->p_es;
368     *p_es->pp_last = p_buffer;
369     while ( p_buffer != NULL )
370     {
371         p_es->pp_last = &p_buffer->p_next;
372         p_buffer = p_buffer->p_next;
373     }
374
375     vlc_mutex_unlock( p_sys->p_lock );
376
377     return VLC_SUCCESS;
378 }
379
380
381 /*
382  * Bridge in
383  */
384
385 typedef struct in_sout_stream_sys_t
386 {
387     sout_stream_t *p_out;
388     vlc_mutex_t *p_lock;
389     int i_id_offset;
390     mtime_t i_delay;
391
392     char *psz_name;
393
394     bool b_placeholder;
395     bool b_switch_on_iframe;
396     int i_state;
397     mtime_t i_placeholder_delay;
398     sout_stream_id_t *id_video;
399     mtime_t i_last_video;
400     sout_stream_id_t *id_audio;
401     mtime_t i_last_audio;
402 } in_sout_stream_sys_t;
403
404 enum { placeholder_on, placeholder_off };
405
406 /*****************************************************************************
407  * OpenIn:
408  *****************************************************************************/
409 static int OpenIn( vlc_object_t *p_this )
410 {
411     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
412     in_sout_stream_sys_t *p_sys;
413     vlc_value_t val;
414
415     p_sys          = malloc( sizeof( in_sout_stream_sys_t ) );
416
417     p_sys->p_out = sout_StreamNew( p_stream->p_sout, p_stream->psz_next );
418     if( !p_sys->p_out )
419     {
420         msg_Err( p_stream, "cannot create chain" );
421         free( p_sys );
422         return VLC_EGENERIC;
423     }
424
425     config_ChainParse( p_stream, SOUT_CFG_PREFIX_IN, ppsz_sout_options_in,
426                    p_stream->p_cfg );
427
428     var_Create( p_this->p_libvlc, "bridge-lock", VLC_VAR_MUTEX );
429     var_Get( p_this->p_libvlc, "bridge-lock", &val );
430     p_sys->p_lock = val.p_address;
431
432     var_Get( p_stream, SOUT_CFG_PREFIX_IN "id-offset", &val );
433     p_sys->i_id_offset = val.i_int;
434
435     var_Get( p_stream, SOUT_CFG_PREFIX_IN "delay", &val );
436     p_sys->i_delay = (mtime_t)val.i_int * 1000;
437
438     var_Get( p_stream, SOUT_CFG_PREFIX_IN "name", &val );
439     if( asprintf( &p_sys->psz_name, "bridge-struct-%s", val.psz_string )<0 )
440     {
441         free( val.psz_string );
442         free( p_sys );
443         return VLC_ENOMEM;
444     }
445     free( val.psz_string );
446
447     var_Get( p_stream, SOUT_CFG_PREFIX_IN "placeholder", &val );
448     p_sys->b_placeholder = val.b_bool;
449
450     var_Get( p_stream, SOUT_CFG_PREFIX_IN "placeholder-switch-on-iframe", &val);
451     p_sys->b_switch_on_iframe = val.b_bool;
452
453     p_sys->i_state = placeholder_on;
454
455     var_Get( p_stream, SOUT_CFG_PREFIX_IN "placeholder-delay", &val );
456     p_sys->i_placeholder_delay = (mtime_t)val.i_int * 1000;
457
458     p_sys->i_last_video = 0;
459     p_sys->i_last_audio = 0;
460     p_sys->id_video = NULL;
461     p_sys->id_audio = NULL;
462
463     p_stream->pf_add    = AddIn;
464     p_stream->pf_del    = DelIn;
465     p_stream->pf_send   = SendIn;
466
467     p_stream->p_sys     = (sout_stream_sys_t *)p_sys;
468
469     /* update p_sout->i_out_pace_nocontrol */
470     p_stream->p_sout->i_out_pace_nocontrol++;
471
472     return VLC_SUCCESS;
473 }
474
475 /*****************************************************************************
476  * CloseIn:
477  *****************************************************************************/
478 static void CloseIn( vlc_object_t * p_this )
479 {
480     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
481     in_sout_stream_sys_t *p_sys = (in_sout_stream_sys_t *)p_stream->p_sys;
482
483     sout_StreamDelete( p_sys->p_out );
484     p_stream->p_sout->i_out_pace_nocontrol--;
485
486     free( p_sys->psz_name );
487     free( p_sys );
488 }
489
490 struct sout_stream_id_t
491 {
492     sout_stream_id_t *id;
493     int i_cat; /* es category. Used for placeholder option */
494 };
495
496 static sout_stream_id_t * AddIn( sout_stream_t *p_stream, es_format_t *p_fmt )
497 {
498     in_sout_stream_sys_t *p_sys = (in_sout_stream_sys_t *)p_stream->p_sys;
499
500     sout_stream_id_t *id = malloc( sizeof( sout_stream_id_t ) );
501     if( !id ) return NULL;
502
503     id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
504     if( !id->id )
505     {
506         free( id );
507         return NULL;
508     }
509
510     if( p_sys->b_placeholder )
511     {
512         id->i_cat = p_fmt->i_cat;
513         switch( p_fmt->i_cat )
514         {
515             case VIDEO_ES:
516                 if( p_sys->id_video != NULL )
517                     msg_Err( p_stream, "We already had a video es!" );
518                 p_sys->id_video = id->id;
519                 break;
520             case AUDIO_ES:
521                 if( p_sys->id_audio != NULL )
522                     msg_Err( p_stream, "We already had an audio es!" );
523                 p_sys->id_audio = id->id;
524                 break;
525         }
526     }
527
528     return id;
529 }
530
531 static int DelIn( sout_stream_t *p_stream, sout_stream_id_t *id )
532 {
533     in_sout_stream_sys_t *p_sys = (in_sout_stream_sys_t *)p_stream->p_sys;
534
535     if( id == p_sys->id_video ) p_sys->id_video = NULL;
536     if( id == p_sys->id_audio ) p_sys->id_audio = NULL;
537
538     int ret = p_sys->p_out->pf_del( p_sys->p_out, id->id );
539
540     free( id );
541     return ret;
542 }
543
544 static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id,
545                    block_t *p_buffer )
546 {
547     in_sout_stream_sys_t *p_sys = (in_sout_stream_sys_t *)p_stream->p_sys;
548     bridge_t *p_bridge;
549     bool b_no_es = true;
550     int i;
551     int i_date = mdate();
552
553     /* First forward the packet for our own ES */
554     if( !p_sys->b_placeholder )
555         p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer );
556
557     /* Then check all bridged streams */
558     vlc_mutex_lock( p_sys->p_lock );
559
560     p_bridge = GetBridge( p_stream, p_sys->psz_name );
561
562     if( p_bridge )
563     {
564     for ( i = 0; i < p_bridge->i_es_num; i++ )
565     {
566         if ( !p_bridge->pp_es[i]->b_empty )
567             b_no_es = false;
568
569         while ( p_bridge->pp_es[i]->p_block != NULL
570                  && (p_bridge->pp_es[i]->p_block->i_dts + p_sys->i_delay
571                        < i_date
572                       || p_bridge->pp_es[i]->p_block->i_dts + p_sys->i_delay
573                           < p_bridge->pp_es[i]->i_last) )
574         {
575             block_t *p_block = p_bridge->pp_es[i]->p_block;
576             msg_Dbg( p_stream, "dropping a packet (%"PRId64 ")",
577                      i_date - p_block->i_dts - p_sys->i_delay );
578             p_bridge->pp_es[i]->p_block
579                 = p_bridge->pp_es[i]->p_block->p_next;
580             block_Release( p_block );
581         }
582
583         if ( p_bridge->pp_es[i]->p_block == NULL )
584         {
585             p_bridge->pp_es[i]->pp_last = &p_bridge->pp_es[i]->p_block;
586         }
587
588         if ( p_bridge->pp_es[i]->b_changed )
589         {
590             if ( p_bridge->pp_es[i]->b_empty && p_bridge->pp_es[i]->id != NULL )
591             {
592                 p_sys->p_out->pf_del( p_sys->p_out, p_bridge->pp_es[i]->id );
593             }
594             else
595             {
596                 /* We need at least two packets to enter the mux. */
597                 if ( p_bridge->pp_es[i]->p_block == NULL
598                       || p_bridge->pp_es[i]->p_block->p_next == NULL )
599                 {
600                     continue;
601                 }
602
603                 p_bridge->pp_es[i]->fmt.i_id += p_sys->i_id_offset;
604                 if( !p_sys->b_placeholder )
605                 {
606                     p_bridge->pp_es[i]->id = p_sys->p_out->pf_add(
607                                 p_sys->p_out, &p_bridge->pp_es[i]->fmt );
608                     if ( p_bridge->pp_es[i]->id == NULL )
609                     {
610                         msg_Warn( p_stream, "couldn't create chain for id %d",
611                                   p_bridge->pp_es[i]->fmt.i_id );
612                     }
613                 }
614                 msg_Dbg( p_stream, "bridging in input codec=%4.4s id=%d pos=%d",
615                          (char*)&p_bridge->pp_es[i]->fmt.i_codec,
616                          p_bridge->pp_es[i]->fmt.i_id, i );
617             }
618         }
619         p_bridge->pp_es[i]->b_changed = false;
620
621         if ( p_bridge->pp_es[i]->b_empty )
622             continue;
623
624         if ( p_bridge->pp_es[i]->p_block == NULL )
625         {
626             if ( p_bridge->pp_es[i]->id != NULL
627                   && p_bridge->pp_es[i]->i_last < i_date )
628             {
629                 if( !p_sys->b_placeholder )
630                     p_sys->p_out->pf_del( p_sys->p_out,
631                                           p_bridge->pp_es[i]->id );
632                 p_bridge->pp_es[i]->fmt.i_id -= p_sys->i_id_offset;
633                 p_bridge->pp_es[i]->b_changed = true;
634                 p_bridge->pp_es[i]->id = NULL;
635             }
636             continue;
637         }
638
639         if ( p_bridge->pp_es[i]->id != NULL || p_sys->b_placeholder)
640         {
641             block_t *p_block = p_bridge->pp_es[i]->p_block;
642             while ( p_block != NULL )
643             {
644                 p_bridge->pp_es[i]->i_last = p_block->i_dts;
645                 p_block->i_pts += p_sys->i_delay;
646                 p_block->i_dts += p_sys->i_delay;
647                 p_block = p_block->p_next;
648             }
649             sout_stream_id_t *newid = NULL;
650             if( p_sys->b_placeholder )
651             {
652                 switch( p_bridge->pp_es[i]->fmt.i_cat )
653                 {
654                     case VIDEO_ES:
655                         p_sys->i_last_video = i_date;
656                         newid = p_sys->id_video;
657                         if( !newid )
658                             break;
659                         if( !p_sys->b_switch_on_iframe ||
660                             p_sys->i_state == placeholder_off ||
661                             ( p_bridge->pp_es[i]->fmt.i_cat == VIDEO_ES &&
662                               p_bridge->pp_es[i]->p_block->i_flags & BLOCK_FLAG_TYPE_I ) )
663                         {
664                             p_sys->p_out->pf_send( p_sys->p_out,
665                                        newid,
666                                        p_bridge->pp_es[i]->p_block );
667                             p_sys->i_state = placeholder_off;
668                         }
669                         break;
670                     case AUDIO_ES:
671                         newid = p_sys->id_audio;
672                         if( !newid )
673                             break;
674                         p_sys->i_last_audio = i_date;
675                     default:
676                         p_sys->p_out->pf_send( p_sys->p_out,
677                                    newid?newid:p_bridge->pp_es[i]->id,
678                                    p_bridge->pp_es[i]->p_block );
679                         break;
680                 }
681             }
682             else /* !b_placeholder */
683                 p_sys->p_out->pf_send( p_sys->p_out,
684                                        p_bridge->pp_es[i]->id,
685                                        p_bridge->pp_es[i]->p_block );
686         }
687         else
688         {
689             block_ChainRelease( p_bridge->pp_es[i]->p_block );
690         }
691
692         p_bridge->pp_es[i]->p_block = NULL;
693         p_bridge->pp_es[i]->pp_last = &p_bridge->pp_es[i]->p_block;
694     }
695
696     if( b_no_es )
697     {
698         vlc_object_t *p_libvlc = VLC_OBJECT( p_stream->p_libvlc );
699         for ( i = 0; i < p_bridge->i_es_num; i++ )
700             free( p_bridge->pp_es[i] );
701         free( p_bridge->pp_es );
702         free( p_bridge );
703         var_Destroy( p_libvlc, p_sys->psz_name );
704     }
705     }
706
707     if( p_sys->b_placeholder )
708     {
709         switch( id->i_cat )
710         {
711             case VIDEO_ES:
712                 if( ( p_sys->i_last_video + p_sys->i_placeholder_delay < i_date
713                     && (  !p_sys->b_switch_on_iframe
714                        || p_buffer->i_flags & BLOCK_FLAG_TYPE_I ) )
715                   || p_sys->i_state == placeholder_on )
716                 {
717                     p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer );
718                     p_sys->i_state = placeholder_on;
719                 }
720                 else
721                     block_Release( p_buffer );
722                 break;
723
724             case AUDIO_ES:
725                 if( p_sys->i_last_audio + p_sys->i_placeholder_delay < i_date )
726                     p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer );
727                 else
728                     block_Release( p_buffer );
729                 break;
730
731             default:
732                 block_Release( p_buffer ); /* FIXME: placeholder subs anyone? */
733                 break;
734         }
735     }
736
737     vlc_mutex_unlock( p_sys->p_lock );
738
739     return VLC_SUCCESS;
740 }
Note: See TracBrowser for help on using the browser.