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 <vlc_mouse.h>
39 #include <vlc_picture.h>
40 #include "filter_picture.h"
42 /*****************************************************************************
44 *****************************************************************************/
45 static int Create ( vlc_object_t
* );
46 static void Destroy ( vlc_object_t
* );
49 set_description( N_("Magnify/Zoom interactive video filter") )
50 set_shortname( N_( "Magnify" ))
51 set_capability( "video filter", 0 )
52 set_category( CAT_VIDEO
)
53 set_subcategory( SUBCAT_VIDEO_VFILTER
)
55 set_callbacks( Create
, Destroy
)
59 /*****************************************************************************
61 *****************************************************************************/
62 static picture_t
*Filter( filter_t
*, picture_t
* );
63 static int Mouse( filter_t
*, vlc_mouse_t
*, const vlc_mouse_t
*, const vlc_mouse_t
* );
66 static void DrawZoomStatus( uint8_t *, int i_pitch
, int i_width
, int i_height
,
67 int i_offset_x
, int i_offset_y
, bool b_visible
);
68 static void DrawRectangle( uint8_t *, int i_pitch
, int i_width
, int i_height
,
69 int x
, int y
, int i_w
, int i_h
);
74 image_handler_t
*p_image
;
76 int64_t i_hide_timeout
;
78 int i_zoom
; /* zoom level in percent */
79 int i_x
, i_y
; /* top left corner coordinates in original image */
81 bool b_visible
; /* is "interface" visible ? */
83 int64_t i_last_activity
;
89 /*****************************************************************************
91 *****************************************************************************/
92 static int Create( vlc_object_t
*p_this
)
94 filter_t
*p_filter
= (filter_t
*)p_this
;
98 switch( p_filter
->fmt_in
.i_codec
)
104 msg_Err( p_filter
, "Unsupported chroma %4.4s", (char *)&p_filter
->fmt_in
.i_codec
);
107 if( !es_format_IsSimilar( &p_filter
->fmt_in
, &p_filter
->fmt_out
) )
109 msg_Err( p_filter
, "Input and output format does not match" );
113 /* Allocate structure */
114 p_filter
->p_sys
= p_sys
= malloc( sizeof( *p_sys
) );
115 if( !p_filter
->p_sys
)
118 p_sys
->p_image
= image_HandlerCreate( p_filter
);
119 if( !p_sys
->p_image
)
127 p_sys
->i_zoom
= 2*ZOOM_FACTOR
;
128 p_sys
->b_visible
= true;
129 p_sys
->i_last_activity
= mdate();
130 p_sys
->i_hide_timeout
= 1000 * var_InheritInteger( p_filter
, "mouse-hide-timeout" );
133 p_filter
->pf_video_filter
= Filter
;
134 p_filter
->pf_video_mouse
= Mouse
;
138 /*****************************************************************************
140 *****************************************************************************/
141 static void Destroy( vlc_object_t
*p_this
)
143 filter_t
*p_filter
= (filter_t
*)p_this
;
144 filter_sys_t
*p_sys
= p_filter
->p_sys
;
146 image_HandlerDelete( p_sys
->p_image
);
151 /*****************************************************************************
152 * Render: displays previously rendered output
153 *****************************************************************************/
154 static picture_t
*Filter( filter_t
*p_filter
, picture_t
*p_pic
)
156 filter_sys_t
*p_sys
= p_filter
->p_sys
;
160 picture_t
*p_converted
;
163 p_outpic
= filter_NewPicture( p_filter
);
166 picture_Release( p_pic
);
171 const bool b_visible
= p_sys
->b_visible
;
172 const int o_x
= p_sys
->i_x
;
173 const int o_y
= p_sys
->i_y
;
174 const int o_zoom
= p_sys
->i_zoom
;
176 /* background magnified image */
177 if( o_zoom
!= ZOOM_FACTOR
)
179 video_format_t fmt_in
;
180 video_format_t fmt_out
;
181 plane_t orig_planes
[PICTURE_PLANE_MAX
];
182 memcpy(orig_planes
, p_pic
->p
, sizeof orig_planes
);
184 for( int i_plane
= 0; i_plane
< p_pic
->i_planes
; i_plane
++ )
186 const int o_yp
= o_y
* p_outpic
->p
[i_plane
].i_visible_lines
/ p_outpic
->p
[Y_PLANE
].i_visible_lines
;
187 const int o_xp
= o_x
* p_outpic
->p
[i_plane
].i_visible_pitch
/ p_outpic
->p
[Y_PLANE
].i_visible_pitch
;
189 p_pic
->p
[i_plane
].p_pixels
+= o_yp
* p_pic
->p
[i_plane
].i_visible_pitch
+ o_xp
;
193 fmt_in
= p_filter
->fmt_in
.video
;
194 fmt_in
.i_width
= fmt_in
.i_visible_width
= (fmt_in
.i_visible_width
* ZOOM_FACTOR
/ o_zoom
) & ~1;
195 fmt_in
.i_height
= fmt_in
.i_visible_height
= (fmt_in
.i_visible_height
* ZOOM_FACTOR
/ o_zoom
) & ~1;
198 fmt_out
= p_filter
->fmt_out
.video
;
199 p_converted
= image_Convert( p_sys
->p_image
, p_pic
, &fmt_in
, &fmt_out
);
200 memcpy(p_pic
->p
, orig_planes
, sizeof orig_planes
);
202 picture_CopyPixels( p_outpic
, p_converted
);
204 picture_Release( p_converted
);
208 picture_CopyPixels( p_outpic
, p_pic
);
212 p_oyp
= &p_outpic
->p
[Y_PLANE
];
215 video_format_t fmt_out
;
217 /* image visualization */
218 fmt_out
= p_filter
->fmt_out
.video
;
219 fmt_out
.i_width
= fmt_out
.i_visible_width
= (fmt_out
.i_visible_width
/VIS_ZOOM
) & ~1;
220 fmt_out
.i_height
= fmt_out
.i_visible_height
= (fmt_out
.i_visible_height
/VIS_ZOOM
) & ~1;
221 p_converted
= image_Convert( p_sys
->p_image
, p_pic
,
222 &p_pic
->format
, &fmt_out
);
224 /* It will put only what can be copied at the top left */
225 picture_CopyPixels( p_outpic
, p_converted
);
227 picture_Release( p_converted
);
229 /* white rectangle on visualization */
230 v_w
= __MIN( fmt_out
.i_visible_width
* ZOOM_FACTOR
/ o_zoom
, fmt_out
.i_visible_width
- 1 );
231 v_h
= __MIN( fmt_out
.i_visible_height
* ZOOM_FACTOR
/ o_zoom
, fmt_out
.i_visible_height
- 1 );
233 DrawRectangle( p_oyp
->p_pixels
, p_oyp
->i_visible_pitch
,
234 p_oyp
->i_visible_pitch
, p_oyp
->i_visible_lines
,
235 o_x
/VIS_ZOOM
, o_y
/VIS_ZOOM
,
239 v_h
= fmt_out
.i_visible_height
+ 1;
246 /* print a small "VLC ZOOM" */
248 if( b_visible
|| p_sys
->i_last_activity
+ p_sys
->i_hide_timeout
> mdate() )
249 DrawZoomStatus( p_oyp
->p_pixels
, p_oyp
->i_visible_pitch
, p_oyp
->i_pitch
, p_oyp
->i_lines
,
255 memset( p_oyp
->p_pixels
+ (v_h
+9)*p_oyp
->i_pitch
, 0xff, 41 );
256 for( int y
= v_h
+ 10; y
< v_h
+ 90; y
++ )
258 int i_width
= v_h
+ 90 - y
;
259 i_width
= i_width
* i_width
/ 160;
260 if( (80 - y
+ v_h
)*ZOOM_FACTOR
/10 < o_zoom
)
262 memset( p_oyp
->p_pixels
+ y
*p_oyp
->i_pitch
, 0xff, i_width
);
266 p_oyp
->p_pixels
[y
*p_oyp
->i_pitch
] = 0xff;
267 p_oyp
->p_pixels
[y
*p_oyp
->i_pitch
+ i_width
- 1] = 0xff;
272 return CopyInfoAndRelease( p_outpic
, p_pic
);
275 static void DrawZoomStatus( uint8_t *pb_dst
, int i_pitch
, int i_width
, int i_height
,
276 int i_offset_x
, int i_offset_y
, bool b_visible
)
278 static const char *p_hide
=
279 "X X X XXXX XXXXX XXX XXX XX XX X X XXXXX XXXX XXXXXL"
280 "X X X X X X X X X X X X X X X X X X L"
281 " X X X X X X X X X X X XXXXX X X X XXXX L"
282 " X X X X X X X X X X X X X X X X X L"
283 " X XXXXX XXXX XXXXX XXX XXX X X X X XXXXX XXXX XXXXXL";
284 static const char *p_show
=
285 "X X X XXXX XXXXX XXX XXX XX XX XXXX X X XXX X XL"
286 "X X X X X X X X X X X X X X X X X X XL"
287 " X X X X X X X X X X X XXX XXXXX X X X X XL"
288 " X X X X X X X X X X X X X X X X X X XL"
289 " X XXXXX XXXX XXXXX XXX XXX X X XXXX X X XXX X X L";
290 const char *p_draw
= b_visible
? p_hide
: p_show
;
292 for( int 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
)
314 if( x
+ i_w
> i_width
|| y
+ i_h
> i_height
)
318 memset( &pb_dst
[y
* i_pitch
+ x
], 0xff, i_w
);
321 for( int dy
= 1; dy
< i_h
-1; dy
++ )
323 pb_dst
[(y
+dy
) * i_pitch
+ x
+ 0] = 0xff;
324 pb_dst
[(y
+dy
) * i_pitch
+ x
+ i_w
-1] = 0xff;
328 memset( &pb_dst
[(y
+i_h
-1) * i_pitch
+ x
], 0xff, i_w
);
331 static int Mouse( filter_t
*p_filter
, vlc_mouse_t
*p_mouse
, const vlc_mouse_t
*p_old
, const vlc_mouse_t
*p_new
)
333 filter_sys_t
*p_sys
= p_filter
->p_sys
;
334 const video_format_t
*p_fmt
= &p_filter
->fmt_in
.video
;
337 const bool b_click
= vlc_mouse_HasPressed( p_old
, p_new
, MOUSE_BUTTON_LEFT
);
338 const bool b_pressed
= vlc_mouse_IsLeftPressed( p_new
);
342 /* Find the mouse position */
343 if( p_sys
->b_visible
)
345 const int i_visu_width
= p_fmt
->i_visible_width
/ VIS_ZOOM
;
346 const int i_visu_height
= p_fmt
->i_visible_height
/ VIS_ZOOM
;
348 if( p_new
->i_x
>= 0 && p_new
->i_x
< i_visu_width
&&
349 p_new
->i_y
>= 0 && p_new
->i_y
< i_visu_height
)
354 const int v_w
= p_fmt
->i_visible_width
* ZOOM_FACTOR
/ p_sys
->i_zoom
;
355 const int v_h
= p_fmt
->i_visible_height
* ZOOM_FACTOR
/ p_sys
->i_zoom
;
357 p_sys
->i_x
= VLC_CLIP( p_new
->i_x
* VIS_ZOOM
- v_w
/2, 0,
358 (int)p_fmt
->i_visible_width
- v_w
- 1);
359 p_sys
->i_y
= VLC_CLIP( p_new
->i_y
* VIS_ZOOM
- v_h
/2, 0,
360 (int)p_fmt
->i_visible_height
- v_h
- 1);
365 else if( p_new
->i_x
>= 0 && p_new
->i_x
< 80 &&
366 p_new
->i_y
>= i_visu_height
&&
367 p_new
->i_y
< i_visu_height
+ 9 )
372 p_sys
->b_visible
= false;
376 else if( p_new
->i_x
>= 0 &&
377 p_new
->i_x
<= ( i_visu_height
+ 90 - p_new
->i_y
) *
378 ( i_visu_height
+ 90 - p_new
->i_y
) / 160 &&
379 p_new
->i_y
>= i_visu_height
+ 9 &&
380 p_new
->i_y
<= i_visu_height
+ 90 )
385 p_sys
->i_zoom
= __MAX( ZOOM_FACTOR
,
386 (80 + i_visu_height
- p_new
->i_y
+ 2) *
389 const int v_w
= p_fmt
->i_visible_width
* ZOOM_FACTOR
/ p_sys
->i_zoom
;
390 const int v_h
= p_fmt
->i_visible_height
* ZOOM_FACTOR
/ p_sys
->i_zoom
;
391 p_sys
->i_x
= VLC_CLIP( p_sys
->i_x
, 0, (int)p_fmt
->i_visible_width
- v_w
- 1 );
392 p_sys
->i_y
= VLC_CLIP( p_sys
->i_y
, 0, (int)p_fmt
->i_visible_height
- v_h
- 1 );
400 if( p_new
->i_x
>= 0 && p_new
->i_x
< 80 &&
401 p_new
->i_y
>= 0 && p_new
->i_y
<= 10 )
406 p_sys
->b_visible
= true;
412 if( vlc_mouse_HasMoved( p_old
, p_new
) )
413 p_sys
->i_last_activity
= mdate();
420 p_mouse
->i_x
= p_sys
->i_x
+ p_new
->i_x
* ZOOM_FACTOR
/ p_sys
->i_zoom
;
421 p_mouse
->i_y
= p_sys
->i_y
+ p_new
->i_y
* ZOOM_FACTOR
/ p_sys
->i_zoom
;