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