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