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