]> git.sesse.net Git - vlc/blob - modules/stream_out/mosaic_bridge.c
Remove stdlib.h
[vlc] / modules / stream_out / mosaic_bridge.c
1 /*****************************************************************************
2  * mosaic_bridge.c:
3  *****************************************************************************
4  * Copyright (C) 2004-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea@videolan.org>
8  *          Christophe Massiot <massiot@via.ecp.fr>
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 #include <errno.h>                                                 /* ENOMEM */
29 #include <string.h>                                            /* strerror() */
30
31 #include <vlc/vlc.h>
32 #include <vlc_sout.h>
33 #include <vlc_block.h>
34 #include <vlc_codec.h>
35
36 #include <vlc_image.h>
37 #include <vlc_filter.h>
38
39 #include "../video_filter/mosaic.h"
40
41 /*****************************************************************************
42  * Local structures
43  *****************************************************************************/
44 struct sout_stream_sys_t
45 {
46     bridged_es_t *p_es;
47     vlc_mutex_t *p_lock;
48
49     decoder_t       *p_decoder;
50     image_handler_t *p_image; /* filter for resizing */
51     int i_height, i_width;
52     unsigned int i_sar_num, i_sar_den;
53     char *psz_id;
54     vlc_bool_t b_inited;
55
56     int i_chroma; /* force image format chroma */
57
58     filter_t **pp_vfilters;
59     int i_vfilters;
60 };
61
62 #define PICTURE_RING_SIZE 4
63 struct decoder_owner_sys_t
64 {
65     picture_t *pp_pics[PICTURE_RING_SIZE];
66
67     /* Current format in use by the output */
68     video_format_t video;
69 };
70
71 typedef void (* pf_release_t)( picture_t * );
72 static void ReleasePicture( picture_t *p_pic )
73 {
74     p_pic->i_refcount--;
75
76     if ( p_pic->i_refcount <= 0 )
77     {
78         if ( p_pic->p_sys != NULL )
79         {
80             pf_release_t pf_release = (pf_release_t)p_pic->p_sys;
81             p_pic->p_sys = NULL;
82             pf_release( p_pic );
83         }
84         else
85         {
86             if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig );
87             if( p_pic ) free( p_pic );
88         }
89     }
90 }
91
92 /*****************************************************************************
93  * Local prototypes
94  *****************************************************************************/
95 static int  Open    ( vlc_object_t * );
96 static void Close   ( vlc_object_t * );
97 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
98 static int               Del ( sout_stream_t *, sout_stream_id_t * );
99 static int               Send( sout_stream_t *, sout_stream_id_t *, block_t * );
100
101 inline static void video_del_buffer_decoder( decoder_t *, picture_t * );
102 inline static void video_del_buffer_filter( filter_t *, picture_t * );
103 static void video_del_buffer( vlc_object_t *, picture_t * );
104
105 inline static picture_t *video_new_buffer_decoder( decoder_t * );
106 inline static picture_t *video_new_buffer_filter( filter_t * );
107 static picture_t *video_new_buffer( vlc_object_t *, decoder_owner_sys_t *,
108                                     es_format_t *, void (*)( picture_t * ) );
109
110 static void video_link_picture_decoder( decoder_t *, picture_t * );
111 static void video_unlink_picture_decoder( decoder_t *, picture_t * );
112 static int MosaicBridgeCallback( vlc_object_t *, char const *,
113                                  vlc_value_t, vlc_value_t, void * );
114
115 /*****************************************************************************
116  * Module descriptor
117  *****************************************************************************/
118 #define ID_TEXT N_("ID")
119 #define ID_LONGTEXT N_( \
120     "Specify an identifier string for this subpicture" )
121
122 #define WIDTH_TEXT N_("Video width")
123 #define WIDTH_LONGTEXT N_( \
124     "Output video width." )
125 #define HEIGHT_TEXT N_("Video height")
126 #define HEIGHT_LONGTEXT N_( \
127     "Output video height." )
128 #define RATIO_TEXT N_("Sample aspect ratio")
129 #define RATIO_LONGTEXT N_( \
130     "Sample aspect ratio of the destination (1:1, 3:4, 2:3)." )
131
132 #define VFILTER_TEXT N_("Video filter")
133 #define VFILTER_LONGTEXT N_( \
134     "Video filters will be applied to the video stream." );
135
136 #define CHROMA_TEXT N_("Image chroma")
137 #define CHROMA_LONGTEXT N_( \
138     "Force the use of a specific chroma. Use YUVA if you're planning " \
139     "to use the Alphamask or Bluescreen video filter." );
140
141 #define CFG_PREFIX "sout-mosaic-bridge-"
142
143 vlc_module_begin();
144     set_shortname( _( "Mosaic bridge" ) );
145     set_description(_("Mosaic bridge stream output") );
146     set_capability( "sout stream", 0 );
147     add_shortcut( "mosaic-bridge" );
148
149     add_string( CFG_PREFIX "id", "Id", NULL, ID_TEXT, ID_LONGTEXT,
150                 VLC_FALSE );
151     add_integer( CFG_PREFIX "width", 0, NULL, WIDTH_TEXT,
152                  WIDTH_LONGTEXT, VLC_TRUE );
153     add_integer( CFG_PREFIX "height", 0, NULL, HEIGHT_TEXT,
154                  HEIGHT_LONGTEXT, VLC_TRUE );
155     add_string( CFG_PREFIX "sar", "1:1", NULL, RATIO_TEXT,
156                 RATIO_LONGTEXT, VLC_FALSE );
157     add_string( CFG_PREFIX "chroma", 0, NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
158                 VLC_FALSE );
159
160     add_module_list( CFG_PREFIX "vfilter", "video filter2",
161                      NULL, NULL, VFILTER_TEXT, VFILTER_LONGTEXT, VLC_FALSE );
162
163     set_callbacks( Open, Close );
164 vlc_module_end();
165
166 static const char *ppsz_sout_options[] = {
167     "id", "width", "height", "sar", "vfilter", "chroma", NULL
168 };
169
170 /*****************************************************************************
171  * Open
172  *****************************************************************************/
173 static int Open( vlc_object_t *p_this )
174 {
175     sout_stream_t        *p_stream = (sout_stream_t *)p_this;
176     sout_stream_sys_t    *p_sys;
177     vlc_object_t         *p_libvlc = p_this->p_libvlc;
178     vlc_value_t           val;
179
180     config_ChainParse( p_stream, CFG_PREFIX, ppsz_sout_options,
181                        p_stream->p_cfg );
182
183     p_sys = malloc( sizeof( sout_stream_sys_t ) );
184     if( !p_sys )
185     {
186         return VLC_ENOMEM;
187     }
188
189     p_stream->p_sys = p_sys;
190     p_sys->b_inited = VLC_FALSE;
191
192     var_Create( p_libvlc, "mosaic-lock", VLC_VAR_MUTEX );
193     var_Get( p_libvlc, "mosaic-lock", &val );
194     p_sys->p_lock = val.p_address;
195
196     var_Get( p_stream, CFG_PREFIX "id", &val );
197     p_sys->psz_id = val.psz_string;
198
199     p_sys->i_height =
200         var_CreateGetIntegerCommand( p_stream, CFG_PREFIX "height" );
201     var_AddCallback( p_stream, CFG_PREFIX "height", MosaicBridgeCallback,
202                      p_stream );
203
204     p_sys->i_width =
205         var_CreateGetIntegerCommand( p_stream, CFG_PREFIX "width" );
206     var_AddCallback( p_stream, CFG_PREFIX "width", MosaicBridgeCallback,
207                      p_stream );
208
209     var_Get( p_stream, CFG_PREFIX "sar", &val );
210     if ( val.psz_string )
211     {
212         char *psz_parser = strchr( val.psz_string, ':' );
213
214         if( psz_parser )
215         {
216             *psz_parser++ = '\0';
217             p_sys->i_sar_num = atoi( val.psz_string );
218             p_sys->i_sar_den = atoi( psz_parser );
219             vlc_ureduce( &p_sys->i_sar_num, &p_sys->i_sar_den,
220                          p_sys->i_sar_num, p_sys->i_sar_den, 0 );
221         }
222         else
223         {
224             msg_Warn( p_stream, "bad aspect ratio %s", val.psz_string );
225             p_sys->i_sar_num = p_sys->i_sar_den = 1;
226         }
227
228         free( val.psz_string );
229     }
230     else
231     {
232         p_sys->i_sar_num = p_sys->i_sar_den = 1;
233     }
234
235     p_sys->i_chroma = 0;
236     val.psz_string = var_GetNonEmptyString( p_stream, CFG_PREFIX "chroma" );
237     if( val.psz_string && strlen( val.psz_string ) >= 4 )
238     {
239         memcpy( &p_sys->i_chroma, val.psz_string, 4 );
240         msg_Dbg( p_stream, "Forcing image chroma to 0x%.8x (%4.4s)", p_sys->i_chroma, (char*)&p_sys->i_chroma );
241     }
242
243     p_stream->pf_add    = Add;
244     p_stream->pf_del    = Del;
245     p_stream->pf_send   = Send;
246
247     p_stream->p_sout->i_out_pace_nocontrol++;
248
249     return VLC_SUCCESS;
250 }
251
252 /*****************************************************************************
253  * Close
254  *****************************************************************************/
255 static void Close( vlc_object_t * p_this )
256 {
257     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
258     sout_stream_sys_t *p_sys = p_stream->p_sys;
259
260     p_stream->p_sout->i_out_pace_nocontrol--;
261
262     if ( p_sys->psz_id )
263         free( p_sys->psz_id );
264
265     free( p_sys );
266 }
267
268 static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
269 {
270     sout_stream_sys_t *p_sys = p_stream->p_sys;
271     bridge_t *p_bridge;
272     bridged_es_t *p_es;
273     char *psz_chain, *psz_parser;
274     int i;
275
276     if ( p_sys->b_inited )
277     {
278         return NULL;
279     }
280
281     /* Create decoder object */
282     p_sys->p_decoder = vlc_object_create( p_stream, VLC_OBJECT_DECODER );
283     vlc_object_attach( p_sys->p_decoder, p_stream );
284     p_sys->p_decoder->p_module = NULL;
285     p_sys->p_decoder->fmt_in = *p_fmt;
286     p_sys->p_decoder->b_pace_control = VLC_FALSE;
287     p_sys->p_decoder->fmt_out = p_sys->p_decoder->fmt_in;
288     p_sys->p_decoder->fmt_out.i_extra = 0;
289     p_sys->p_decoder->fmt_out.p_extra = 0;
290     p_sys->p_decoder->pf_decode_video = 0;
291     p_sys->p_decoder->pf_vout_buffer_new = video_new_buffer_decoder;
292     p_sys->p_decoder->pf_vout_buffer_del = video_del_buffer_decoder;
293     p_sys->p_decoder->pf_picture_link    = video_link_picture_decoder;
294     p_sys->p_decoder->pf_picture_unlink  = video_unlink_picture_decoder;
295     p_sys->p_decoder->p_owner = malloc( sizeof(decoder_owner_sys_t) );
296     for( i = 0; i < PICTURE_RING_SIZE; i++ )
297         p_sys->p_decoder->p_owner->pp_pics[i] = 0;
298     p_sys->p_decoder->p_owner->video = p_fmt->video;
299     //p_sys->p_decoder->p_cfg = p_sys->p_video_cfg;
300
301     p_sys->p_decoder->p_module =
302         module_Need( p_sys->p_decoder, "decoder", "$codec", 0 );
303
304     if( !p_sys->p_decoder->p_module )
305     {
306         msg_Err( p_stream, "cannot find decoder" );
307         vlc_object_detach( p_sys->p_decoder );
308         vlc_object_destroy( p_sys->p_decoder );
309         return NULL;
310     }
311
312     p_sys->b_inited = VLC_TRUE;
313     vlc_mutex_lock( p_sys->p_lock );
314
315     p_bridge = GetBridge( p_stream );
316     if ( p_bridge == NULL )
317     {
318         vlc_object_t *p_libvlc = p_stream->p_libvlc;
319         vlc_value_t val;
320
321         p_bridge = malloc( sizeof( bridge_t ) );
322
323         var_Create( p_libvlc, "mosaic-struct", VLC_VAR_ADDRESS );
324         val.p_address = p_bridge;
325         var_Set( p_libvlc, "mosaic-struct", val );
326
327         p_bridge->i_es_num = 0;
328         p_bridge->pp_es = NULL;
329     }
330
331     for ( i = 0; i < p_bridge->i_es_num; i++ )
332     {
333         if ( p_bridge->pp_es[i]->b_empty )
334             break;
335     }
336
337     if ( i == p_bridge->i_es_num )
338     {
339         p_bridge->pp_es = realloc( p_bridge->pp_es,
340                                    (p_bridge->i_es_num + 1)
341                                      * sizeof(bridged_es_t *) );
342         p_bridge->i_es_num++;
343         p_bridge->pp_es[i] = malloc( sizeof(bridged_es_t) );
344     }
345
346     p_sys->p_es = p_es = p_bridge->pp_es[i];
347
348     //p_es->fmt = *p_fmt;
349     p_es->psz_id = p_sys->psz_id;
350     p_es->p_picture = NULL;
351     p_es->pp_last = &p_es->p_picture;
352     p_es->b_empty = VLC_FALSE;
353
354     vlc_mutex_unlock( p_sys->p_lock );
355
356     if ( p_sys->i_height || p_sys->i_width )
357     {
358         p_sys->p_image = image_HandlerCreate( p_stream );
359     }
360     else
361     {
362         p_sys->p_image = NULL;
363     }
364
365     msg_Dbg( p_stream, "mosaic bridge id=%s pos=%d", p_es->psz_id, i );
366
367     /* Create user specified video filters */
368     psz_chain = var_GetNonEmptyString( p_stream, CFG_PREFIX "vfilter" );
369     msg_Dbg( p_stream, "psz_chain: %s\n", psz_chain );
370     {
371         config_chain_t *p_cfg;
372         for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
373         {
374             msg_Dbg( p_stream, " - %s\n", p_cfg->psz_value );
375         }
376     }
377     p_sys->i_vfilters = 0;
378     p_sys->pp_vfilters = NULL;
379     psz_parser = psz_chain;
380     while( psz_parser && *psz_parser )
381     {
382         config_chain_t *p_cfg;
383         char *psz_name;
384         filter_t **pp_vfilter;
385         psz_parser = config_ChainCreate( &psz_name, &p_cfg, psz_parser );
386         p_sys->i_vfilters++;
387         p_sys->pp_vfilters =
388             (filter_t **)realloc( p_sys->pp_vfilters,
389                                   p_sys->i_vfilters * sizeof(filter_t *) );
390         pp_vfilter = p_sys->pp_vfilters+(p_sys->i_vfilters - 1);
391         *pp_vfilter = vlc_object_create( p_stream, VLC_OBJECT_FILTER );
392         vlc_object_attach( *pp_vfilter, p_stream );
393         (*pp_vfilter)->pf_vout_buffer_new = video_new_buffer_filter;
394         (*pp_vfilter)->pf_vout_buffer_del = video_del_buffer_filter;
395         (*pp_vfilter)->fmt_in = p_sys->p_decoder->fmt_out;
396         if( p_sys->i_chroma )
397             (*pp_vfilter)->fmt_in.video.i_chroma = p_sys->i_chroma;
398         (*pp_vfilter)->fmt_out = (*pp_vfilter)->fmt_in;
399         (*pp_vfilter)->p_cfg = p_cfg;
400         (*pp_vfilter)->p_module =
401             module_Need( *pp_vfilter, "video filter2", psz_name, VLC_TRUE );
402         if( (*pp_vfilter)->p_module )
403         {
404             /* It worked! */
405             (*pp_vfilter)->p_owner = (filter_owner_sys_t *)
406                 p_sys->p_decoder->p_owner;
407             msg_Err( p_stream, "Added video filter %s to the chain",
408                      psz_name );
409         }
410         else
411         {
412             /* Crap ... we didn't find a filter */
413             msg_Warn( p_stream,
414                       "no video filter matching name \"%s\" found",
415                       psz_name );
416             vlc_object_detach( *pp_vfilter );
417             vlc_object_destroy( *pp_vfilter );
418             p_sys->i_vfilters--;
419         }
420     }
421     free( psz_chain );
422
423     return (sout_stream_id_t *)p_sys;
424 }
425
426 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
427 {
428     sout_stream_sys_t *p_sys = p_stream->p_sys;
429     bridge_t *p_bridge;
430     bridged_es_t *p_es;
431     vlc_bool_t b_last_es = VLC_TRUE;
432     filter_t **pp_vfilter, **pp_end;
433     int i;
434
435     if ( !p_sys->b_inited )
436     {
437         return VLC_SUCCESS;
438     }
439
440     if ( p_sys->p_decoder != NULL )
441     {
442         picture_t **pp_ring = p_sys->p_decoder->p_owner->pp_pics;
443
444         if( p_sys->p_decoder->p_module )
445             module_Unneed( p_sys->p_decoder, p_sys->p_decoder->p_module );
446         vlc_object_detach( p_sys->p_decoder );
447         vlc_object_destroy( p_sys->p_decoder );
448
449         for( i = 0; i < PICTURE_RING_SIZE; i++ )
450         {
451             if ( pp_ring[i] != NULL )
452             {
453                 if ( pp_ring[i]->p_data_orig != NULL )
454                     free( pp_ring[i]->p_data_orig );
455                 free( pp_ring[i]->p_sys );
456                 free( pp_ring[i] );
457             }
458         }
459     }
460
461     /* Destroy user specified video filters */
462     pp_vfilter = p_sys->pp_vfilters;
463     pp_end = pp_vfilter + p_sys->i_vfilters;
464     for( ; pp_vfilter < pp_end; pp_vfilter++ )
465     {
466         vlc_object_detach( *pp_vfilter );
467         if( (*pp_vfilter)->p_module )
468             module_Unneed( *pp_vfilter, (*pp_vfilter)->p_module );
469         vlc_object_destroy( *pp_vfilter );
470     }
471     free( p_sys->pp_vfilters );
472
473     vlc_mutex_lock( p_sys->p_lock );
474
475     p_bridge = GetBridge( p_stream );
476     p_es = p_sys->p_es;
477
478     p_es->b_empty = VLC_TRUE;
479     while ( p_es->p_picture )
480     {
481         picture_t *p_next = p_es->p_picture->p_next;
482         p_es->p_picture->pf_release( p_es->p_picture );
483         p_es->p_picture = p_next;
484     }
485
486     for ( i = 0; i < p_bridge->i_es_num; i++ )
487     {
488         if ( !p_bridge->pp_es[i]->b_empty )
489         {
490             b_last_es = VLC_FALSE;
491             break;
492         }
493     }
494
495     if ( b_last_es )
496     {
497         vlc_object_t *p_libvlc = p_stream->p_libvlc;
498         for ( i = 0; i < p_bridge->i_es_num; i++ )
499             free( p_bridge->pp_es[i] );
500         free( p_bridge->pp_es );
501         free( p_bridge );
502         var_Destroy( p_libvlc, "mosaic-struct" );
503     }
504
505     vlc_mutex_unlock( p_sys->p_lock );
506
507     if ( p_sys->p_image )
508     {
509         image_HandlerDelete( p_sys->p_image );
510     }
511
512     p_sys->b_inited = VLC_FALSE;
513
514     return VLC_SUCCESS;
515 }
516
517 /*****************************************************************************
518  * PushPicture : push a picture in the mosaic-struct structure
519  *****************************************************************************/
520 static void PushPicture( sout_stream_t *p_stream, picture_t *p_picture )
521 {
522     sout_stream_sys_t *p_sys = p_stream->p_sys;
523     bridged_es_t *p_es = p_sys->p_es;
524
525     vlc_mutex_lock( p_sys->p_lock );
526
527     *p_es->pp_last = p_picture;
528     p_picture->p_next = NULL;
529     p_es->pp_last = &p_picture->p_next;
530
531     vlc_mutex_unlock( p_sys->p_lock );
532 }
533
534 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
535                  block_t *p_buffer )
536 {
537     sout_stream_sys_t *p_sys = p_stream->p_sys;
538     picture_t *p_pic;
539
540     if ( (sout_stream_sys_t *)id != p_sys )
541     {
542         block_ChainRelease( p_buffer );
543         return VLC_SUCCESS;
544     }
545
546     while ( (p_pic = p_sys->p_decoder->pf_decode_video( p_sys->p_decoder,
547                                                         &p_buffer )) )
548     {
549         picture_t *p_new_pic;
550
551         if( p_sys->i_height || p_sys->i_width )
552         {
553             video_format_t fmt_out, fmt_in;
554
555             memset( &fmt_in, 0, sizeof(video_format_t) );
556             memset( &fmt_out, 0, sizeof(video_format_t) );
557             fmt_in = p_sys->p_decoder->fmt_out.video;
558
559
560             if( p_sys->i_chroma )
561                 fmt_out.i_chroma = p_sys->i_chroma;
562             else
563                 fmt_out.i_chroma = VLC_FOURCC('I','4','2','0');
564
565             if ( !p_sys->i_height )
566             {
567                 fmt_out.i_width = p_sys->i_width;
568                 fmt_out.i_height = (p_sys->i_width * VOUT_ASPECT_FACTOR
569                     * p_sys->i_sar_num / p_sys->i_sar_den / fmt_in.i_aspect)
570                       & ~0x1;
571             }
572             else if ( !p_sys->i_width )
573             {
574                 fmt_out.i_height = p_sys->i_height;
575                 fmt_out.i_width = (p_sys->i_height * fmt_in.i_aspect
576                     * p_sys->i_sar_den / p_sys->i_sar_num / VOUT_ASPECT_FACTOR)
577                       & ~0x1;
578             }
579             else
580             {
581                 fmt_out.i_width = p_sys->i_width;
582                 fmt_out.i_height = p_sys->i_height;
583             }
584             fmt_out.i_visible_width = fmt_out.i_width;
585             fmt_out.i_visible_height = fmt_out.i_height;
586
587             p_new_pic = image_Convert( p_sys->p_image,
588                                        p_pic, &fmt_in, &fmt_out );
589             if ( p_new_pic == NULL )
590             {
591                 msg_Err( p_stream, "image conversion failed" );
592                 continue;
593             }
594         }
595         else
596         {
597             /* TODO: chroma conversion if needed */
598
599             p_new_pic = (picture_t*)malloc( sizeof(picture_t) );
600             if( p_new_pic == NULL )
601             {
602                 msg_Err( p_stream, "image conversion failed" );
603                 continue;
604             }
605
606             if( vout_AllocatePicture(
607                                   p_stream, p_new_pic, p_pic->format.i_chroma,
608                                   p_pic->format.i_width, p_pic->format.i_height,
609                                   p_sys->p_decoder->fmt_out.video.i_aspect )
610                 != VLC_SUCCESS )
611             {
612                 free( p_new_pic );
613                 msg_Err( p_stream, "image allocation failed" );
614                 continue;
615             }
616
617             vout_CopyPicture( p_stream, p_new_pic, p_pic );
618         }
619
620         p_new_pic->i_refcount = 1;
621         p_new_pic->i_status = DESTROYED_PICTURE;
622         p_new_pic->i_type   = DIRECT_PICTURE;
623         p_new_pic->p_sys = (picture_sys_t *)p_new_pic->pf_release;
624         p_new_pic->pf_release = ReleasePicture;
625         p_new_pic->date = p_pic->date;
626         p_pic->pf_release( p_pic );
627
628         if( p_sys->pp_vfilters )
629         {
630             /* Apply user specified video filters */
631             filter_t **pp_vfilter = p_sys->pp_vfilters;
632             filter_t **pp_end = pp_vfilter + p_sys->i_vfilters;
633             for( ; pp_vfilter < pp_end; pp_vfilter++ )
634             {
635                 (*pp_vfilter)->fmt_in.i_codec = p_new_pic->format.i_chroma;
636                 (*pp_vfilter)->fmt_out.i_codec = p_new_pic->format.i_chroma;
637                 (*pp_vfilter)->fmt_in.video = p_new_pic->format;
638                 (*pp_vfilter)->fmt_out.video = p_new_pic->format;
639                 p_new_pic = (*pp_vfilter)->pf_video_filter( *pp_vfilter,
640                                                              p_new_pic );
641                 if( !p_new_pic )
642                 {
643                     msg_Err( p_stream, "video filter failed" );
644                     break;
645                 }
646             }
647             if( !p_new_pic ) continue;
648         }
649
650         PushPicture( p_stream, p_new_pic );
651     }
652
653     return VLC_SUCCESS;
654 }
655
656 struct picture_sys_t
657 {
658     vlc_object_t *p_owner;
659     vlc_bool_t b_dead;
660 };
661
662 static void video_release_buffer_decoder( picture_t *p_pic )
663 {
664     if( p_pic && !p_pic->i_refcount && p_pic->pf_release && p_pic->p_sys )
665     {
666         video_del_buffer_decoder( (decoder_t *)p_pic->p_sys->p_owner, p_pic );
667     }
668     else if( p_pic && p_pic->i_refcount > 0 ) p_pic->i_refcount--;
669 }
670
671 static void video_release_buffer_filter( picture_t *p_pic )
672 {
673     if( p_pic && !p_pic->i_refcount && p_pic->pf_release && p_pic->p_sys )
674     {
675         video_del_buffer_filter( (filter_t *)p_pic->p_sys->p_owner, p_pic );
676     }
677     else if( p_pic && p_pic->i_refcount > 0 ) p_pic->i_refcount--;
678 }
679
680 inline static picture_t *video_new_buffer_decoder( decoder_t *p_dec )
681 {
682     return video_new_buffer( VLC_OBJECT( p_dec ),
683                              (decoder_owner_sys_t *)p_dec->p_owner,
684                              &p_dec->fmt_out,
685                              video_release_buffer_decoder );
686 }
687
688 inline static picture_t *video_new_buffer_filter( filter_t *p_filter )
689 {
690     return video_new_buffer( VLC_OBJECT( p_filter ),
691                              (decoder_owner_sys_t *)p_filter->p_owner,
692                              &p_filter->fmt_out,
693                              video_release_buffer_filter );
694 }
695
696 static picture_t *video_new_buffer( vlc_object_t *p_this,
697                                     decoder_owner_sys_t *p_sys,
698                                     es_format_t *fmt_out,
699                                     void ( *pf_release )( picture_t * ) )
700 {
701     picture_t **pp_ring = p_sys->pp_pics;
702     picture_t *p_pic;
703     int i;
704
705     if( fmt_out->video.i_width != p_sys->video.i_width ||
706         fmt_out->video.i_height != p_sys->video.i_height ||
707         fmt_out->video.i_chroma != p_sys->video.i_chroma ||
708         fmt_out->video.i_aspect != p_sys->video.i_aspect )
709     {
710         if( !fmt_out->video.i_sar_num ||
711             !fmt_out->video.i_sar_den )
712         {
713             fmt_out->video.i_sar_num =
714                 fmt_out->video.i_aspect * fmt_out->video.i_height;
715
716             fmt_out->video.i_sar_den =
717                 VOUT_ASPECT_FACTOR * fmt_out->video.i_width;
718         }
719
720         vlc_ureduce( &fmt_out->video.i_sar_num,
721                      &fmt_out->video.i_sar_den,
722                      fmt_out->video.i_sar_num,
723                      fmt_out->video.i_sar_den, 0 );
724
725         if( !fmt_out->video.i_visible_width ||
726             !fmt_out->video.i_visible_height )
727         {
728             fmt_out->video.i_visible_width = fmt_out->video.i_width;
729             fmt_out->video.i_visible_height = fmt_out->video.i_height;
730         }
731
732         fmt_out->video.i_chroma = fmt_out->i_codec;
733         p_sys->video = fmt_out->video;
734
735         for( i = 0; i < PICTURE_RING_SIZE; i++ )
736         {
737             if ( pp_ring[i] != NULL )
738             {
739                 if ( pp_ring[i]->i_status == DESTROYED_PICTURE )
740                 {
741                     if ( pp_ring[i]->p_data_orig != NULL )
742                         free( pp_ring[i]->p_data_orig );
743                     free( pp_ring[i]->p_sys );
744                     free( pp_ring[i] );
745                 }
746                 else
747                 {
748                     pp_ring[i]->p_sys->b_dead = VLC_TRUE;
749                 }
750                 pp_ring[i] = NULL;
751             }
752         }
753     }
754
755     /* Find an empty space in the picture ring buffer */
756     for( i = 0; i < PICTURE_RING_SIZE; i++ )
757     {
758         if( pp_ring[i] != NULL && pp_ring[i]->i_status == DESTROYED_PICTURE )
759         {
760             pp_ring[i]->i_status = RESERVED_PICTURE;
761             return pp_ring[i];
762         }
763     }
764     for( i = 0; i < PICTURE_RING_SIZE; i++ )
765     {
766         if( pp_ring[i] == NULL ) break;
767     }
768
769     if( i == PICTURE_RING_SIZE )
770     {
771         msg_Err( p_this, "decoder/filter is leaking pictures, "
772                  "resetting its ring buffer" );
773
774         for( i = 0; i < PICTURE_RING_SIZE; i++ )
775         {
776             pp_ring[i]->pf_release( pp_ring[i] );
777         }
778
779         i = 0;
780     }
781
782     p_pic = malloc( sizeof(picture_t) );
783     fmt_out->video.i_chroma = fmt_out->i_codec;
784     vout_AllocatePicture( p_this, p_pic,
785                           fmt_out->video.i_chroma,
786                           fmt_out->video.i_width,
787                           fmt_out->video.i_height,
788                           fmt_out->video.i_aspect );
789
790     if( !p_pic->i_planes )
791     {
792         free( p_pic );
793         return NULL;
794     }
795
796     p_pic->pf_release = pf_release;
797     p_pic->p_sys = malloc( sizeof(picture_sys_t) );
798     p_pic->p_sys->p_owner = p_this;
799     p_pic->p_sys->b_dead = VLC_FALSE;
800     p_pic->i_status = RESERVED_PICTURE;
801
802     pp_ring[i] = p_pic;
803
804     return p_pic;
805 }
806
807 inline static void video_del_buffer_decoder( decoder_t *p_this,
808                                              picture_t *p_pic )
809 {
810     video_del_buffer( VLC_OBJECT( p_this ), p_pic );
811 }
812
813 inline static void video_del_buffer_filter( filter_t *p_this,
814                                             picture_t *p_pic )
815 {
816     video_del_buffer( VLC_OBJECT( p_this ), p_pic );
817 }
818
819 static void video_del_buffer( vlc_object_t *p_this, picture_t *p_pic )
820 {
821     p_pic->i_refcount = 0;
822     p_pic->i_status = DESTROYED_PICTURE;
823     if ( p_pic->p_sys->b_dead )
824     {
825         if ( p_pic->p_data_orig != NULL )
826             free( p_pic->p_data_orig );
827         free( p_pic->p_sys );
828         free( p_pic );
829     }
830 }
831
832 static void video_link_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
833 {
834     p_pic->i_refcount++;
835 }
836
837 static void video_unlink_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
838 {
839     video_release_buffer_decoder( p_pic );
840 }
841
842
843 /**********************************************************************
844  * Callback to update (some) params on the fly
845  **********************************************************************/
846 static int MosaicBridgeCallback( vlc_object_t *p_this, char const *psz_var,
847                                  vlc_value_t oldval, vlc_value_t newval,
848                                  void *p_data )
849 {
850     sout_stream_t *p_stream = (sout_stream_t *)p_data;
851     sout_stream_sys_t *p_sys = p_stream->p_sys;
852     int i_ret = VLC_SUCCESS;
853
854 #define VAR_IS( a ) !strcmp( psz_var, CFG_PREFIX a )
855     if( VAR_IS( "height" ) )
856     {
857         /* We create the handler before updating the value in p_sys
858          * so we don't have to worry about locking */
859         if( !p_sys->p_image && newval.i_int )
860             p_sys->p_image = image_HandlerCreate( p_stream );
861         p_sys->i_height = newval.i_int;
862     }
863     else if( VAR_IS( "width" ) )
864     {
865         /* We create the handler before updating the value in p_sys
866          * so we don't have to worry about locking */
867         if( !p_sys->p_image && newval.i_int )
868             p_sys->p_image = image_HandlerCreate( p_stream );
869         p_sys->i_width = newval.i_int;
870     }
871 #undef VAR_IS
872
873     return i_ret;
874 }