]> git.sesse.net Git - vlc/blob - modules/stream_out/mosaic_bridge.c
Add picture specific alpha setting for mosaic pictures.
[vlc] / modules / stream_out / mosaic_bridge.c
1 /*****************************************************************************
2  * mosaic_bridge.c:
3  *****************************************************************************
4  * Copyright (C) 2004-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea@videolan.org>
8  *          Christophe Massiot <massiot@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <errno.h>                                                 /* ENOMEM */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <vlc/vlc.h>
35 #include <vlc_sout.h>
36 #include <vlc_block.h>
37 #include <vlc_codec.h>
38
39 #include <vlc_image.h>
40 #include <vlc_filter.h>
41
42 #include "../video_filter/mosaic.h"
43
44 /*****************************************************************************
45  * Local structures
46  *****************************************************************************/
47 struct sout_stream_sys_t
48 {
49     bridged_es_t *p_es;
50     vlc_mutex_t *p_lock;
51
52     decoder_t       *p_decoder;
53     image_handler_t *p_image; /* filter for resizing */
54     int i_height, i_width;
55     unsigned int i_sar_num, i_sar_den;
56     char *psz_id;
57     bool b_inited;
58
59     int i_chroma; /* force image format chroma */
60
61     filter_t **pp_vfilters;
62     int i_vfilters;
63 };
64
65 #define PICTURE_RING_SIZE 4
66 struct decoder_owner_sys_t
67 {
68     picture_t *pp_pics[PICTURE_RING_SIZE];
69
70     /* Current format in use by the output */
71     video_format_t video;
72 };
73
74 typedef void (* pf_release_t)( picture_t * );
75 static void ReleasePicture( picture_t *p_pic )
76 {
77     p_pic->i_refcount--;
78
79     if ( p_pic->i_refcount <= 0 )
80     {
81         if ( p_pic->p_sys != NULL )
82         {
83             pf_release_t pf_release = (pf_release_t)p_pic->p_sys;
84             p_pic->p_sys = NULL;
85             pf_release( p_pic );
86         }
87         else
88         {
89             if( p_pic )
90             {
91                 free( p_pic->p_data_orig );
92                 free( p_pic );
93             }
94         }
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( _( "Mosaic bridge" ) );
172     set_description(_("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 *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 sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
307 {
308     sout_stream_sys_t *p_sys = p_stream->p_sys;
309     bridge_t *p_bridge;
310     bridged_es_t *p_es;
311     char *psz_chain, *psz_parser;
312     int i;
313
314     if ( p_sys->b_inited )
315     {
316         return NULL;
317     }
318
319     /* Create decoder object */
320     p_sys->p_decoder = vlc_object_create( p_stream, VLC_OBJECT_DECODER );
321     vlc_object_attach( p_sys->p_decoder, p_stream );
322     p_sys->p_decoder->p_module = NULL;
323     p_sys->p_decoder->fmt_in = *p_fmt;
324     p_sys->p_decoder->b_pace_control = false;
325     p_sys->p_decoder->fmt_out = p_sys->p_decoder->fmt_in;
326     p_sys->p_decoder->fmt_out.i_extra = 0;
327     p_sys->p_decoder->fmt_out.p_extra = 0;
328     p_sys->p_decoder->pf_decode_video = 0;
329     p_sys->p_decoder->pf_vout_buffer_new = video_new_buffer_decoder;
330     p_sys->p_decoder->pf_vout_buffer_del = video_del_buffer_decoder;
331     p_sys->p_decoder->pf_picture_link    = video_link_picture_decoder;
332     p_sys->p_decoder->pf_picture_unlink  = video_unlink_picture_decoder;
333     p_sys->p_decoder->p_owner = malloc( sizeof(decoder_owner_sys_t) );
334     for( i = 0; i < PICTURE_RING_SIZE; i++ )
335         p_sys->p_decoder->p_owner->pp_pics[i] = 0;
336     p_sys->p_decoder->p_owner->video = p_fmt->video;
337     //p_sys->p_decoder->p_cfg = p_sys->p_video_cfg;
338
339     p_sys->p_decoder->p_module =
340         module_Need( p_sys->p_decoder, "decoder", "$codec", 0 );
341
342     if( !p_sys->p_decoder->p_module )
343     {
344         msg_Err( p_stream, "cannot find decoder" );
345         vlc_object_detach( p_sys->p_decoder );
346         vlc_object_release( p_sys->p_decoder );
347         return NULL;
348     }
349
350     p_sys->b_inited = true;
351     vlc_mutex_lock( p_sys->p_lock );
352
353     p_bridge = GetBridge( p_stream );
354     if ( p_bridge == NULL )
355     {
356         vlc_object_t *p_libvlc = VLC_OBJECT( p_stream->p_libvlc );
357         vlc_value_t val;
358
359         p_bridge = malloc( sizeof( bridge_t ) );
360
361         var_Create( p_libvlc, "mosaic-struct", VLC_VAR_ADDRESS );
362         val.p_address = p_bridge;
363         var_Set( p_libvlc, "mosaic-struct", val );
364
365         p_bridge->i_es_num = 0;
366         p_bridge->pp_es = NULL;
367     }
368
369     for ( i = 0; i < p_bridge->i_es_num; i++ )
370     {
371         if ( p_bridge->pp_es[i]->b_empty )
372             break;
373     }
374
375     if ( i == p_bridge->i_es_num )
376     {
377         p_bridge->pp_es = realloc( p_bridge->pp_es,
378                                    (p_bridge->i_es_num + 1)
379                                      * sizeof(bridged_es_t *) );
380         p_bridge->i_es_num++;
381         p_bridge->pp_es[i] = malloc( sizeof(bridged_es_t) );
382     }
383
384     p_sys->p_es = p_es = p_bridge->pp_es[i];
385
386     p_es->i_alpha = var_GetInteger( p_stream, CFG_PREFIX "alpha" );
387     p_es->i_x = var_GetInteger( p_stream, CFG_PREFIX "x" );
388     p_es->i_y = var_GetInteger( p_stream, CFG_PREFIX "y" );
389
390     //p_es->fmt = *p_fmt;
391     p_es->psz_id = p_sys->psz_id;
392     p_es->p_picture = NULL;
393     p_es->pp_last = &p_es->p_picture;
394     p_es->b_empty = false;
395
396     vlc_mutex_unlock( p_sys->p_lock );
397
398     if ( p_sys->i_height || p_sys->i_width )
399     {
400         p_sys->p_image = image_HandlerCreate( p_stream );
401     }
402     else
403     {
404         p_sys->p_image = NULL;
405     }
406
407     msg_Dbg( p_stream, "mosaic bridge id=%s pos=%d", p_es->psz_id, i );
408
409     /* Create user specified video filters */
410     psz_chain = var_GetNonEmptyString( p_stream, CFG_PREFIX "vfilter" );
411     msg_Dbg( p_stream, "psz_chain: %s\n", psz_chain );
412     {
413         config_chain_t *p_cfg;
414         for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
415         {
416             msg_Dbg( p_stream, " - %s\n", p_cfg->psz_value );
417         }
418     }
419     p_sys->i_vfilters = 0;
420     p_sys->pp_vfilters = NULL;
421     psz_parser = psz_chain;
422     while( psz_parser && *psz_parser )
423     {
424         config_chain_t *p_cfg;
425         char *psz_name;
426         filter_t **pp_vfilter;
427         psz_parser = config_ChainCreate( &psz_name, &p_cfg, psz_parser );
428         p_sys->i_vfilters++;
429         p_sys->pp_vfilters =
430             (filter_t **)realloc( p_sys->pp_vfilters,
431                                   p_sys->i_vfilters * sizeof(filter_t *) );
432         pp_vfilter = p_sys->pp_vfilters+(p_sys->i_vfilters - 1);
433         *pp_vfilter = vlc_object_create( p_stream, VLC_OBJECT_FILTER );
434         vlc_object_attach( *pp_vfilter, p_stream );
435         (*pp_vfilter)->pf_vout_buffer_new = video_new_buffer_filter;
436         (*pp_vfilter)->pf_vout_buffer_del = video_del_buffer_filter;
437         (*pp_vfilter)->fmt_in = p_sys->p_decoder->fmt_out;
438         if( p_sys->i_chroma )
439             (*pp_vfilter)->fmt_in.video.i_chroma = p_sys->i_chroma;
440         (*pp_vfilter)->fmt_out = (*pp_vfilter)->fmt_in;
441         (*pp_vfilter)->p_cfg = p_cfg;
442         (*pp_vfilter)->p_module =
443             module_Need( *pp_vfilter, "video filter2", psz_name, true );
444         if( (*pp_vfilter)->p_module )
445         {
446             /* It worked! */
447             (*pp_vfilter)->p_owner = (filter_owner_sys_t *)
448                 p_sys->p_decoder->p_owner;
449             msg_Err( p_stream, "Added video filter %s to the chain",
450                      psz_name );
451         }
452         else
453         {
454             /* Crap ... we didn't find a filter */
455             msg_Warn( p_stream,
456                       "no video filter matching name \"%s\" found",
457                       psz_name );
458             vlc_object_detach( *pp_vfilter );
459             vlc_object_release( *pp_vfilter );
460             p_sys->i_vfilters--;
461         }
462     }
463     free( psz_chain );
464
465     return (sout_stream_id_t *)p_sys;
466 }
467
468 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
469 {
470     VLC_UNUSED(id);
471     sout_stream_sys_t *p_sys = p_stream->p_sys;
472     bridge_t *p_bridge;
473     bridged_es_t *p_es;
474     bool b_last_es = true;
475     filter_t **pp_vfilter, **pp_end;
476     int i;
477
478     if ( !p_sys->b_inited )
479     {
480         return VLC_SUCCESS;
481     }
482
483     if ( p_sys->p_decoder != NULL )
484     {
485         picture_t **pp_ring = p_sys->p_decoder->p_owner->pp_pics;
486
487         if( p_sys->p_decoder->p_module )
488             module_Unneed( p_sys->p_decoder, p_sys->p_decoder->p_module );
489         vlc_object_detach( p_sys->p_decoder );
490         vlc_object_release( p_sys->p_decoder );
491
492         for( i = 0; i < PICTURE_RING_SIZE; i++ )
493         {
494             if ( pp_ring[i] != NULL )
495             {
496                 free( pp_ring[i]->p_data_orig );
497                 free( pp_ring[i]->p_sys );
498                 free( pp_ring[i] );
499             }
500         }
501     }
502
503     /* Destroy user specified video filters */
504     pp_vfilter = p_sys->pp_vfilters;
505     pp_end = pp_vfilter + p_sys->i_vfilters;
506     for( ; pp_vfilter < pp_end; pp_vfilter++ )
507     {
508         vlc_object_detach( *pp_vfilter );
509         if( (*pp_vfilter)->p_module )
510             module_Unneed( *pp_vfilter, (*pp_vfilter)->p_module );
511         vlc_object_release( *pp_vfilter );
512     }
513     free( p_sys->pp_vfilters );
514
515     vlc_mutex_lock( p_sys->p_lock );
516
517     p_bridge = GetBridge( p_stream );
518     p_es = p_sys->p_es;
519
520     p_es->b_empty = true;
521     while ( p_es->p_picture )
522     {
523         picture_t *p_next = p_es->p_picture->p_next;
524         p_es->p_picture->pf_release( p_es->p_picture );
525         p_es->p_picture = p_next;
526     }
527
528     for ( i = 0; i < p_bridge->i_es_num; i++ )
529     {
530         if ( !p_bridge->pp_es[i]->b_empty )
531         {
532             b_last_es = false;
533             break;
534         }
535     }
536
537     if ( b_last_es )
538     {
539         vlc_object_t *p_libvlc = VLC_OBJECT( p_stream->p_libvlc );
540         for ( i = 0; i < p_bridge->i_es_num; i++ )
541             free( p_bridge->pp_es[i] );
542         free( p_bridge->pp_es );
543         free( p_bridge );
544         var_Destroy( p_libvlc, "mosaic-struct" );
545     }
546
547     vlc_mutex_unlock( p_sys->p_lock );
548
549     if ( p_sys->p_image )
550     {
551         image_HandlerDelete( p_sys->p_image );
552     }
553
554     p_sys->b_inited = false;
555
556     return VLC_SUCCESS;
557 }
558
559 /*****************************************************************************
560  * PushPicture : push a picture in the mosaic-struct structure
561  *****************************************************************************/
562 static void PushPicture( sout_stream_t *p_stream, picture_t *p_picture )
563 {
564     sout_stream_sys_t *p_sys = p_stream->p_sys;
565     bridged_es_t *p_es = p_sys->p_es;
566
567     vlc_mutex_lock( p_sys->p_lock );
568
569     *p_es->pp_last = p_picture;
570     p_picture->p_next = NULL;
571     p_es->pp_last = &p_picture->p_next;
572
573     vlc_mutex_unlock( p_sys->p_lock );
574 }
575
576 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
577                  block_t *p_buffer )
578 {
579     sout_stream_sys_t *p_sys = p_stream->p_sys;
580     picture_t *p_pic;
581
582     if ( (sout_stream_sys_t *)id != p_sys )
583     {
584         block_ChainRelease( p_buffer );
585         return VLC_SUCCESS;
586     }
587
588     while ( (p_pic = p_sys->p_decoder->pf_decode_video( p_sys->p_decoder,
589                                                         &p_buffer )) )
590     {
591         picture_t *p_new_pic;
592
593         if( p_sys->i_height || p_sys->i_width )
594         {
595             video_format_t fmt_out, fmt_in;
596
597             memset( &fmt_in, 0, sizeof(video_format_t) );
598             memset( &fmt_out, 0, sizeof(video_format_t) );
599             fmt_in = p_sys->p_decoder->fmt_out.video;
600
601
602             if( p_sys->i_chroma )
603                 fmt_out.i_chroma = p_sys->i_chroma;
604             else
605                 fmt_out.i_chroma = VLC_FOURCC('I','4','2','0');
606
607             if ( !p_sys->i_height )
608             {
609                 fmt_out.i_width = p_sys->i_width;
610                 fmt_out.i_height = (p_sys->i_width * VOUT_ASPECT_FACTOR
611                     * p_sys->i_sar_num / p_sys->i_sar_den / fmt_in.i_aspect)
612                       & ~0x1;
613             }
614             else if ( !p_sys->i_width )
615             {
616                 fmt_out.i_height = p_sys->i_height;
617                 fmt_out.i_width = (p_sys->i_height * fmt_in.i_aspect
618                     * p_sys->i_sar_den / p_sys->i_sar_num / VOUT_ASPECT_FACTOR)
619                       & ~0x1;
620             }
621             else
622             {
623                 fmt_out.i_width = p_sys->i_width;
624                 fmt_out.i_height = p_sys->i_height;
625             }
626             fmt_out.i_visible_width = fmt_out.i_width;
627             fmt_out.i_visible_height = fmt_out.i_height;
628
629             p_new_pic = image_Convert( p_sys->p_image,
630                                        p_pic, &fmt_in, &fmt_out );
631             if ( p_new_pic == NULL )
632             {
633                 msg_Err( p_stream, "image conversion failed" );
634                 continue;
635             }
636         }
637         else
638         {
639             /* TODO: chroma conversion if needed */
640
641             p_new_pic = (picture_t*)malloc( sizeof(picture_t) );
642             if( p_new_pic == NULL )
643             {
644                 msg_Err( p_stream, "image conversion failed" );
645                 continue;
646             }
647
648             if( vout_AllocatePicture(
649                                   p_stream, p_new_pic, p_pic->format.i_chroma,
650                                   p_pic->format.i_width, p_pic->format.i_height,
651                                   p_sys->p_decoder->fmt_out.video.i_aspect )
652                 != VLC_SUCCESS )
653             {
654                 free( p_new_pic );
655                 msg_Err( p_stream, "image allocation failed" );
656                 continue;
657             }
658
659             vout_CopyPicture( p_stream, p_new_pic, p_pic );
660         }
661
662         p_new_pic->i_refcount = 1;
663         p_new_pic->i_status = DESTROYED_PICTURE;
664         p_new_pic->i_type   = DIRECT_PICTURE;
665         p_new_pic->p_sys = (picture_sys_t *)p_new_pic->pf_release;
666         p_new_pic->pf_release = ReleasePicture;
667         p_new_pic->date = p_pic->date;
668         p_pic->pf_release( p_pic );
669
670         if( p_sys->pp_vfilters )
671         {
672             /* Apply user specified video filters */
673             filter_t **pp_vfilter = p_sys->pp_vfilters;
674             filter_t **pp_end = pp_vfilter + p_sys->i_vfilters;
675             for( ; pp_vfilter < pp_end; pp_vfilter++ )
676             {
677                 (*pp_vfilter)->fmt_in.i_codec = p_new_pic->format.i_chroma;
678                 (*pp_vfilter)->fmt_out.i_codec = p_new_pic->format.i_chroma;
679                 (*pp_vfilter)->fmt_in.video = p_new_pic->format;
680                 (*pp_vfilter)->fmt_out.video = p_new_pic->format;
681                 p_new_pic = (*pp_vfilter)->pf_video_filter( *pp_vfilter,
682                                                              p_new_pic );
683                 if( !p_new_pic )
684                 {
685                     msg_Err( p_stream, "video filter failed" );
686                     break;
687                 }
688             }
689             if( !p_new_pic ) continue;
690         }
691
692         PushPicture( p_stream, p_new_pic );
693     }
694
695     return VLC_SUCCESS;
696 }
697
698 struct picture_sys_t
699 {
700     vlc_object_t *p_owner;
701     bool b_dead;
702 };
703
704 static void video_release_buffer_decoder( picture_t *p_pic )
705 {
706     if( p_pic && !p_pic->i_refcount && p_pic->pf_release && p_pic->p_sys )
707     {
708         video_del_buffer_decoder( (decoder_t *)p_pic->p_sys->p_owner, p_pic );
709     }
710     else if( p_pic && p_pic->i_refcount > 0 ) p_pic->i_refcount--;
711 }
712
713 static void video_release_buffer_filter( picture_t *p_pic )
714 {
715     if( p_pic && !p_pic->i_refcount && p_pic->pf_release && p_pic->p_sys )
716     {
717         video_del_buffer_filter( (filter_t *)p_pic->p_sys->p_owner, p_pic );
718     }
719     else if( p_pic && p_pic->i_refcount > 0 ) p_pic->i_refcount--;
720 }
721
722 inline static picture_t *video_new_buffer_decoder( decoder_t *p_dec )
723 {
724     return video_new_buffer( VLC_OBJECT( p_dec ),
725                              (decoder_owner_sys_t *)p_dec->p_owner,
726                              &p_dec->fmt_out,
727                              video_release_buffer_decoder );
728 }
729
730 inline static picture_t *video_new_buffer_filter( filter_t *p_filter )
731 {
732     return video_new_buffer( VLC_OBJECT( p_filter ),
733                              (decoder_owner_sys_t *)p_filter->p_owner,
734                              &p_filter->fmt_out,
735                              video_release_buffer_filter );
736 }
737
738 static picture_t *video_new_buffer( vlc_object_t *p_this,
739                                     decoder_owner_sys_t *p_sys,
740                                     es_format_t *fmt_out,
741                                     void ( *pf_release )( picture_t * ) )
742 {
743     picture_t **pp_ring = p_sys->pp_pics;
744     picture_t *p_pic;
745     int i;
746
747     if( fmt_out->video.i_width != p_sys->video.i_width ||
748         fmt_out->video.i_height != p_sys->video.i_height ||
749         fmt_out->video.i_chroma != p_sys->video.i_chroma ||
750         fmt_out->video.i_aspect != p_sys->video.i_aspect )
751     {
752         if( !fmt_out->video.i_sar_num ||
753             !fmt_out->video.i_sar_den )
754         {
755             fmt_out->video.i_sar_num =
756                 fmt_out->video.i_aspect * fmt_out->video.i_height;
757
758             fmt_out->video.i_sar_den =
759                 VOUT_ASPECT_FACTOR * fmt_out->video.i_width;
760         }
761
762         vlc_ureduce( &fmt_out->video.i_sar_num,
763                      &fmt_out->video.i_sar_den,
764                      fmt_out->video.i_sar_num,
765                      fmt_out->video.i_sar_den, 0 );
766
767         if( !fmt_out->video.i_visible_width ||
768             !fmt_out->video.i_visible_height )
769         {
770             fmt_out->video.i_visible_width = fmt_out->video.i_width;
771             fmt_out->video.i_visible_height = fmt_out->video.i_height;
772         }
773
774         fmt_out->video.i_chroma = fmt_out->i_codec;
775         p_sys->video = fmt_out->video;
776
777         for( i = 0; i < PICTURE_RING_SIZE; i++ )
778         {
779             if ( pp_ring[i] != NULL )
780             {
781                 if ( pp_ring[i]->i_status == DESTROYED_PICTURE )
782                 {
783                     free( pp_ring[i]->p_data_orig );
784                     free( pp_ring[i]->p_sys );
785                     free( pp_ring[i] );
786                 }
787                 else
788                 {
789                     pp_ring[i]->p_sys->b_dead = true;
790                 }
791                 pp_ring[i] = NULL;
792             }
793         }
794     }
795
796     /* Find an empty space in the picture ring buffer */
797     for( i = 0; i < PICTURE_RING_SIZE; i++ )
798     {
799         if( pp_ring[i] != NULL && pp_ring[i]->i_status == DESTROYED_PICTURE )
800         {
801             pp_ring[i]->i_status = RESERVED_PICTURE;
802             return pp_ring[i];
803         }
804     }
805     for( i = 0; i < PICTURE_RING_SIZE; i++ )
806     {
807         if( pp_ring[i] == NULL ) break;
808     }
809
810     if( i == PICTURE_RING_SIZE )
811     {
812         msg_Err( p_this, "decoder/filter is leaking pictures, "
813                  "resetting its ring buffer" );
814
815         for( i = 0; i < PICTURE_RING_SIZE; i++ )
816         {
817             pp_ring[i]->pf_release( pp_ring[i] );
818         }
819
820         i = 0;
821     }
822
823     p_pic = malloc( sizeof(picture_t) );
824     if( !p_pic ) return NULL;
825     fmt_out->video.i_chroma = fmt_out->i_codec;
826     vout_AllocatePicture( p_this, p_pic,
827                           fmt_out->video.i_chroma,
828                           fmt_out->video.i_width,
829                           fmt_out->video.i_height,
830                           fmt_out->video.i_aspect );
831
832     if( !p_pic->i_planes )
833     {
834         free( p_pic );
835         return NULL;
836     }
837
838     p_pic->pf_release = pf_release;
839     p_pic->p_sys = malloc( sizeof(picture_sys_t) );
840     p_pic->p_sys->p_owner = p_this;
841     p_pic->p_sys->b_dead = false;
842     p_pic->i_status = RESERVED_PICTURE;
843
844     pp_ring[i] = p_pic;
845
846     return p_pic;
847 }
848
849 inline static void video_del_buffer_decoder( decoder_t *p_this,
850                                              picture_t *p_pic )
851 {
852     VLC_UNUSED(p_this);
853     video_del_buffer( p_pic );
854 }
855
856 inline static void video_del_buffer_filter( filter_t *p_this,
857                                             picture_t *p_pic )
858 {
859     VLC_UNUSED(p_this);
860     video_del_buffer( p_pic );
861 }
862
863 static void video_del_buffer( picture_t *p_pic )
864 {
865     p_pic->i_refcount = 0;
866     p_pic->i_status = DESTROYED_PICTURE;
867     if ( p_pic->p_sys->b_dead )
868     {
869         free( p_pic->p_data_orig );
870         free( p_pic->p_sys );
871         free( p_pic );
872     }
873 }
874
875 static void video_link_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
876 {
877     VLC_UNUSED(p_dec);
878     p_pic->i_refcount++;
879 }
880
881 static void video_unlink_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
882 {
883     VLC_UNUSED(p_dec);
884     video_release_buffer_decoder( p_pic );
885 }
886
887
888 /**********************************************************************
889  * Callback to update (some) params on the fly
890  **********************************************************************/
891 static int HeightCallback( vlc_object_t *p_this, char const *psz_var,
892                            vlc_value_t oldval, vlc_value_t newval,
893                            void *p_data )
894 {
895     VLC_UNUSED(p_this); VLC_UNUSED(oldval);
896     sout_stream_t *p_stream = (sout_stream_t *)p_data;
897     sout_stream_sys_t *p_sys = p_stream->p_sys;
898
899     /* We create the handler before updating the value in p_sys
900      * so we don't have to worry about locking */
901     if( !p_sys->p_image && newval.i_int )
902         p_sys->p_image = image_HandlerCreate( p_stream );
903     p_sys->i_height = newval.i_int;
904
905     return VLC_SUCCESS;
906 }
907
908 static int WidthCallback( vlc_object_t *p_this, char const *psz_var,
909                            vlc_value_t oldval, vlc_value_t newval,
910                            void *p_data )
911 {
912     VLC_UNUSED(p_this); VLC_UNUSED(oldval);
913     sout_stream_t *p_stream = (sout_stream_t *)p_data;
914     sout_stream_sys_t *p_sys = p_stream->p_sys;
915
916     /* We create the handler before updating the value in p_sys
917      * so we don't have to worry about locking */
918     if( !p_sys->p_image && newval.i_int )
919         p_sys->p_image = image_HandlerCreate( p_stream );
920     p_sys->i_width = newval.i_int;
921
922     return VLC_SUCCESS;
923 }
924
925 static int alphaCallback( vlc_object_t *p_this, char const *psz_var,
926                           vlc_value_t oldval, vlc_value_t newval,
927                           void *p_data )
928 {
929     VLC_UNUSED(p_this); VLC_UNUSED(oldval);
930     sout_stream_t *p_stream = (sout_stream_t *)p_data;
931     sout_stream_sys_t *p_sys = p_stream->p_sys;
932
933     if( p_sys->p_es )
934         p_sys->p_es->i_alpha = newval.i_int;
935
936     return VLC_SUCCESS;
937 }
938
939 static int xCallback( vlc_object_t *p_this, char const *psz_var,
940                       vlc_value_t oldval, vlc_value_t newval,
941                       void *p_data )
942 {
943     VLC_UNUSED(p_this); VLC_UNUSED(oldval);
944     sout_stream_t *p_stream = (sout_stream_t *)p_data;
945     sout_stream_sys_t *p_sys = p_stream->p_sys;
946
947     if( p_sys->p_es )
948         p_sys->p_es->i_x = newval.i_int;
949
950     return VLC_SUCCESS;
951 }
952
953 static int yCallback( vlc_object_t *p_this, char const *psz_var,
954                       vlc_value_t oldval, vlc_value_t newval,
955                       void *p_data )
956 {
957     VLC_UNUSED(p_this); VLC_UNUSED(oldval);
958     sout_stream_t *p_stream = (sout_stream_t *)p_data;
959     sout_stream_sys_t *p_sys = p_stream->p_sys;
960
961     if( p_sys->p_es )
962         p_sys->p_es->i_y = newval.i_int;
963
964     return VLC_SUCCESS;
965 }