]> git.sesse.net Git - vlc/blob - modules/stream_out/mosaic_bridge.c
smem should only start when explicitly requested
[vlc] / modules / stream_out / mosaic_bridge.c
1 /*****************************************************************************
2  * mosaic_bridge.c:
3  *****************************************************************************
4  * Copyright (C) 2004-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea@videolan.org>
8  *          Christophe Massiot <massiot@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <errno.h>                                                 /* ENOMEM */
34
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_sout.h>
38 #include <vlc_block.h>
39 #include <vlc_codec.h>
40 #include <vlc_meta.h>
41
42 #include <vlc_image.h>
43 #include <vlc_filter.h>
44
45 #include "../video_filter/mosaic.h"
46
47 #include <assert.h>
48
49 /*****************************************************************************
50  * Local structures
51  *****************************************************************************/
52 struct sout_stream_sys_t
53 {
54     bridged_es_t *p_es;
55     vlc_mutex_t *p_lock;
56
57     decoder_t       *p_decoder;
58     image_handler_t *p_image; /* filter for resizing */
59     int i_height, i_width;
60     unsigned int i_sar_num, i_sar_den;
61     char *psz_id;
62     bool b_inited;
63
64     int i_chroma; /* force image format chroma */
65
66     filter_chain_t *p_vf2;
67 };
68
69 struct decoder_owner_sys_t
70 {
71     /* Current format in use by the output */
72     video_format_t video;
73 };
74
75 /*****************************************************************************
76  * Local prototypes
77  *****************************************************************************/
78 static int  Open    ( vlc_object_t * );
79 static void Close   ( vlc_object_t * );
80 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
81 static int               Del ( sout_stream_t *, sout_stream_id_t * );
82 static int               Send( sout_stream_t *, sout_stream_id_t *, block_t * );
83
84 inline static void video_del_buffer_decoder( decoder_t *, picture_t * );
85 inline static void video_del_buffer_filter( filter_t *, picture_t * );
86
87 inline static picture_t *video_new_buffer_decoder( decoder_t * );
88 inline static picture_t *video_new_buffer_filter( filter_t * );
89 static picture_t *video_new_buffer( vlc_object_t *, decoder_owner_sys_t *,
90                                     es_format_t * );
91
92 static void video_link_picture_decoder( decoder_t *, picture_t * );
93 static void video_unlink_picture_decoder( decoder_t *, picture_t * );
94
95 static int HeightCallback( vlc_object_t *, char const *,
96                            vlc_value_t, vlc_value_t, void * );
97 static int WidthCallback( vlc_object_t *, char const *,
98                           vlc_value_t, vlc_value_t, void * );
99 static int alphaCallback( vlc_object_t *, char const *,
100                           vlc_value_t, vlc_value_t, void * );
101 static int xCallback( vlc_object_t *, char const *,
102                       vlc_value_t, vlc_value_t, void * );
103 static int yCallback( vlc_object_t *, char const *,
104                       vlc_value_t, vlc_value_t, void * );
105
106 /*****************************************************************************
107  * Module descriptor
108  *****************************************************************************/
109 #define ID_TEXT N_("ID")
110 #define ID_LONGTEXT N_( \
111     "Specify an identifier string for this subpicture" )
112
113 #define WIDTH_TEXT N_("Video width")
114 #define WIDTH_LONGTEXT N_( \
115     "Output video width." )
116 #define HEIGHT_TEXT N_("Video height")
117 #define HEIGHT_LONGTEXT N_( \
118     "Output video height." )
119 #define RATIO_TEXT N_("Sample aspect ratio")
120 #define RATIO_LONGTEXT N_( \
121     "Sample aspect ratio of the destination (1:1, 3:4, 2:3)." )
122
123 #define VFILTER_TEXT N_("Video filter")
124 #define VFILTER_LONGTEXT N_( \
125     "Video filters will be applied to the video stream." )
126
127 #define CHROMA_TEXT N_("Image chroma")
128 #define CHROMA_LONGTEXT N_( \
129     "Force the use of a specific chroma. Use YUVA if you're planning " \
130     "to use the Alphamask or Bluescreen video filter." )
131
132 #define ALPHA_TEXT N_("Transparency")
133 #define ALPHA_LONGTEXT N_( \
134     "Transparency of the mosaic picture." )
135
136 #define X_TEXT N_("X offset")
137 #define X_LONGTEXT N_( \
138     "X coordinate of the upper left corner in the mosaic if non negative." )
139
140 #define Y_TEXT N_("Y offset")
141 #define Y_LONGTEXT N_( \
142     "Y coordinate of the upper left corner in the mosaic if non negative." )
143
144 #define CFG_PREFIX "sout-mosaic-bridge-"
145
146 vlc_module_begin ()
147     set_shortname( N_( "Mosaic bridge" ) )
148     set_description(N_("Mosaic bridge stream output") )
149     set_capability( "sout stream", 0 )
150     add_shortcut( "mosaic-bridge" )
151
152     add_string( CFG_PREFIX "id", "Id", NULL, ID_TEXT, ID_LONGTEXT,
153                 false )
154     add_integer( CFG_PREFIX "width", 0, NULL, WIDTH_TEXT,
155                  WIDTH_LONGTEXT, true )
156     add_integer( CFG_PREFIX "height", 0, NULL, HEIGHT_TEXT,
157                  HEIGHT_LONGTEXT, true )
158     add_string( CFG_PREFIX "sar", "1:1", NULL, RATIO_TEXT,
159                 RATIO_LONGTEXT, false )
160     add_string( CFG_PREFIX "chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
161                 false )
162
163     add_module_list( CFG_PREFIX "vfilter", "video filter2",
164                      NULL, NULL, VFILTER_TEXT, VFILTER_LONGTEXT, false )
165
166     add_integer_with_range( CFG_PREFIX "alpha", 255, 0, 255, NULL,
167                             ALPHA_TEXT, ALPHA_LONGTEXT, false )
168     add_integer( CFG_PREFIX "x", -1, NULL, X_TEXT, X_LONGTEXT, false )
169     add_integer( CFG_PREFIX "y", -1, NULL, Y_TEXT, Y_LONGTEXT, false )
170
171     set_callbacks( Open, Close )
172 vlc_module_end ()
173
174 static const char *const ppsz_sout_options[] = {
175     "id", "width", "height", "sar", "vfilter", "chroma", "alpha", "x", "y", NULL
176 };
177
178 /*****************************************************************************
179  * Open
180  *****************************************************************************/
181 static int Open( vlc_object_t *p_this )
182 {
183     sout_stream_t        *p_stream = (sout_stream_t *)p_this;
184     sout_stream_sys_t    *p_sys;
185     vlc_object_t         *p_libvlc = VLC_OBJECT( p_this->p_libvlc );
186     vlc_value_t           val;
187
188     config_ChainParse( p_stream, CFG_PREFIX, ppsz_sout_options,
189                        p_stream->p_cfg );
190
191     p_sys = malloc( sizeof( sout_stream_sys_t ) );
192     if( !p_sys )
193         return VLC_ENOMEM;
194
195     p_stream->p_sys = p_sys;
196     p_sys->b_inited = false;
197
198     var_Create( p_libvlc, "mosaic-lock", VLC_VAR_MUTEX );
199     var_Get( p_libvlc, "mosaic-lock", &val );
200     p_sys->p_lock = val.p_address;
201
202     p_sys->psz_id = var_CreateGetString( p_stream, CFG_PREFIX "id" );
203
204     p_sys->i_height =
205         var_CreateGetIntegerCommand( p_stream, CFG_PREFIX "height" );
206     var_AddCallback( p_stream, CFG_PREFIX "height", HeightCallback, p_stream );
207
208     p_sys->i_width =
209         var_CreateGetIntegerCommand( p_stream, CFG_PREFIX "width" );
210     var_AddCallback( p_stream, CFG_PREFIX "width", WidthCallback, p_stream );
211
212     var_Get( p_stream, CFG_PREFIX "sar", &val );
213     if( val.psz_string )
214     {
215         char *psz_parser = strchr( val.psz_string, ':' );
216
217         if( psz_parser )
218         {
219             *psz_parser++ = '\0';
220             p_sys->i_sar_num = atoi( val.psz_string );
221             p_sys->i_sar_den = atoi( psz_parser );
222             vlc_ureduce( &p_sys->i_sar_num, &p_sys->i_sar_den,
223                          p_sys->i_sar_num, p_sys->i_sar_den, 0 );
224         }
225         else
226         {
227             msg_Warn( p_stream, "bad aspect ratio %s", val.psz_string );
228             p_sys->i_sar_num = p_sys->i_sar_den = 1;
229         }
230
231         free( val.psz_string );
232     }
233     else
234     {
235         p_sys->i_sar_num = p_sys->i_sar_den = 1;
236     }
237
238     p_sys->i_chroma = 0;
239     val.psz_string = var_GetNonEmptyString( p_stream, CFG_PREFIX "chroma" );
240     if( val.psz_string && strlen( val.psz_string ) >= 4 )
241     {
242         memcpy( &p_sys->i_chroma, val.psz_string, 4 );
243         msg_Dbg( p_stream, "Forcing image chroma to 0x%.8x (%4.4s)", p_sys->i_chroma, (char*)&p_sys->i_chroma );
244     }
245     free( val.psz_string );
246
247 #define INT_COMMAND( a ) do { \
248     var_Create( p_stream, CFG_PREFIX #a, \
249                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND ); \
250     var_AddCallback( p_stream, CFG_PREFIX #a, a ## Callback, \
251                      p_stream ); } while(0)
252     INT_COMMAND( alpha );
253     INT_COMMAND( x );
254     INT_COMMAND( y );
255
256 #undef INT_COMMAND
257
258     p_stream->pf_add    = Add;
259     p_stream->pf_del    = Del;
260     p_stream->pf_send   = Send;
261
262     p_stream->p_sout->i_out_pace_nocontrol++;
263
264     return VLC_SUCCESS;
265 }
266
267 /*****************************************************************************
268  * Close
269  *****************************************************************************/
270 static void Close( vlc_object_t * p_this )
271 {
272     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
273     sout_stream_sys_t *p_sys = p_stream->p_sys;
274
275     /* Delete the callbacks */
276     var_DelCallback( p_stream, CFG_PREFIX "height", HeightCallback, p_stream );
277     var_DelCallback( p_stream, CFG_PREFIX "width", WidthCallback, p_stream );
278     var_DelCallback( p_stream, CFG_PREFIX "alpha", alphaCallback, p_stream );
279     var_DelCallback( p_stream, CFG_PREFIX "x", xCallback, p_stream );
280     var_DelCallback( p_stream, CFG_PREFIX "y", yCallback, p_stream );
281
282     p_stream->p_sout->i_out_pace_nocontrol--;
283
284     free( p_sys->psz_id );
285
286     free( p_sys );
287 }
288
289 static int video_filter_buffer_allocation_init( filter_t *p_filter, void *p_data )
290 {
291     p_filter->pf_vout_buffer_new = video_new_buffer_filter;
292     p_filter->pf_vout_buffer_del = video_del_buffer_filter;
293     p_filter->p_owner = p_data;
294     return VLC_SUCCESS;
295 }
296
297 static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
298 {
299     sout_stream_sys_t *p_sys = p_stream->p_sys;
300     bridge_t *p_bridge;
301     bridged_es_t *p_es;
302     char *psz_chain;
303     int i;
304
305     if( p_sys->b_inited || p_fmt->i_cat != VIDEO_ES )
306         return NULL;
307
308     /* Create decoder object */
309     p_sys->p_decoder = vlc_object_create( p_stream, VLC_OBJECT_DECODER );
310     if( !p_sys->p_decoder )
311         return NULL;
312     vlc_object_attach( p_sys->p_decoder, p_stream );
313     p_sys->p_decoder->p_module = NULL;
314     p_sys->p_decoder->fmt_in = *p_fmt;
315     p_sys->p_decoder->b_pace_control = false;
316     p_sys->p_decoder->fmt_out = p_sys->p_decoder->fmt_in;
317     p_sys->p_decoder->fmt_out.i_extra = 0;
318     p_sys->p_decoder->fmt_out.p_extra = 0;
319     p_sys->p_decoder->pf_decode_video = 0;
320     p_sys->p_decoder->pf_vout_buffer_new = video_new_buffer_decoder;
321     p_sys->p_decoder->pf_vout_buffer_del = video_del_buffer_decoder;
322     p_sys->p_decoder->pf_picture_link    = video_link_picture_decoder;
323     p_sys->p_decoder->pf_picture_unlink  = video_unlink_picture_decoder;
324     p_sys->p_decoder->p_owner = malloc( sizeof(decoder_owner_sys_t) );
325     if( !p_sys->p_decoder->p_owner )
326     {
327         vlc_object_detach( p_sys->p_decoder );
328         vlc_object_release( p_sys->p_decoder );
329         return NULL;
330     }
331
332     p_sys->p_decoder->p_owner->video = p_fmt->video;
333     //p_sys->p_decoder->p_cfg = p_sys->p_video_cfg;
334
335     p_sys->p_decoder->p_module =
336         module_need( p_sys->p_decoder, "decoder", "$codec", false );
337
338     if( !p_sys->p_decoder->p_module || !p_sys->p_decoder->pf_decode_video )
339     {
340         if( p_sys->p_decoder->p_module )
341         {
342             msg_Err( p_stream, "instanciated a non video decoder" );
343             module_unneed( p_sys->p_decoder, p_sys->p_decoder->p_module );
344         }
345         else
346         {
347             msg_Err( p_stream, "cannot find decoder" );
348         }
349         free( p_sys->p_decoder->p_owner );
350         vlc_object_detach( p_sys->p_decoder );
351         vlc_object_release( p_sys->p_decoder );
352         return NULL;
353     }
354
355     p_sys->b_inited = true;
356     vlc_mutex_lock( p_sys->p_lock );
357
358     p_bridge = GetBridge( p_stream );
359     if ( p_bridge == NULL )
360     {
361         vlc_object_t *p_libvlc = VLC_OBJECT( p_stream->p_libvlc );
362         vlc_value_t val;
363
364         p_bridge = malloc( sizeof( bridge_t ) );
365
366         var_Create( p_libvlc, "mosaic-struct", VLC_VAR_ADDRESS );
367         val.p_address = p_bridge;
368         var_Set( p_libvlc, "mosaic-struct", val );
369
370         p_bridge->i_es_num = 0;
371         p_bridge->pp_es = NULL;
372     }
373
374     for ( i = 0; i < p_bridge->i_es_num; i++ )
375     {
376         if ( p_bridge->pp_es[i]->b_empty )
377             break;
378     }
379
380     if ( i == p_bridge->i_es_num )
381     {
382         p_bridge->pp_es = realloc( p_bridge->pp_es,
383                                    (p_bridge->i_es_num + 1)
384                                      * sizeof(bridged_es_t *) );
385         p_bridge->i_es_num++;
386         p_bridge->pp_es[i] = malloc( sizeof(bridged_es_t) );
387     }
388
389     p_sys->p_es = p_es = p_bridge->pp_es[i];
390
391     p_es->i_alpha = var_GetInteger( p_stream, CFG_PREFIX "alpha" );
392     p_es->i_x = var_GetInteger( p_stream, CFG_PREFIX "x" );
393     p_es->i_y = var_GetInteger( p_stream, CFG_PREFIX "y" );
394
395     //p_es->fmt = *p_fmt;
396     p_es->psz_id = p_sys->psz_id;
397     p_es->p_picture = NULL;
398     p_es->pp_last = &p_es->p_picture;
399     p_es->b_empty = false;
400
401     vlc_mutex_unlock( p_sys->p_lock );
402
403     if ( p_sys->i_height || p_sys->i_width )
404     {
405         p_sys->p_image = image_HandlerCreate( p_stream );
406     }
407     else
408     {
409         p_sys->p_image = NULL;
410     }
411
412     msg_Dbg( p_stream, "mosaic bridge id=%s pos=%d", p_es->psz_id, i );
413
414     /* Create user specified video filters */
415     psz_chain = var_GetNonEmptyString( p_stream, CFG_PREFIX "vfilter" );
416     msg_Dbg( p_stream, "psz_chain: %s", psz_chain );
417     if( psz_chain )
418     {
419         p_sys->p_vf2 = filter_chain_New( p_stream, "video filter2", false,
420                                          video_filter_buffer_allocation_init,
421                                          NULL, p_sys->p_decoder->p_owner );
422         es_format_t fmt;
423         es_format_Copy( &fmt, &p_sys->p_decoder->fmt_out );
424         if( p_sys->i_chroma )
425             fmt.video.i_chroma = p_sys->i_chroma;
426         filter_chain_Reset( p_sys->p_vf2, &fmt, &fmt );
427         filter_chain_AppendFromString( p_sys->p_vf2, psz_chain );
428         free( psz_chain );
429     }
430     else
431     {
432         p_sys->p_vf2 = NULL;
433     }
434
435     return (sout_stream_id_t *)p_sys;
436 }
437
438 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
439 {
440     VLC_UNUSED(id);
441     sout_stream_sys_t *p_sys = p_stream->p_sys;
442     bridge_t *p_bridge;
443     bridged_es_t *p_es;
444     bool b_last_es = true;
445     int i;
446
447     if( !p_sys->b_inited )
448         return VLC_SUCCESS;
449
450     if( p_sys->p_decoder != NULL )
451     {
452         decoder_owner_sys_t *p_owner = p_sys->p_decoder->p_owner;
453
454         if( p_sys->p_decoder->p_module )
455             module_unneed( p_sys->p_decoder, p_sys->p_decoder->p_module );
456         if( p_sys->p_decoder->p_description )
457             vlc_meta_Delete( p_sys->p_decoder->p_description );
458
459         vlc_object_detach( p_sys->p_decoder );
460         vlc_object_release( p_sys->p_decoder );
461
462         free( p_owner );
463     }
464
465     /* Destroy user specified video filters */
466     if( p_sys->p_vf2 )
467         filter_chain_Delete( p_sys->p_vf2 );
468
469     vlc_mutex_lock( p_sys->p_lock );
470
471     p_bridge = GetBridge( p_stream );
472     p_es = p_sys->p_es;
473
474     p_es->b_empty = true;
475     while ( p_es->p_picture )
476     {
477         picture_t *p_next = p_es->p_picture->p_next;
478         picture_Release( p_es->p_picture );
479         p_es->p_picture = p_next;
480     }
481
482     for ( i = 0; i < p_bridge->i_es_num; i++ )
483     {
484         if ( !p_bridge->pp_es[i]->b_empty )
485         {
486             b_last_es = false;
487             break;
488         }
489     }
490
491     if ( b_last_es )
492     {
493         vlc_object_t *p_libvlc = VLC_OBJECT( p_stream->p_libvlc );
494         for ( i = 0; i < p_bridge->i_es_num; i++ )
495             free( p_bridge->pp_es[i] );
496         free( p_bridge->pp_es );
497         free( p_bridge );
498         var_Destroy( p_libvlc, "mosaic-struct" );
499     }
500
501     vlc_mutex_unlock( p_sys->p_lock );
502
503     if ( p_sys->p_image )
504     {
505         image_HandlerDelete( p_sys->p_image );
506     }
507
508     p_sys->b_inited = false;
509
510     return VLC_SUCCESS;
511 }
512
513 /*****************************************************************************
514  * PushPicture : push a picture in the mosaic-struct structure
515  *****************************************************************************/
516 static void PushPicture( sout_stream_t *p_stream, picture_t *p_picture )
517 {
518     sout_stream_sys_t *p_sys = p_stream->p_sys;
519     bridged_es_t *p_es = p_sys->p_es;
520
521     vlc_mutex_lock( p_sys->p_lock );
522
523     *p_es->pp_last = p_picture;
524     p_picture->p_next = NULL;
525     p_es->pp_last = &p_picture->p_next;
526
527     vlc_mutex_unlock( p_sys->p_lock );
528 }
529
530 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
531                  block_t *p_buffer )
532 {
533     sout_stream_sys_t *p_sys = p_stream->p_sys;
534     picture_t *p_pic;
535
536     if ( (sout_stream_sys_t *)id != p_sys )
537     {
538         block_ChainRelease( p_buffer );
539         return VLC_SUCCESS;
540     }
541
542     while ( (p_pic = p_sys->p_decoder->pf_decode_video( p_sys->p_decoder,
543                                                         &p_buffer )) )
544     {
545         picture_t *p_new_pic;
546
547         if( p_sys->i_height || p_sys->i_width )
548         {
549             video_format_t fmt_out, fmt_in;
550
551             memset( &fmt_in, 0, sizeof(video_format_t) );
552             memset( &fmt_out, 0, sizeof(video_format_t) );
553             fmt_in = p_sys->p_decoder->fmt_out.video;
554
555
556             if( p_sys->i_chroma )
557                 fmt_out.i_chroma = p_sys->i_chroma;
558             else
559                 fmt_out.i_chroma = VLC_CODEC_I420;
560
561             if ( !p_sys->i_height )
562             {
563                 fmt_out.i_width = p_sys->i_width;
564                 fmt_out.i_height = (p_sys->i_width * VOUT_ASPECT_FACTOR
565                     * p_sys->i_sar_num / p_sys->i_sar_den / fmt_in.i_aspect)
566                       & ~0x1;
567             }
568             else if ( !p_sys->i_width )
569             {
570                 fmt_out.i_height = p_sys->i_height;
571                 fmt_out.i_width = (p_sys->i_height * fmt_in.i_aspect
572                     * p_sys->i_sar_den / p_sys->i_sar_num / VOUT_ASPECT_FACTOR)
573                       & ~0x1;
574             }
575             else
576             {
577                 fmt_out.i_width = p_sys->i_width;
578                 fmt_out.i_height = p_sys->i_height;
579             }
580             fmt_out.i_visible_width = fmt_out.i_width;
581             fmt_out.i_visible_height = fmt_out.i_height;
582
583             p_new_pic = image_Convert( p_sys->p_image,
584                                        p_pic, &fmt_in, &fmt_out );
585             if( p_new_pic == NULL )
586             {
587                 msg_Err( p_stream, "image conversion failed" );
588                 picture_Release( p_pic );
589                 continue;
590             }
591         }
592         else
593         {
594             /* TODO: chroma conversion if needed */
595
596             p_new_pic = picture_New( p_pic->format.i_chroma,
597                                      p_pic->format.i_width, p_pic->format.i_height,
598                                      p_sys->p_decoder->fmt_out.video.i_aspect );
599             if( !p_new_pic )
600             {
601                 picture_Release( p_pic );
602                 msg_Err( p_stream, "image allocation failed" );
603                 continue;
604             }
605
606             picture_Copy( p_new_pic, p_pic );
607         }
608         picture_Release( p_pic );
609
610         if( p_sys->p_vf2 )
611             p_new_pic = filter_chain_VideoFilter( p_sys->p_vf2, p_new_pic );
612
613         PushPicture( p_stream, p_new_pic );
614     }
615
616     return VLC_SUCCESS;
617 }
618
619 inline static picture_t *video_new_buffer_decoder( decoder_t *p_dec )
620 {
621     return video_new_buffer( VLC_OBJECT( p_dec ),
622                              (decoder_owner_sys_t *)p_dec->p_owner,
623                              &p_dec->fmt_out );
624 }
625
626 inline static picture_t *video_new_buffer_filter( filter_t *p_filter )
627 {
628     return video_new_buffer( VLC_OBJECT( p_filter ),
629                              (decoder_owner_sys_t *)p_filter->p_owner,
630                              &p_filter->fmt_out );
631 }
632
633 static picture_t *video_new_buffer( vlc_object_t *p_this,
634                                     decoder_owner_sys_t *p_sys,
635                                     es_format_t *fmt_out )
636 {
637     VLC_UNUSED(p_this);
638     if( fmt_out->video.i_width != p_sys->video.i_width ||
639         fmt_out->video.i_height != p_sys->video.i_height ||
640         fmt_out->video.i_chroma != p_sys->video.i_chroma ||
641         fmt_out->video.i_aspect != p_sys->video.i_aspect )
642     {
643         if( !fmt_out->video.i_sar_num ||
644             !fmt_out->video.i_sar_den )
645         {
646             fmt_out->video.i_sar_num =
647                 fmt_out->video.i_aspect * fmt_out->video.i_height;
648
649             fmt_out->video.i_sar_den =
650                 VOUT_ASPECT_FACTOR * fmt_out->video.i_width;
651         }
652
653         vlc_ureduce( &fmt_out->video.i_sar_num,
654                      &fmt_out->video.i_sar_den,
655                      fmt_out->video.i_sar_num,
656                      fmt_out->video.i_sar_den, 0 );
657
658         if( !fmt_out->video.i_visible_width ||
659             !fmt_out->video.i_visible_height )
660         {
661             fmt_out->video.i_visible_width = fmt_out->video.i_width;
662             fmt_out->video.i_visible_height = fmt_out->video.i_height;
663         }
664
665         fmt_out->video.i_chroma = fmt_out->i_codec;
666         p_sys->video = fmt_out->video;
667     }
668
669     /* */
670     fmt_out->video.i_chroma = fmt_out->i_codec;
671
672     return picture_New( fmt_out->video.i_chroma,
673                         fmt_out->video.i_width,
674                         fmt_out->video.i_height,
675                         fmt_out->video.i_aspect );
676 }
677
678 inline static void video_del_buffer_decoder( decoder_t *p_this,
679                                              picture_t *p_pic )
680 {
681     VLC_UNUSED(p_this);
682     picture_Release( p_pic );
683 }
684
685 inline static void video_del_buffer_filter( filter_t *p_this,
686                                             picture_t *p_pic )
687 {
688     VLC_UNUSED(p_this);
689     picture_Release( p_pic );
690 }
691
692 static void video_link_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
693 {
694     VLC_UNUSED(p_dec);
695     picture_Hold( p_pic );
696 }
697
698 static void video_unlink_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
699 {
700     VLC_UNUSED(p_dec);
701     picture_Release( p_pic );
702 }
703
704
705 /**********************************************************************
706  * Callback to update (some) params on the fly
707  **********************************************************************/
708 static int HeightCallback( vlc_object_t *p_this, char const *psz_var,
709                            vlc_value_t oldval, vlc_value_t newval,
710                            void *p_data )
711 {
712     VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(psz_var);
713     sout_stream_t *p_stream = (sout_stream_t *)p_data;
714     sout_stream_sys_t *p_sys = p_stream->p_sys;
715
716     /* We create the handler before updating the value in p_sys
717      * so we don't have to worry about locking */
718     if( !p_sys->p_image && newval.i_int )
719         p_sys->p_image = image_HandlerCreate( p_stream );
720     p_sys->i_height = newval.i_int;
721
722     return VLC_SUCCESS;
723 }
724
725 static int WidthCallback( vlc_object_t *p_this, char const *psz_var,
726                            vlc_value_t oldval, vlc_value_t newval,
727                            void *p_data )
728 {
729     VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(psz_var);
730     sout_stream_t *p_stream = (sout_stream_t *)p_data;
731     sout_stream_sys_t *p_sys = p_stream->p_sys;
732
733     /* We create the handler before updating the value in p_sys
734      * so we don't have to worry about locking */
735     if( !p_sys->p_image && newval.i_int )
736         p_sys->p_image = image_HandlerCreate( p_stream );
737     p_sys->i_width = newval.i_int;
738
739     return VLC_SUCCESS;
740 }
741
742 static int alphaCallback( vlc_object_t *p_this, char const *psz_var,
743                           vlc_value_t oldval, vlc_value_t newval,
744                           void *p_data )
745 {
746     VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(psz_var);
747     sout_stream_t *p_stream = (sout_stream_t *)p_data;
748     sout_stream_sys_t *p_sys = p_stream->p_sys;
749
750     if( p_sys->p_es )
751         p_sys->p_es->i_alpha = newval.i_int;
752
753     return VLC_SUCCESS;
754 }
755
756 static int xCallback( vlc_object_t *p_this, char const *psz_var,
757                       vlc_value_t oldval, vlc_value_t newval,
758                       void *p_data )
759 {
760     VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(psz_var);
761     sout_stream_t *p_stream = (sout_stream_t *)p_data;
762     sout_stream_sys_t *p_sys = p_stream->p_sys;
763
764     if( p_sys->p_es )
765         p_sys->p_es->i_x = newval.i_int;
766
767     return VLC_SUCCESS;
768 }
769
770 static int yCallback( vlc_object_t *p_this, char const *psz_var,
771                       vlc_value_t oldval, vlc_value_t newval,
772                       void *p_data )
773 {
774     VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(psz_var);
775     sout_stream_t *p_stream = (sout_stream_t *)p_data;
776     sout_stream_sys_t *p_sys = p_stream->p_sys;
777
778     if( p_sys->p_es )
779         p_sys->p_es->i_y = newval.i_int;
780
781     return VLC_SUCCESS;
782 }