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