Use calloc.
[vlc/asuraparaju-public.git] / modules / video_filter / wrapper.c
blob9271c9723788b59b18ac327a027349447ce8ef32
1 /*****************************************************************************
2 * wrapper.c: a "video filter2/splitter" with mouse to "video filter" wrapper.
3 *****************************************************************************
4 * Copyright (C) 2009 Laurent Aimar
5 * $Id$
7 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31 #include <assert.h>
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_vout.h>
36 #include <vlc_filter.h>
37 #include <vlc_video_splitter.h>
39 #include "filter_common.h"
41 /*****************************************************************************
42 * Module descriptor
43 *****************************************************************************/
44 static int Open ( vlc_object_t *, const char *psz_name, bool b_filter );
45 static void Close( vlc_object_t * );
47 #define DECLARE_OPEN(name,filter) \
48 static int Open##name ( vlc_object_t *p_this ) { return Open( p_this, #name, filter ); }
50 DECLARE_OPEN(magnify, true)
51 DECLARE_OPEN(puzzle, true)
52 DECLARE_OPEN(logo, true)
54 DECLARE_OPEN(clone, false)
55 DECLARE_OPEN(wall, false)
56 DECLARE_OPEN(panoramix, false)
58 #undef DECLARE_OPEN
60 #define DECLARE_MODULE(name) \
61 set_description( "Video filter "#name" wrapper" ) \
62 set_shortname( "Video filter"#name" wrapper" ) \
63 set_capability( "video filter", 0 ) \
64 set_callbacks( Open##name, Close ) \
65 add_shortcut( #name )
67 vlc_module_begin()
68 set_category( CAT_VIDEO )
69 set_subcategory( SUBCAT_VIDEO_VFILTER )
71 DECLARE_MODULE(magnify)
73 add_submodule()
74 DECLARE_MODULE(puzzle)
76 add_submodule()
77 DECLARE_MODULE(logo)
79 add_submodule()
80 DECLARE_MODULE(clone)
82 add_submodule()
83 DECLARE_MODULE(wall)
85 add_submodule()
86 DECLARE_MODULE(panoramix)
88 vlc_module_end()
90 #undef DECLARE_MODULE
92 /*****************************************************************************
93 * Local prototypes
94 *****************************************************************************/
95 static int Init ( vout_thread_t * );
96 static void End ( vout_thread_t * );
97 static void Render ( vout_thread_t *, picture_t * );
98 static int Control ( vout_thread_t *, int, va_list );
100 struct vout_sys_t
102 int i_vout;
103 vout_thread_t **pp_vout;
105 es_format_t fmt;
107 vlc_mutex_t lock;
108 filter_chain_t *p_chain;
109 video_splitter_t *p_splitter;
111 vlc_mouse_t *p_mouse_src;
112 vlc_mouse_t mouse;
115 /* */
116 static int FilterAllocationInit ( filter_t *, void * );
117 static void FilterAllocationClean( filter_t * );
119 /* */
120 static int FullscreenEventUp( vlc_object_t *, char const *,
121 vlc_value_t, vlc_value_t, void * );
122 static int FullscreenEventDown( vlc_object_t *, char const *,
123 vlc_value_t, vlc_value_t, void * );
124 static int SplitterPictureNew( video_splitter_t *, picture_t *pp_picture[] );
125 static void SplitterPictureDel( video_splitter_t *, picture_t *pp_picture[] );
127 /* */
128 static int MouseEvent( vlc_object_t *, char const *,
129 vlc_value_t, vlc_value_t, void * );
130 static void VoutsClean( vout_thread_t *p_vout, int i_count );
133 * Open our wrapper instance.
135 static int Open( vlc_object_t *p_this, const char *psz_name, bool b_filter )
137 vout_thread_t *p_vout = (vout_thread_t *)p_this;
138 vout_sys_t *p_sys;
140 msg_Err( p_vout, "Opening video %s wrapper for %s",
141 b_filter ? "filter" : "splitter", psz_name );
143 /* */
144 es_format_t fmt;
145 es_format_Init( &fmt, VIDEO_ES, p_vout->render.i_chroma );
146 video_format_Setup( &fmt.video, p_vout->render.i_chroma,
147 p_vout->render.i_width, p_vout->render.i_height,
148 p_vout->render.i_aspect * p_vout->render.i_height,
149 VOUT_ASPECT_FACTOR * p_vout->render.i_width );
151 /* Try to open our real module */
152 filter_chain_t *p_chain = NULL;
153 video_splitter_t *p_splitter = NULL;
154 if( b_filter )
156 p_chain = filter_chain_New( p_vout, "video filter2", false,
157 FilterAllocationInit, FilterAllocationClean, p_vout );
158 if( !p_chain )
159 return VLC_ENOMEM;
161 filter_chain_Reset( p_chain, &fmt, &fmt );
163 filter_t *p_filter =
164 filter_chain_AppendFilter( p_chain, psz_name, p_vout->p_cfg, &fmt, &fmt );
166 if( !p_filter )
168 msg_Err( p_vout, "Failed to open filter '%s'", psz_name );
169 filter_chain_Delete( p_chain );
170 return VLC_EGENERIC;
173 else
175 p_splitter = video_splitter_New( VLC_OBJECT(p_vout), psz_name, &fmt.video );
176 if( !p_splitter )
178 msg_Err( p_vout, "Failed to open splitter '%s'", psz_name );
179 return VLC_EGENERIC;
181 assert( p_splitter->i_output > 0 );
183 p_splitter->p_owner = (video_splitter_owner_t*)p_vout;
184 p_splitter->pf_picture_new = SplitterPictureNew;
185 p_splitter->pf_picture_del = SplitterPictureDel;
188 /* */
189 p_vout->p_sys = p_sys = malloc( sizeof(*p_sys) );
190 if( !p_sys )
191 goto error;
193 p_sys->i_vout = p_chain ? 1 : p_splitter->i_output;
194 p_sys->pp_vout = calloc( p_sys->i_vout, sizeof(*p_sys->pp_vout) );;
195 p_sys->p_mouse_src = calloc( p_sys->i_vout, sizeof(*p_sys->p_mouse_src) );
197 p_sys->fmt = fmt;
198 vlc_mutex_init( &p_sys->lock );
199 p_sys->p_chain = p_chain;
200 p_sys->p_splitter = p_splitter;
201 vlc_mouse_Init( &p_sys->mouse );
202 for( int i = 0; i < p_sys->i_vout; i++ )
203 vlc_mouse_Init( &p_sys->p_mouse_src[i] );
205 p_vout->pf_init = Init;
206 p_vout->pf_end = End;
207 p_vout->pf_manage = NULL;
208 p_vout->pf_render = Render;
209 p_vout->pf_display = NULL;
210 p_vout->pf_control = Control;
212 return VLC_SUCCESS;
214 error:
215 if( p_chain )
216 filter_chain_Delete( p_chain );
217 if( p_splitter )
218 video_splitter_Delete( p_splitter );
219 return VLC_ENOMEM;
223 * Close our wrapper instance
225 static void Close( vlc_object_t *p_this )
227 vout_thread_t *p_vout = (vout_thread_t *)p_this;
228 vout_sys_t *p_sys = p_vout->p_sys;
230 if( p_sys->p_chain )
231 filter_chain_Delete( p_sys->p_chain );
232 if( p_sys->p_splitter )
233 video_splitter_Delete( p_sys->p_splitter );
235 vlc_mutex_destroy( &p_sys->lock );
236 es_format_Clean( &p_sys->fmt );
237 free( p_sys->p_mouse_src );
238 free( p_sys->pp_vout );
240 free( p_vout->p_sys );
244 * Initialise our wrapper
246 static int Init( vout_thread_t *p_vout )
248 vout_sys_t *p_sys = p_vout->p_sys;
250 assert( p_vout->render.i_chroma == p_sys->fmt.video.i_chroma &&
251 p_vout->render.i_width == p_sys->fmt.video.i_width &&
252 p_vout->render.i_height == p_sys->fmt.video.i_height );
254 /* Initialize the output structure */
255 I_OUTPUTPICTURES = 0;
256 p_vout->output.i_chroma = p_vout->render.i_chroma;
257 p_vout->output.i_width = p_vout->render.i_width;
258 p_vout->output.i_height = p_vout->render.i_height;
259 p_vout->output.i_aspect = p_vout->render.i_aspect;
261 p_vout->fmt_out = p_vout->fmt_in;
263 /* Try to open the real video output */
264 msg_Dbg( p_vout, "spawning the real video output(s)" );
266 video_format_t fmt = p_vout->fmt_out;
268 if( p_sys->p_chain )
270 p_sys->pp_vout[0] = vout_Create( p_vout, &fmt );
271 if( !p_sys->pp_vout[0] )
273 msg_Err( p_vout, "cannot open vout, aborting" );
274 return VLC_EGENERIC;
276 vout_filter_AddChild( p_vout, p_sys->pp_vout[0], MouseEvent );
278 else
280 video_splitter_t *p_splitter = p_sys->p_splitter;
282 /* */
283 const int i_org_align = var_CreateGetInteger( p_vout, "align" );
284 const int i_org_x = var_CreateGetInteger( p_vout, "video-x" );
285 const int i_org_y = var_CreateGetInteger( p_vout, "video-y" );
286 const char *psz_org_vout = var_CreateGetNonEmptyString( p_vout, "vout" );
288 /* */
289 for( int i = 0; i < p_splitter->i_output; i++ )
291 const video_splitter_output_t *p_cfg = &p_splitter->p_output[i];
293 /* */
294 var_SetInteger( p_vout, "align", p_cfg->window.i_align);
296 var_SetInteger( p_vout, "video-x", i_org_x + p_cfg->window.i_x );
297 var_SetInteger( p_vout, "video-y", i_org_y + p_cfg->window.i_y );
299 if( p_cfg->psz_module )
300 var_SetString( p_vout, "vout", p_cfg->psz_module );
302 /* */
303 video_format_t fmt = p_cfg->fmt;
304 p_sys->pp_vout[i] = vout_Create( p_vout, &fmt );
305 if( !p_sys->pp_vout[i] )
307 msg_Err( p_vout, "cannot open vout, aborting" );
308 VoutsClean( p_vout, i );
309 return VLC_EGENERIC;
313 /* Attach once pp_vout is completly field to avoid race conditions */
314 for( int i = 0; i < p_splitter->i_output; i++ )
315 vout_filter_SetupChild( p_vout, p_sys->pp_vout[i],
316 MouseEvent,
317 FullscreenEventUp, FullscreenEventDown, true );
318 /* Restore settings */
319 var_SetInteger( p_vout, "align", i_org_align );
320 var_SetInteger( p_vout, "video-x", i_org_x );
321 var_SetInteger( p_vout, "video-y", i_org_y );
322 var_SetString( p_vout, "vout", psz_org_vout ? psz_org_vout : "" );
325 vout_filter_AllocateDirectBuffers( p_vout, VOUT_MAX_PICTURES );
327 return VLC_SUCCESS;
331 * Clean up our wrapper
333 static void End( vout_thread_t *p_vout )
335 vout_sys_t *p_sys = p_vout->p_sys;
337 VoutsClean( p_vout, p_sys->i_vout );
339 vout_filter_ReleaseDirectBuffers( p_vout );
343 * Control the real vout
345 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
347 vout_sys_t *p_sys = p_vout->p_sys;
348 int i_ret = VLC_SUCCESS;
350 for( int i = 0; i < p_sys->i_vout; i++ )
351 i_ret = vout_vaControl( p_sys->pp_vout[i], i_query, args );
352 return i_ret;
356 * Filter a picture
358 static void Render( vout_thread_t *p_vout, picture_t *p_src )
360 vout_sys_t *p_sys = p_vout->p_sys;
362 vlc_mutex_lock( &p_sys->lock );
364 picture_t *pp_dst[p_sys->i_vout];
366 if( p_sys->p_chain )
368 pp_dst[0] = filter_chain_VideoFilter( p_sys->p_chain, p_src );
370 else
372 if( video_splitter_Filter( p_sys->p_splitter, pp_dst, p_src ) )
374 for( int i = 0; i < p_sys->i_vout; i++ )
375 pp_dst[i] = NULL;
378 for( int i = 0; i < p_sys->i_vout; i++ )
380 picture_t *p_dst = pp_dst[i];
381 if( p_dst )
382 vout_DisplayPicture( p_sys->pp_vout[i], p_dst );
385 vlc_mutex_unlock( &p_sys->lock );
388 /* */
389 static void VoutsClean( vout_thread_t *p_vout, int i_count )
391 vout_sys_t *p_sys = p_vout->p_sys;
393 /* Detach all vouts before destroying them */
394 for( int i = 0; i < i_count; i++ )
396 if( p_sys->p_chain )
397 vout_filter_DelChild( p_vout, p_sys->pp_vout[i], MouseEvent );
398 else
399 vout_filter_SetupChild( p_vout, p_sys->pp_vout[i],
400 MouseEvent,
401 FullscreenEventUp, FullscreenEventDown, false );
404 for( int i = 0; i < i_count; i++ )
405 vout_CloseAndRelease( p_sys->pp_vout[i] );
407 static int VoutsNewPicture( vout_thread_t *p_vout, picture_t *pp_dst[] )
409 vout_sys_t *p_sys = p_vout->p_sys;
411 for( int i = 0; i < p_sys->i_vout; i++ )
413 picture_t *p_picture = NULL;
414 for( ;; )
416 p_picture = vout_CreatePicture( p_sys->pp_vout[i], 0, 0, 0 );
417 if( p_picture )
418 break;
420 if( !vlc_object_alive( p_vout ) || p_vout->b_error )
421 break;
422 msleep( VOUT_OUTMEM_SLEEP );
424 /* FIXME what to do with the allocated picture ? */
425 if( !p_picture )
426 return VLC_EGENERIC;
428 pp_dst[i] = p_picture;
430 return VLC_SUCCESS;
434 * Callback for mouse events
436 static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
437 vlc_value_t oldval, vlc_value_t newval, void *p_data )
439 VLC_UNUSED(psz_var); VLC_UNUSED(oldval); VLC_UNUSED(newval);
440 vout_thread_t *p_vout = p_data;
441 vout_sys_t *p_sys = p_vout->p_sys;
442 int i_index;
444 for( i_index = 0; i_index < p_sys->i_vout; i_index++ )
446 if( p_this == VLC_OBJECT(p_sys->pp_vout[i_index]) )
447 break;
449 if( i_index >= p_sys->i_vout )
451 msg_Err( p_vout, "Failed to find vout source in MouseEvent" );
452 return VLC_SUCCESS;
455 vout_thread_t *p_vout_src = p_sys->pp_vout[i_index];
457 vlc_mouse_t m;
458 vlc_mouse_Init( &m );
459 m.i_x = var_GetInteger( p_vout_src, "mouse-x" );
460 m.i_y = var_GetInteger( p_vout_src, "mouse-y" );
461 m.i_pressed = var_GetInteger( p_vout_src, "mouse-button-down" );
463 vlc_mutex_lock( &p_sys->lock );
465 vlc_mouse_t nmouse;
466 vlc_mouse_t omouse = p_sys->mouse;
468 int i_ret;
469 if( p_sys->p_chain )
471 i_ret = filter_chain_MouseFilter( p_sys->p_chain, &nmouse, &m );
473 else
475 vlc_mouse_t *p_mouse_src = &p_sys->p_mouse_src[i_index];
477 i_ret = video_splitter_Mouse( p_sys->p_splitter, &nmouse, i_index, p_mouse_src, &m );
478 *p_mouse_src = m;
481 if( !i_ret )
482 p_sys->mouse = nmouse;
483 vlc_mutex_unlock( &p_sys->lock );
485 if( i_ret )
486 return VLC_EGENERIC;
488 if( vlc_mouse_HasMoved( &omouse, &nmouse ) )
490 var_SetInteger( p_vout, "mouse-x", nmouse.i_x );
491 var_SetInteger( p_vout, "mouse-y", nmouse.i_y );
492 var_SetBool( p_vout, "mouse-moved", true );
494 if( vlc_mouse_HasButton( &omouse, &nmouse ) )
496 var_SetInteger( p_vout, "mouse-button-down", nmouse.i_pressed );
497 if( vlc_mouse_HasPressed( &omouse, &nmouse, MOUSE_BUTTON_LEFT ) )
498 var_SetBool( p_vout, "mouse-clicked", true );
500 if( m.b_double_click )
502 /* Nothing with current API */
503 msg_Warn( p_vout, "Ignoring double click" );
505 return VLC_SUCCESS;
508 /* -- Filter callbacks -- */
510 static picture_t *VideoBufferNew( filter_t *p_filter )
512 vout_thread_t *p_vout = (vout_thread_t*)p_filter->p_owner;
514 picture_t *pp_picture[1];
515 if( VoutsNewPicture( p_vout, pp_picture ) )
516 return NULL;
517 return pp_picture[0];
519 static void VideoBufferDelete( filter_t *p_filter, picture_t *p_picture )
521 VLC_UNUSED(p_filter); VLC_UNUSED(p_picture);
522 /* FIXME is there anything to do ? */
525 static int FilterAllocationInit( filter_t *p_filter, void *p_data )
527 VLC_UNUSED( p_data );
529 p_filter->pf_video_buffer_new = VideoBufferNew;
530 p_filter->pf_video_buffer_del = VideoBufferDelete;
531 p_filter->p_owner = p_data;
533 return VLC_SUCCESS;
535 static void FilterAllocationClean( filter_t *p_filter )
537 p_filter->pf_video_buffer_new = NULL;
538 p_filter->pf_video_buffer_del = NULL;
541 /* -- Splitter callbacks -- */
544 * Forward fullscreen event to/from the childrens.
546 * FIXME probably unsafe (pp_vout[] content)
548 static bool IsFullscreenActive( vout_thread_t *p_vout )
550 vout_sys_t *p_sys = p_vout->p_sys;
551 for( int i = 0; i < p_sys->i_vout; i++ )
553 if( var_GetBool( p_sys->pp_vout[i], "fullscreen" ) )
554 return true;
556 return false;
558 static int FullscreenEventUp( vlc_object_t *p_this, char const *psz_var,
559 vlc_value_t oldval, vlc_value_t newval, void *p_data )
561 vout_thread_t *p_vout = p_data;
562 VLC_UNUSED(oldval); VLC_UNUSED(p_this); VLC_UNUSED(psz_var); VLC_UNUSED(newval);
564 const bool b_fullscreen = IsFullscreenActive( p_vout );
565 if( !var_GetBool( p_vout, "fullscreen" ) != !b_fullscreen )
566 return var_SetBool( p_vout, "fullscreen", b_fullscreen );
567 return VLC_SUCCESS;
569 static int FullscreenEventDown( vlc_object_t *p_this, char const *psz_var,
570 vlc_value_t oldval, vlc_value_t newval, void *p_data )
572 vout_thread_t *p_vout = (vout_thread_t*)p_this;
573 vout_sys_t *p_sys = p_vout->p_sys;
574 VLC_UNUSED(oldval); VLC_UNUSED(p_data); VLC_UNUSED(psz_var);
576 const bool b_fullscreen = IsFullscreenActive( p_vout );
577 if( !b_fullscreen != !newval.b_bool )
579 for( int i = 0; i < p_sys->i_vout; i++ )
581 vout_thread_t *p_child = p_sys->pp_vout[i];
582 if( !var_GetBool( p_child, "fullscreen" ) != !newval.b_bool )
584 var_SetBool( p_child, "fullscreen", newval.b_bool );
585 if( newval.b_bool )
586 return VLC_SUCCESS;
590 return VLC_SUCCESS;
593 static int SplitterPictureNew( video_splitter_t *p_splitter, picture_t *pp_picture[] )
595 vout_thread_t *p_vout = (vout_thread_t*)p_splitter->p_owner;
597 return VoutsNewPicture( p_vout, pp_picture );
599 static void SplitterPictureDel( video_splitter_t *p_splitter, picture_t *pp_picture[] )
601 VLC_UNUSED(p_splitter); VLC_UNUSED(pp_picture);
602 /* FIXME is there anything to do ? */