1 /*****************************************************************************
2 * magnify.c : Magnify/Zoom interactive effect
3 *****************************************************************************
4 * Copyright (C) 2005-2009 VLC authors and VideoLAN
7 * Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
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 Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_image.h>
37 #include <vlc_filter.h>
38 #include "filter_picture.h"
40 /*****************************************************************************
42 *****************************************************************************/
43 static int Create ( vlc_object_t
* );
44 static void Destroy ( vlc_object_t
* );
47 set_description( N_("Magnify/Zoom interactive video filter") )
48 set_shortname( N_( "Magnify" ))
49 set_capability( "video filter2", 0 )
50 set_category( CAT_VIDEO
)
51 set_subcategory( SUBCAT_VIDEO_VFILTER
)
53 set_callbacks( Create
, Destroy
)
57 /*****************************************************************************
59 *****************************************************************************/
60 static picture_t
*Filter( filter_t
*, picture_t
* );
61 static int Mouse( filter_t
*, vlc_mouse_t
*, const vlc_mouse_t
*, const vlc_mouse_t
* );
64 static void DrawZoomStatus( uint8_t *, int i_pitch
, int i_width
, int i_height
,
65 int i_offset_x
, int i_offset_y
, bool b_visible
);
66 static void DrawRectangle( uint8_t *, int i_pitch
, int i_width
, int i_height
,
67 int x
, int y
, int i_w
, int i_h
);
72 image_handler_t
*p_image
;
74 int64_t i_hide_timeout
;
76 int i_zoom
; /* zoom level in percent */
77 int i_x
, i_y
; /* top left corner coordinates in original image */
79 bool b_visible
; /* is "interface" visible ? */
81 int64_t i_last_activity
;
87 /*****************************************************************************
89 *****************************************************************************/
90 static int Create( vlc_object_t
*p_this
)
92 filter_t
*p_filter
= (filter_t
*)p_this
;
96 switch( p_filter
->fmt_in
.i_codec
)
102 msg_Err( p_filter
, "Unsupported chroma" );
105 if( !es_format_IsSimilar( &p_filter
->fmt_in
, &p_filter
->fmt_out
) )
107 msg_Err( p_filter
, "Input and output format does not match" );
111 /* Allocate structure */
112 p_filter
->p_sys
= p_sys
= malloc( sizeof( *p_sys
) );
113 if( !p_filter
->p_sys
)
116 p_sys
->p_image
= image_HandlerCreate( p_filter
);
117 if( !p_sys
->p_image
)
125 p_sys
->i_zoom
= 2*ZOOM_FACTOR
;
126 p_sys
->b_visible
= true;
127 p_sys
->i_last_activity
= mdate();
128 p_sys
->i_hide_timeout
= 1000 * var_CreateGetInteger( p_filter
, "mouse-hide-timeout" ); /* FIXME */
131 p_filter
->pf_video_filter
= Filter
;
132 p_filter
->pf_video_mouse
= Mouse
;
136 /*****************************************************************************
138 *****************************************************************************/
139 static void Destroy( vlc_object_t
*p_this
)
141 filter_t
*p_filter
= (filter_t
*)p_this
;
142 filter_sys_t
*p_sys
= p_filter
->p_sys
;
144 image_HandlerDelete( p_sys
->p_image
);
149 /*****************************************************************************
150 * Render: displays previously rendered output
151 *****************************************************************************/
152 static picture_t
*Filter( filter_t
*p_filter
, picture_t
*p_pic
)
154 filter_sys_t
*p_sys
= p_filter
->p_sys
;
158 picture_t
*p_converted
;
162 p_outpic
= filter_NewPicture( p_filter
);
165 picture_Release( p_pic
);
170 const bool b_visible
= p_sys
->b_visible
;
171 const int o_x
= p_sys
->i_x
;
172 const int o_y
= p_sys
->i_y
;
173 const int o_zoom
= p_sys
->i_zoom
;
175 /* background magnified image */
176 if( o_zoom
!= ZOOM_FACTOR
)
178 video_format_t fmt_in
;
179 video_format_t fmt_out
;
183 for( i_plane
= 0; i_plane
< p_pic
->i_planes
; i_plane
++ )
185 const int o_yp
= o_y
* p_outpic
->p
[i_plane
].i_lines
/ p_outpic
->p
[Y_PLANE
].i_lines
;
186 const int o_xp
= o_x
* p_outpic
->p
[i_plane
].i_pitch
/ p_outpic
->p
[Y_PLANE
].i_pitch
;
188 crop
.p
[i_plane
].p_pixels
+= o_yp
* p_pic
->p
[i_plane
].i_pitch
+ o_xp
;
192 fmt_in
= p_filter
->fmt_in
.video
;
193 fmt_in
.i_width
= (fmt_in
.i_width
* ZOOM_FACTOR
/ o_zoom
) & ~1;
194 fmt_in
.i_height
= (fmt_in
.i_height
* ZOOM_FACTOR
/ o_zoom
) & ~1;
197 fmt_out
= p_filter
->fmt_out
.video
;
199 p_converted
= image_Convert( p_sys
->p_image
, &crop
, &fmt_in
, &fmt_out
);
201 picture_CopyPixels( p_outpic
, p_converted
);
203 picture_Release( p_converted
);
207 picture_CopyPixels( p_outpic
, p_pic
);
211 p_oyp
= &p_outpic
->p
[Y_PLANE
];
214 video_format_t fmt_out
;
216 /* image visualization */
217 fmt_out
= p_filter
->fmt_out
.video
;
218 fmt_out
.i_width
= (fmt_out
.i_width
/VIS_ZOOM
) & ~1;
219 fmt_out
.i_height
= (fmt_out
.i_height
/VIS_ZOOM
) & ~1;
220 p_converted
= image_Convert( p_sys
->p_image
, p_pic
,
221 &p_pic
->format
, &fmt_out
);
223 /* It will put only what can be copied at the top left */
224 picture_CopyPixels( p_outpic
, p_converted
);
226 picture_Release( p_converted
);
228 /* white rectangle on visualization */
229 v_w
= __MIN( fmt_out
.i_width
* ZOOM_FACTOR
/ o_zoom
, fmt_out
.i_width
- 1 );
230 v_h
= __MIN( fmt_out
.i_height
* ZOOM_FACTOR
/ o_zoom
, fmt_out
.i_height
- 1 );
232 DrawRectangle( p_oyp
->p_pixels
, p_oyp
->i_pitch
,
233 p_oyp
->i_pitch
, p_oyp
->i_lines
,
234 o_x
/VIS_ZOOM
, o_y
/VIS_ZOOM
,
238 v_h
= fmt_out
.i_height
+ 1;
245 /* print a small "VLC ZOOM" */
247 if( b_visible
|| p_sys
->i_last_activity
+ p_sys
->i_hide_timeout
> mdate() )
248 DrawZoomStatus( p_oyp
->p_pixels
, p_oyp
->i_pitch
, p_oyp
->i_pitch
, p_oyp
->i_lines
,
254 memset( p_oyp
->p_pixels
+ (v_h
+9)*p_oyp
->i_pitch
, 0xff, 41 );
255 for( int y
= v_h
+ 10; y
< v_h
+ 90; y
++ )
257 int i_width
= v_h
+ 90 - y
;
258 i_width
= i_width
* i_width
/ 160;
259 if( (80 - y
+ v_h
)*ZOOM_FACTOR
/10 < o_zoom
)
261 memset( p_oyp
->p_pixels
+ y
*p_oyp
->i_pitch
, 0xff, i_width
);
265 p_oyp
->p_pixels
[y
*p_oyp
->i_pitch
] = 0xff;
266 p_oyp
->p_pixels
[y
*p_oyp
->i_pitch
+ i_width
- 1] = 0xff;
271 return CopyInfoAndRelease( p_outpic
, p_pic
);
274 static void DrawZoomStatus( uint8_t *pb_dst
, int i_pitch
, int i_width
, int i_height
,
275 int i_offset_x
, int i_offset_y
, bool b_visible
)
277 static const char *p_hide
=
278 "X X X XXXX XXXXX XXX XXX XX XX X X XXXXX XXXX XXXXXL"
279 "X X X X X X X X X X X X X X X X X X L"
280 " X X X X X X X X X X X XXXXX X X X XXXX L"
281 " X X X X X X X X X X X X X X X X X L"
282 " X XXXXX XXXX XXXXX XXX XXX X X X X XXXXX XXXX XXXXXL";
283 static const char *p_show
=
284 "X X X XXXX XXXXX XXX XXX XX XX XXXX X X XXX X XL"
285 "X X X X X X X X X X X X X X X X X X XL"
286 " X X X X X X X X X X X XXX XXXXX X X X X XL"
287 " X X X X X X X X X X X X X X X X X X XL"
288 " X XXXXX XXXX XXXXX XXX XXX X X XXXX X X XXX X X L";
289 const char *p_draw
= b_visible
? p_hide
: p_show
;
292 for( i
= 0, x
= i_offset_x
, y
= i_offset_y
; p_draw
[i
] != '\0'; i
++ )
294 if( p_draw
[i
] == 'X' )
296 if( x
< i_width
&& y
< i_height
)
297 pb_dst
[y
*i_pitch
+ x
] = 0xff;
300 else if( p_draw
[i
] == ' ' )
304 else if( p_draw
[i
] == 'L' )
311 static void DrawRectangle( uint8_t *pb_dst
, int i_pitch
, int i_width
, int i_height
,
312 int x
, int y
, int i_w
, int i_h
)
316 if( x
+ i_w
> i_width
|| y
+ i_h
> i_height
)
320 memset( &pb_dst
[y
* i_pitch
+ x
], 0xff, i_w
);
323 for( dy
= 1; dy
< i_h
-1; dy
++ )
325 pb_dst
[(y
+dy
) * i_pitch
+ x
+ 0] = 0xff;
326 pb_dst
[(y
+dy
) * i_pitch
+ x
+ i_w
-1] = 0xff;
330 memset( &pb_dst
[(y
+i_h
-1) * i_pitch
+ x
], 0xff, i_w
);
333 static int Mouse( filter_t
*p_filter
, vlc_mouse_t
*p_mouse
, const vlc_mouse_t
*p_old
, const vlc_mouse_t
*p_new
)
335 filter_sys_t
*p_sys
= p_filter
->p_sys
;
336 const video_format_t
*p_fmt
= &p_filter
->fmt_in
.video
;
339 const bool b_click
= vlc_mouse_HasPressed( p_old
, p_new
, MOUSE_BUTTON_LEFT
);
340 const bool b_pressed
= vlc_mouse_IsLeftPressed( p_new
);
344 /* Find the mouse position */
345 if( p_sys
->b_visible
)
347 const int i_visu_width
= p_fmt
->i_width
/ VIS_ZOOM
;
348 const int i_visu_height
= p_fmt
->i_height
/ VIS_ZOOM
;
350 if( p_new
->i_x
>= 0 && p_new
->i_x
< i_visu_width
&&
351 p_new
->i_y
>= 0 && p_new
->i_y
< i_visu_height
)
356 const int v_w
= p_fmt
->i_width
* ZOOM_FACTOR
/ p_sys
->i_zoom
;
357 const int v_h
= p_fmt
->i_height
* ZOOM_FACTOR
/ p_sys
->i_zoom
;
359 p_sys
->i_x
= VLC_CLIP( p_new
->i_x
* VIS_ZOOM
- v_w
/2, 0,
360 (int)p_fmt
->i_width
- v_w
- 1);
361 p_sys
->i_y
= VLC_CLIP( p_new
->i_y
* VIS_ZOOM
- v_h
/2, 0,
362 (int)p_fmt
->i_height
- v_h
- 1);
367 else if( p_new
->i_x
>= 0 && p_new
->i_x
< 80 &&
368 p_new
->i_y
>= i_visu_height
&&
369 p_new
->i_y
< i_visu_height
+ 9 )
374 p_sys
->b_visible
= false;
378 else if( p_new
->i_x
>= 0 &&
379 p_new
->i_x
<= ( i_visu_height
+ 90 - p_new
->i_y
) *
380 ( i_visu_height
+ 90 - p_new
->i_y
) / 160 &&
381 p_new
->i_y
>= i_visu_height
+ 9 &&
382 p_new
->i_y
<= i_visu_height
+ 90 )
387 p_sys
->i_zoom
= __MAX( ZOOM_FACTOR
,
388 (80 + i_visu_height
- p_new
->i_y
+ 2) *
391 const int v_w
= p_fmt
->i_width
* ZOOM_FACTOR
/ p_sys
->i_zoom
;
392 const int v_h
= p_fmt
->i_height
* ZOOM_FACTOR
/ p_sys
->i_zoom
;
393 p_sys
->i_x
= VLC_CLIP( p_sys
->i_x
, 0, (int)p_fmt
->i_width
- v_w
- 1 );
394 p_sys
->i_y
= VLC_CLIP( p_sys
->i_y
, 0, (int)p_fmt
->i_height
- v_h
- 1 );
402 if( p_new
->i_x
>= 0 && p_new
->i_x
< 80 &&
403 p_new
->i_y
>= 0 && p_new
->i_y
<= 10 )
408 p_sys
->b_visible
= true;
414 if( vlc_mouse_HasMoved( p_old
, p_new
) )
415 p_sys
->i_last_activity
= mdate();
422 p_mouse
->i_x
= p_sys
->i_x
+ p_new
->i_x
* ZOOM_FACTOR
/ p_sys
->i_zoom
;
423 p_mouse
->i_y
= p_sys
->i_y
+ p_new
->i_y
* ZOOM_FACTOR
/ p_sys
->i_zoom
;