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