X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fvideo_filter%2Fwrapper.c;h=94823b686d35a14a32d2b071938750442957c5e7;hb=3894020366b7b15c865b382dc74fbda6da192a05;hp=2ad2337a5c3e09b4384c6ad80381d86d3e62b4b7;hpb=86afb29f843d31f31d5dda83108020221d20df26;p=vlc diff --git a/modules/video_filter/wrapper.c b/modules/video_filter/wrapper.c index 2ad2337a5c..94823b686d 100644 --- a/modules/video_filter/wrapper.c +++ b/modules/video_filter/wrapper.c @@ -1,5 +1,5 @@ /***************************************************************************** - * 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$ @@ -34,21 +34,26 @@ #include #include #include +#include #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(puzzle) -DECLARE_OPEN(logo) +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 @@ -71,6 +76,15 @@ vlc_module_begin() 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 @@ -85,67 +99,112 @@ static int Control ( vout_thread_t *, int, va_list ); 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 FullscreenEventUp( vlc_object_t *, char const *, + vlc_value_t, vlc_value_t, void * ); +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 ); + if( fmt.video.i_sar_num <= 0 || fmt.video.i_sar_den <= 0 ) + { + fmt.video.i_sar_num = fmt.video.i_aspect * fmt.video.i_visible_height; + fmt.video.i_sar_den = VOUT_ASPECT_FACTOR * fmt.video.i_visible_width; + } - 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 ) + /* 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; @@ -155,6 +214,13 @@ static int Open( vlc_object_t *p_this, const char *psz_name ) 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; } /** @@ -165,9 +231,15 @@ static void Close( vlc_object_t *p_this ) 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 ); } @@ -193,20 +265,69 @@ static int Init( vout_thread_t *p_vout ) 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 field 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, + FullscreenEventUp, 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; } @@ -217,8 +338,7 @@ static void End( vout_thread_t *p_vout ) { 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 ); } @@ -228,7 +348,12 @@ static void End( vout_thread_t *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; } /** @@ -239,33 +364,124 @@ static void Render( vout_thread_t *p_vout, picture_t *p_src ) 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, + FullscreenEventUp, 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 ); @@ -293,23 +509,16 @@ static int MouseEvent( vlc_object_t *p_this, char const *psz_var, 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 ) { @@ -333,3 +542,67 @@ static void FilterAllocationClean( filter_t *p_filter ) p_filter->pf_vout_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 FullscreenEventUp( 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 = p_data; + VLC_UNUSED(oldval); VLC_UNUSED(p_this); VLC_UNUSED(psz_var); VLC_UNUSED(newval); + + const bool b_fullscreen = IsFullscreenActive( p_vout ); + if( !var_GetBool( p_vout, "fullscreen" ) != !b_fullscreen ) + return var_SetBool( p_vout, "fullscreen", b_fullscreen ); + return VLC_SUCCESS; +} +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); + + const bool b_fullscreen = IsFullscreenActive( p_vout ); + if( !b_fullscreen != !newval.b_bool ) + { + for( int i = 0; i < p_sys->i_vout; i++ ) + { + vout_thread_t *p_child = p_sys->pp_vout[i]; + if( !var_GetBool( p_child, "fullscreen" ) != !newval.b_bool ) + { + var_SetBool( p_child, "fullscreen", newval.b_bool ); + if( newval.b_bool ) + return VLC_SUCCESS; + } + } + } + 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 ? */ +} +