/*****************************************************************************
- * wrapper.c: a "video filter2" with mouse to "video filter" wrapper.
+ * wrapper.c: a "video filter2/splitter" with mouse to "video filter" wrapper.
*****************************************************************************
* Copyright (C) 2009 Laurent Aimar
* $Id$
#include <vlc_plugin.h>
#include <vlc_vout.h>
#include <vlc_filter.h>
+#include <vlc_video_splitter.h>
#include "filter_common.h"
/*****************************************************************************
* Module descriptor
*****************************************************************************/
-static int Open ( vlc_object_t *, const char *psz_name );
+static int Open ( vlc_object_t *, const char *psz_name, bool b_filter );
static void Close( vlc_object_t * );
-#define DECLARE_OPEN(name) \
- static int Open##name ( vlc_object_t *p_this ) { return Open( p_this, #name ); }
+#define DECLARE_OPEN(name,filter) \
+ static int Open##name ( vlc_object_t *p_this ) { return Open( p_this, #name, filter ); }
-DECLARE_OPEN(magnify)
+DECLARE_OPEN(magnify, true)
+DECLARE_OPEN(puzzle, true)
+DECLARE_OPEN(logo, true)
+
+DECLARE_OPEN(clone, false)
+DECLARE_OPEN(wall, false)
+DECLARE_OPEN(panoramix, false)
#undef DECLARE_OPEN
set_subcategory( SUBCAT_VIDEO_VFILTER )
DECLARE_MODULE(magnify)
- //add_submodule()
+
+ add_submodule()
+ DECLARE_MODULE(puzzle)
+
+ add_submodule()
+ DECLARE_MODULE(logo)
+
+ add_submodule()
+ DECLARE_MODULE(clone)
+
+ add_submodule()
+ DECLARE_MODULE(wall)
+
+ add_submodule()
+ DECLARE_MODULE(panoramix)
+
vlc_module_end()
#undef DECLARE_MODULE
struct vout_sys_t
{
- vout_thread_t *p_vout;
+ int i_vout;
+ vout_thread_t **pp_vout;
- es_format_t fmt;
+ es_format_t fmt;
- vlc_mutex_t lock;
- filter_chain_t *p_chain;
- vlc_mouse_t mouse;
-};
+ vlc_mutex_t lock;
+ filter_chain_t *p_chain;
+ video_splitter_t *p_splitter;
-static int MouseEvent( vlc_object_t *, char const *,
- vlc_value_t, vlc_value_t, void * );
+ vlc_mouse_t *p_mouse_src;
+ vlc_mouse_t mouse;
+};
+/* */
static int FilterAllocationInit ( filter_t *, void * );
static void FilterAllocationClean( filter_t * );
+/* */
+static int FullscreenEventDown( vlc_object_t *, char const *,
+ vlc_value_t, vlc_value_t, void * );
+static int SplitterPictureNew( video_splitter_t *, picture_t *pp_picture[] );
+static void SplitterPictureDel( video_splitter_t *, picture_t *pp_picture[] );
+
+/* */
+static int MouseEvent( vlc_object_t *, char const *,
+ vlc_value_t, vlc_value_t, void * );
+static void VoutsClean( vout_thread_t *p_vout, int i_count );
+
/**
* Open our wrapper instance.
*/
-static int Open( vlc_object_t *p_this, const char *psz_name )
+static int Open( vlc_object_t *p_this, const char *psz_name, bool b_filter )
{
vout_thread_t *p_vout = (vout_thread_t *)p_this;
vout_sys_t *p_sys;
- msg_Err( p_vout, "Opening video filter wrapper for %s", psz_name );
-
- /* Try to open our filter */
- filter_chain_t *p_chain =
- filter_chain_New( p_vout, "video filter2", false,
- FilterAllocationInit, FilterAllocationClean, p_vout );
- if( !p_chain )
- return VLC_ENOMEM;
+ msg_Err( p_vout, "Opening video %s wrapper for %s",
+ b_filter ? "filter" : "splitter", psz_name );
+ /* */
es_format_t fmt;
es_format_Init( &fmt, VIDEO_ES, p_vout->render.i_chroma );
video_format_Setup( &fmt.video, p_vout->render.i_chroma,
p_vout->render.i_width, p_vout->render.i_height,
- p_vout->render.i_aspect );
-
- filter_chain_Reset( p_chain, &fmt, &fmt );
-
- filter_t *p_filter =
- filter_chain_AppendFilter( p_chain, psz_name, NULL, &fmt, &fmt );
+ p_vout->render.i_aspect * p_vout->render.i_height,
+ VOUT_ASPECT_FACTOR * p_vout->render.i_width );
- if( !p_filter )
+ /* Try to open our real module */
+ filter_chain_t *p_chain = NULL;
+ video_splitter_t *p_splitter = NULL;
+ if( b_filter )
{
- msg_Err( p_vout, "Failed to open filter '%s'", psz_name );
- filter_chain_Delete( p_chain );
- return VLC_EGENERIC;
+ p_chain = filter_chain_New( p_vout, "video filter2", false,
+ FilterAllocationInit, FilterAllocationClean, p_vout );
+ if( !p_chain )
+ return VLC_ENOMEM;
+
+ filter_chain_Reset( p_chain, &fmt, &fmt );
+
+ filter_t *p_filter =
+ filter_chain_AppendFilter( p_chain, psz_name, p_vout->p_cfg, &fmt, &fmt );
+
+ if( !p_filter )
+ {
+ msg_Err( p_vout, "Failed to open filter '%s'", psz_name );
+ filter_chain_Delete( p_chain );
+ return VLC_EGENERIC;
+ }
+ }
+ else
+ {
+ p_splitter = video_splitter_New( VLC_OBJECT(p_vout), psz_name, &fmt.video );
+ if( !p_splitter )
+ {
+ msg_Err( p_vout, "Failed to open splitter '%s'", psz_name );
+ return VLC_EGENERIC;
+ }
+ assert( p_splitter->i_output > 0 );
+
+ p_splitter->p_owner = (video_splitter_owner_t*)p_vout;
+ p_splitter->pf_picture_new = SplitterPictureNew;
+ p_splitter->pf_picture_del = SplitterPictureDel;
}
+ /* */
p_vout->p_sys = p_sys = malloc( sizeof(*p_sys) );
if( !p_sys )
- {
- filter_chain_Delete( p_chain );
- return VLC_ENOMEM;
- }
+ goto error;
+
+ p_sys->i_vout = p_chain ? 1 : p_splitter->i_output;
+ p_sys->pp_vout = calloc( p_sys->i_vout, sizeof(*p_sys->pp_vout) );;
+ p_sys->p_mouse_src = calloc( p_sys->i_vout, sizeof(*p_sys->p_mouse_src) );
+
p_sys->fmt = fmt;
vlc_mutex_init( &p_sys->lock );
- p_sys->p_chain = p_chain;
- p_sys->p_vout = NULL;
+ p_sys->p_chain = p_chain;
+ p_sys->p_splitter = p_splitter;
vlc_mouse_Init( &p_sys->mouse );
+ for( int i = 0; i < p_sys->i_vout; i++ )
+ vlc_mouse_Init( &p_sys->p_mouse_src[i] );
p_vout->pf_init = Init;
p_vout->pf_end = End;
p_vout->pf_control = Control;
return VLC_SUCCESS;
+
+error:
+ if( p_chain )
+ filter_chain_Delete( p_chain );
+ if( p_splitter )
+ video_splitter_Delete( p_splitter );
+ return VLC_ENOMEM;
}
/**
vout_thread_t *p_vout = (vout_thread_t *)p_this;
vout_sys_t *p_sys = p_vout->p_sys;
- filter_chain_Delete( p_sys->p_chain );
+ if( p_sys->p_chain )
+ filter_chain_Delete( p_sys->p_chain );
+ if( p_sys->p_splitter )
+ video_splitter_Delete( p_sys->p_splitter );
+
vlc_mutex_destroy( &p_sys->lock );
es_format_Clean( &p_sys->fmt );
+ free( p_sys->p_mouse_src );
+ free( p_sys->pp_vout );
free( p_vout->p_sys );
}
p_vout->fmt_out = p_vout->fmt_in;
/* Try to open the real video output */
- msg_Dbg( p_vout, "spawning the real video output" );
+ msg_Dbg( p_vout, "spawning the real video output(s)" );
video_format_t fmt = p_vout->fmt_out;
- p_sys->p_vout = vout_Create( p_vout, &fmt );
- if( !p_sys->p_vout )
+
+ if( p_sys->p_chain )
{
- msg_Err( p_vout, "cannot open vout, aborting" );
- return VLC_EGENERIC;
+ p_sys->pp_vout[0] = vout_Create( p_vout, &fmt );
+ if( !p_sys->pp_vout[0] )
+ {
+ msg_Err( p_vout, "cannot open vout, aborting" );
+ return VLC_EGENERIC;
+ }
+ vout_filter_AddChild( p_vout, p_sys->pp_vout[0], MouseEvent );
+ }
+ else
+ {
+ video_splitter_t *p_splitter = p_sys->p_splitter;
+
+ /* */
+ const int i_org_align = var_CreateGetInteger( p_vout, "align" );
+ const int i_org_x = var_CreateGetInteger( p_vout, "video-x" );
+ const int i_org_y = var_CreateGetInteger( p_vout, "video-y" );
+ const char *psz_org_vout = var_CreateGetNonEmptyString( p_vout, "vout" );
+
+ /* */
+ for( int i = 0; i < p_splitter->i_output; i++ )
+ {
+ const video_splitter_output_t *p_cfg = &p_splitter->p_output[i];
+
+ /* */
+ var_SetInteger( p_vout, "align", p_cfg->window.i_align);
+
+ var_SetInteger( p_vout, "video-x", i_org_x + p_cfg->window.i_x );
+ var_SetInteger( p_vout, "video-y", i_org_y + p_cfg->window.i_y );
+
+ if( p_cfg->psz_module )
+ var_SetString( p_vout, "vout", p_cfg->psz_module );
+
+ /* */
+ video_format_t fmt = p_cfg->fmt;
+ p_sys->pp_vout[i] = vout_Create( p_vout, &fmt );
+ if( !p_sys->pp_vout[i] )
+ {
+ msg_Err( p_vout, "cannot open vout, aborting" );
+ VoutsClean( p_vout, i );
+ return VLC_EGENERIC;
+ }
+ }
+
+ /* Attach once pp_vout is completly filed to avoid race conditions */
+ for( int i = 0; i < p_splitter->i_output; i++ )
+ vout_filter_SetupChild( p_vout, p_sys->pp_vout[i],
+ MouseEvent,
+ FullscreenEventDown, true );
+ /* Restore settings */
+ var_SetInteger( p_vout, "align", i_org_align );
+ var_SetInteger( p_vout, "video-x", i_org_x );
+ var_SetInteger( p_vout, "video-y", i_org_y );
+ var_SetString( p_vout, "vout", psz_org_vout ? psz_org_vout : "" );
}
vout_filter_AllocateDirectBuffers( p_vout, VOUT_MAX_PICTURES );
- vout_filter_AddChild( p_vout, p_vout->p_sys->p_vout, MouseEvent );
-
return VLC_SUCCESS;
}
{
vout_sys_t *p_sys = p_vout->p_sys;
- vout_filter_DelChild( p_vout, p_sys->p_vout, MouseEvent );
- vout_CloseAndRelease( p_sys->p_vout );
+ VoutsClean( p_vout, p_sys->i_vout );
vout_filter_ReleaseDirectBuffers( p_vout );
}
*/
static int Control( vout_thread_t *p_vout, int i_query, va_list args )
{
- return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
+ vout_sys_t *p_sys = p_vout->p_sys;
+ int i_ret = VLC_SUCCESS;
+
+ for( int i = 0; i < p_sys->i_vout; i++ )
+ i_ret = vout_vaControl( p_sys->pp_vout[i], i_query, args );
+ return i_ret;
}
/**
vout_sys_t *p_sys = p_vout->p_sys;
vlc_mutex_lock( &p_sys->lock );
- picture_t *p_dst = filter_chain_VideoFilter( p_sys->p_chain, p_src );
- if( p_dst )
- vout_DisplayPicture( p_sys->p_vout, p_dst );
+
+ picture_t *pp_dst[p_sys->i_vout];
+
+ if( p_sys->p_chain )
+ {
+ pp_dst[0] = filter_chain_VideoFilter( p_sys->p_chain, p_src );
+ }
+ else
+ {
+ if( video_splitter_Filter( p_sys->p_splitter, pp_dst, p_src ) )
+ {
+ for( int i = 0; i < p_sys->i_vout; i++ )
+ pp_dst[i] = NULL;
+ }
+ }
+ for( int i = 0; i < p_sys->i_vout; i++ )
+ {
+ picture_t *p_dst = pp_dst[i];
+ if( p_dst )
+ vout_DisplayPicture( p_sys->pp_vout[i], p_dst );
+ }
+
vlc_mutex_unlock( &p_sys->lock );
}
+/* */
+static void VoutsClean( vout_thread_t *p_vout, int i_count )
+{
+ vout_sys_t *p_sys = p_vout->p_sys;
+
+ /* Detach all vouts before destroying them */
+ for( int i = 0; i < i_count; i++ )
+ {
+ if( p_sys->p_chain )
+ vout_filter_DelChild( p_vout, p_sys->pp_vout[i], MouseEvent );
+ else
+ vout_filter_SetupChild( p_vout, p_sys->pp_vout[i],
+ MouseEvent,
+ FullscreenEventDown, false );
+ }
+
+ for( int i = 0; i < i_count; i++ )
+ vout_CloseAndRelease( p_sys->pp_vout[i] );
+}
+static int VoutsNewPicture( vout_thread_t *p_vout, picture_t *pp_dst[] )
+{
+ vout_sys_t *p_sys = p_vout->p_sys;
+
+ for( int i = 0; i < p_sys->i_vout; i++ )
+ {
+ picture_t *p_picture = NULL;
+ for( ;; )
+ {
+ p_picture = vout_CreatePicture( p_sys->pp_vout[i], 0, 0, 0 );
+ if( p_picture )
+ break;
+
+ if( !vlc_object_alive( p_vout ) || p_vout->b_error )
+ break;
+ msleep( VOUT_OUTMEM_SLEEP );
+ }
+ /* FIXME what to do with the allocated picture ? */
+ if( !p_picture )
+ return VLC_EGENERIC;
+
+ pp_dst[i] = p_picture;
+ }
+ return VLC_SUCCESS;
+}
+
/**
* Callback for mouse events
*/
static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
+ VLC_UNUSED(psz_var); VLC_UNUSED(oldval); VLC_UNUSED(newval);
vout_thread_t *p_vout = p_data;
vout_sys_t *p_sys = p_vout->p_sys;
+ int i_index;
+
+ for( i_index = 0; i_index < p_sys->i_vout; i_index++ )
+ {
+ if( p_this == VLC_OBJECT(p_sys->pp_vout[i_index]) )
+ break;
+ }
+ if( i_index >= p_sys->i_vout )
+ {
+ msg_Err( p_vout, "Failed to find vout source in MouseEvent" );
+ return VLC_SUCCESS;
+ }
+
+ vout_thread_t *p_vout_src = p_sys->pp_vout[i_index];
vlc_mouse_t m;
vlc_mouse_Init( &m );
- m.i_x = var_GetInteger( p_sys->p_vout, "mouse-x" );
- m.i_y = var_GetInteger( p_sys->p_vout, "mouse-y" );
- m.i_pressed = var_GetInteger( p_sys->p_vout, "mouse-button-down" );
+ m.i_x = var_GetInteger( p_vout_src, "mouse-x" );
+ m.i_y = var_GetInteger( p_vout_src, "mouse-y" );
+ m.i_pressed = var_GetInteger( p_vout_src, "mouse-button-down" );
vlc_mutex_lock( &p_sys->lock );
vlc_mouse_t nmouse;
vlc_mouse_t omouse = p_sys->mouse;
- int i_ret = filter_chain_MouseFilter( p_sys->p_chain, &nmouse, &m );
+ int i_ret;
+ if( p_sys->p_chain )
+ {
+ i_ret = filter_chain_MouseFilter( p_sys->p_chain, &nmouse, &m );
+ }
+ else
+ {
+ vlc_mouse_t *p_mouse_src = &p_sys->p_mouse_src[i_index];
+
+ i_ret = video_splitter_Mouse( p_sys->p_splitter, &nmouse, i_index, p_mouse_src, &m );
+ *p_mouse_src = m;
+ }
+
if( !i_ret )
p_sys->mouse = nmouse;
vlc_mutex_unlock( &p_sys->lock );
return VLC_SUCCESS;
}
-/* */
+/* -- Filter callbacks -- */
+
static picture_t *VideoBufferNew( filter_t *p_filter )
{
vout_thread_t *p_vout = (vout_thread_t*)p_filter->p_owner;
- vout_sys_t *p_sys = p_vout->p_sys;
- picture_t *p_picture;
- for( ;; )
- {
- p_picture = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 );
- if( p_picture )
- return p_picture;
-
- if( !vlc_object_alive( p_vout ) || p_vout->b_error )
- return NULL;
- msleep( VOUT_OUTMEM_SLEEP );
- }
+ picture_t *pp_picture[1];
+ if( VoutsNewPicture( p_vout, pp_picture ) )
+ return NULL;
+ return pp_picture[0];
}
static void VideoBufferDelete( filter_t *p_filter, picture_t *p_picture )
{
{
VLC_UNUSED( p_data );
- p_filter->pf_vout_buffer_new = VideoBufferNew;
- p_filter->pf_vout_buffer_del = VideoBufferDelete;
+ p_filter->pf_video_buffer_new = VideoBufferNew;
+ p_filter->pf_video_buffer_del = VideoBufferDelete;
p_filter->p_owner = p_data;
return VLC_SUCCESS;
}
static void FilterAllocationClean( filter_t *p_filter )
{
- p_filter->pf_vout_buffer_new = NULL;
- p_filter->pf_vout_buffer_del = NULL;
+ p_filter->pf_video_buffer_new = NULL;
+ p_filter->pf_video_buffer_del = NULL;
+}
+
+/* -- Splitter callbacks -- */
+
+/**
+ * Forward fullscreen event to/from the childrens.
+ *
+ * FIXME probably unsafe (pp_vout[] content)
+ */
+static bool IsFullscreenActive( vout_thread_t *p_vout )
+{
+ vout_sys_t *p_sys = p_vout->p_sys;
+ for( int i = 0; i < p_sys->i_vout; i++ )
+ {
+ if( var_GetBool( p_sys->pp_vout[i], "fullscreen" ) )
+ return true;
+ }
+ return false;
+}
+static int FullscreenEventDown( vlc_object_t *p_this, char const *psz_var,
+ vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+ vout_thread_t *p_vout = (vout_thread_t*)p_this;
+ vout_sys_t *p_sys = p_vout->p_sys;
+ VLC_UNUSED(oldval); VLC_UNUSED(p_data); VLC_UNUSED(psz_var);
+
+ for( int i = 0; i < p_sys->i_vout; i++ )
+ {
+ vout_thread_t *p_child = p_sys->pp_vout[i];
+ var_SetBool( p_child, "fullscreen", newval.b_bool );
+ }
+ return VLC_SUCCESS;
+}
+
+static int SplitterPictureNew( video_splitter_t *p_splitter, picture_t *pp_picture[] )
+{
+ vout_thread_t *p_vout = (vout_thread_t*)p_splitter->p_owner;
+
+ return VoutsNewPicture( p_vout, pp_picture );
+}
+static void SplitterPictureDel( video_splitter_t *p_splitter, picture_t *pp_picture[] )
+{
+ VLC_UNUSED(p_splitter); VLC_UNUSED(pp_picture);
+ /* FIXME is there anything to do ? */
}