1 /*****************************************************************************
2 * rotate.c : video rotation filter
3 *****************************************************************************
4 * Copyright (C) 2000-2008 the VideoLAN team
7 * Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <math.h> /* sin(), cos() */
34 #include <vlc_common.h>
35 #include <vlc_plugin.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
* );
46 static picture_t
*Filter( filter_t
*, picture_t
* );
47 static picture_t
*FilterPacked( filter_t
*, picture_t
* );
49 static int RotateCallback( vlc_object_t
*p_this
, char const *psz_var
,
50 vlc_value_t oldval
, vlc_value_t newval
,
53 static int PreciseRotateCallback( vlc_object_t
*p_this
, char const *psz_var
,
54 vlc_value_t oldval
, vlc_value_t newval
,
57 #define ANGLE_TEXT N_("Angle in degrees")
58 #define ANGLE_LONGTEXT N_("Angle in degrees (0 to 359)")
60 #define FILTER_PREFIX "rotate-"
62 /*****************************************************************************
64 *****************************************************************************/
66 set_description( N_("Rotate video filter") )
67 set_shortname( N_( "Rotate" ))
68 set_capability( "video filter2", 0 )
69 set_category( CAT_VIDEO
)
70 set_subcategory( SUBCAT_VIDEO_VFILTER
)
72 add_integer_with_range( FILTER_PREFIX
"angle", 30, 0, 359, NULL
,
73 ANGLE_TEXT
, ANGLE_LONGTEXT
, false )
75 add_shortcut( "rotate" )
76 set_callbacks( Create
, Destroy
)
79 static const char *const ppsz_filter_options
[] = {
83 /*****************************************************************************
85 *****************************************************************************/
93 static inline void cache_trigo( int i_angle
, int *i_sin
, int *i_cos
)
95 const double f_angle
= (((double)i_angle
)*M_PI
)/1800.;
96 *i_sin
= (int)(sin( f_angle
)*4096.);
97 *i_cos
= (int)(cos( f_angle
)*4096.);
100 /*****************************************************************************
101 * Create: allocates Distort video filter
102 *****************************************************************************/
103 static int Create( vlc_object_t
*p_this
)
105 filter_t
*p_filter
= (filter_t
*)p_this
;
108 if( p_filter
->fmt_in
.video
.i_chroma
!= p_filter
->fmt_out
.video
.i_chroma
)
110 msg_Err( p_filter
, "Input and output chromas don't match" );
114 switch( p_filter
->fmt_in
.video
.i_chroma
)
117 p_filter
->pf_video_filter
= Filter
;
121 p_filter
->pf_video_filter
= FilterPacked
;
125 msg_Err( p_filter
, "Unsupported input chroma (%4.4s)",
126 (char*)&(p_filter
->fmt_in
.video
.i_chroma
) );
130 /* Allocate structure */
131 p_filter
->p_sys
= malloc( sizeof( filter_sys_t
) );
132 if( p_filter
->p_sys
== NULL
)
134 p_sys
= p_filter
->p_sys
;
136 config_ChainParse( p_filter
, FILTER_PREFIX
, ppsz_filter_options
,
139 int i_angle
= var_CreateGetIntegerCommand( p_filter
,
140 FILTER_PREFIX
"angle" ) * 10;
141 cache_trigo( i_angle
, &p_sys
->i_sin
, &p_sys
->i_cos
);
142 var_Create( p_filter
, FILTER_PREFIX
"deciangle",
143 VLC_VAR_INTEGER
|VLC_VAR_ISCOMMAND
);
144 vlc_spin_init( &p_sys
->lock
);
145 var_AddCallback( p_filter
, FILTER_PREFIX
"angle", RotateCallback
, p_sys
);
146 var_AddCallback( p_filter
, FILTER_PREFIX
"deciangle",
147 PreciseRotateCallback
, p_sys
);
152 /*****************************************************************************
153 * Destroy: destroy Distort filter
154 *****************************************************************************/
155 static void Destroy( vlc_object_t
*p_this
)
157 filter_t
*p_filter
= (filter_t
*)p_this
;
159 var_DelCallback( p_filter
, FILTER_PREFIX
"angle", RotateCallback
, p_filter
->p_sys
);
160 var_DelCallback( p_filter
, FILTER_PREFIX
"deciangle",
161 PreciseRotateCallback
, p_filter
->p_sys
);
162 vlc_spin_destroy( &p_filter
->p_sys
->lock
);
163 free( p_filter
->p_sys
);
166 /*****************************************************************************
168 *****************************************************************************/
169 static picture_t
*Filter( filter_t
*p_filter
, picture_t
*p_pic
)
172 filter_sys_t
*p_sys
= p_filter
->p_sys
;
174 if( !p_pic
) return NULL
;
176 p_outpic
= filter_NewPicture( p_filter
);
179 picture_Release( p_pic
);
183 vlc_spin_lock( &p_sys
->lock
);
184 const int i_sin
= p_sys
->i_sin
;
185 const int i_cos
= p_sys
->i_cos
;
186 vlc_spin_unlock( &p_sys
->lock
);
188 for( int i_plane
= 0 ; i_plane
< p_pic
->i_planes
; i_plane
++ )
190 const int i_visible_lines
= p_pic
->p
[i_plane
].i_visible_lines
;
191 const int i_visible_pitch
= p_pic
->p
[i_plane
].i_visible_pitch
;
192 const int i_pitch
= p_pic
->p
[i_plane
].i_pitch
;
193 const int i_hidden_pitch
= i_pitch
- i_visible_pitch
;
195 const int i_aspect
= __MAX( 1, ( i_visible_lines
* p_pic
->p
[Y_PLANE
].i_visible_pitch
) / ( p_pic
->p
[Y_PLANE
].i_visible_lines
* i_visible_pitch
));
196 /* = 2 for U and V planes in YUV 4:2:2, = 1 otherwise */
198 const int i_line_center
= i_visible_lines
>>1;
199 const int i_col_center
= i_visible_pitch
>>1;
201 const uint8_t *p_in
= p_pic
->p
[i_plane
].p_pixels
;
202 uint8_t *p_out
= p_outpic
->p
[i_plane
].p_pixels
;
203 uint8_t *p_outendline
= p_out
+ i_visible_pitch
;
204 const uint8_t *p_outend
= p_out
+ i_visible_lines
* i_pitch
;
206 const uint8_t black_pixel
= ( i_plane
== Y_PLANE
) ? 0x00 : 0x80;
208 const int i_line_next
= i_cos
/ i_aspect
-i_sin
*i_visible_pitch
;
209 const int i_col_next
= -i_sin
/ i_aspect
-i_cos
*i_visible_pitch
;
210 int i_line_orig0
= ( - i_cos
* i_line_center
/ i_aspect
211 - i_sin
* i_col_center
+ (1<<11) );
212 int i_col_orig0
= i_sin
* i_line_center
/ i_aspect
213 - i_cos
* i_col_center
+ (1<<11);
214 for( ; p_outendline
< p_outend
;
215 p_out
+= i_hidden_pitch
, p_outendline
+= i_pitch
,
216 i_line_orig0
+= i_line_next
, i_col_orig0
+= i_col_next
)
218 for( ; p_out
< p_outendline
;
219 p_out
++, i_line_orig0
+= i_sin
, i_col_orig0
+= i_cos
)
221 const int i_line_orig
= (i_line_orig0
>>12)*i_aspect
+ i_line_center
;
222 const int i_col_orig
= (i_col_orig0
>>12) + i_col_center
;
223 const uint8_t* p_orig_offset
= p_in
+ i_line_orig
* i_pitch
225 const uint8_t i_line_percent
= (i_line_orig0
>>4) & 255;
226 const uint8_t i_col_percent
= (i_col_orig0
>>4) & 255;
228 if( -1 <= i_line_orig
&& i_line_orig
< i_visible_lines
229 && -1 <= i_col_orig
&& i_col_orig
< i_visible_pitch
)
234 if( ( i_col_orig
> i_visible_pitch
/2 ) )
237 uint8_t i_curpix
= black_pixel
;
238 uint8_t i_colpix
= black_pixel
;
239 uint8_t i_linpix
= black_pixel
;
240 uint8_t i_nexpix
= black_pixel
;
241 if( ( 0 <= i_line_orig
) && ( 0 <= i_col_orig
) )
242 i_curpix
= *p_orig_offset
;
245 if( ( i_col_orig
< i_visible_pitch
- 1)
246 && ( i_line_orig
>= 0 ) )
247 i_colpix
= *p_orig_offset
;
249 p_orig_offset
+=i_pitch
;
250 if( ( i_line_orig
< i_visible_lines
- 1)
251 && ( i_col_orig
< i_visible_pitch
- 1) )
252 i_nexpix
= *p_orig_offset
;
255 if( ( i_line_orig
< i_visible_lines
- 1)
256 && ( i_col_orig
>= 0 ) )
257 i_linpix
= *p_orig_offset
;
259 unsigned int temp
= 0;
261 (256 - i_line_percent
) * ( 256 - i_col_percent
);
263 i_line_percent
* (256 - i_col_percent
);
265 ( i_col_percent
) * ( i_line_percent
);
267 i_col_percent
* (256 - i_line_percent
);
271 else if (i_col_orig
== i_visible_pitch
/2 )
272 { *p_out
= black_pixel
;
275 *p_out
= *p_orig_offset
;
281 *p_out
= black_pixel
;
287 return CopyInfoAndRelease( p_outpic
, p_pic
);
290 /*****************************************************************************
292 *****************************************************************************/
293 static picture_t
*FilterPacked( filter_t
*p_filter
, picture_t
*p_pic
)
296 filter_sys_t
*p_sys
= p_filter
->p_sys
;
298 if( !p_pic
) return NULL
;
300 int i_u_offset
, i_v_offset
, i_y_offset
;
302 if( GetPackedYuvOffsets( p_pic
->format
.i_chroma
, &i_y_offset
,
303 &i_u_offset
, &i_v_offset
) != VLC_SUCCESS
)
305 msg_Warn( p_filter
, "Unsupported input chroma (%4.4s)",
306 (char*)&(p_pic
->format
.i_chroma
) );
307 picture_Release( p_pic
);
311 p_outpic
= filter_NewPicture( p_filter
);
314 picture_Release( p_pic
);
318 const uint8_t *p_in
= p_pic
->p
->p_pixels
+i_y_offset
;
319 const uint8_t *p_in_u
= p_pic
->p
->p_pixels
+i_u_offset
;
320 const uint8_t *p_in_v
= p_pic
->p
->p_pixels
+i_v_offset
;
322 const int i_pitch
= p_pic
->p
->i_pitch
;
323 const int i_visible_pitch
= p_pic
->p
->i_visible_pitch
>>1; /* In fact it's i_visible_pixels */
324 const int i_visible_lines
= p_pic
->p
->i_visible_lines
;
326 uint8_t *p_out
= p_outpic
->p
->p_pixels
+i_y_offset
;
327 uint8_t *p_out_u
= p_outpic
->p
->p_pixels
+i_u_offset
;
328 uint8_t *p_out_v
= p_outpic
->p
->p_pixels
+i_v_offset
;
330 const int i_line_center
= i_visible_lines
>>1;
331 const int i_col_center
= i_visible_pitch
>>1;
333 vlc_spin_lock( &p_sys
->lock
);
334 const int i_sin
= p_sys
->i_sin
;
335 const int i_cos
= p_sys
->i_cos
;
336 vlc_spin_unlock( &p_sys
->lock
);
339 for( i_line
= 0; i_line
< i_visible_lines
; i_line
++ )
341 for( i_col
= 0; i_col
< i_visible_pitch
; i_col
++ )
345 /* Handle "1st Y", U and V */
346 i_line_orig
= i_line_center
+
347 ( ( i_sin
* ( i_col
- i_col_center
)
348 + i_cos
* ( i_line
- i_line_center
) )>>12 );
349 i_col_orig
= i_col_center
+
350 ( ( i_cos
* ( i_col
- i_col_center
)
351 - i_sin
* ( i_line
- i_line_center
) )>>12 );
352 if( 0 <= i_col_orig
&& i_col_orig
< i_visible_pitch
353 && 0 <= i_line_orig
&& i_line_orig
< i_visible_lines
)
355 p_out
[i_line
*i_pitch
+2*i_col
] = p_in
[i_line_orig
*i_pitch
+2*i_col_orig
];
357 p_out_u
[i_line
*i_pitch
+2*i_col
] = p_in_u
[i_line_orig
*i_pitch
+4*i_col_orig
];
358 p_out_v
[i_line
*i_pitch
+2*i_col
] = p_in_v
[i_line_orig
*i_pitch
+4*i_col_orig
];
362 p_out
[i_line
*i_pitch
+2*i_col
] = 0x00;
363 p_out_u
[i_line
*i_pitch
+2*i_col
] = 0x80;
364 p_out_v
[i_line
*i_pitch
+2*i_col
] = 0x80;
369 if( i_col
>= i_visible_pitch
)
372 i_line_orig
= i_line_center
+
373 ( ( i_sin
* ( i_col
- i_col_center
)
374 + i_cos
* ( i_line
- i_line_center
) )>>12 );
375 i_col_orig
= i_col_center
+
376 ( ( i_cos
* ( i_col
- i_col_center
)
377 - i_sin
* ( i_line
- i_line_center
) )>>12 );
378 if( 0 <= i_col_orig
&& i_col_orig
< i_visible_pitch
379 && 0 <= i_line_orig
&& i_line_orig
< i_visible_lines
)
381 p_out
[i_line
*i_pitch
+2*i_col
] = p_in
[i_line_orig
*i_pitch
+2*i_col_orig
];
385 p_out
[i_line
*i_pitch
+2*i_col
] = 0x00;
390 return CopyInfoAndRelease( p_outpic
, p_pic
);
393 /*****************************************************************************
394 * Angle modification callbacks.
395 *****************************************************************************/
396 static int RotateCallback( vlc_object_t
*p_this
, char const *psz_var
,
397 vlc_value_t oldval
, vlc_value_t newval
,
402 return PreciseRotateCallback( p_this
, psz_var
, oldval
, newval
, p_data
);
405 static int PreciseRotateCallback( vlc_object_t
*p_this
, char const *psz_var
,
406 vlc_value_t oldval
, vlc_value_t newval
,
409 VLC_UNUSED(p_this
); VLC_UNUSED(psz_var
); VLC_UNUSED(oldval
);
410 filter_sys_t
*p_sys
= (filter_sys_t
*)p_data
;
413 cache_trigo( newval
.i_int
, &i_sin
, &i_cos
);
414 vlc_spin_lock( &p_sys
->lock
);
415 p_sys
->i_sin
= i_sin
;
416 p_sys
->i_cos
= i_cos
;
417 vlc_spin_unlock( &p_sys
->lock
);