2 * transition_affine.c -- affine transformations
3 * Copyright (C) 2003-2010 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
5 * Author: Dan Dennedy <dan@dennedy.org>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <framework/mlt_transition.h>
23 #include <framework/mlt.h>
33 /** Calculate real geometry.
36 static void geometry_calculate( mlt_transition this, const char *store, struct mlt_geometry_item_s *output, float position )
38 mlt_properties properties = MLT_TRANSITION_PROPERTIES( this );
39 mlt_geometry geometry = mlt_properties_get_data( properties, store, NULL );
40 int mirror_off = mlt_properties_get_int( properties, "mirror_off" );
41 int repeat_off = mlt_properties_get_int( properties, "repeat_off" );
42 int length = mlt_geometry_get_length( geometry );
45 if ( !repeat_off && position >= length && length != 0 )
47 int section = position / length;
48 position -= section * length;
49 if ( !mirror_off && section % 2 == 1 )
50 position = length - position;
53 // Fetch the key for the position
54 mlt_geometry_fetch( geometry, output, position );
58 static mlt_geometry transition_parse_keys( mlt_transition this, const char *name, const char *store, int normalised_width, int normalised_height )
60 // Get the properties of the transition
61 mlt_properties properties = MLT_TRANSITION_PROPERTIES( this );
63 // Try to fetch it first
64 mlt_geometry geometry = mlt_properties_get_data( properties, store, NULL );
66 // Get the in and out position
67 int always_active = mlt_properties_get_int( properties, "always_active" );
68 mlt_position in = mlt_transition_get_in( this );
69 mlt_position out = !always_active ? mlt_transition_get_out( this ) : -1;
71 // Determine length and obtain cycle
72 int length = out - in + 1;
73 double cycle = mlt_properties_get_double( properties, "cycle" );
75 // Allow a geometry repeat cycle
81 if ( geometry == NULL )
83 // Get the new style geometry string
84 char *property = mlt_properties_get( properties, name );
86 // Create an empty geometries object
87 geometry = mlt_geometry_init( );
89 // Parse the geometry if we have one
90 mlt_geometry_parse( geometry, property, length, normalised_width, normalised_height );
93 mlt_properties_set_data( properties, store, geometry, 0, ( mlt_destructor )mlt_geometry_close, NULL );
97 // Check for updates and refresh if necessary
98 mlt_geometry_refresh( geometry, mlt_properties_get( properties, name ), length, normalised_width, normalised_height );
104 static mlt_geometry composite_calculate( mlt_transition this, struct mlt_geometry_item_s *result, int nw, int nh, float position )
106 // Structures for geometry
107 mlt_geometry start = transition_parse_keys( this, "geometry", "geometries", nw, nh );
109 // Do the calculation
110 geometry_calculate( this, "geometries", result, position );
115 static inline float composite_calculate_key( mlt_transition this, const char *name, const char *store, int norm, float position )
117 // Struct for the result
118 struct mlt_geometry_item_s result;
120 // Structures for geometry
121 transition_parse_keys( this, name, store, norm, 0 );
123 // Do the calculation
124 geometry_calculate( this, store, &result, position );
135 static void affine_init( float this[3][3] )
148 // Multiply two this affine transform with that
149 static void affine_multiply( float this[3][3], float that[3][3] )
155 for ( i = 0; i < 3; i ++ )
156 for ( j = 0; j < 3; j ++ )
157 output[i][j] = this[i][0] * that[j][0] + this[i][1] * that[j][1] + this[i][2] * that[j][2];
159 this[0][0] = output[0][0];
160 this[0][1] = output[0][1];
161 this[0][2] = output[0][2];
162 this[1][0] = output[1][0];
163 this[1][1] = output[1][1];
164 this[1][2] = output[1][2];
165 this[2][0] = output[2][0];
166 this[2][1] = output[2][1];
167 this[2][2] = output[2][2];
170 // Rotate by a given angle
171 static void affine_rotate_x( float this[3][3], float angle )
174 affine[0][0] = cos( angle * M_PI / 180 );
175 affine[0][1] = 0 - sin( angle * M_PI / 180 );
177 affine[1][0] = sin( angle * M_PI / 180 );
178 affine[1][1] = cos( angle * M_PI / 180 );
183 affine_multiply( this, affine );
186 static void affine_rotate_y( float this[3][3], float angle )
189 affine[0][0] = cos( angle * M_PI / 180 );
191 affine[0][2] = 0 - sin( angle * M_PI / 180 );
195 affine[2][0] = sin( angle * M_PI / 180 );
197 affine[2][2] = cos( angle * M_PI / 180 );
198 affine_multiply( this, affine );
201 static void affine_rotate_z( float this[3][3], float angle )
208 affine[1][1] = cos( angle * M_PI / 180 );
209 affine[1][2] = sin( angle * M_PI / 180 );
211 affine[2][1] = - sin( angle * M_PI / 180 );
212 affine[2][2] = cos( angle * M_PI / 180 );
213 affine_multiply( this, affine );
216 static void affine_scale( float this[3][3], float sx, float sy )
228 affine_multiply( this, affine );
231 // Shear by a given value
232 static void affine_shear( float this[3][3], float shear_x, float shear_y, float shear_z )
236 affine[0][1] = tan( shear_x * M_PI / 180 );
238 affine[1][0] = tan( shear_y * M_PI / 180 );
240 affine[1][2] = tan( shear_z * M_PI / 180 );
244 affine_multiply( this, affine );
247 static void affine_offset( float this[3][3], float x, float y )
253 // Obtain the mapped x coordinate of the input
254 static inline double MapX( float this[3][3], float x, float y )
256 return this[0][0] * x + this[0][1] * y + this[0][2];
259 // Obtain the mapped y coordinate of the input
260 static inline double MapY( float this[3][3], float x, float y )
262 return this[1][0] * x + this[1][1] * y + this[1][2];
265 static inline double MapZ( float this[3][3], float x, float y )
267 return this[2][0] * x + this[2][1] * y + this[2][2];
270 #define MAX( x, y ) x > y ? x : y
271 #define MIN( x, y ) x < y ? x : y
273 static void affine_max_output( float this[3][3], float *w, float *h, float dz, float max_width, float max_height )
275 int tlx = MapX( this, -max_width, max_height ) / dz;
276 int tly = MapY( this, -max_width, max_height ) / dz;
277 int trx = MapX( this, max_width, max_height ) / dz;
278 int try = MapY( this, max_width, max_height ) / dz;
279 int blx = MapX( this, -max_width, -max_height ) / dz;
280 int bly = MapY( this, -max_width, -max_height ) / dz;
281 int brx = MapX( this, max_width, -max_height ) / dz;
282 int bry = MapY( this, max_width, -max_height ) / dz;
289 max_x = MAX( tlx, trx );
290 max_x = MAX( max_x, blx );
291 max_x = MAX( max_x, brx );
293 min_x = MIN( tlx, trx );
294 min_x = MIN( min_x, blx );
295 min_x = MIN( min_x, brx );
297 max_y = MAX( tly, try );
298 max_y = MAX( max_y, bly );
299 max_y = MAX( max_y, bry );
301 min_y = MIN( tly, try );
302 min_y = MIN( min_y, bly );
303 min_y = MIN( min_y, bry );
305 *w = ( float )( max_x - min_x + 1 ) / max_width / 2.0;
306 *h = ( float )( max_y - min_y + 1 ) / max_height / 2.0;
309 #define IN_RANGE( v, r ) ( v >= - r / 2 && v < r / 2 )
311 static inline void get_affine( affine_t *affine, mlt_transition this, float position )
313 mlt_properties properties = MLT_TRANSITION_PROPERTIES( this );
314 int keyed = mlt_properties_get_int( properties, "keyed" );
318 float fix_rotate_x = mlt_properties_get_double( properties, "fix_rotate_x" );
319 float fix_rotate_y = mlt_properties_get_double( properties, "fix_rotate_y" );
320 float fix_rotate_z = mlt_properties_get_double( properties, "fix_rotate_z" );
321 float rotate_x = mlt_properties_get_double( properties, "rotate_x" );
322 float rotate_y = mlt_properties_get_double( properties, "rotate_y" );
323 float rotate_z = mlt_properties_get_double( properties, "rotate_z" );
324 float fix_shear_x = mlt_properties_get_double( properties, "fix_shear_x" );
325 float fix_shear_y = mlt_properties_get_double( properties, "fix_shear_y" );
326 float fix_shear_z = mlt_properties_get_double( properties, "fix_shear_z" );
327 float shear_x = mlt_properties_get_double( properties, "shear_x" );
328 float shear_y = mlt_properties_get_double( properties, "shear_y" );
329 float shear_z = mlt_properties_get_double( properties, "shear_z" );
330 float ox = mlt_properties_get_double( properties, "ox" );
331 float oy = mlt_properties_get_double( properties, "oy" );
333 affine_rotate_x( affine->matrix, fix_rotate_x + rotate_x * position );
334 affine_rotate_y( affine->matrix, fix_rotate_y + rotate_y * position );
335 affine_rotate_z( affine->matrix, fix_rotate_z + rotate_z * position );
336 affine_shear( affine->matrix,
337 fix_shear_x + shear_x * position,
338 fix_shear_y + shear_y * position,
339 fix_shear_z + shear_z * position );
340 affine_offset( affine->matrix, ox, oy );
344 float rotate_x = composite_calculate_key( this, "rotate_x", "rotate_x_info", 360, position );
345 float rotate_y = composite_calculate_key( this, "rotate_y", "rotate_y_info", 360, position );
346 float rotate_z = composite_calculate_key( this, "rotate_z", "rotate_z_info", 360, position );
347 float shear_x = composite_calculate_key( this, "shear_x", "shear_x_info", 360, position );
348 float shear_y = composite_calculate_key( this, "shear_y", "shear_y_info", 360, position );
349 float shear_z = composite_calculate_key( this, "shear_z", "shear_z_info", 360, position );
350 float o_x = composite_calculate_key( this, "ox", "ox_info", 0, position );
351 float o_y = composite_calculate_key( this, "oy", "oy_info", 0, position );
353 affine_rotate_x( affine->matrix, rotate_x );
354 affine_rotate_y( affine->matrix, rotate_y );
355 affine_rotate_z( affine->matrix, rotate_z );
356 affine_shear( affine->matrix, shear_x, shear_y, shear_z );
357 affine_offset( affine->matrix, o_x, o_y );
364 static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
366 // Get the b frame from the stack
367 mlt_frame b_frame = mlt_frame_pop_frame( a_frame );
369 // Get the transition object
370 mlt_transition this = mlt_frame_pop_service( a_frame );
372 // Get the properties of the transition
373 mlt_properties properties = MLT_TRANSITION_PROPERTIES( this );
375 // Get the properties of the a frame
376 mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame );
378 // Get the properties of the b frame
379 mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame );
381 // Image, format, width, height and image for the b frame
382 uint8_t *b_image = NULL;
383 mlt_image_format b_format = mlt_image_rgb24a;
387 // Get the unique name to retrieve the frame position
388 char *name = mlt_properties_get( properties, "_unique_id" );
390 // Assign the current position to the name
391 mlt_position position = mlt_properties_get_position( a_props, name );
393 mlt_properties props = mlt_properties_get_data( b_props, "_producer", NULL );
394 int always_active = mlt_properties_get_int( properties, "always_active" );
396 mlt_position in = !always_active ? mlt_properties_get_position( properties, "in" ) : mlt_properties_get_int( props, "in" );
397 mlt_position out = !always_active ? mlt_properties_get_position( properties, "out" ) : mlt_properties_get_int( props, "out" );
398 int mirror = mlt_properties_get_position( properties, "mirror" );
399 int length = out - in + 1;
401 // Obtain the normalised width and height from the a_frame
402 int normalised_width = mlt_properties_get_int( a_props, "normalised_width" );
403 int normalised_height = mlt_properties_get_int( a_props, "normalised_height" );
405 double consumer_ar = mlt_properties_get_double( a_props, "consumer_aspect_ratio" );
407 // Structures for geometry
408 struct mlt_geometry_item_s result;
410 if ( mirror && position > length / 2 )
411 position = abs( position - length );
413 // Fetch the a frame image
414 *format = mlt_image_rgb24a;
415 mlt_frame_get_image( a_frame, image, format, width, height, 1 );
417 // Calculate the region now
418 mlt_service_lock( MLT_TRANSITION_SERVICE( this ) );
419 composite_calculate( this, &result, normalised_width, normalised_height, ( float )position );
420 mlt_service_unlock( MLT_TRANSITION_SERVICE( this ) );
422 // Fetch the b frame image
423 result.w = ( result.w * *width / normalised_width );
424 result.h = ( result.h * *height / normalised_height );
425 result.x = ( result.x * *width / normalised_width );
426 result.y = ( result.y * *height / normalised_height );
428 // Request full resolution of b frame image.
429 b_width = mlt_properties_get_int( b_props, "real_width" );
430 b_height = mlt_properties_get_int( b_props, "real_height" );
431 mlt_properties_set_int( b_props, "rescale_width", b_width );
432 mlt_properties_set_int( b_props, "rescale_height", b_height );
434 // Suppress padding and aspect normalization.
435 char *interps = mlt_properties_get( b_props, "rescale.interp" );
437 interps = strdup( interps );
438 mlt_properties_set( b_props, "rescale.interp", "none" );
439 if ( mlt_properties_get_double( b_props, "aspect_ratio" ) == 0.0 )
440 mlt_properties_set_double( b_props, "aspect_ratio", consumer_ar );
442 // This is not a field-aware transform.
443 mlt_properties_set_int( b_props, "consumer_deinterlace", 1 );
445 mlt_frame_get_image( b_frame, &b_image, &b_format, &b_width, &b_height, 0 );
447 // Check that both images are of the correct format and process
448 if ( *format == mlt_image_rgb24a && b_format == mlt_image_rgb24a )
456 // Get values from the transition
457 float scale_x = mlt_properties_get_double( properties, "scale_x" );
458 float scale_y = mlt_properties_get_double( properties, "scale_y" );
459 int scale = mlt_properties_get_int( properties, "scale" );
460 float geom_scale_x = (float) b_width / result.w;
461 float geom_scale_y = (float) b_height / result.h;
462 float cx = result.x + result.w / 2.0;
463 float cy = result.y + result.h / 2.0;
464 float lower_x = - cx;
465 float lower_y = - cy;
466 float x_offset = (float) b_width / 2.0;
467 float y_offset = (float) b_height / 2.0;
469 interpp interp = interpBL_b32;
470 int i, j; // loop counters
472 affine_init( affine.matrix );
474 // Compute the affine transform
475 get_affine( &affine, this, ( float )position );
476 dz = MapZ( affine.matrix, 0, 0 );
477 if ( ( int )abs( dz * 1000 ) < 25 )
484 // Factor scaling into the transformation based on output resolution.
485 if ( mlt_properties_get_int( properties, "distort" ) )
487 scale_x = geom_scale_x * ( scale_x == 0 ? 1 : scale_x );
488 scale_y = geom_scale_y * ( scale_y == 0 ? 1 : scale_y );
492 // Determine scale with respect to aspect ratio.
493 double consumer_dar = consumer_ar * normalised_width / normalised_height;
494 double b_ar = mlt_properties_get_double( b_props, "aspect_ratio" );
495 double b_dar = b_ar * b_width / b_height;
497 if ( b_dar > consumer_dar )
499 scale_x = geom_scale_x * ( scale_x == 0 ? 1 : scale_x );
500 scale_y = geom_scale_x * ( scale_y == 0 ? 1 : scale_y );
504 scale_x = geom_scale_y * ( scale_x == 0 ? 1 : scale_x );
505 scale_y = geom_scale_y * ( scale_y == 0 ? 1 : scale_y );
507 scale_x *= consumer_ar / b_ar;
511 affine_max_output( affine.matrix, &sw, &sh, dz, *width, *height );
512 affine_scale( affine.matrix, sw * MIN( geom_scale_x, geom_scale_y ), sh * MIN( geom_scale_x, geom_scale_y ) );
514 else if ( scale_x != 0 && scale_y != 0 )
516 affine_scale( affine.matrix, scale_x, scale_y );
519 // Set the interpolation function
520 if ( interps == NULL || strcmp( interps, "nearest" ) == 0 || strcmp( interps, "neighbor" ) == 0 )
521 interp = interpNN_b32;
522 else if ( strcmp( interps, "tiles" ) == 0 || strcmp( interps, "fast_bilinear" ) == 0 )
523 interp = interpNN_b32;
524 else if ( strcmp( interps, "bilinear" ) == 0 )
525 interp = interpBL_b32;
526 else if ( strcmp( interps, "bicubic" ) == 0 )
527 interp = interpBC_b32;
529 else if ( strcmp( interps, "hyper" ) == 0 || strcmp( interps, "sinc" ) == 0 || strcmp( interps, "lanczos" ) == 0 )
530 interp = interpBC_b32;
531 else if ( strcmp( interps, "spline" ) == 0 ) // TODO: spline 4x4 or 6x6
532 interp = interpBC_b32;
534 // Do the transform with interpolation
535 for ( i = 0, y = lower_y; i < *height; i++, y++ )
537 for ( j = 0, x = lower_x; j < *width; j++, x++ )
539 dx = MapX( affine.matrix, x, y ) / dz + x_offset;
540 dy = MapY( affine.matrix, x, y ) / dz + y_offset;
541 if ( dx >= 0 && dx < (b_width - 1) && dy >=0 && dy < (b_height - 1) )
542 interp( b_image, b_width, b_height, dx, dy, result.mix/100.0, p );
553 /** Affine transition processing.
556 static mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame )
558 // Get a unique name to store the frame position
559 char *name = mlt_properties_get( MLT_TRANSITION_PROPERTIES( transition ), "_unique_id" );
561 // Assign the current position to the name
562 mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame );
563 mlt_properties_set_position( a_props, name, mlt_frame_get_position( a_frame ) - mlt_transition_get_in( transition ) );
565 // Push the transition on to the frame
566 mlt_frame_push_service( a_frame, transition );
568 // Push the b_frame on to the stack
569 mlt_frame_push_frame( a_frame, b_frame );
571 // Push the transition method
572 mlt_frame_push_get_image( a_frame, transition_get_image );
577 /** Constructor for the filter.
580 mlt_transition transition_affine_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
582 mlt_transition transition = mlt_transition_new( );
583 if ( transition != NULL )
585 mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "distort", 0 );
586 mlt_properties_set( MLT_TRANSITION_PROPERTIES( transition ), "geometry", "0,0:100%x100%" );
587 // Inform apps and framework that this is a video only transition
588 mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "_transition_type", 1 );
589 transition->process = transition_process;