]> git.sesse.net Git - mlt/blob - src/modules/plus/transition_affine.c
Cleanup license declarations and remove dv1394d references.
[mlt] / src / modules / plus / transition_affine.c
1 /*
2  * transition_affine.c -- affine transformations
3  * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4  * Author: Charles Yates <charles.yates@pandora.be>
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "transition_affine.h"
22 #include <framework/mlt.h>
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <ctype.h>
27 #include <string.h>
28 #include <math.h>
29
30 /** Calculate real geometry.
31 */
32
33 static void geometry_calculate( mlt_transition this, char *store, struct mlt_geometry_item_s *output, float position )
34 {
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 );
40
41         // Allow wrapping
42         if ( !repeat_off && position >= length && length != 0 )
43         {
44                 int section = position / length;
45                 position -= section * length;
46                 if ( !mirror_off && section % 2 == 1 )
47                         position = length - position;
48         }
49
50         // Fetch the key for the position
51         mlt_geometry_fetch( geometry, output, position );
52 }
53
54
55 static mlt_geometry transition_parse_keys( mlt_transition this, char *name, char *store, int normalised_width, int normalised_height )
56 {
57         // Get the properties of the transition
58         mlt_properties properties = MLT_TRANSITION_PROPERTIES( this );
59
60         // Try to fetch it first
61         mlt_geometry geometry = mlt_properties_get_data( properties, store, NULL );
62
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 );
66
67         // Determine length and obtain cycle
68         int length = out - in + 1;
69         double cycle = mlt_properties_get_double( properties, "cycle" );
70
71         // Allow a geometry repeat cycle
72         if ( cycle >= 1 )
73                 length = cycle;
74         else if ( cycle > 0 )
75                 length *= cycle;
76
77         if ( geometry == NULL )
78         {
79                 // Get the new style geometry string
80                 char *property = mlt_properties_get( properties, name );
81
82                 // Create an empty geometries object
83                 geometry = mlt_geometry_init( );
84
85                 // Parse the geometry if we have one
86                 mlt_geometry_parse( geometry, property, length, normalised_width, normalised_height );
87
88                 // Store it
89                 mlt_properties_set_data( properties, store, geometry, 0, ( mlt_destructor )mlt_geometry_close, NULL );
90         }
91         else
92         {
93                 // Check for updates and refresh if necessary
94                 mlt_geometry_refresh( geometry, mlt_properties_get( properties, name ), length, normalised_width, normalised_height );
95         }
96
97         return geometry;
98 }
99
100 static mlt_geometry composite_calculate( mlt_transition this, struct mlt_geometry_item_s *result, int nw, int nh, float position )
101 {
102         // Structures for geometry
103         mlt_geometry start = transition_parse_keys( this, "geometry", "geometries", nw, nh );
104
105         // Do the calculation
106         geometry_calculate( this, "geometries", result, position );
107
108         return start;
109 }
110
111 static inline float composite_calculate_key( mlt_transition this, char *name, char *store, int norm, float position )
112 {
113         // Struct for the result
114         struct mlt_geometry_item_s result;
115
116         // Structures for geometry
117         transition_parse_keys( this, name, store, norm, 0 );
118
119         // Do the calculation
120         geometry_calculate( this, store, &result, position );
121
122         return result.x;
123 }
124
125 typedef struct 
126 {
127         float matrix[3][3];
128 }
129 affine_t;
130
131 static void affine_init( float this[3][3] )
132 {
133         this[0][0] = 1;
134         this[0][1] = 0;
135         this[0][2] = 0;
136         this[1][0] = 0;
137         this[1][1] = 1;
138         this[1][2] = 0;
139         this[2][0] = 0;
140         this[2][1] = 0;
141         this[2][2] = 1;
142 }
143
144 // Multiply two this affine transform with that
145 static void affine_multiply( float this[3][3], float that[3][3] )
146 {
147         float output[3][3];
148         int i;
149         int j;
150
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];
154
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];
164 }
165
166 // Rotate by a given angle
167 static void affine_rotate_x( float this[3][3], float angle )
168 {
169         float affine[3][3];
170         affine[0][0] = cos( angle * M_PI / 180 );
171         affine[0][1] = 0 - sin( angle * M_PI / 180 );
172         affine[0][2] = 0;
173         affine[1][0] = sin( angle * M_PI / 180 );
174         affine[1][1] = cos( angle * M_PI / 180 );
175         affine[1][2] = 0;
176         affine[2][0] = 0;
177         affine[2][1] = 0;
178         affine[2][2] = 1;
179         affine_multiply( this, affine );
180 }
181
182 static void affine_rotate_y( float this[3][3], float angle )
183 {
184         float affine[3][3];
185         affine[0][0] = cos( angle * M_PI / 180 );
186         affine[0][1] = 0;
187         affine[0][2] = 0 - sin( angle * M_PI / 180 );
188         affine[1][0] = 0;
189         affine[1][1] = 1;
190         affine[1][2] = 0;
191         affine[2][0] = sin( angle * M_PI / 180 );
192         affine[2][1] = 0;
193         affine[2][2] = cos( angle * M_PI / 180 );
194         affine_multiply( this, affine );
195 }
196
197 static void affine_rotate_z( float this[3][3], float angle )
198 {
199         float affine[3][3];
200         affine[0][0] = 1;
201         affine[0][1] = 0;
202         affine[0][2] = 0;
203         affine[1][0] = 0;
204         affine[1][1] = cos( angle * M_PI / 180 );
205         affine[1][2] = sin( angle * M_PI / 180 );
206         affine[2][0] = 0;
207         affine[2][1] = - sin( angle * M_PI / 180 );
208         affine[2][2] = cos( angle * M_PI / 180 );
209         affine_multiply( this, affine );
210 }
211
212 static void affine_scale( float this[3][3], float sx, float sy )
213 {
214         float affine[3][3];
215         affine[0][0] = sx;
216         affine[0][1] = 0;
217         affine[0][2] = 0;
218         affine[1][0] = 0;
219         affine[1][1] = sy;
220         affine[1][2] = 0;
221         affine[2][0] = 0;
222         affine[2][1] = 0;
223         affine[2][2] = 1;
224         affine_multiply( this, affine );
225 }
226
227 // Shear by a given value
228 static void affine_shear( float this[3][3], float shear_x, float shear_y, float shear_z )
229 {
230         float affine[3][3];
231         affine[0][0] = 1;
232         affine[0][1] = tan( shear_x * M_PI / 180 );
233         affine[0][2] = 0;
234         affine[1][0] = tan( shear_y * M_PI / 180 );
235         affine[1][1] = 1;
236         affine[1][2] = tan( shear_z * M_PI / 180 );
237         affine[2][0] = 0;
238         affine[2][1] = 0;
239         affine[2][2] = 1;
240         affine_multiply( this, affine );
241 }
242
243 static void affine_offset( float this[3][3], int x, int y )
244 {
245         this[0][2] += x;
246         this[1][2] += y;
247 }
248
249 // Obtain the mapped x coordinate of the input
250 static inline double MapX( float this[3][3], int x, int y )
251 {
252         return this[0][0] * x + this[0][1] * y + this[0][2];
253 }
254
255 // Obtain the mapped y coordinate of the input
256 static inline double MapY( float this[3][3], int x, int y )
257 {
258         return this[1][0] * x + this[1][1] * y + this[1][2];
259 }
260
261 static inline double MapZ( float this[3][3], int x, int y )
262 {
263         return this[2][0] * x + this[2][1] * y + this[2][2];
264 }
265
266 #define MAX( x, y ) x > y ? x : y
267 #define MIN( x, y ) x < y ? x : y
268
269 static void affine_max_output( float this[3][3], float *w, float *h, float dz )
270 {
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;
279
280         int max_x;
281         int max_y;
282         int min_x;
283         int min_y;
284
285         max_x = MAX( tlx, trx );
286         max_x = MAX( max_x, blx );
287         max_x = MAX( max_x, brx );
288
289         min_x = MIN( tlx, trx );
290         min_x = MIN( min_x, blx );
291         min_x = MIN( min_x, brx );
292
293         max_y = MAX( tly, try );
294         max_y = MAX( max_y, bly );
295         max_y = MAX( max_y, bry );
296
297         min_y = MIN( tly, try );
298         min_y = MIN( min_y, bly );
299         min_y = MIN( min_y, bry );
300
301         *w = ( float )( max_x - min_x + 1 ) / 1440.0;
302         *h = ( float )( max_y - min_y + 1 ) / 1152.0;
303 }
304
305 #define IN_RANGE( v, r )        ( v >= - r / 2 && v < r / 2 )
306
307 static inline void get_affine( affine_t *affine, mlt_transition this, float position )
308 {
309         mlt_properties properties = MLT_TRANSITION_PROPERTIES( this );
310         int keyed = mlt_properties_get_int( properties, "keyed" );
311         affine_init( affine->matrix );
312
313         if ( keyed == 0 )
314         {
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" );
329
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 );
338         }
339         else
340         {
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 );
347
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 );
352         }
353 }
354
355 /** Get the image.
356 */
357
358 static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
359 {
360         // Get the b frame from the stack
361         mlt_frame b_frame = mlt_frame_pop_frame( a_frame );
362
363         // Get the transition object
364         mlt_transition this = mlt_frame_pop_service( a_frame );
365
366         // Get the properties of the transition
367         mlt_properties properties = MLT_TRANSITION_PROPERTIES( this );
368
369         // Get the properties of the a frame
370         mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame );
371
372         // Get the properties of the b frame
373         mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame );
374
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;
378         int b_width;
379         int b_height;
380
381         // Get the unique name to retrieve the frame position
382         char *name = mlt_properties_get( properties, "_unique_id" );
383
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;
390
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" );
394
395         double consumer_ar = mlt_properties_get_double( a_props, "consumer_aspect_ratio" ) ;
396
397         // Structures for geometry
398         struct mlt_geometry_item_s result;
399
400         if ( mirror && position > length / 2 )
401                 position = abs( position - length );
402
403         // Fetch the a frame image
404         mlt_frame_get_image( a_frame, image, format, width, height, 1 );
405
406         // Calculate the region now
407         composite_calculate( this, &result, normalised_width, normalised_height, ( float )position );
408
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;
416         b_width = result.w;
417         b_height = result.h;
418
419         if ( mlt_properties_get_double( b_props, "aspect_ratio" ) == 0.0 )
420                 mlt_properties_set_double( b_props, "aspect_ratio", consumer_ar );
421
422         if ( !strcmp( mlt_properties_get( a_props, "rescale.interp" ), "none" ) )
423         {
424                 mlt_properties_set( b_props, "rescale.interp", "nearest" );
425                 mlt_properties_set_double( b_props, "consumer_aspect_ratio", consumer_ar );
426         }
427         else
428         {
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 );
431         }
432
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 );
435         result.w = b_width;
436         result.h = b_height;
437
438         // Check that both images are of the correct format and process
439         if ( *format == mlt_image_yuv422 && b_format == mlt_image_yuv422 )
440         {
441                 register int x, y;
442                 register int dx, dy;
443                 double dz;
444                 float sw, sh;
445
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" );
450
451                 uint8_t *p = *image;
452                 uint8_t *q = *image;
453
454                 int cx = result.x + ( b_width >> 1 );
455                 int cy = result.y + ( b_height >> 1 );
456         
457                 int lower_x = 0 - cx;
458                 int upper_x = *width - cx;
459                 int lower_y = 0 - cy;
460                 int upper_y = *height - cy;
461
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;
466
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;
470                 float mix;
471
472                 affine_t affine;
473
474                 get_affine( &affine, this, ( float )position );
475
476                 q = *image;
477
478                 dz = MapZ( affine.matrix, 0, 0 );
479
480                 if ( mask == NULL )
481                 {
482                         mask = mlt_pool_alloc( *width * *height );
483                         pmask = mask;
484                         memset( mask, 255, *width * *height );
485                 }
486
487                 if ( ( int )abs( dz * 1000 ) < 25 )
488                         goto getout;
489
490                 if ( scale )
491                 {
492                         affine_max_output( affine.matrix, &sw, &sh, dz );
493                         affine_scale( affine.matrix, sw, sh );
494                 }
495                 else if ( scale_x != 0 && scale_y != 0 )
496                 {
497                         affine_scale( affine.matrix, scale_x, scale_y );
498                 }
499
500                 if ( alpha == NULL )
501                 {
502                         for ( y = lower_y; y < upper_y; y ++ )
503                         {
504                                 p = q;
505
506                                 for ( x = lower_x; x < upper_x; x ++ )
507                                 {
508                                         dx = MapX( affine.matrix, x, y ) / dz + x_offset;
509                                         dy = MapY( affine.matrix, x, y ) / dz + y_offset;
510
511                                         if ( dx >= 0 && dx < b_width && dy >=0 && dy < b_height )
512                                         {
513                                                 *pmask ++;
514                                                 dx -= dx & 1;
515                                                 *p ++ = *( b_image + dy * b_stride + ( dx << 1 ) );
516                                                 *p ++ = *( b_image + dy * b_stride + ( dx << 1 ) + ( ( x & 1 ) << 1 ) + 1 );
517                                         }
518                                         else
519                                         {
520                                                 p += 2;
521                                                 pmask ++;
522                                         }
523                                 }
524
525                                 q += a_stride;
526                         }
527                 }
528                 else
529                 {
530                         for ( y = lower_y; y < upper_y; y ++ )
531                         {
532                                 p = q;
533
534                                 for ( x = lower_x; x < upper_x; x ++ )
535                                 {
536                                         dx = MapX( affine.matrix, x, y ) / dz + x_offset;
537                                         dy = MapY( affine.matrix, x, y ) / dz + y_offset;
538
539                                         if ( dx >= 0 && dx < b_width && dy >=0 && dy < b_height )
540                                         {
541                                                 *pmask ++ = *( alpha + dy * b_width + dx );
542                                                 mix = ( float )*( alpha + dy * b_width + dx ) / 255.0;
543                                                 dx -= dx & 1;
544                                                 *p = *p * ( 1 - mix ) + mix * *( b_image + dy * b_stride + ( dx << 1 ) );
545                                                 p ++;
546                                                 *p = *p * ( 1 - mix ) + mix * *( b_image + dy * b_stride + ( dx << 1 ) + ( ( x & 1 ) << 1 ) + 1 );
547                                                 p ++;
548                                         }
549                                         else
550                                         {
551                                                 p += 2;
552                                                 pmask ++;
553                                         }
554                                 }
555
556                                 q += a_stride;
557                         }
558                 }
559
560 getout:
561                 a_frame->get_alpha_mask = NULL;
562                 mlt_properties_set_data( a_props, "alpha", mask, 0, mlt_pool_release, NULL );
563         }
564
565         return 0;
566 }
567
568 /** Affine transition processing.
569 */
570
571 static mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame )
572 {
573         // Get a unique name to store the frame position
574         char *name = mlt_properties_get( MLT_TRANSITION_PROPERTIES( transition ), "_unique_id" );
575
576         // Assign the current position to the name
577         mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame );
578         mlt_properties_set_position( a_props, name, mlt_frame_get_position( a_frame ) );
579
580         // Push the transition on to the frame
581         mlt_frame_push_service( a_frame, transition );
582
583         // Push the b_frame on to the stack
584         mlt_frame_push_frame( a_frame, b_frame );
585
586         // Push the transition method
587         mlt_frame_push_get_image( a_frame, transition_get_image );
588
589         return a_frame;
590 }
591
592 /** Constructor for the filter.
593 */
594
595 mlt_transition transition_affine_init( char *arg )
596 {
597         mlt_transition transition = mlt_transition_new( );
598         if ( transition != NULL )
599         {
600                 mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "sx", 1 );
601                 mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "sy", 1 );
602                 mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "distort", 0 );
603                 mlt_properties_set( MLT_TRANSITION_PROPERTIES( transition ), "geometry", "0,0:100%x100%" );
604                 // Inform apps and framework that this is a video only transition
605                 mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "_transition_type", 1 );
606                 transition->process = transition_process;
607         }
608         return transition;
609 }