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