2 * transition_affine.c -- affine transformations
3 * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <framework/mlt_transition.h>
22 #include <framework/mlt.h>
30 /** Calculate real geometry.
33 static void geometry_calculate( mlt_transition this, const 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, const char *name, const 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, const char *name, const 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 *format = mlt_image_yuv422;
405 mlt_frame_get_image( a_frame, image, format, width, height, 1 );
407 // Calculate the region now
408 composite_calculate( this, &result, normalised_width, normalised_height, ( float )position );
410 // Fetch the b frame image
411 result.w = ( int )( result.w * *width / normalised_width );
412 result.h = ( int )( result.h * *height / normalised_height );
413 result.x = ( int )( result.x * *width / normalised_width );
414 result.y = ( int )( result.y * *height / normalised_height );
415 //result.w -= ( int )abs( result.w ) % 2;
416 //result.x -= ( int )abs( result.x ) % 2;
420 if ( mlt_properties_get_double( b_props, "aspect_ratio" ) == 0.0 )
421 mlt_properties_set_double( b_props, "aspect_ratio", consumer_ar );
423 if ( !strcmp( mlt_properties_get( a_props, "rescale.interp" ), "none" ) )
425 mlt_properties_set( b_props, "rescale.interp", "nearest" );
426 mlt_properties_set_double( b_props, "consumer_aspect_ratio", consumer_ar );
430 mlt_properties_set( b_props, "rescale.interp", mlt_properties_get( a_props, "rescale.interp" ) );
431 mlt_properties_set_double( b_props, "consumer_aspect_ratio", consumer_ar );
434 mlt_properties_set_int( b_props, "distort", mlt_properties_get_int( properties, "distort" ) );
435 mlt_frame_get_image( b_frame, &b_image, &b_format, &b_width, &b_height, 0 );
439 // Check that both images are of the correct format and process
440 if ( *format == mlt_image_yuv422 && b_format == mlt_image_yuv422 )
447 // Get values from the transition
448 float scale_x = mlt_properties_get_double( properties, "scale_x" );
449 float scale_y = mlt_properties_get_double( properties, "scale_y" );
450 int scale = mlt_properties_get_int( properties, "scale" );
455 int cx = result.x + ( b_width >> 1 );
456 int cy = result.y + ( b_height >> 1 );
459 int lower_x = 0 - cx;
460 int upper_x = *width - cx;
461 int lower_y = 0 - cy;
462 int upper_y = *height - cy;
464 int b_stride = b_width << 1;
465 int a_stride = *width << 1;
466 int x_offset = ( int )result.w >> 1;
467 int y_offset = ( int )result.h >> 1;
469 uint8_t *alpha = mlt_frame_get_alpha_mask( b_frame );
470 uint8_t *mask = mlt_frame_get_alpha_mask( a_frame );
471 uint8_t *pmask = mask;
476 get_affine( &affine, this, ( float )position );
480 dz = MapZ( affine.matrix, 0, 0 );
484 mask = mlt_pool_alloc( *width * *height );
486 memset( mask, 255, *width * *height );
489 if ( ( int )abs( dz * 1000 ) < 25 )
494 affine_max_output( affine.matrix, &sw, &sh, dz );
495 affine_scale( affine.matrix, sw, sh );
497 else if ( scale_x != 0 && scale_y != 0 )
499 affine_scale( affine.matrix, scale_x, scale_y );
504 for ( y = lower_y; y < upper_y; y ++ )
508 for ( x = lower_x; x < upper_x; x ++ )
510 dx = MapX( affine.matrix, x, y ) / dz + x_offset;
511 dy = MapY( affine.matrix, x, y ) / dz + y_offset;
513 if ( dx >= 0 && dx < b_width && dy >=0 && dy < b_height )
517 *p ++ = *( b_image + dy * b_stride + ( dx << 1 ) );
518 *p ++ = *( b_image + dy * b_stride + ( dx << 1 ) + ( ( x & 1 ) << 1 ) + 1 );
532 for ( y = lower_y; y < upper_y; y ++ )
536 for ( x = lower_x; x < upper_x; x ++ )
538 dx = MapX( affine.matrix, x, y ) / dz + x_offset;
539 dy = MapY( affine.matrix, x, y ) / dz + y_offset;
541 if ( dx >= 0 && dx < b_width && dy >=0 && dy < b_height )
543 *pmask ++ = *( alpha + dy * b_width + dx );
544 mix = ( float )*( alpha + dy * b_width + dx ) / 255.0;
546 *p = *p * ( 1 - mix ) + mix * *( b_image + dy * b_stride + ( dx << 1 ) );
548 *p = *p * ( 1 - mix ) + mix * *( b_image + dy * b_stride + ( dx << 1 ) + ( ( x & 1 ) << 1 ) + 1 );
563 a_frame->get_alpha_mask = NULL;
564 mlt_properties_set_data( a_props, "alpha", mask, 0, mlt_pool_release, NULL );
570 /** Affine transition processing.
573 static mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame )
575 // Get a unique name to store the frame position
576 char *name = mlt_properties_get( MLT_TRANSITION_PROPERTIES( transition ), "_unique_id" );
578 // Assign the current position to the name
579 mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame );
580 mlt_properties_set_position( a_props, name, mlt_frame_get_position( a_frame ) );
582 // Push the transition on to the frame
583 mlt_frame_push_service( a_frame, transition );
585 // Push the b_frame on to the stack
586 mlt_frame_push_frame( a_frame, b_frame );
588 // Push the transition method
589 mlt_frame_push_get_image( a_frame, transition_get_image );
594 /** Constructor for the filter.
597 mlt_transition transition_affine_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
599 mlt_transition transition = mlt_transition_new( );
600 if ( transition != NULL )
602 mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "sx", 1 );
603 mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "sy", 1 );
604 mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "distort", 0 );
605 mlt_properties_set( MLT_TRANSITION_PROPERTIES( transition ), "geometry", "0,0:100%x100%" );
606 // Inform apps and framework that this is a video only transition
607 mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "_transition_type", 1 );
608 transition->process = transition_process;