i18: Translate one more string
[vlc/vlc-acra.git] / modules / stream_out / mosaic_bridge.c
blobdaec5cdb93d9eb460c824aac71a2651249582889
1 /*****************************************************************************
2 * mosaic_bridge.c:
3 *****************************************************************************
4 * Copyright (C) 2004-2007 the VideoLAN team
5 * $Id$
7 * Authors: Antoine Cellerier <dionoea@videolan.org>
8 * Christophe Massiot <massiot@via.ecp.fr>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
26 * Preamble
27 *****************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
33 #include <errno.h> /* ENOMEM */
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>
41 #include <vlc_image.h>
42 #include <vlc_filter.h>
44 #include "../video_filter/mosaic.h"
46 #include <assert.h>
48 /*****************************************************************************
49 * Local structures
50 *****************************************************************************/
51 struct sout_stream_sys_t
53 bridged_es_t *p_es;
54 vlc_mutex_t *p_lock;
56 decoder_t *p_decoder;
57 image_handler_t *p_image; /* filter for resizing */
58 int i_height, i_width;
59 unsigned int i_sar_num, i_sar_den;
60 char *psz_id;
61 bool b_inited;
63 int i_chroma; /* force image format chroma */
65 filter_chain_t *p_vf2;
68 #define PICTURE_RING_SIZE 4
69 struct decoder_owner_sys_t
71 picture_t *pp_pics[PICTURE_RING_SIZE];
73 /* Current format in use by the output */
74 video_format_t video;
77 typedef void (* pf_release_t)( picture_t * );
78 static void ReleasePicture( picture_t *p_pic )
80 assert( p_pic );
82 if( --p_pic->i_refcount > 0 )
83 return;
85 if( p_pic->p_sys )
87 pf_release_t pf_release = (pf_release_t)p_pic->p_sys;
88 p_pic->p_sys = NULL;
89 pf_release( p_pic );
91 else
93 free( p_pic->p_q );
94 free( p_pic->p_data_orig );
95 free( p_pic );
99 /*****************************************************************************
100 * Local prototypes
101 *****************************************************************************/
102 static int Open ( vlc_object_t * );
103 static void Close ( vlc_object_t * );
104 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
105 static int Del ( sout_stream_t *, sout_stream_id_t * );
106 static int Send( sout_stream_t *, sout_stream_id_t *, block_t * );
108 inline static void video_del_buffer_decoder( decoder_t *, picture_t * );
109 inline static void video_del_buffer_filter( filter_t *, picture_t * );
110 static void video_del_buffer( picture_t * );
112 inline static picture_t *video_new_buffer_decoder( decoder_t * );
113 inline static picture_t *video_new_buffer_filter( filter_t * );
114 static picture_t *video_new_buffer( vlc_object_t *, decoder_owner_sys_t *,
115 es_format_t *, void (*)( picture_t * ) );
117 static void video_link_picture_decoder( decoder_t *, picture_t * );
118 static void video_unlink_picture_decoder( decoder_t *, picture_t * );
120 static int HeightCallback( vlc_object_t *, char const *,
121 vlc_value_t, vlc_value_t, void * );
122 static int WidthCallback( vlc_object_t *, char const *,
123 vlc_value_t, vlc_value_t, void * );
124 static int alphaCallback( vlc_object_t *, char const *,
125 vlc_value_t, vlc_value_t, void * );
126 static int xCallback( vlc_object_t *, char const *,
127 vlc_value_t, vlc_value_t, void * );
128 static int yCallback( vlc_object_t *, char const *,
129 vlc_value_t, vlc_value_t, void * );
131 /*****************************************************************************
132 * Module descriptor
133 *****************************************************************************/
134 #define ID_TEXT N_("ID")
135 #define ID_LONGTEXT N_( \
136 "Specify an identifier string for this subpicture" )
138 #define WIDTH_TEXT N_("Video width")
139 #define WIDTH_LONGTEXT N_( \
140 "Output video width." )
141 #define HEIGHT_TEXT N_("Video height")
142 #define HEIGHT_LONGTEXT N_( \
143 "Output video height." )
144 #define RATIO_TEXT N_("Sample aspect ratio")
145 #define RATIO_LONGTEXT N_( \
146 "Sample aspect ratio of the destination (1:1, 3:4, 2:3)." )
148 #define VFILTER_TEXT N_("Video filter")
149 #define VFILTER_LONGTEXT N_( \
150 "Video filters will be applied to the video stream." )
152 #define CHROMA_TEXT N_("Image chroma")
153 #define CHROMA_LONGTEXT N_( \
154 "Force the use of a specific chroma. Use YUVA if you're planning " \
155 "to use the Alphamask or Bluescreen video filter." )
157 #define ALPHA_TEXT N_("Transparency")
158 #define ALPHA_LONGTEXT N_( \
159 "Transparency of the mosaic picture." )
161 #define X_TEXT N_("X offset")
162 #define X_LONGTEXT N_( \
163 "X coordinate of the upper left corner in the mosaic if non negative." )
165 #define Y_TEXT N_("Y offset")
166 #define Y_LONGTEXT N_( \
167 "Y coordinate of the upper left corner in the mosaic if non negative." )
169 #define CFG_PREFIX "sout-mosaic-bridge-"
171 vlc_module_begin ()
172 set_shortname( N_( "Mosaic bridge" ) )
173 set_description(N_("Mosaic bridge stream output") )
174 set_capability( "sout stream", 0 )
175 add_shortcut( "mosaic-bridge" )
177 add_string( CFG_PREFIX "id", "Id", NULL, ID_TEXT, ID_LONGTEXT,
178 false );
179 add_integer( CFG_PREFIX "width", 0, NULL, WIDTH_TEXT,
180 WIDTH_LONGTEXT, true );
181 add_integer( CFG_PREFIX "height", 0, NULL, HEIGHT_TEXT,
182 HEIGHT_LONGTEXT, true );
183 add_string( CFG_PREFIX "sar", "1:1", NULL, RATIO_TEXT,
184 RATIO_LONGTEXT, false );
185 add_string( CFG_PREFIX "chroma", 0, NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
186 false );
188 add_module_list( CFG_PREFIX "vfilter", "video filter2",
189 NULL, NULL, VFILTER_TEXT, VFILTER_LONGTEXT, false );
191 add_integer_with_range( CFG_PREFIX "alpha", 255, 0, 255, NULL,
192 ALPHA_TEXT, ALPHA_LONGTEXT, false );
193 add_integer( CFG_PREFIX "x", -1, NULL, X_TEXT, X_LONGTEXT, false )
194 add_integer( CFG_PREFIX "y", -1, NULL, Y_TEXT, Y_LONGTEXT, false )
196 set_callbacks( Open, Close )
197 vlc_module_end ()
199 static const char *const ppsz_sout_options[] = {
200 "id", "width", "height", "sar", "vfilter", "chroma", "alpha", "x", "y", NULL
203 /*****************************************************************************
204 * Open
205 *****************************************************************************/
206 static int Open( vlc_object_t *p_this )
208 sout_stream_t *p_stream = (sout_stream_t *)p_this;
209 sout_stream_sys_t *p_sys;
210 vlc_object_t *p_libvlc = VLC_OBJECT( p_this->p_libvlc );
211 vlc_value_t val;
213 config_ChainParse( p_stream, CFG_PREFIX, ppsz_sout_options,
214 p_stream->p_cfg );
216 p_sys = malloc( sizeof( sout_stream_sys_t ) );
217 if( !p_sys )
218 return VLC_ENOMEM;
220 p_stream->p_sys = p_sys;
221 p_sys->b_inited = false;
223 var_Create( p_libvlc, "mosaic-lock", VLC_VAR_MUTEX );
224 var_Get( p_libvlc, "mosaic-lock", &val );
225 p_sys->p_lock = val.p_address;
227 p_sys->psz_id = var_CreateGetString( p_stream, CFG_PREFIX "id" );
229 p_sys->i_height =
230 var_CreateGetIntegerCommand( p_stream, CFG_PREFIX "height" );
231 var_AddCallback( p_stream, CFG_PREFIX "height", HeightCallback, p_stream );
233 p_sys->i_width =
234 var_CreateGetIntegerCommand( p_stream, CFG_PREFIX "width" );
235 var_AddCallback( p_stream, CFG_PREFIX "width", WidthCallback, p_stream );
237 var_Get( p_stream, CFG_PREFIX "sar", &val );
238 if( val.psz_string )
240 char *psz_parser = strchr( val.psz_string, ':' );
242 if( psz_parser )
244 *psz_parser++ = '\0';
245 p_sys->i_sar_num = atoi( val.psz_string );
246 p_sys->i_sar_den = atoi( psz_parser );
247 vlc_ureduce( &p_sys->i_sar_num, &p_sys->i_sar_den,
248 p_sys->i_sar_num, p_sys->i_sar_den, 0 );
250 else
252 msg_Warn( p_stream, "bad aspect ratio %s", val.psz_string );
253 p_sys->i_sar_num = p_sys->i_sar_den = 1;
256 free( val.psz_string );
258 else
260 p_sys->i_sar_num = p_sys->i_sar_den = 1;
263 p_sys->i_chroma = 0;
264 val.psz_string = var_GetNonEmptyString( p_stream, CFG_PREFIX "chroma" );
265 if( val.psz_string && strlen( val.psz_string ) >= 4 )
267 memcpy( &p_sys->i_chroma, val.psz_string, 4 );
268 msg_Dbg( p_stream, "Forcing image chroma to 0x%.8x (%4.4s)", p_sys->i_chroma, (char*)&p_sys->i_chroma );
270 free( val.psz_string );
272 #define INT_COMMAND( a ) do { \
273 var_Create( p_stream, CFG_PREFIX #a, \
274 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND ); \
275 var_AddCallback( p_stream, CFG_PREFIX #a, a ## Callback, \
276 p_stream ); } while(0)
277 INT_COMMAND( alpha );
278 INT_COMMAND( x );
279 INT_COMMAND( y );
281 #undef INT_COMMAND
283 p_stream->pf_add = Add;
284 p_stream->pf_del = Del;
285 p_stream->pf_send = Send;
287 p_stream->p_sout->i_out_pace_nocontrol++;
289 return VLC_SUCCESS;
292 /*****************************************************************************
293 * Close
294 *****************************************************************************/
295 static void Close( vlc_object_t * p_this )
297 sout_stream_t *p_stream = (sout_stream_t*)p_this;
298 sout_stream_sys_t *p_sys = p_stream->p_sys;
300 p_stream->p_sout->i_out_pace_nocontrol--;
302 free( p_sys->psz_id );
304 free( p_sys );
307 static int video_filter_buffer_allocation_init( filter_t *p_filter, void *p_data )
309 p_filter->pf_vout_buffer_new = video_new_buffer_filter;
310 p_filter->pf_vout_buffer_del = video_del_buffer_filter;
311 p_filter->p_owner = p_data;
312 return VLC_SUCCESS;
315 static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
317 sout_stream_sys_t *p_sys = p_stream->p_sys;
318 bridge_t *p_bridge;
319 bridged_es_t *p_es;
320 char *psz_chain;
321 int i;
323 if( p_sys->b_inited || p_fmt->i_cat != VIDEO_ES )
324 return NULL;
326 /* Create decoder object */
327 p_sys->p_decoder = vlc_object_create( p_stream, VLC_OBJECT_DECODER );
328 if( !p_sys->p_decoder )
329 return NULL;
330 vlc_object_attach( p_sys->p_decoder, p_stream );
331 p_sys->p_decoder->p_module = NULL;
332 p_sys->p_decoder->fmt_in = *p_fmt;
333 p_sys->p_decoder->b_pace_control = false;
334 p_sys->p_decoder->fmt_out = p_sys->p_decoder->fmt_in;
335 p_sys->p_decoder->fmt_out.i_extra = 0;
336 p_sys->p_decoder->fmt_out.p_extra = 0;
337 p_sys->p_decoder->pf_decode_video = 0;
338 p_sys->p_decoder->pf_vout_buffer_new = video_new_buffer_decoder;
339 p_sys->p_decoder->pf_vout_buffer_del = video_del_buffer_decoder;
340 p_sys->p_decoder->pf_picture_link = video_link_picture_decoder;
341 p_sys->p_decoder->pf_picture_unlink = video_unlink_picture_decoder;
342 p_sys->p_decoder->p_owner = malloc( sizeof(decoder_owner_sys_t) );
343 if( !p_sys->p_decoder->p_owner )
345 vlc_object_detach( p_sys->p_decoder );
346 vlc_object_release( p_sys->p_decoder );
347 return NULL;
350 for( i = 0; i < PICTURE_RING_SIZE; i++ )
351 p_sys->p_decoder->p_owner->pp_pics[i] = NULL;
352 p_sys->p_decoder->p_owner->video = p_fmt->video;
353 //p_sys->p_decoder->p_cfg = p_sys->p_video_cfg;
355 p_sys->p_decoder->p_module =
356 module_need( p_sys->p_decoder, "decoder", "$codec", 0 );
358 if( !p_sys->p_decoder->p_module || !p_sys->p_decoder->pf_decode_video )
360 if( p_sys->p_decoder->p_module )
362 msg_Err( p_stream, "instanciated a non video decoder" );
363 module_unneed( p_sys->p_decoder, p_sys->p_decoder->p_module );
365 else
367 msg_Err( p_stream, "cannot find decoder" );
369 free( p_sys->p_decoder->p_owner );
370 vlc_object_detach( p_sys->p_decoder );
371 vlc_object_release( p_sys->p_decoder );
372 return NULL;
375 p_sys->b_inited = true;
376 vlc_mutex_lock( p_sys->p_lock );
378 p_bridge = GetBridge( p_stream );
379 if ( p_bridge == NULL )
381 vlc_object_t *p_libvlc = VLC_OBJECT( p_stream->p_libvlc );
382 vlc_value_t val;
384 p_bridge = malloc( sizeof( bridge_t ) );
386 var_Create( p_libvlc, "mosaic-struct", VLC_VAR_ADDRESS );
387 val.p_address = p_bridge;
388 var_Set( p_libvlc, "mosaic-struct", val );
390 p_bridge->i_es_num = 0;
391 p_bridge->pp_es = NULL;
394 for ( i = 0; i < p_bridge->i_es_num; i++ )
396 if ( p_bridge->pp_es[i]->b_empty )
397 break;
400 if ( i == p_bridge->i_es_num )
402 p_bridge->pp_es = realloc( p_bridge->pp_es,
403 (p_bridge->i_es_num + 1)
404 * sizeof(bridged_es_t *) );
405 p_bridge->i_es_num++;
406 p_bridge->pp_es[i] = malloc( sizeof(bridged_es_t) );
409 p_sys->p_es = p_es = p_bridge->pp_es[i];
411 p_es->i_alpha = var_GetInteger( p_stream, CFG_PREFIX "alpha" );
412 p_es->i_x = var_GetInteger( p_stream, CFG_PREFIX "x" );
413 p_es->i_y = var_GetInteger( p_stream, CFG_PREFIX "y" );
415 //p_es->fmt = *p_fmt;
416 p_es->psz_id = p_sys->psz_id;
417 p_es->p_picture = NULL;
418 p_es->pp_last = &p_es->p_picture;
419 p_es->b_empty = false;
421 vlc_mutex_unlock( p_sys->p_lock );
423 if ( p_sys->i_height || p_sys->i_width )
425 p_sys->p_image = image_HandlerCreate( p_stream );
427 else
429 p_sys->p_image = NULL;
432 msg_Dbg( p_stream, "mosaic bridge id=%s pos=%d", p_es->psz_id, i );
434 /* Create user specified video filters */
435 psz_chain = var_GetNonEmptyString( p_stream, CFG_PREFIX "vfilter" );
436 msg_Dbg( p_stream, "psz_chain: %s\n", psz_chain );
437 if( psz_chain )
439 p_sys->p_vf2 = filter_chain_New( p_stream, "video filter2", false,
440 video_filter_buffer_allocation_init,
441 NULL, p_sys->p_decoder->p_owner );
442 es_format_t fmt;
443 es_format_Copy( &fmt, &p_sys->p_decoder->fmt_out );
444 if( p_sys->i_chroma )
445 fmt.video.i_chroma = p_sys->i_chroma;
446 filter_chain_Reset( p_sys->p_vf2, &fmt, &fmt );
447 filter_chain_AppendFromString( p_sys->p_vf2, psz_chain );
448 free( psz_chain );
450 else
452 p_sys->p_vf2 = NULL;
455 return (sout_stream_id_t *)p_sys;
458 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
460 VLC_UNUSED(id);
461 sout_stream_sys_t *p_sys = p_stream->p_sys;
462 bridge_t *p_bridge;
463 bridged_es_t *p_es;
464 bool b_last_es = true;
465 int i;
467 if( !p_sys->b_inited )
468 return VLC_SUCCESS;
470 if( p_sys->p_decoder != NULL )
472 decoder_owner_sys_t *p_owner = p_sys->p_decoder->p_owner;
474 if( p_sys->p_decoder->p_module )
475 module_unneed( p_sys->p_decoder, p_sys->p_decoder->p_module );
476 vlc_object_detach( p_sys->p_decoder );
477 vlc_object_release( p_sys->p_decoder );
479 picture_t **pp_ring = p_owner->pp_pics;
480 for( i = 0; i < PICTURE_RING_SIZE; i++ )
482 if ( pp_ring[i] != NULL )
484 free( pp_ring[i]->p_data_orig );
485 free( pp_ring[i]->p_sys );
486 free( pp_ring[i] );
489 free( p_owner );
492 /* Destroy user specified video filters */
493 if( p_sys->p_vf2 )
494 filter_chain_Delete( p_sys->p_vf2 );
496 vlc_mutex_lock( p_sys->p_lock );
498 p_bridge = GetBridge( p_stream );
499 p_es = p_sys->p_es;
501 p_es->b_empty = true;
502 while ( p_es->p_picture )
504 picture_t *p_next = p_es->p_picture->p_next;
505 p_es->p_picture->pf_release( p_es->p_picture );
506 p_es->p_picture = p_next;
509 for ( i = 0; i < p_bridge->i_es_num; i++ )
511 if ( !p_bridge->pp_es[i]->b_empty )
513 b_last_es = false;
514 break;
518 if ( b_last_es )
520 vlc_object_t *p_libvlc = VLC_OBJECT( p_stream->p_libvlc );
521 for ( i = 0; i < p_bridge->i_es_num; i++ )
522 free( p_bridge->pp_es[i] );
523 free( p_bridge->pp_es );
524 free( p_bridge );
525 var_Destroy( p_libvlc, "mosaic-struct" );
528 vlc_mutex_unlock( p_sys->p_lock );
530 if ( p_sys->p_image )
532 image_HandlerDelete( p_sys->p_image );
535 p_sys->b_inited = false;
537 return VLC_SUCCESS;
540 /*****************************************************************************
541 * PushPicture : push a picture in the mosaic-struct structure
542 *****************************************************************************/
543 static void PushPicture( sout_stream_t *p_stream, picture_t *p_picture )
545 sout_stream_sys_t *p_sys = p_stream->p_sys;
546 bridged_es_t *p_es = p_sys->p_es;
548 vlc_mutex_lock( p_sys->p_lock );
550 *p_es->pp_last = p_picture;
551 p_picture->p_next = NULL;
552 p_es->pp_last = &p_picture->p_next;
554 vlc_mutex_unlock( p_sys->p_lock );
557 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
558 block_t *p_buffer )
560 sout_stream_sys_t *p_sys = p_stream->p_sys;
561 picture_t *p_pic;
563 if ( (sout_stream_sys_t *)id != p_sys )
565 block_ChainRelease( p_buffer );
566 return VLC_SUCCESS;
569 while ( (p_pic = p_sys->p_decoder->pf_decode_video( p_sys->p_decoder,
570 &p_buffer )) )
572 picture_t *p_new_pic;
574 if( p_sys->i_height || p_sys->i_width )
576 video_format_t fmt_out, fmt_in;
578 memset( &fmt_in, 0, sizeof(video_format_t) );
579 memset( &fmt_out, 0, sizeof(video_format_t) );
580 fmt_in = p_sys->p_decoder->fmt_out.video;
583 if( p_sys->i_chroma )
584 fmt_out.i_chroma = p_sys->i_chroma;
585 else
586 fmt_out.i_chroma = VLC_FOURCC('I','4','2','0');
588 if ( !p_sys->i_height )
590 fmt_out.i_width = p_sys->i_width;
591 fmt_out.i_height = (p_sys->i_width * VOUT_ASPECT_FACTOR
592 * p_sys->i_sar_num / p_sys->i_sar_den / fmt_in.i_aspect)
593 & ~0x1;
595 else if ( !p_sys->i_width )
597 fmt_out.i_height = p_sys->i_height;
598 fmt_out.i_width = (p_sys->i_height * fmt_in.i_aspect
599 * p_sys->i_sar_den / p_sys->i_sar_num / VOUT_ASPECT_FACTOR)
600 & ~0x1;
602 else
604 fmt_out.i_width = p_sys->i_width;
605 fmt_out.i_height = p_sys->i_height;
607 fmt_out.i_visible_width = fmt_out.i_width;
608 fmt_out.i_visible_height = fmt_out.i_height;
610 p_new_pic = image_Convert( p_sys->p_image,
611 p_pic, &fmt_in, &fmt_out );
612 if ( p_new_pic == NULL )
614 msg_Err( p_stream, "image conversion failed" );
615 picture_Release( p_pic );
616 continue;
619 else
621 /* TODO: chroma conversion if needed */
623 p_new_pic = (picture_t*)malloc( sizeof(picture_t) );
624 if( p_new_pic == NULL )
626 msg_Err( p_stream, "image conversion failed" );
627 continue;
630 if( vout_AllocatePicture(
631 p_stream, p_new_pic, p_pic->format.i_chroma,
632 p_pic->format.i_width, p_pic->format.i_height,
633 p_sys->p_decoder->fmt_out.video.i_aspect )
634 != VLC_SUCCESS )
636 picture_Release( p_pic );
637 free( p_new_pic );
638 msg_Err( p_stream, "image allocation failed" );
639 continue;
642 picture_Copy( p_new_pic, p_pic );
645 p_new_pic->i_refcount = 1;
646 p_new_pic->i_status = DESTROYED_PICTURE;
647 p_new_pic->i_type = DIRECT_PICTURE;
648 p_new_pic->p_sys = (picture_sys_t *)p_new_pic->pf_release;
649 p_new_pic->pf_release = ReleasePicture;
650 p_new_pic->date = p_pic->date;
651 picture_Release( p_pic );
653 if( p_sys->p_vf2 )
654 p_new_pic = filter_chain_VideoFilter( p_sys->p_vf2, p_new_pic );
656 PushPicture( p_stream, p_new_pic );
659 return VLC_SUCCESS;
662 struct picture_sys_t
664 vlc_object_t *p_owner;
665 bool b_dead;
668 static void video_release_buffer_decoder( picture_t *p_pic )
670 assert( p_pic && p_pic->p_sys );
672 if( --p_pic->i_refcount > 0 )
673 return;
675 video_del_buffer_decoder( (decoder_t *)p_pic->p_sys->p_owner, p_pic );
678 static void video_release_buffer_filter( picture_t *p_pic )
680 assert( p_pic );
682 if( --p_pic->i_refcount > 0 )
683 return;
685 assert( p_pic->p_sys );
687 video_del_buffer_filter( (filter_t *)p_pic->p_sys->p_owner, p_pic );
690 inline static picture_t *video_new_buffer_decoder( decoder_t *p_dec )
692 return video_new_buffer( VLC_OBJECT( p_dec ),
693 (decoder_owner_sys_t *)p_dec->p_owner,
694 &p_dec->fmt_out,
695 video_release_buffer_decoder );
698 inline static picture_t *video_new_buffer_filter( filter_t *p_filter )
700 return video_new_buffer( VLC_OBJECT( p_filter ),
701 (decoder_owner_sys_t *)p_filter->p_owner,
702 &p_filter->fmt_out,
703 video_release_buffer_filter );
706 static picture_t *video_new_buffer( vlc_object_t *p_this,
707 decoder_owner_sys_t *p_sys,
708 es_format_t *fmt_out,
709 void ( *pf_release )( picture_t * ) )
711 picture_t **pp_ring = p_sys->pp_pics;
712 picture_t *p_pic;
713 int i;
715 if( fmt_out->video.i_width != p_sys->video.i_width ||
716 fmt_out->video.i_height != p_sys->video.i_height ||
717 fmt_out->video.i_chroma != p_sys->video.i_chroma ||
718 fmt_out->video.i_aspect != p_sys->video.i_aspect )
720 if( !fmt_out->video.i_sar_num ||
721 !fmt_out->video.i_sar_den )
723 fmt_out->video.i_sar_num =
724 fmt_out->video.i_aspect * fmt_out->video.i_height;
726 fmt_out->video.i_sar_den =
727 VOUT_ASPECT_FACTOR * fmt_out->video.i_width;
730 vlc_ureduce( &fmt_out->video.i_sar_num,
731 &fmt_out->video.i_sar_den,
732 fmt_out->video.i_sar_num,
733 fmt_out->video.i_sar_den, 0 );
735 if( !fmt_out->video.i_visible_width ||
736 !fmt_out->video.i_visible_height )
738 fmt_out->video.i_visible_width = fmt_out->video.i_width;
739 fmt_out->video.i_visible_height = fmt_out->video.i_height;
742 fmt_out->video.i_chroma = fmt_out->i_codec;
743 p_sys->video = fmt_out->video;
745 for( i = 0; i < PICTURE_RING_SIZE; i++ )
747 if ( pp_ring[i] != NULL )
749 if ( pp_ring[i]->i_status == DESTROYED_PICTURE )
751 free( pp_ring[i]->p_data_orig );
752 free( pp_ring[i]->p_sys );
753 free( pp_ring[i] );
755 else
757 pp_ring[i]->p_sys->b_dead = true;
759 pp_ring[i] = NULL;
764 /* Find an empty space in the picture ring buffer */
765 for( i = 0; i < PICTURE_RING_SIZE; i++ )
767 if( pp_ring[i] != NULL && pp_ring[i]->i_status == DESTROYED_PICTURE )
769 pp_ring[i]->i_status = RESERVED_PICTURE;
770 pp_ring[i]->i_refcount = 1;
771 return pp_ring[i];
774 for( i = 0; i < PICTURE_RING_SIZE; i++ )
776 if( pp_ring[i] == NULL ) break;
779 if( i == PICTURE_RING_SIZE )
781 msg_Err( p_this, "decoder/filter is leaking pictures, "
782 "resetting its ring buffer" );
784 for( i = 0; i < PICTURE_RING_SIZE; i++ )
786 pp_ring[i]->p_sys->b_dead = true;
787 pp_ring[i]->pf_release( pp_ring[i] );
788 pp_ring[i] = NULL;
791 i = 0;
794 p_pic = malloc( sizeof(picture_t) );
795 if( !p_pic ) return NULL;
796 fmt_out->video.i_chroma = fmt_out->i_codec;
797 if( vout_AllocatePicture( p_this, p_pic,
798 fmt_out->video.i_chroma,
799 fmt_out->video.i_width,
800 fmt_out->video.i_height,
801 fmt_out->video.i_aspect ) != VLC_SUCCESS )
803 free( p_pic );
804 return NULL;
807 if( !p_pic->i_planes )
809 free( p_pic );
810 return NULL;
813 p_pic->pf_release = pf_release;
814 p_pic->i_refcount = 1;
815 p_pic->p_sys = malloc( sizeof(picture_sys_t) );
816 p_pic->p_sys->p_owner = p_this;
817 p_pic->p_sys->b_dead = false;
818 p_pic->i_status = RESERVED_PICTURE;
820 pp_ring[i] = p_pic;
822 return p_pic;
825 inline static void video_del_buffer_decoder( decoder_t *p_this,
826 picture_t *p_pic )
828 VLC_UNUSED(p_this);
829 video_del_buffer( p_pic );
832 inline static void video_del_buffer_filter( filter_t *p_this,
833 picture_t *p_pic )
835 VLC_UNUSED(p_this);
836 video_del_buffer( p_pic );
839 static void video_del_buffer( picture_t *p_pic )
841 p_pic->i_refcount = 0;
842 p_pic->i_status = DESTROYED_PICTURE;
843 if ( p_pic->p_sys->b_dead )
845 free( p_pic->p_data_orig );
846 free( p_pic->p_sys );
847 free( p_pic );
851 static void video_link_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
853 VLC_UNUSED(p_dec);
854 p_pic->i_refcount++;
857 static void video_unlink_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
859 VLC_UNUSED(p_dec);
860 video_release_buffer_decoder( p_pic );
864 /**********************************************************************
865 * Callback to update (some) params on the fly
866 **********************************************************************/
867 static int HeightCallback( vlc_object_t *p_this, char const *psz_var,
868 vlc_value_t oldval, vlc_value_t newval,
869 void *p_data )
871 VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(psz_var);
872 sout_stream_t *p_stream = (sout_stream_t *)p_data;
873 sout_stream_sys_t *p_sys = p_stream->p_sys;
875 /* We create the handler before updating the value in p_sys
876 * so we don't have to worry about locking */
877 if( !p_sys->p_image && newval.i_int )
878 p_sys->p_image = image_HandlerCreate( p_stream );
879 p_sys->i_height = newval.i_int;
881 return VLC_SUCCESS;
884 static int WidthCallback( vlc_object_t *p_this, char const *psz_var,
885 vlc_value_t oldval, vlc_value_t newval,
886 void *p_data )
888 VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(psz_var);
889 sout_stream_t *p_stream = (sout_stream_t *)p_data;
890 sout_stream_sys_t *p_sys = p_stream->p_sys;
892 /* We create the handler before updating the value in p_sys
893 * so we don't have to worry about locking */
894 if( !p_sys->p_image && newval.i_int )
895 p_sys->p_image = image_HandlerCreate( p_stream );
896 p_sys->i_width = newval.i_int;
898 return VLC_SUCCESS;
901 static int alphaCallback( vlc_object_t *p_this, char const *psz_var,
902 vlc_value_t oldval, vlc_value_t newval,
903 void *p_data )
905 VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(psz_var);
906 sout_stream_t *p_stream = (sout_stream_t *)p_data;
907 sout_stream_sys_t *p_sys = p_stream->p_sys;
909 if( p_sys->p_es )
910 p_sys->p_es->i_alpha = newval.i_int;
912 return VLC_SUCCESS;
915 static int xCallback( vlc_object_t *p_this, char const *psz_var,
916 vlc_value_t oldval, vlc_value_t newval,
917 void *p_data )
919 VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(psz_var);
920 sout_stream_t *p_stream = (sout_stream_t *)p_data;
921 sout_stream_sys_t *p_sys = p_stream->p_sys;
923 if( p_sys->p_es )
924 p_sys->p_es->i_x = newval.i_int;
926 return VLC_SUCCESS;
929 static int yCallback( vlc_object_t *p_this, char const *psz_var,
930 vlc_value_t oldval, vlc_value_t newval,
931 void *p_data )
933 VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(psz_var);
934 sout_stream_t *p_stream = (sout_stream_t *)p_data;
935 sout_stream_sys_t *p_sys = p_stream->p_sys;
937 if( p_sys->p_es )
938 p_sys->p_es->i_y = newval.i_int;
940 return VLC_SUCCESS;