]> git.sesse.net Git - vlc/blob - modules/video_filter/magnify.c
Attempt to fix zsh completion
[vlc] / modules / video_filter / magnify.c
1 /*****************************************************************************
2  * magnify.c : Magnify/Zoom interactive effect
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea -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 #include <vlc/vlc.h>
29 #include <vlc_vout.h>
30
31 #include <math.h>
32
33 #include "filter_common.h"
34 #include "vlc_image.h"
35 #include "vlc_input.h"
36 #include "vlc_playlist.h"
37
38 /*****************************************************************************
39  * Local prototypes
40  *****************************************************************************/
41 static int  Create    ( vlc_object_t * );
42 static void Destroy   ( vlc_object_t * );
43
44 static int  Init      ( vout_thread_t * );
45 static void End       ( vout_thread_t * );
46 static void Render    ( vout_thread_t *, picture_t * );
47
48 static int  SendEvents   ( vlc_object_t *, char const *,
49                            vlc_value_t, vlc_value_t, void * );
50 static int  MouseEvent   ( vlc_object_t *, char const *,
51                            vlc_value_t, vlc_value_t, void * );
52
53 /*****************************************************************************
54  * Module descriptor
55  *****************************************************************************/
56 vlc_module_begin();
57     set_description( _("Magnify/Zoom interactive video filter") );
58     set_shortname( _( "Magnify" ));
59     set_capability( "video filter", 0 );
60     set_category( CAT_VIDEO );
61     set_subcategory( SUBCAT_VIDEO_VFILTER );
62
63     set_callbacks( Create, Destroy );
64 vlc_module_end();
65
66 /*****************************************************************************
67  * vout_sys_t: Magnify video output method descriptor
68  *****************************************************************************/
69 struct vout_sys_t
70 {
71     vout_thread_t *p_vout;
72
73     image_handler_t *p_image;
74
75     int i_zoom; /* zoom level in percent */
76     int i_x, i_y; /* top left corner coordinates in original image */
77
78     vlc_bool_t b_visible; /* is "interface" visible ? */
79 };
80
81 /*****************************************************************************
82  * Control: control facility for the vout (forwards to child vout)
83  *****************************************************************************/
84 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
85 {
86     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
87 }
88
89 /*****************************************************************************
90  * Create: allocates Magnify video thread output method
91  *****************************************************************************/
92 static int Create( vlc_object_t *p_this )
93 {
94     vout_thread_t *p_vout = (vout_thread_t *)p_this;
95
96     /* Allocate structure */
97     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
98     if( p_vout->p_sys == NULL )
99     {
100         msg_Err( p_vout, "out of memory" );
101         return VLC_ENOMEM;
102     }
103
104     p_vout->p_sys->p_image = image_HandlerCreate( p_vout );
105
106     p_vout->pf_init = Init;
107     p_vout->pf_end = End;
108     p_vout->pf_manage = NULL;
109     p_vout->pf_render = Render;
110     p_vout->pf_display = NULL;
111     p_vout->pf_control = Control;
112
113     return VLC_SUCCESS;
114 }
115
116 /*****************************************************************************
117  * Init: initialize Magnify video thread output method
118  *****************************************************************************/
119 static int Init( vout_thread_t *p_vout )
120 {
121     int i_index;
122     picture_t *p_pic;
123     video_format_t fmt;
124
125     memset( &fmt, 0, sizeof(video_format_t) );
126     I_OUTPUTPICTURES = 0;
127
128     /* Initialize the output structure */
129     p_vout->output.i_chroma = p_vout->render.i_chroma;
130     p_vout->output.i_width  = p_vout->render.i_width;
131     p_vout->output.i_height = p_vout->render.i_height;
132     p_vout->output.i_aspect = p_vout->render.i_aspect;
133
134     p_vout->fmt_out = p_vout->fmt_in;
135     fmt = p_vout->fmt_out;
136
137     /* Try to open the real video output */
138     msg_Dbg( p_vout, "spawning the real video output" );
139
140     p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
141
142     /* Everything failed */
143     if( p_vout->p_sys->p_vout == NULL )
144     {
145         msg_Err( p_vout, "cannot open vout, aborting" );
146         return VLC_EGENERIC;
147     }
148
149 #define VIS_ZOOM 4
150     p_vout->p_sys->i_x = 0;
151     p_vout->p_sys->i_y = 0;
152 #define ZOOM_FACTOR 100
153     p_vout->p_sys->i_zoom = 200;
154     p_vout->p_sys->b_visible = VLC_TRUE;
155
156     var_AddCallback( p_vout->p_sys->p_vout, "mouse-x", MouseEvent, p_vout );
157     var_AddCallback( p_vout->p_sys->p_vout, "mouse-y", MouseEvent, p_vout );
158     var_AddCallback( p_vout->p_sys->p_vout, "mouse-clicked",
159                      MouseEvent, p_vout);
160
161     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
162     ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
163     ADD_PARENT_CALLBACKS( SendEventsToChild );
164
165     return VLC_SUCCESS;
166 }
167
168 /*****************************************************************************
169  * End: terminate Magnify video thread output method
170  *****************************************************************************/
171 static void End( vout_thread_t *p_vout )
172 {
173     int i_index;
174
175     /* Free the fake output buffers we allocated */
176     for( i_index = I_OUTPUTPICTURES ; i_index ; )
177     {
178         i_index--;
179         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
180     }
181
182     var_DelCallback( p_vout->p_sys->p_vout, "mouse-x", MouseEvent, p_vout);
183     var_DelCallback( p_vout->p_sys->p_vout, "mouse-y", MouseEvent, p_vout);
184     var_DelCallback( p_vout->p_sys->p_vout, "mouse-clicked", MouseEvent, p_vout);
185 }
186
187 /*****************************************************************************
188  * Destroy: destroy Magnify video thread output method
189  *****************************************************************************/
190 static void Destroy( vlc_object_t *p_this )
191 {
192     vout_thread_t *p_vout = (vout_thread_t *)p_this;
193
194     if( p_vout->p_sys->p_vout )
195     {
196         DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
197         vlc_object_detach( p_vout->p_sys->p_vout );
198         vout_Destroy( p_vout->p_sys->p_vout );
199     }
200
201     image_HandlerDelete( p_vout->p_sys->p_image );
202
203     DEL_PARENT_CALLBACKS( SendEventsToChild );
204
205     free( p_vout->p_sys );
206 }
207
208 /*****************************************************************************
209  * Render: displays previously rendered output
210  *****************************************************************************/
211 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
212 {
213     picture_t *p_outpic;
214
215     int o_x = p_vout->p_sys->i_x;
216     int o_y = p_vout->p_sys->i_y;
217     int o_zoom = p_vout->p_sys->i_zoom;
218     int x,y,o_yp,o_xp;
219     int v_w, v_h;
220     video_format_t fmt_out;
221     picture_t *p_converted;
222     plane_t *p_oyp=NULL;
223
224     memset( &fmt_out, 0, sizeof(video_format_t) );
225     /* This is a new frame. Get a structure from the video_output. */
226     while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
227               == NULL )
228     {
229         if( p_vout->b_die || p_vout->b_error )
230         {
231             return;
232         }
233         msleep( VOUT_OUTMEM_SLEEP );
234     }
235
236     vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
237
238     p_oyp = &(p_outpic->p[Y_PLANE]);
239
240     /* background magnified image */
241     if( o_zoom != ZOOM_FACTOR )
242     {
243 #define magnify( plane ) \
244     o_yp = o_y*p_outpic->p[plane].i_lines/p_outpic->p[Y_PLANE].i_lines; \
245     o_xp = o_x*p_outpic->p[plane].i_pitch/p_outpic->p[Y_PLANE].i_pitch; \
246     for( y=0; y<p_outpic->p[plane].i_visible_lines; y++ ) \
247     { \
248         for( x=0; x<p_outpic->p[plane].i_visible_pitch; x++ ) \
249         { \
250             p_outpic->p[plane].p_pixels[y*p_outpic->p[plane].i_pitch+x] = \
251                 p_pic->p[plane].p_pixels[ \
252                     ( o_yp + y*ZOOM_FACTOR/o_zoom )*p_outpic->p[plane].i_pitch \
253                     + o_xp + x*ZOOM_FACTOR/o_zoom \
254                 ]; \
255         } \
256     }
257     magnify( Y_PLANE );
258     magnify( U_PLANE );
259     magnify( V_PLANE );
260 #undef magnify
261     }
262     else
263     {
264 #define copy( plane ) \
265         p_vout->p_libvlc-> \
266         pf_memcpy( p_outpic->p[plane].p_pixels, p_pic->p[plane].p_pixels, \
267             p_outpic->p[plane].i_lines * p_outpic->p[plane].i_pitch );
268         copy( Y_PLANE );
269         copy( U_PLANE );
270         copy( V_PLANE );
271 #undef copy
272     }
273
274     if( p_vout->p_sys->b_visible )
275     {
276         /* image visualization */
277         fmt_out = p_vout->fmt_out;
278         fmt_out.i_width = p_vout->render.i_width/VIS_ZOOM;
279         fmt_out.i_height = p_vout->render.i_height/VIS_ZOOM;
280         p_converted = image_Convert( p_vout->p_sys->p_image, p_pic,
281                                      &(p_pic->format), &fmt_out );
282     #define copyimage( plane ) \
283         for( y=0; y<p_converted->p[plane].i_visible_lines; y++) \
284         { \
285             p_vout->p_libvlc->pf_memcpy( \
286             p_outpic->p[plane].p_pixels+y*p_outpic->p[plane].i_pitch, \
287             p_converted->p[plane].p_pixels+y*p_converted->p[plane].i_pitch, \
288             p_converted->p[plane].i_visible_pitch ); \
289         }
290         copyimage( Y_PLANE );
291         copyimage( U_PLANE );
292         copyimage( V_PLANE );
293     #undef copyimage
294         p_converted->pf_release( p_converted );
295
296         /* white rectangle on visualization */
297         v_w = p_oyp->i_pitch*ZOOM_FACTOR/(VIS_ZOOM*o_zoom);
298         v_h = (o_y+p_oyp->i_lines*ZOOM_FACTOR/o_zoom)/VIS_ZOOM;
299         /* top line */
300         p_vout->p_libvlc->pf_memset( p_oyp->p_pixels
301                                      + o_y/VIS_ZOOM*p_oyp->i_pitch
302                                      + o_x/VIS_ZOOM, 0xff, v_w+1 );
303
304         for( y = o_y/VIS_ZOOM+1; y < v_h; y++ )
305         {
306             /* left line */
307             p_oyp->p_pixels[
308                 y*p_oyp->i_pitch+o_x/VIS_ZOOM
309             ] = 0xff;
310             /* right line */
311             p_oyp->p_pixels[
312                 y*p_oyp->i_pitch+o_x/VIS_ZOOM + v_w
313             ] = 0xff;
314         }
315         /* bottom line */
316         p_vout->p_libvlc->pf_memset( p_oyp->p_pixels
317                                      + v_h*p_oyp->i_pitch
318                                      + o_x/VIS_ZOOM, 0xff, v_w+1 );
319
320         /* */
321         v_h = p_oyp->i_lines/VIS_ZOOM;
322     }
323     else
324     {
325         v_h = 1;
326     }
327
328     /* print a small "VLC ZOOM" ... gruikkkkkkkkk */
329 #define DRAW(a) {int c,l=1;L a;}
330 #define L ;l++,c=1
331 #define X ;draw(l,c);c+=1
332 #define o +1
333 #define draw(y,x) p_oyp->p_pixels[(v_h+y)*p_oyp->i_pitch+x] = 0xff;
334 if( p_vout->p_sys->b_visible )
335 DRAW(
336 X o o o X o X o o o o o o X X X X o o o X X X X X o o X X X o o o X X X o o X X o X X o o o X o o o X o X X X X X o X X X X o o X X X X X L
337 X o o o X o X o o o o o X o o o o o o o o o o X o o X o o o X o X o o o X o X o X o X o o o X o o o X o o o X o o o X o o o X o X o o o o L
338 o X o X o o X o o o o o X o o o o o o o o o X o o o X o o o X o X o o o X o X o o o X o o o X X X X X o o o X o o o X o o o X o X X X X o L
339 o X o X o o X o o o o o X o o o o o o o o X o o o o X o o o X o X o o o X o X o o o X o o o X o o o X o o o X o o o X o o o X o X o o o o L
340 o o X o o o X X X X X o o X X X X o o o X X X X X o o X X X o o o X X X o o X o o o X o o o X o o o X o X X X X X o X X X X o o X X X X X L
341 )
342 else
343 DRAW(
344 X o o o X o X o o o o o o X X X X o o o X X X X X o o X X X o o o X X X o o X X o X X o o o o X X X X o X o o o X o o X X X o o X o o o X L
345 X o o o X o X o o o o o X o o o o o o o o o o X o o X o o o X o X o o o X o X o X o X o o o X o o o o o X o o o X o X o o o X o X o o o X L
346 o X o X o o X o o o o o X o o o o o o o o o X o o o X o o o X o X o o o X o X o o o X o o o o X X X o o X X X X X o X o o o X o X o X o X L
347 o X o X o o X o o o o o X o o o o o o o o X o o o o X o o o X o X o o o X o X o o o X o o o o o o o X o X o o o X o X o o o X o X o X o X L
348 o o X o o o X X X X X o o X X X X o o o X X X X X o o X X X o o o X X X o o X o o o X o o o X X X X o o X o o o X o o X X X o o o X o X o L
349 )
350 #undef DRAW
351 #undef L
352 #undef X
353 #undef O
354 #undef draw
355
356     if( p_vout->p_sys->b_visible )
357     {
358         /* zoom gauge */
359         p_vout->p_libvlc->pf_memset( p_oyp->p_pixels
360                                      + (v_h+9)*p_oyp->i_pitch,
361                                      0xff, 41 );
362         for( y = v_h + 10; y < v_h + 90; y++ )
363         {
364             int width = v_h + 90 - y;
365             width = (width*width)/160;
366             if( (80 - y + v_h)*10 < o_zoom )
367             {
368                 p_vout->p_libvlc->pf_memset( p_oyp->p_pixels
369                                              + y*p_oyp->i_pitch,
370                                              0xff, width );
371             }
372             else
373             {
374                 p_oyp->p_pixels[y*p_oyp->i_pitch] = 0xff;
375                 p_oyp->p_pixels[y*p_oyp->i_pitch + width - 1] = 0xff;
376             }
377         }
378     }
379
380     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
381 }
382
383 /*****************************************************************************
384  * SendEvents: forward mouse and keyboard events to the parent p_vout
385  *****************************************************************************/
386 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
387                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
388 {
389     var_Set( (vlc_object_t *)p_data, psz_var, newval );
390
391     return VLC_SUCCESS;
392 }
393
394 /*****************************************************************************
395  * SendEventsToChild: forward events to the child/children vout
396  *****************************************************************************/
397 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
398                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
399 {
400     vout_thread_t *p_vout = (vout_thread_t *)p_this;
401     var_Set( p_vout->p_sys->p_vout, psz_var, newval );
402     return VLC_SUCCESS;
403 }
404
405 /*****************************************************************************
406  * MouseEvent: callback for mouse events
407  *****************************************************************************/
408 static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
409                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
410 {
411     vout_thread_t *p_vout = (vout_thread_t*)p_data;
412     vlc_value_t vald,valx,valy;
413
414 #define MOUSE_DOWN    1
415 #define MOUSE_CLICKED 2
416 #define MOUSE_MOVE_X  4
417 #define MOUSE_MOVE_Y  8
418 #define MOUSE_MOVE    12
419     uint8_t mouse= 0;
420
421     int v_h = p_vout->output.i_height*ZOOM_FACTOR/p_vout->p_sys->i_zoom;
422     int v_w = p_vout->output.i_width*ZOOM_FACTOR/p_vout->p_sys->i_zoom;
423
424     if( psz_var[6] == 'x' ) mouse |= MOUSE_MOVE_X;
425     if( psz_var[6] == 'y' ) mouse |= MOUSE_MOVE_Y;
426     if( psz_var[6] == 'c' ) mouse |= MOUSE_CLICKED;
427
428     var_Get( p_vout->p_sys->p_vout, "mouse-button-down", &vald );
429     if( vald.i_int & 0x1 ) mouse |= MOUSE_DOWN;
430     var_Get( p_vout->p_sys->p_vout, "mouse-y", &valy );
431     var_Get( p_vout->p_sys->p_vout, "mouse-x", &valx );
432
433     if( ( mouse&MOUSE_MOVE && mouse&MOUSE_DOWN)
434         || mouse&MOUSE_CLICKED )
435     {
436     /* (mouse moved and mouse button is down) or (mouse clicked) */
437         if( p_vout->p_sys->b_visible )
438         {
439             if(    0 <= valy.i_int
440                 && valy.i_int < (int)p_vout->output.i_height/VIS_ZOOM
441                 && 0 <= valx.i_int
442                 && valx.i_int < (int)p_vout->output.i_width/VIS_ZOOM )
443             {
444             /* mouse is over visualisation */
445                 p_vout->p_sys->i_x = __MIN( __MAX( valx.i_int*VIS_ZOOM - v_w/2, 0 ),
446                                             p_vout->output.i_width - v_w - 1);
447                 p_vout->p_sys->i_y = __MIN( __MAX( valy.i_int * VIS_ZOOM - v_h/2,
448                                         0 ), p_vout->output.i_height - v_h - 1);
449             }
450             else if( valx.i_int >= 0 && valx.i_int < 80
451                 && valy.i_int >= (int)p_vout->output.i_height/VIS_ZOOM
452                 && valy.i_int < (int)p_vout->output.i_height/VIS_ZOOM + 9
453                 && mouse&MOUSE_CLICKED )
454             {
455             /* mouse is over the "VLC ZOOM HIDE" text */
456                 p_vout->p_sys->b_visible = VLC_FALSE;
457             }
458             else if(    (int)p_vout->output.i_height/VIS_ZOOM + 9 <= valy.i_int
459                      && valy.i_int <= (int)p_vout->output.i_height/VIS_ZOOM + 90
460                      && 0 <= valx.i_int
461                      && valx.i_int <=
462                      (( (int)p_vout->output.i_height/VIS_ZOOM + 90 -  valy.i_int)
463                *( (int)p_vout->output.i_height/VIS_ZOOM + 90 -  valy.i_int))/160 )
464             {
465             /* mouse is over zoom gauge */
466                 p_vout->p_sys->i_zoom = __MAX( ZOOM_FACTOR,
467                                 ( 80 + (int)p_vout->output.i_height/VIS_ZOOM
468                                    - valy.i_int + 2) * ZOOM_FACTOR/10 );
469             }
470             else if( mouse&MOUSE_MOVE_X && !(mouse&MOUSE_CLICKED) )
471             {
472                 p_vout->p_sys->i_x -= (newval.i_int - oldval.i_int)
473                                       *ZOOM_FACTOR/p_vout->p_sys->i_zoom;
474             }
475             else if( mouse&MOUSE_MOVE_Y && !(mouse&MOUSE_CLICKED) )
476             {
477                 p_vout->p_sys->i_y -= (newval.i_int - oldval.i_int)
478                                       *ZOOM_FACTOR/p_vout->p_sys->i_zoom;
479             }
480         }
481         else
482         {
483             if( valx.i_int >= 0 && valx.i_int < 80 && valy.i_int >= 0
484                 && valy.i_int <= 10 && mouse&MOUSE_CLICKED )
485             {
486             /* mouse is over the "VLC ZOOM SHOW" text */
487                 p_vout->p_sys->b_visible = VLC_TRUE;
488             }
489             else if( mouse&MOUSE_MOVE_X && !(mouse&MOUSE_CLICKED) )
490             {
491                 p_vout->p_sys->i_x -= (newval.i_int - oldval.i_int)
492                                       *ZOOM_FACTOR/p_vout->p_sys->i_zoom;
493             }
494             else if( mouse&MOUSE_MOVE_Y && !(mouse&MOUSE_CLICKED) )
495             {
496                 p_vout->p_sys->i_y -= (newval.i_int - oldval.i_int)
497                                       *ZOOM_FACTOR/p_vout->p_sys->i_zoom;
498             }
499         }
500     }
501
502     p_vout->p_sys->i_x =
503          __MAX( 0, __MIN( p_vout->p_sys->i_x, (int)p_vout->output.i_width
504          - (int)p_vout->output.i_width*ZOOM_FACTOR/p_vout->p_sys->i_zoom - 1 ));
505     p_vout->p_sys->i_y =
506          __MAX( 0, __MIN( p_vout->p_sys->i_y, (int)p_vout->output.i_height
507         - (int)p_vout->output.i_height*ZOOM_FACTOR/p_vout->p_sys->i_zoom - 1 ));
508
509
510     return VLC_SUCCESS;
511 }