]> git.sesse.net Git - vlc/blob - modules/stream_out/mosaic_bridge.c
Remove most stray semi-colons in module descriptions
[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_q );
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( N_( "Mosaic bridge" ) )
173     set_description(N_("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 *const 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         return VLC_ENOMEM;
219
220     p_stream->p_sys = p_sys;
221     p_sys->b_inited = false;
222
223     var_Create( p_libvlc, "mosaic-lock", VLC_VAR_MUTEX );
224     var_Get( p_libvlc, "mosaic-lock", &val );
225     p_sys->p_lock = val.p_address;
226
227     p_sys->psz_id = var_CreateGetString( p_stream, CFG_PREFIX "id" );
228
229     p_sys->i_height =
230         var_CreateGetIntegerCommand( p_stream, CFG_PREFIX "height" );
231     var_AddCallback( p_stream, CFG_PREFIX "height", HeightCallback, p_stream );
232
233     p_sys->i_width =
234         var_CreateGetIntegerCommand( p_stream, CFG_PREFIX "width" );
235     var_AddCallback( p_stream, CFG_PREFIX "width", WidthCallback, p_stream );
236
237     var_Get( p_stream, CFG_PREFIX "sar", &val );
238     if( val.psz_string )
239     {
240         char *psz_parser = strchr( val.psz_string, ':' );
241
242         if( psz_parser )
243         {
244             *psz_parser++ = '\0';
245             p_sys->i_sar_num = atoi( val.psz_string );
246             p_sys->i_sar_den = atoi( psz_parser );
247             vlc_ureduce( &p_sys->i_sar_num, &p_sys->i_sar_den,
248                          p_sys->i_sar_num, p_sys->i_sar_den, 0 );
249         }
250         else
251         {
252             msg_Warn( p_stream, "bad aspect ratio %s", val.psz_string );
253             p_sys->i_sar_num = p_sys->i_sar_den = 1;
254         }
255
256         free( val.psz_string );
257     }
258     else
259     {
260         p_sys->i_sar_num = p_sys->i_sar_den = 1;
261     }
262
263     p_sys->i_chroma = 0;
264     val.psz_string = var_GetNonEmptyString( p_stream, CFG_PREFIX "chroma" );
265     if( val.psz_string && strlen( val.psz_string ) >= 4 )
266     {
267         memcpy( &p_sys->i_chroma, val.psz_string, 4 );
268         msg_Dbg( p_stream, "Forcing image chroma to 0x%.8x (%4.4s)", p_sys->i_chroma, (char*)&p_sys->i_chroma );
269     }
270     free( val.psz_string );
271
272 #define INT_COMMAND( a ) do { \
273     var_Create( p_stream, CFG_PREFIX #a, \
274                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND ); \
275     var_AddCallback( p_stream, CFG_PREFIX #a, a ## Callback, \
276                      p_stream ); } while(0)
277     INT_COMMAND( alpha );
278     INT_COMMAND( x );
279     INT_COMMAND( y );
280
281 #undef INT_COMMAND
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 int video_filter_buffer_allocation_init( filter_t *p_filter, void *p_data )
308 {
309     p_filter->pf_vout_buffer_new = video_new_buffer_filter;
310     p_filter->pf_vout_buffer_del = video_del_buffer_filter;
311     p_filter->p_owner = p_data;
312     return VLC_SUCCESS;
313 }
314
315 static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
316 {
317     sout_stream_sys_t *p_sys = p_stream->p_sys;
318     bridge_t *p_bridge;
319     bridged_es_t *p_es;
320     char *psz_chain;
321     int i;
322
323     if( p_sys->b_inited || p_fmt->i_cat != VIDEO_ES )
324         return NULL;
325
326     /* Create decoder object */
327     p_sys->p_decoder = vlc_object_create( p_stream, VLC_OBJECT_DECODER );
328     if( !p_sys->p_decoder )
329         return NULL;
330     vlc_object_attach( p_sys->p_decoder, p_stream );
331     p_sys->p_decoder->p_module = NULL;
332     p_sys->p_decoder->fmt_in = *p_fmt;
333     p_sys->p_decoder->b_pace_control = false;
334     p_sys->p_decoder->fmt_out = p_sys->p_decoder->fmt_in;
335     p_sys->p_decoder->fmt_out.i_extra = 0;
336     p_sys->p_decoder->fmt_out.p_extra = 0;
337     p_sys->p_decoder->pf_decode_video = 0;
338     p_sys->p_decoder->pf_vout_buffer_new = video_new_buffer_decoder;
339     p_sys->p_decoder->pf_vout_buffer_del = video_del_buffer_decoder;
340     p_sys->p_decoder->pf_picture_link    = video_link_picture_decoder;
341     p_sys->p_decoder->pf_picture_unlink  = video_unlink_picture_decoder;
342     p_sys->p_decoder->p_owner = malloc( sizeof(decoder_owner_sys_t) );
343     if( !p_sys->p_decoder->p_owner )
344     {
345         vlc_object_detach( p_sys->p_decoder );
346         vlc_object_release( p_sys->p_decoder );
347         return NULL;
348     }
349
350     for( i = 0; i < PICTURE_RING_SIZE; i++ )
351         p_sys->p_decoder->p_owner->pp_pics[i] = NULL;
352     p_sys->p_decoder->p_owner->video = p_fmt->video;
353     //p_sys->p_decoder->p_cfg = p_sys->p_video_cfg;
354
355     p_sys->p_decoder->p_module =
356         module_need( p_sys->p_decoder, "decoder", "$codec", 0 );
357
358     if( !p_sys->p_decoder->p_module || !p_sys->p_decoder->pf_decode_video )
359     {
360         if( p_sys->p_decoder->p_module )
361         {
362             msg_Err( p_stream, "instanciated a non video decoder" );
363             module_unneed( p_sys->p_decoder, p_sys->p_decoder->p_module );
364         }
365         else
366         {
367             msg_Err( p_stream, "cannot find decoder" );
368         }
369         free( p_sys->p_decoder->p_owner );
370         vlc_object_detach( p_sys->p_decoder );
371         vlc_object_release( p_sys->p_decoder );
372         return NULL;
373     }
374
375     p_sys->b_inited = true;
376     vlc_mutex_lock( p_sys->p_lock );
377
378     p_bridge = GetBridge( p_stream );
379     if ( p_bridge == NULL )
380     {
381         vlc_object_t *p_libvlc = VLC_OBJECT( p_stream->p_libvlc );
382         vlc_value_t val;
383
384         p_bridge = malloc( sizeof( bridge_t ) );
385
386         var_Create( p_libvlc, "mosaic-struct", VLC_VAR_ADDRESS );
387         val.p_address = p_bridge;
388         var_Set( p_libvlc, "mosaic-struct", val );
389
390         p_bridge->i_es_num = 0;
391         p_bridge->pp_es = NULL;
392     }
393
394     for ( i = 0; i < p_bridge->i_es_num; i++ )
395     {
396         if ( p_bridge->pp_es[i]->b_empty )
397             break;
398     }
399
400     if ( i == p_bridge->i_es_num )
401     {
402         p_bridge->pp_es = realloc( p_bridge->pp_es,
403                                    (p_bridge->i_es_num + 1)
404                                      * sizeof(bridged_es_t *) );
405         p_bridge->i_es_num++;
406         p_bridge->pp_es[i] = malloc( sizeof(bridged_es_t) );
407     }
408
409     p_sys->p_es = p_es = p_bridge->pp_es[i];
410
411     p_es->i_alpha = var_GetInteger( p_stream, CFG_PREFIX "alpha" );
412     p_es->i_x = var_GetInteger( p_stream, CFG_PREFIX "x" );
413     p_es->i_y = var_GetInteger( p_stream, CFG_PREFIX "y" );
414
415     //p_es->fmt = *p_fmt;
416     p_es->psz_id = p_sys->psz_id;
417     p_es->p_picture = NULL;
418     p_es->pp_last = &p_es->p_picture;
419     p_es->b_empty = false;
420
421     vlc_mutex_unlock( p_sys->p_lock );
422
423     if ( p_sys->i_height || p_sys->i_width )
424     {
425         p_sys->p_image = image_HandlerCreate( p_stream );
426     }
427     else
428     {
429         p_sys->p_image = NULL;
430     }
431
432     msg_Dbg( p_stream, "mosaic bridge id=%s pos=%d", p_es->psz_id, i );
433
434     /* Create user specified video filters */
435     psz_chain = var_GetNonEmptyString( p_stream, CFG_PREFIX "vfilter" );
436     msg_Dbg( p_stream, "psz_chain: %s\n", psz_chain );
437     if( psz_chain )
438     {
439         p_sys->p_vf2 = filter_chain_New( p_stream, "video filter2", false,
440                                          video_filter_buffer_allocation_init,
441                                          NULL, p_sys->p_decoder->p_owner );
442         es_format_t fmt;
443         es_format_Copy( &fmt, &p_sys->p_decoder->fmt_out );
444         if( p_sys->i_chroma )
445             fmt.video.i_chroma = p_sys->i_chroma;
446         filter_chain_Reset( p_sys->p_vf2, &fmt, &fmt );
447         filter_chain_AppendFromString( p_sys->p_vf2, psz_chain );
448         free( psz_chain );
449     }
450     else
451     {
452         p_sys->p_vf2 = NULL;
453     }
454
455     return (sout_stream_id_t *)p_sys;
456 }
457
458 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
459 {
460     VLC_UNUSED(id);
461     sout_stream_sys_t *p_sys = p_stream->p_sys;
462     bridge_t *p_bridge;
463     bridged_es_t *p_es;
464     bool b_last_es = true;
465     int i;
466
467     if( !p_sys->b_inited )
468         return VLC_SUCCESS;
469
470     if( p_sys->p_decoder != NULL )
471     {
472         decoder_owner_sys_t *p_owner = p_sys->p_decoder->p_owner;
473
474         if( p_sys->p_decoder->p_module )
475             module_unneed( p_sys->p_decoder, p_sys->p_decoder->p_module );
476         vlc_object_detach( p_sys->p_decoder );
477         vlc_object_release( p_sys->p_decoder );
478
479         picture_t **pp_ring = p_owner->pp_pics;
480         for( i = 0; i < PICTURE_RING_SIZE; i++ )
481         {
482             if ( pp_ring[i] != NULL )
483             {
484                 free( pp_ring[i]->p_data_orig );
485                 free( pp_ring[i]->p_sys );
486                 free( pp_ring[i] );
487             }
488         }
489         free( p_owner );
490     }
491
492     /* Destroy user specified video filters */
493     if( p_sys->p_vf2 )
494         filter_chain_Delete( p_sys->p_vf2 );
495
496     vlc_mutex_lock( p_sys->p_lock );
497
498     p_bridge = GetBridge( p_stream );
499     p_es = p_sys->p_es;
500
501     p_es->b_empty = true;
502     while ( p_es->p_picture )
503     {
504         picture_t *p_next = p_es->p_picture->p_next;
505         p_es->p_picture->pf_release( p_es->p_picture );
506         p_es->p_picture = p_next;
507     }
508
509     for ( i = 0; i < p_bridge->i_es_num; i++ )
510     {
511         if ( !p_bridge->pp_es[i]->b_empty )
512         {
513             b_last_es = false;
514             break;
515         }
516     }
517
518     if ( b_last_es )
519     {
520         vlc_object_t *p_libvlc = VLC_OBJECT( p_stream->p_libvlc );
521         for ( i = 0; i < p_bridge->i_es_num; i++ )
522             free( p_bridge->pp_es[i] );
523         free( p_bridge->pp_es );
524         free( p_bridge );
525         var_Destroy( p_libvlc, "mosaic-struct" );
526     }
527
528     vlc_mutex_unlock( p_sys->p_lock );
529
530     if ( p_sys->p_image )
531     {
532         image_HandlerDelete( p_sys->p_image );
533     }
534
535     p_sys->b_inited = false;
536
537     return VLC_SUCCESS;
538 }
539
540 /*****************************************************************************
541  * PushPicture : push a picture in the mosaic-struct structure
542  *****************************************************************************/
543 static void PushPicture( sout_stream_t *p_stream, picture_t *p_picture )
544 {
545     sout_stream_sys_t *p_sys = p_stream->p_sys;
546     bridged_es_t *p_es = p_sys->p_es;
547
548     vlc_mutex_lock( p_sys->p_lock );
549
550     *p_es->pp_last = p_picture;
551     p_picture->p_next = NULL;
552     p_es->pp_last = &p_picture->p_next;
553
554     vlc_mutex_unlock( p_sys->p_lock );
555 }
556
557 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
558                  block_t *p_buffer )
559 {
560     sout_stream_sys_t *p_sys = p_stream->p_sys;
561     picture_t *p_pic;
562
563     if ( (sout_stream_sys_t *)id != p_sys )
564     {
565         block_ChainRelease( p_buffer );
566         return VLC_SUCCESS;
567     }
568
569     while ( (p_pic = p_sys->p_decoder->pf_decode_video( p_sys->p_decoder,
570                                                         &p_buffer )) )
571     {
572         picture_t *p_new_pic;
573
574         if( p_sys->i_height || p_sys->i_width )
575         {
576             video_format_t fmt_out, fmt_in;
577
578             memset( &fmt_in, 0, sizeof(video_format_t) );
579             memset( &fmt_out, 0, sizeof(video_format_t) );
580             fmt_in = p_sys->p_decoder->fmt_out.video;
581
582
583             if( p_sys->i_chroma )
584                 fmt_out.i_chroma = p_sys->i_chroma;
585             else
586                 fmt_out.i_chroma = VLC_FOURCC('I','4','2','0');
587
588             if ( !p_sys->i_height )
589             {
590                 fmt_out.i_width = p_sys->i_width;
591                 fmt_out.i_height = (p_sys->i_width * VOUT_ASPECT_FACTOR
592                     * p_sys->i_sar_num / p_sys->i_sar_den / fmt_in.i_aspect)
593                       & ~0x1;
594             }
595             else if ( !p_sys->i_width )
596             {
597                 fmt_out.i_height = p_sys->i_height;
598                 fmt_out.i_width = (p_sys->i_height * fmt_in.i_aspect
599                     * p_sys->i_sar_den / p_sys->i_sar_num / VOUT_ASPECT_FACTOR)
600                       & ~0x1;
601             }
602             else
603             {
604                 fmt_out.i_width = p_sys->i_width;
605                 fmt_out.i_height = p_sys->i_height;
606             }
607             fmt_out.i_visible_width = fmt_out.i_width;
608             fmt_out.i_visible_height = fmt_out.i_height;
609
610             p_new_pic = image_Convert( p_sys->p_image,
611                                        p_pic, &fmt_in, &fmt_out );
612             if ( p_new_pic == NULL )
613             {
614                 msg_Err( p_stream, "image conversion failed" );
615                 picture_Release( p_pic );
616                 continue;
617             }
618         }
619         else
620         {
621             /* TODO: chroma conversion if needed */
622
623             p_new_pic = (picture_t*)malloc( sizeof(picture_t) );
624             if( p_new_pic == NULL )
625             {
626                 msg_Err( p_stream, "image conversion failed" );
627                 continue;
628             }
629
630             if( vout_AllocatePicture(
631                                   p_stream, p_new_pic, p_pic->format.i_chroma,
632                                   p_pic->format.i_width, p_pic->format.i_height,
633                                   p_sys->p_decoder->fmt_out.video.i_aspect )
634                 != VLC_SUCCESS )
635             {
636                 picture_Release( p_pic );
637                 free( p_new_pic );
638                 msg_Err( p_stream, "image allocation failed" );
639                 continue;
640             }
641
642             picture_Copy( p_new_pic, p_pic );
643         }
644
645         p_new_pic->i_refcount = 1;
646         p_new_pic->i_status = DESTROYED_PICTURE;
647         p_new_pic->i_type   = DIRECT_PICTURE;
648         p_new_pic->p_sys = (picture_sys_t *)p_new_pic->pf_release;
649         p_new_pic->pf_release = ReleasePicture;
650         p_new_pic->date = p_pic->date;
651         picture_Release( p_pic );
652
653         if( p_sys->p_vf2 )
654             p_new_pic = filter_chain_VideoFilter( p_sys->p_vf2, p_new_pic );
655
656         PushPicture( p_stream, p_new_pic );
657     }
658
659     return VLC_SUCCESS;
660 }
661
662 struct picture_sys_t
663 {
664     vlc_object_t *p_owner;
665     bool b_dead;
666 };
667
668 static void video_release_buffer_decoder( picture_t *p_pic )
669 {
670     assert( p_pic && p_pic->p_sys );
671
672     if( --p_pic->i_refcount > 0 )
673         return;
674
675     video_del_buffer_decoder( (decoder_t *)p_pic->p_sys->p_owner, p_pic );
676 }
677
678 static void video_release_buffer_filter( picture_t *p_pic )
679 {
680     assert( p_pic );
681
682     if( --p_pic->i_refcount > 0 )
683         return;
684
685     assert( p_pic->p_sys );
686
687     video_del_buffer_filter( (filter_t *)p_pic->p_sys->p_owner, p_pic );
688 }
689
690 inline static picture_t *video_new_buffer_decoder( decoder_t *p_dec )
691 {
692     return video_new_buffer( VLC_OBJECT( p_dec ),
693                              (decoder_owner_sys_t *)p_dec->p_owner,
694                              &p_dec->fmt_out,
695                              video_release_buffer_decoder );
696 }
697
698 inline static picture_t *video_new_buffer_filter( filter_t *p_filter )
699 {
700     return video_new_buffer( VLC_OBJECT( p_filter ),
701                              (decoder_owner_sys_t *)p_filter->p_owner,
702                              &p_filter->fmt_out,
703                              video_release_buffer_filter );
704 }
705
706 static picture_t *video_new_buffer( vlc_object_t *p_this,
707                                     decoder_owner_sys_t *p_sys,
708                                     es_format_t *fmt_out,
709                                     void ( *pf_release )( picture_t * ) )
710 {
711     picture_t **pp_ring = p_sys->pp_pics;
712     picture_t *p_pic;
713     int i;
714
715     if( fmt_out->video.i_width != p_sys->video.i_width ||
716         fmt_out->video.i_height != p_sys->video.i_height ||
717         fmt_out->video.i_chroma != p_sys->video.i_chroma ||
718         fmt_out->video.i_aspect != p_sys->video.i_aspect )
719     {
720         if( !fmt_out->video.i_sar_num ||
721             !fmt_out->video.i_sar_den )
722         {
723             fmt_out->video.i_sar_num =
724                 fmt_out->video.i_aspect * fmt_out->video.i_height;
725
726             fmt_out->video.i_sar_den =
727                 VOUT_ASPECT_FACTOR * fmt_out->video.i_width;
728         }
729
730         vlc_ureduce( &fmt_out->video.i_sar_num,
731                      &fmt_out->video.i_sar_den,
732                      fmt_out->video.i_sar_num,
733                      fmt_out->video.i_sar_den, 0 );
734
735         if( !fmt_out->video.i_visible_width ||
736             !fmt_out->video.i_visible_height )
737         {
738             fmt_out->video.i_visible_width = fmt_out->video.i_width;
739             fmt_out->video.i_visible_height = fmt_out->video.i_height;
740         }
741
742         fmt_out->video.i_chroma = fmt_out->i_codec;
743         p_sys->video = fmt_out->video;
744
745         for( i = 0; i < PICTURE_RING_SIZE; i++ )
746         {
747             if ( pp_ring[i] != NULL )
748             {
749                 if ( pp_ring[i]->i_status == DESTROYED_PICTURE )
750                 {
751                     free( pp_ring[i]->p_data_orig );
752                     free( pp_ring[i]->p_sys );
753                     free( pp_ring[i] );
754                 }
755                 else
756                 {
757                     pp_ring[i]->p_sys->b_dead = true;
758                 }
759                 pp_ring[i] = NULL;
760             }
761         }
762     }
763
764     /* Find an empty space in the picture ring buffer */
765     for( i = 0; i < PICTURE_RING_SIZE; i++ )
766     {
767         if( pp_ring[i] != NULL && pp_ring[i]->i_status == DESTROYED_PICTURE )
768         {
769             pp_ring[i]->i_status = RESERVED_PICTURE;
770             pp_ring[i]->i_refcount = 1;
771             return pp_ring[i];
772         }
773     }
774     for( i = 0; i < PICTURE_RING_SIZE; i++ )
775     {
776         if( pp_ring[i] == NULL ) break;
777     }
778
779     if( i == PICTURE_RING_SIZE )
780     {
781         msg_Err( p_this, "decoder/filter is leaking pictures, "
782                  "resetting its ring buffer" );
783
784         for( i = 0; i < PICTURE_RING_SIZE; i++ )
785         {
786             pp_ring[i]->p_sys->b_dead = true;
787             pp_ring[i]->pf_release( pp_ring[i] );
788             pp_ring[i] = NULL;
789         }
790
791         i = 0;
792     }
793
794     p_pic = malloc( sizeof(picture_t) );
795     if( !p_pic ) return NULL;
796     fmt_out->video.i_chroma = fmt_out->i_codec;
797     if( vout_AllocatePicture( p_this, p_pic,
798                           fmt_out->video.i_chroma,
799                           fmt_out->video.i_width,
800                           fmt_out->video.i_height,
801                           fmt_out->video.i_aspect ) != VLC_SUCCESS )
802     {
803         free( p_pic );
804         return NULL;
805     }
806
807     if( !p_pic->i_planes )
808     {
809         free( p_pic );
810         return NULL;
811     }
812
813     p_pic->pf_release = pf_release;
814     p_pic->i_refcount = 1;
815     p_pic->p_sys = malloc( sizeof(picture_sys_t) );
816     p_pic->p_sys->p_owner = p_this;
817     p_pic->p_sys->b_dead = false;
818     p_pic->i_status = RESERVED_PICTURE;
819
820     pp_ring[i] = p_pic;
821
822     return p_pic;
823 }
824
825 inline static void video_del_buffer_decoder( decoder_t *p_this,
826                                              picture_t *p_pic )
827 {
828     VLC_UNUSED(p_this);
829     video_del_buffer( p_pic );
830 }
831
832 inline static void video_del_buffer_filter( filter_t *p_this,
833                                             picture_t *p_pic )
834 {
835     VLC_UNUSED(p_this);
836     video_del_buffer( p_pic );
837 }
838
839 static void video_del_buffer( picture_t *p_pic )
840 {
841     p_pic->i_refcount = 0;
842     p_pic->i_status = DESTROYED_PICTURE;
843     if ( p_pic->p_sys->b_dead )
844     {
845         free( p_pic->p_data_orig );
846         free( p_pic->p_sys );
847         free( p_pic );
848     }
849 }
850
851 static void video_link_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
852 {
853     VLC_UNUSED(p_dec);
854     p_pic->i_refcount++;
855 }
856
857 static void video_unlink_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
858 {
859     VLC_UNUSED(p_dec);
860     video_release_buffer_decoder( p_pic );
861 }
862
863
864 /**********************************************************************
865  * Callback to update (some) params on the fly
866  **********************************************************************/
867 static int HeightCallback( vlc_object_t *p_this, char const *psz_var,
868                            vlc_value_t oldval, vlc_value_t newval,
869                            void *p_data )
870 {
871     VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(psz_var);
872     sout_stream_t *p_stream = (sout_stream_t *)p_data;
873     sout_stream_sys_t *p_sys = p_stream->p_sys;
874
875     /* We create the handler before updating the value in p_sys
876      * so we don't have to worry about locking */
877     if( !p_sys->p_image && newval.i_int )
878         p_sys->p_image = image_HandlerCreate( p_stream );
879     p_sys->i_height = newval.i_int;
880
881     return VLC_SUCCESS;
882 }
883
884 static int WidthCallback( vlc_object_t *p_this, char const *psz_var,
885                            vlc_value_t oldval, vlc_value_t newval,
886                            void *p_data )
887 {
888     VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(psz_var);
889     sout_stream_t *p_stream = (sout_stream_t *)p_data;
890     sout_stream_sys_t *p_sys = p_stream->p_sys;
891
892     /* We create the handler before updating the value in p_sys
893      * so we don't have to worry about locking */
894     if( !p_sys->p_image && newval.i_int )
895         p_sys->p_image = image_HandlerCreate( p_stream );
896     p_sys->i_width = newval.i_int;
897
898     return VLC_SUCCESS;
899 }
900
901 static int alphaCallback( vlc_object_t *p_this, char const *psz_var,
902                           vlc_value_t oldval, vlc_value_t newval,
903                           void *p_data )
904 {
905     VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(psz_var);
906     sout_stream_t *p_stream = (sout_stream_t *)p_data;
907     sout_stream_sys_t *p_sys = p_stream->p_sys;
908
909     if( p_sys->p_es )
910         p_sys->p_es->i_alpha = newval.i_int;
911
912     return VLC_SUCCESS;
913 }
914
915 static int xCallback( vlc_object_t *p_this, char const *psz_var,
916                       vlc_value_t oldval, vlc_value_t newval,
917                       void *p_data )
918 {
919     VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(psz_var);
920     sout_stream_t *p_stream = (sout_stream_t *)p_data;
921     sout_stream_sys_t *p_sys = p_stream->p_sys;
922
923     if( p_sys->p_es )
924         p_sys->p_es->i_x = newval.i_int;
925
926     return VLC_SUCCESS;
927 }
928
929 static int yCallback( vlc_object_t *p_this, char const *psz_var,
930                       vlc_value_t oldval, vlc_value_t newval,
931                       void *p_data )
932 {
933     VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(psz_var);
934     sout_stream_t *p_stream = (sout_stream_t *)p_data;
935     sout_stream_sys_t *p_sys = p_stream->p_sys;
936
937     if( p_sys->p_es )
938         p_sys->p_es->i_y = newval.i_int;
939
940     return VLC_SUCCESS;
941 }