2 * transition_affine.c -- affine transformations
3 * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include "transition_affine.h"
22 #include <framework/mlt.h>
30 /** Calculate real geometry.
33 static void geometry_calculate( mlt_transition
this, char *store
, struct mlt_geometry_item_s
*output
, float position
)
35 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
36 mlt_geometry geometry
= mlt_properties_get_data( properties
, store
, NULL
);
37 int mirror_off
= mlt_properties_get_int( properties
, "mirror_off" );
38 int repeat_off
= mlt_properties_get_int( properties
, "repeat_off" );
39 int length
= mlt_geometry_get_length( geometry
);
42 if ( !repeat_off
&& position
>= length
&& length
!= 0 )
44 int section
= position
/ length
;
45 position
-= section
* length
;
46 if ( !mirror_off
&& section
% 2 == 1 )
47 position
= length
- position
;
50 // Fetch the key for the position
51 mlt_geometry_fetch( geometry
, output
, position
);
55 static mlt_geometry
transition_parse_keys( mlt_transition
this, char *name
, char *store
, int normalised_width
, int normalised_height
)
57 // Get the properties of the transition
58 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
60 // Try to fetch it first
61 mlt_geometry geometry
= mlt_properties_get_data( properties
, store
, NULL
);
63 // Get the in and out position
64 mlt_position in
= mlt_transition_get_in( this );
65 mlt_position out
= mlt_transition_get_out( this );
67 // Determine length and obtain cycle
68 int length
= out
- in
+ 1;
69 double cycle
= mlt_properties_get_double( properties
, "cycle" );
71 // Allow a geometry repeat cycle
77 if ( geometry
== NULL
)
79 // Get the new style geometry string
80 char *property
= mlt_properties_get( properties
, name
);
82 // Create an empty geometries object
83 geometry
= mlt_geometry_init( );
85 // Parse the geometry if we have one
86 mlt_geometry_parse( geometry
, property
, length
, normalised_width
, normalised_height
);
89 mlt_properties_set_data( properties
, store
, geometry
, 0, ( mlt_destructor
)mlt_geometry_close
, NULL
);
93 // Check for updates and refresh if necessary
94 mlt_geometry_refresh( geometry
, mlt_properties_get( properties
, name
), length
, normalised_width
, normalised_height
);
100 static mlt_geometry
composite_calculate( mlt_transition
this, struct mlt_geometry_item_s
*result
, int nw
, int nh
, float position
)
102 // Structures for geometry
103 mlt_geometry start
= transition_parse_keys( this, "geometry", "geometries", nw
, nh
);
105 // Do the calculation
106 geometry_calculate( this, "geometries", result
, position
);
111 static inline float composite_calculate_key( mlt_transition
this, char *name
, char *store
, int norm
, float position
)
113 // Struct for the result
114 struct mlt_geometry_item_s result
;
116 // Structures for geometry
117 transition_parse_keys( this, name
, store
, norm
, 0 );
119 // Do the calculation
120 geometry_calculate( this, store
, &result
, position
);
131 static void affine_init( float this[3][3] )
144 // Multiply two this affine transform with that
145 static void affine_multiply( float this[3][3], float that
[3][3] )
151 for ( i
= 0; i
< 3; i
++ )
152 for ( j
= 0; j
< 3; j
++ )
153 output
[i
][j
] = this[i
][0] * that
[j
][0] + this[i
][1] * that
[j
][1] + this[i
][2] * that
[j
][2];
155 this[0][0] = output
[0][0];
156 this[0][1] = output
[0][1];
157 this[0][2] = output
[0][2];
158 this[1][0] = output
[1][0];
159 this[1][1] = output
[1][1];
160 this[1][2] = output
[1][2];
161 this[2][0] = output
[2][0];
162 this[2][1] = output
[2][1];
163 this[2][2] = output
[2][2];
166 // Rotate by a given angle
167 static void affine_rotate_x( float this[3][3], float angle
)
170 affine
[0][0] = cos( angle
* M_PI
/ 180 );
171 affine
[0][1] = 0 - sin( angle
* M_PI
/ 180 );
173 affine
[1][0] = sin( angle
* M_PI
/ 180 );
174 affine
[1][1] = cos( angle
* M_PI
/ 180 );
179 affine_multiply( this, affine
);
182 static void affine_rotate_y( float this[3][3], float angle
)
185 affine
[0][0] = cos( angle
* M_PI
/ 180 );
187 affine
[0][2] = 0 - sin( angle
* M_PI
/ 180 );
191 affine
[2][0] = sin( angle
* M_PI
/ 180 );
193 affine
[2][2] = cos( angle
* M_PI
/ 180 );
194 affine_multiply( this, affine
);
197 static void affine_rotate_z( float this[3][3], float angle
)
204 affine
[1][1] = cos( angle
* M_PI
/ 180 );
205 affine
[1][2] = sin( angle
* M_PI
/ 180 );
207 affine
[2][1] = - sin( angle
* M_PI
/ 180 );
208 affine
[2][2] = cos( angle
* M_PI
/ 180 );
209 affine_multiply( this, affine
);
212 static void affine_scale( float this[3][3], float sx
, float sy
)
224 affine_multiply( this, affine
);
227 // Shear by a given value
228 static void affine_shear( float this[3][3], float shear_x
, float shear_y
, float shear_z
)
232 affine
[0][1] = tan( shear_x
* M_PI
/ 180 );
234 affine
[1][0] = tan( shear_y
* M_PI
/ 180 );
236 affine
[1][2] = tan( shear_z
* M_PI
/ 180 );
240 affine_multiply( this, affine
);
243 static void affine_offset( float this[3][3], int x
, int y
)
249 // Obtain the mapped x coordinate of the input
250 static inline double MapX( float this[3][3], int x
, int y
)
252 return this[0][0] * x
+ this[0][1] * y
+ this[0][2];
255 // Obtain the mapped y coordinate of the input
256 static inline double MapY( float this[3][3], int x
, int y
)
258 return this[1][0] * x
+ this[1][1] * y
+ this[1][2];
261 static inline double MapZ( float this[3][3], int x
, int y
)
263 return this[2][0] * x
+ this[2][1] * y
+ this[2][2];
266 #define MAX( x, y ) x > y ? x : y
267 #define MIN( x, y ) x < y ? x : y
269 static void affine_max_output( float this[3][3], float *w
, float *h
, float dz
)
271 int tlx
= MapX( this, -720, 576 ) / dz
;
272 int tly
= MapY( this, -720, 576 ) / dz
;
273 int trx
= MapX( this, 720, 576 ) / dz
;
274 int try = MapY( this, 720, 576 ) / dz
;
275 int blx
= MapX( this, -720, -576 ) / dz
;
276 int bly
= MapY( this, -720, -576 ) / dz
;
277 int brx
= MapX( this, 720, -576 ) / dz
;
278 int bry
= MapY( this, 720, -576 ) / dz
;
285 max_x
= MAX( tlx
, trx
);
286 max_x
= MAX( max_x
, blx
);
287 max_x
= MAX( max_x
, brx
);
289 min_x
= MIN( tlx
, trx
);
290 min_x
= MIN( min_x
, blx
);
291 min_x
= MIN( min_x
, brx
);
293 max_y
= MAX( tly
, try );
294 max_y
= MAX( max_y
, bly
);
295 max_y
= MAX( max_y
, bry
);
297 min_y
= MIN( tly
, try );
298 min_y
= MIN( min_y
, bly
);
299 min_y
= MIN( min_y
, bry
);
301 *w
= ( float )( max_x
- min_x
+ 1 ) / 1440.0;
302 *h
= ( float )( max_y
- min_y
+ 1 ) / 1152.0;
305 #define IN_RANGE( v, r ) ( v >= - r / 2 && v < r / 2 )
307 static inline void get_affine( affine_t
*affine
, mlt_transition
this, float position
)
309 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
310 int keyed
= mlt_properties_get_int( properties
, "keyed" );
311 affine_init( affine
->matrix
);
315 float fix_rotate_x
= mlt_properties_get_double( properties
, "fix_rotate_x" );
316 float fix_rotate_y
= mlt_properties_get_double( properties
, "fix_rotate_y" );
317 float fix_rotate_z
= mlt_properties_get_double( properties
, "fix_rotate_z" );
318 float rotate_x
= mlt_properties_get_double( properties
, "rotate_x" );
319 float rotate_y
= mlt_properties_get_double( properties
, "rotate_y" );
320 float rotate_z
= mlt_properties_get_double( properties
, "rotate_z" );
321 float fix_shear_x
= mlt_properties_get_double( properties
, "fix_shear_x" );
322 float fix_shear_y
= mlt_properties_get_double( properties
, "fix_shear_y" );
323 float fix_shear_z
= mlt_properties_get_double( properties
, "fix_shear_z" );
324 float shear_x
= mlt_properties_get_double( properties
, "shear_x" );
325 float shear_y
= mlt_properties_get_double( properties
, "shear_y" );
326 float shear_z
= mlt_properties_get_double( properties
, "shear_z" );
327 float ox
= mlt_properties_get_double( properties
, "ox" );
328 float oy
= mlt_properties_get_double( properties
, "oy" );
330 affine_rotate_x( affine
->matrix
, fix_rotate_x
+ rotate_x
* position
);
331 affine_rotate_y( affine
->matrix
, fix_rotate_y
+ rotate_y
* position
);
332 affine_rotate_z( affine
->matrix
, fix_rotate_z
+ rotate_z
* position
);
333 affine_shear( affine
->matrix
,
334 fix_shear_x
+ shear_x
* position
,
335 fix_shear_y
+ shear_y
* position
,
336 fix_shear_z
+ shear_z
* position
);
337 affine_offset( affine
->matrix
, ox
, oy
);
341 float rotate_x
= composite_calculate_key( this, "rotate_x", "rotate_x_info", 360, position
);
342 float rotate_y
= composite_calculate_key( this, "rotate_y", "rotate_y_info", 360, position
);
343 float rotate_z
= composite_calculate_key( this, "rotate_z", "rotate_z_info", 360, position
);
344 float shear_x
= composite_calculate_key( this, "shear_x", "shear_x_info", 360, position
);
345 float shear_y
= composite_calculate_key( this, "shear_y", "shear_y_info", 360, position
);
346 float shear_z
= composite_calculate_key( this, "shear_z", "shear_z_info", 360, position
);
348 affine_rotate_x( affine
->matrix
, rotate_x
);
349 affine_rotate_y( affine
->matrix
, rotate_y
);
350 affine_rotate_z( affine
->matrix
, rotate_z
);
351 affine_shear( affine
->matrix
, shear_x
, shear_y
, shear_z
);
358 static int transition_get_image( mlt_frame a_frame
, uint8_t **image
, mlt_image_format
*format
, int *width
, int *height
, int writable
)
360 // Get the b frame from the stack
361 mlt_frame b_frame
= mlt_frame_pop_frame( a_frame
);
363 // Get the transition object
364 mlt_transition
this = mlt_frame_pop_service( a_frame
);
366 // Get the properties of the transition
367 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
369 // Get the properties of the a frame
370 mlt_properties a_props
= MLT_FRAME_PROPERTIES( a_frame
);
372 // Get the properties of the b frame
373 mlt_properties b_props
= MLT_FRAME_PROPERTIES( b_frame
);
375 // Image, format, width, height and image for the b frame
376 uint8_t *b_image
= NULL
;
377 mlt_image_format b_format
= mlt_image_yuv422
;
381 // Get the unique name to retrieve the frame position
382 char *name
= mlt_properties_get( properties
, "_unique_id" );
384 // Assign the current position to the name
385 mlt_position position
= mlt_properties_get_position( a_props
, name
);
386 mlt_position in
= mlt_properties_get_position( properties
, "in" );
387 mlt_position out
= mlt_properties_get_position( properties
, "out" );
388 int mirror
= mlt_properties_get_position( properties
, "mirror" );
389 int length
= out
- in
+ 1;
391 // Obtain the normalised width and height from the a_frame
392 int normalised_width
= mlt_properties_get_int( a_props
, "normalised_width" );
393 int normalised_height
= mlt_properties_get_int( a_props
, "normalised_height" );
395 double consumer_ar
= mlt_properties_get_double( a_props
, "consumer_aspect_ratio" ) ;
397 // Structures for geometry
398 struct mlt_geometry_item_s result
;
400 if ( mirror
&& position
> length
/ 2 )
401 position
= abs( position
- length
);
403 // Fetch the a frame image
404 mlt_frame_get_image( a_frame
, image
, format
, width
, height
, 1 );
406 // Calculate the region now
407 composite_calculate( this, &result
, normalised_width
, normalised_height
, ( float )position
);
409 // Fetch the b frame image
410 result
.w
= ( int )( result
.w
* *width
/ normalised_width
);
411 result
.h
= ( int )( result
.h
* *height
/ normalised_height
);
412 result
.x
= ( int )( result
.x
* *width
/ normalised_width
);
413 result
.y
= ( int )( result
.y
* *height
/ normalised_height
);
414 //result.w -= ( int )abs( result.w ) % 2;
415 //result.x -= ( int )abs( result.x ) % 2;
419 if ( mlt_properties_get_double( b_props
, "aspect_ratio" ) == 0.0 )
420 mlt_properties_set_double( b_props
, "aspect_ratio", consumer_ar
);
422 if ( !strcmp( mlt_properties_get( a_props
, "rescale.interp" ), "none" ) )
424 mlt_properties_set( b_props
, "rescale.interp", "nearest" );
425 mlt_properties_set_double( b_props
, "consumer_aspect_ratio", consumer_ar
);
429 mlt_properties_set( b_props
, "rescale.interp", mlt_properties_get( a_props
, "rescale.interp" ) );
430 mlt_properties_set_double( b_props
, "consumer_aspect_ratio", consumer_ar
);
433 mlt_properties_set_int( b_props
, "distort", mlt_properties_get_int( properties
, "distort" ) );
434 mlt_frame_get_image( b_frame
, &b_image
, &b_format
, &b_width
, &b_height
, 0 );
438 // Check that both images are of the correct format and process
439 if ( *format
== mlt_image_yuv422
&& b_format
== mlt_image_yuv422
)
446 // Get values from the transition
447 float scale_x
= mlt_properties_get_double( properties
, "scale_x" );
448 float scale_y
= mlt_properties_get_double( properties
, "scale_y" );
449 int scale
= mlt_properties_get_int( properties
, "scale" );
454 int cx
= result
.x
+ ( b_width
>> 1 );
455 int cy
= result
.y
+ ( b_height
>> 1 );
457 int lower_x
= 0 - cx
;
458 int upper_x
= *width
- cx
;
459 int lower_y
= 0 - cy
;
460 int upper_y
= *height
- cy
;
462 int b_stride
= b_width
<< 1;
463 int a_stride
= *width
<< 1;
464 int x_offset
= ( int )result
.w
>> 1;
465 int y_offset
= ( int )result
.h
>> 1;
467 uint8_t *alpha
= mlt_frame_get_alpha_mask( b_frame
);
468 uint8_t *mask
= mlt_frame_get_alpha_mask( a_frame
);
469 uint8_t *pmask
= mask
;
474 get_affine( &affine
, this, ( float )position
);
476 lower_x
-= ( lower_x
& 1 );
477 upper_x
-= ( upper_x
& 1 );
481 dz
= MapZ( affine
.matrix
, 0, 0 );
485 mask
= mlt_pool_alloc( *width
* *height
);
487 memset( mask
, 255, *width
* *height
);
490 if ( ( int )abs( dz
* 1000 ) < 25 )
495 affine_max_output( affine
.matrix
, &sw
, &sh
, dz
);
496 affine_scale( affine
.matrix
, sw
, sh
);
498 else if ( scale_x
!= 0 && scale_y
!= 0 )
500 affine_scale( affine
.matrix
, scale_x
, scale_y
);
505 for ( y
= lower_y
; y
< upper_y
; y
++ )
509 for ( x
= lower_x
; x
< upper_x
; x
++ )
511 dx
= MapX( affine
.matrix
, x
, y
) / dz
+ x_offset
;
512 dy
= MapY( affine
.matrix
, x
, y
) / dz
+ y_offset
;
514 if ( dx
>= 0 && dx
< b_width
&& dy
>=0 && dy
< b_height
)
518 *p
++ = *( b_image
+ dy
* b_stride
+ ( dx
<< 1 ) );
519 *p
++ = *( b_image
+ dy
* b_stride
+ ( dx
<< 1 ) + ( ( x
& 1 ) << 1 ) + 1 );
533 for ( y
= lower_y
; y
< upper_y
; y
++ )
537 for ( x
= lower_x
; x
< upper_x
; x
++ )
539 dx
= MapX( affine
.matrix
, x
, y
) / dz
+ x_offset
;
540 dy
= MapY( affine
.matrix
, x
, y
) / dz
+ y_offset
;
542 if ( dx
>= 0 && dx
< b_width
&& dy
>=0 && dy
< b_height
)
544 *pmask
++ = *( alpha
+ dy
* b_width
+ dx
);
545 mix
= ( float )*( alpha
+ dy
* b_width
+ dx
) / 255.0;
547 *p
= *p
* ( 1 - mix
) + mix
* *( b_image
+ dy
* b_stride
+ ( dx
<< 1 ) );
549 *p
= *p
* ( 1 - mix
) + mix
* *( b_image
+ dy
* b_stride
+ ( dx
<< 1 ) + ( ( x
& 1 ) << 1 ) + 1 );
564 a_frame
->get_alpha_mask
= NULL
;
565 mlt_properties_set_data( a_props
, "alpha", mask
, 0, mlt_pool_release
, NULL
);
571 /** Affine transition processing.
574 static mlt_frame
transition_process( mlt_transition transition
, mlt_frame a_frame
, mlt_frame b_frame
)
576 // Get a unique name to store the frame position
577 char *name
= mlt_properties_get( MLT_TRANSITION_PROPERTIES( transition
), "_unique_id" );
579 // Assign the current position to the name
580 mlt_properties a_props
= MLT_FRAME_PROPERTIES( a_frame
);
581 mlt_properties_set_position( a_props
, name
, mlt_frame_get_position( a_frame
) );
583 // Push the transition on to the frame
584 mlt_frame_push_service( a_frame
, transition
);
586 // Push the b_frame on to the stack
587 mlt_frame_push_frame( a_frame
, b_frame
);
589 // Push the transition method
590 mlt_frame_push_get_image( a_frame
, transition_get_image
);
595 /** Constructor for the filter.
598 mlt_transition
transition_affine_init( char *arg
)
600 mlt_transition transition
= mlt_transition_new( );
601 if ( transition
!= NULL
)
603 mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition
), "sx", 1 );
604 mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition
), "sy", 1 );
605 mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition
), "distort", 0 );
606 mlt_properties_set( MLT_TRANSITION_PROPERTIES( transition
), "geometry", "0,0:100%x100%" );
607 // Inform apps and framework that this is a video only transition
608 mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition
), "_transition_type", 1 );
609 transition
->process
= transition_process
;