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