]> git.sesse.net Git - vlc/blob - modules/video_filter/wrapper.c
Added a wrapper for "video filter2" as a "video filter"
[vlc] / modules / video_filter / wrapper.c
1 /*****************************************************************************
2  * wrapper.c: a "video filter2" with mouse to "video filter" wrapper.
3  *****************************************************************************
4  * Copyright (C) 2009 Laurent Aimar
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31 #include <assert.h>
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_vout.h>
36 #include <vlc_filter.h>
37
38 #include "filter_common.h"
39
40 /*****************************************************************************
41  * Module descriptor
42  *****************************************************************************/
43 static int  Open ( vlc_object_t *, const char *psz_name );
44 static void Close( vlc_object_t * );
45
46 #define DECLARE_OPEN(name) \
47     static int  Open##name ( vlc_object_t *p_this ) { return Open( p_this, #name ); }
48
49 DECLARE_OPEN(magnify)
50
51 #undef DECLARE_OPEN
52
53 #define DECLARE_MODULE(name)                            \
54     set_description( "Video filter "#name" wrapper" )   \
55     set_shortname( "Video filter"#name" wrapper" )      \
56     set_capability( "video filter", 0 )                 \
57     set_callbacks( Open##name, Close )                  \
58     add_shortcut( #name )
59
60 vlc_module_begin()
61     set_category( CAT_VIDEO )
62     set_subcategory( SUBCAT_VIDEO_VFILTER )
63
64     DECLARE_MODULE(magnify)
65     //add_submodule()
66 vlc_module_end()
67
68 #undef DECLARE_MODULE
69
70 /*****************************************************************************
71  * Local prototypes
72  *****************************************************************************/
73 static int  Init      ( vout_thread_t * );
74 static void End       ( vout_thread_t * );
75 static void Render    ( vout_thread_t *, picture_t * );
76 static int Control    ( vout_thread_t *, int, va_list );
77
78 struct vout_sys_t
79 {
80     vout_thread_t *p_vout;
81
82     es_format_t    fmt;
83
84     vlc_mutex_t    lock;
85     filter_chain_t *p_chain;
86     vlc_mouse_t    mouse;
87 };
88
89 static int  MouseEvent( vlc_object_t *, char const *,
90                         vlc_value_t, vlc_value_t, void * );
91
92 static int  FilterAllocationInit ( filter_t *, void * );
93 static void FilterAllocationClean( filter_t * );
94
95 /**
96  * Open our wrapper instance.
97  */
98 static int Open( vlc_object_t *p_this, const char *psz_name )
99 {
100     vout_thread_t *p_vout = (vout_thread_t *)p_this;
101     vout_sys_t *p_sys;
102
103     msg_Err( p_vout, "Opening video filter wrapper for %s", psz_name );
104
105     /* Try to open our filter */
106     filter_chain_t *p_chain =
107         filter_chain_New( p_vout, "video filter2", false,
108                           FilterAllocationInit, FilterAllocationClean, p_vout );
109     if( !p_chain )
110         return VLC_ENOMEM;
111
112     es_format_t fmt;
113     es_format_Init( &fmt, VIDEO_ES, p_vout->render.i_chroma );
114     video_format_Setup( &fmt.video, p_vout->render.i_chroma,
115                         p_vout->render.i_width, p_vout->render.i_height,
116                         p_vout->render.i_aspect );
117
118     filter_chain_Reset( p_chain, &fmt, &fmt );
119
120     filter_t *p_filter =
121         filter_chain_AppendFilter( p_chain, psz_name, NULL, &fmt, &fmt );
122
123     if( !p_filter )
124     {
125         msg_Err( p_vout, "Failed to open filter '%s'", psz_name );
126         filter_chain_Delete( p_chain );
127         return VLC_EGENERIC;
128     }
129
130     p_vout->p_sys = p_sys = malloc( sizeof(*p_sys) );
131     if( !p_sys )
132     {
133         filter_chain_Delete( p_chain );
134         return VLC_ENOMEM;
135     }
136     p_sys->fmt = fmt;
137     vlc_mutex_init( &p_sys->lock );
138     p_sys->p_chain = p_chain;
139     p_sys->p_vout = NULL;
140     vlc_mouse_Init( &p_sys->mouse );
141
142     p_vout->pf_init = Init;
143     p_vout->pf_end = End;
144     p_vout->pf_manage = NULL;
145     p_vout->pf_render = Render;
146     p_vout->pf_display = NULL;
147     p_vout->pf_control = Control;
148
149     return VLC_SUCCESS;
150 }
151
152 /**
153  * Close our wrapper instance
154  */
155 static void Close( vlc_object_t *p_this )
156 {
157     vout_thread_t *p_vout = (vout_thread_t *)p_this;
158     vout_sys_t *p_sys = p_vout->p_sys;
159
160     filter_chain_Delete( p_sys->p_chain );
161     vlc_mutex_destroy( &p_sys->lock );
162     es_format_Clean( &p_sys->fmt );
163
164     free( p_vout->p_sys );
165 }
166
167 /**
168  * Initialise our wrapper
169  */
170 static int Init( vout_thread_t *p_vout )
171 {
172     vout_sys_t *p_sys = p_vout->p_sys;
173
174     assert( p_vout->render.i_chroma == p_sys->fmt.video.i_chroma &&
175             p_vout->render.i_width  == p_sys->fmt.video.i_width &&
176             p_vout->render.i_height == p_sys->fmt.video.i_height );
177
178     /* Initialize the output structure */
179     I_OUTPUTPICTURES = 0;
180     p_vout->output.i_chroma = p_vout->render.i_chroma;
181     p_vout->output.i_width  = p_vout->render.i_width;
182     p_vout->output.i_height = p_vout->render.i_height;
183     p_vout->output.i_aspect = p_vout->render.i_aspect;
184
185     p_vout->fmt_out = p_vout->fmt_in;
186
187     /* Try to open the real video output */
188     msg_Dbg( p_vout, "spawning the real video output" );
189
190     video_format_t fmt = p_vout->fmt_out;
191     p_sys->p_vout = vout_Create( p_vout, &fmt );
192     if( !p_sys->p_vout )
193     {
194         msg_Err( p_vout, "cannot open vout, aborting" );
195         return VLC_EGENERIC;
196     }
197
198     vout_filter_AllocateDirectBuffers( p_vout, VOUT_MAX_PICTURES );
199
200     vout_filter_AddChild( p_vout, p_vout->p_sys->p_vout, MouseEvent );
201
202     return VLC_SUCCESS;
203 }
204
205 /**
206  * Clean up our wrapper
207  */
208 static void End( vout_thread_t *p_vout )
209 {
210     vout_sys_t *p_sys = p_vout->p_sys;
211
212     vout_filter_DelChild( p_vout, p_sys->p_vout, MouseEvent );
213     vout_CloseAndRelease( p_sys->p_vout );
214
215     vout_filter_ReleaseDirectBuffers( p_vout );
216 }
217
218 /**
219  * Control the real vout
220  */
221 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
222 {
223     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
224 }
225
226 /**
227  * Filter a picture
228  */
229 static void Render( vout_thread_t *p_vout, picture_t *p_src )
230 {
231     vout_sys_t *p_sys = p_vout->p_sys;
232
233     vlc_mutex_lock( &p_sys->lock );
234     picture_t *p_dst = filter_chain_VideoFilter( p_sys->p_chain, p_src );
235     if( p_dst )
236         vout_DisplayPicture( p_sys->p_vout, p_dst );
237     vlc_mutex_unlock( &p_sys->lock );
238 }
239
240 /**
241  * Callback for mouse events
242  */
243 static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
244                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
245 {
246     vout_thread_t *p_vout = p_data;
247     vout_sys_t *p_sys = p_vout->p_sys;
248
249     vlc_mouse_t m;
250     vlc_mouse_Init( &m );
251     m.i_x = var_GetInteger( p_sys->p_vout, "mouse-x" );
252     m.i_y = var_GetInteger( p_sys->p_vout, "mouse-y" );
253     m.i_pressed = var_GetInteger( p_sys->p_vout, "mouse-button-down" );
254
255     vlc_mutex_lock( &p_sys->lock );
256
257     vlc_mouse_t nmouse;
258     vlc_mouse_t omouse = p_sys->mouse;
259
260     int i_ret = filter_chain_MouseFilter( p_sys->p_chain, &nmouse, &m );
261     if( !i_ret )
262         p_sys->mouse = nmouse;
263     vlc_mutex_unlock( &p_sys->lock );
264
265     if( i_ret )
266         return VLC_EGENERIC;
267
268     if( vlc_mouse_HasMoved( &omouse, &nmouse ) )
269     {
270         var_SetInteger( p_vout, "mouse-x", nmouse.i_x );
271         var_SetInteger( p_vout, "mouse-y", nmouse.i_y );
272         var_SetBool( p_vout, "mouse-moved", true );
273     }
274     if( vlc_mouse_HasButton( &omouse, &nmouse ) )
275     {
276         var_SetInteger( p_vout, "mouse-button-down", nmouse.i_pressed );
277         if( vlc_mouse_HasPressed( &omouse, &nmouse, MOUSE_BUTTON_LEFT ) )
278             var_SetBool( p_vout, "mouse-clicked", true );
279     }
280     if( m.b_double_click )
281     {
282         /* Nothing with current API */
283         msg_Warn( p_vout, "Ignoring double click" );
284     }
285     return VLC_SUCCESS;
286 }
287
288 /* */
289 static picture_t *VideoBufferNew( filter_t *p_filter )
290 {
291     vout_thread_t *p_vout = (vout_thread_t*)p_filter->p_owner;
292     vout_sys_t *p_sys = p_vout->p_sys;
293
294     picture_t *p_picture;
295     for( ;; )
296     {
297         p_picture = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 );
298         if( p_picture )
299             return p_picture;
300
301         if( !vlc_object_alive( p_vout ) || p_vout->b_error )
302             return NULL;
303         msleep( VOUT_OUTMEM_SLEEP );
304     }
305 }
306 static void VideoBufferDelete( filter_t *p_filter, picture_t *p_picture )
307 {
308     VLC_UNUSED(p_filter); VLC_UNUSED(p_picture);
309     /* FIXME is there anything to do ? */
310 }
311
312 static int FilterAllocationInit( filter_t *p_filter, void *p_data )
313 {
314     VLC_UNUSED( p_data );
315
316     p_filter->pf_vout_buffer_new = VideoBufferNew;
317     p_filter->pf_vout_buffer_del = VideoBufferDelete;
318     p_filter->p_owner = p_data;
319
320     return VLC_SUCCESS;
321 }
322 static void FilterAllocationClean( filter_t *p_filter )
323 {
324     p_filter->pf_vout_buffer_new = NULL;
325     p_filter->pf_vout_buffer_del = NULL;
326 }
327