2 * mlt_geometry.h -- provides the geometry API
3 * Copyright (C) 2004-2005 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 "mlt_geometry.h"
22 #include "mlt_tokeniser.h"
23 #include "mlt_factory.h"
30 typedef struct geometry_item_s
32 struct mlt_geometry_item_s data;
33 struct geometry_item_s *next, *prev;
45 geometry_s, *geometry;
47 // Create a new geometry structure
48 mlt_geometry mlt_geometry_init( )
50 mlt_geometry this = calloc( 1, sizeof( struct mlt_geometry_s ) );
53 this->local = calloc( 1, sizeof( geometry_s ) );
54 if ( this->local != NULL )
56 geometry self = this->local;
57 char *normalisation = mlt_environment( "MLT_NORMALISATION" );
59 if ( normalisation == NULL || strcmp( normalisation, "NTSC" ) )
73 static int mlt_geometry_drop( mlt_geometry this, geometry_item item )
75 geometry self = this->local;
77 if ( item == self->item )
79 self->item = item->next;
80 if ( self->item != NULL )
81 self->item->prev = NULL;
83 else if ( item->next != NULL )
85 item->next->prev = item->prev;
87 else if ( item->prev != NULL )
89 item->prev->next = item->next;
90 item->next->prev = item->prev;
98 static void mlt_geometry_clean( mlt_geometry this )
100 geometry self = this->local;
104 mlt_geometry_drop( this, self->item );
107 // Parse the geometry specification for a given length and normalised width/height (-1 for default)
108 // data is constructed as: [frame=]X,Y:WxH[:mix][;[frame=]X,Y:WxH[:mix]]*
109 // and X, Y, W and H can have trailing % chars to indicate percentage of normalised size
110 int mlt_geometry_parse( mlt_geometry this, char *data, int length, int nw, int nh )
114 // Create a tokeniser
115 mlt_tokeniser tokens = mlt_tokeniser_init( );
117 // Get the local/private structure
118 geometry self = this->local;
120 // Clean the existing geometry
121 mlt_geometry_clean( this );
123 // Update the info on the data
125 self->length = length;
131 self->data = strdup( data );
135 mlt_tokeniser_parse_new( tokens, data, ";" );
137 // Iterate through each token
138 for ( i = 0; i < mlt_tokeniser_count( tokens ); i ++ )
140 struct mlt_geometry_item_s item;
141 char *value = mlt_tokeniser_get_string( tokens, i );
144 memset( &item, 0, sizeof( struct mlt_geometry_item_s ) );
146 // Now parse the item
147 mlt_geometry_parse_item( this, &item, value );
149 // Now insert into place
150 mlt_geometry_insert( this, &item );
153 // Remove the tokeniser
154 mlt_tokeniser_close( tokens );
160 // Conditionally refresh in case of a change
161 int mlt_geometry_refresh( mlt_geometry this, char *data, int length, int nw, int nh )
163 geometry self = this->local;
164 int changed = ( length != -1 && length != self->length );
165 changed = changed || ( nw != -1 && nw != self->nw );
166 changed = changed || ( nh != -1 && nh != self->nh );
167 changed = changed || ( data != NULL && ( self->data == NULL || strcmp( data, self->data ) ) );
169 return mlt_geometry_parse( this, data, length, nw, nh );
173 int mlt_geometry_get_length( mlt_geometry this )
175 // Get the local/private structure
176 geometry self = this->local;
182 void mlt_geometry_set_length( mlt_geometry this, int length )
184 // Get the local/private structure
185 geometry self = this->local;
188 self->length = length;
191 int mlt_geometry_parse_item( mlt_geometry this, mlt_geometry_item item, char *value )
195 // Get the local/private structure
196 geometry self = this->local;
198 if ( value != NULL && strcmp( value, "" ) )
200 char *p = strchr( value, '=' );
204 // Determine if a position has been specified
207 item->frame = atoi( value );
211 // Special case - frame < 0
212 if ( item->frame < 0 )
213 item->frame += self->length;
215 // Obtain the current value at this position - this allows new
216 // frames to be created which don't specify all values
217 mlt_geometry_fetch( this, item, item->frame );
219 // Iterate through the remainder of value
223 temp = strtod( value, &p );
225 // Check if a value was specified
231 if ( count == 0 || count == 2 )
232 temp *= self->nw / 100.0;
233 else if ( count == 1 || count == 3 )
234 temp *= self->nh / 100.0;
238 // Special case - distort token
245 // Actually, we don't care about the delimiter at all..
248 // Assign to the item
251 case 0: item->x = temp; break;
252 case 1: item->y = temp; break;
253 case 2: item->w = temp; break;
254 case 3: item->h = temp; break;
255 case 4: item->mix = temp; break;
263 // Update the value pointer
279 static inline float linearstep( float start, float end, float position, int length )
281 float o = ( end - start ) / length;
282 return start + position * o;
285 // Fetch a geometry item for an absolute position
286 int mlt_geometry_fetch( mlt_geometry this, mlt_geometry_item item, float position )
288 // Get the local geometry
289 geometry self = this->local;
291 // Need to find the nearest key to the position specifed
292 geometry_item key = self->item;
294 // Iterate through the keys until we reach last or have
295 while( key != NULL && key->next != NULL && position >= key->next->data.frame )
300 // Position is situated before the first key - all zeroes
301 if ( position < key->data.frame )
303 memset( item, 0, sizeof( struct mlt_geometry_item_s ) );
306 // Position is a key itself - no iterpolation need
307 else if ( position == key->data.frame )
309 memcpy( item, &key->data, sizeof( struct mlt_geometry_item_s ) );
311 // Position is after the last key - no interpolation, but not a key frame
312 else if ( key->next == NULL )
314 memcpy( item, &key->data, sizeof( struct mlt_geometry_item_s ) );
317 // Interpolation is needed - position > key and there is a following key
321 item->frame = position;
322 position -= key->data.frame;
323 item->x = linearstep( key->data.x, key->next->data.x, position, key->next->data.frame - key->data.frame );
324 item->y = linearstep( key->data.y, key->next->data.y, position, key->next->data.frame - key->data.frame );
325 item->w = linearstep( key->data.w, key->next->data.w, position, key->next->data.frame - key->data.frame );
326 item->h = linearstep( key->data.h, key->next->data.h, position, key->next->data.frame - key->data.frame );
327 item->mix = linearstep( key->data.mix, key->next->data.mix, position, key->next->data.frame - key->data.frame );
328 item->distort = key->data.distort;
329 position += key->data.frame;
332 item->frame = position;
336 memset( item, 0, sizeof( struct mlt_geometry_item_s ) );
343 // Specify a geometry item at an absolute position
344 int mlt_geometry_insert( mlt_geometry this, mlt_geometry_item item )
346 // Get the local/private geometry structure
347 geometry self = this->local;
349 // Create a new local item (this may be removed if a key already exists at this position)
350 geometry_item new = calloc( 1, sizeof( struct geometry_item_s ) );
351 memcpy( &new->data, item, sizeof( struct mlt_geometry_item_s ) );
354 // Determine if we need to insert or append to the list, or if it's a new list
355 if ( self->item != NULL )
357 // Get the first item
358 geometry_item place = self->item;
360 // Locate an existing nearby item
361 while ( place->next != NULL && item->frame > place->data.frame )
364 if ( item->frame < place->data.frame )
366 if ( place == self->item )
369 place->prev->next = new;
371 new->prev = place->prev;
374 else if ( item->frame > place->data.frame )
376 new->next = place->next;
382 memcpy( &place->data, &new->data, sizeof( struct mlt_geometry_item_s ) );
391 // TODO: Error checking
395 // Remove the key at the specified position
396 int mlt_geometry_remove( mlt_geometry this, int position )
400 // Get the local/private geometry structure
401 geometry self = this->local;
403 // Get the first item
404 geometry_item place = self->item;
406 while( place != NULL && position < place->data.frame )
409 if ( place != NULL && position == place->data.frame )
410 ret = mlt_geometry_drop( this, place );
415 // Get the key at the position or the next following
416 int mlt_geometry_key( mlt_geometry this, mlt_geometry_item item, int position )
418 // Get the local/private geometry structure
419 geometry self = this->local;
421 // Get the first item
422 geometry_item place = self->item;
424 while( place != NULL && position > place->data.frame )
428 memcpy( item, &place->data, sizeof( struct mlt_geometry_item_s ) );
430 return place == NULL;
433 char *mlt_geometry_serialise_cut( mlt_geometry this, int in, int out )
435 struct mlt_geometry_item_s item;
436 char *ret = malloc( 1000 );
443 out = mlt_geometry_get_length( this );
457 // If it's the first frame, then it's not necessarily a key
458 if ( item.frame == in )
460 if ( mlt_geometry_fetch( this, &item, item.frame ) )
463 // Typically, we move from key to key
464 else if ( item.frame < out )
466 if ( mlt_geometry_key( this, &item, item.frame ) )
469 // Special case - crop at the out point
470 if ( item.frame > out )
471 mlt_geometry_fetch( this, &item, out );
473 // We've handled the last key
479 if ( item.frame - in != 0 )
480 sprintf( temp, "%d=", item.frame - in );
482 sprintf( temp + strlen( temp ), "%.0f,%.0f:%.0fx%.0f%s", item.x, item.y, item.w, item.h, item.distort ? "!" : "" );
485 sprintf( temp + strlen( temp ), ":%.0f", item.mix );
487 if ( used + strlen( temp ) > size )
490 ret = realloc( ret, size );
493 if ( ret != NULL && used != 0 )
500 used += strlen( temp );
511 // Serialise the current geometry
512 char *mlt_geometry_serialise( mlt_geometry this )
514 geometry self = this->local;
515 char *ret = mlt_geometry_serialise_cut( this, 0, self->length );
524 // Close the geometry
525 void mlt_geometry_close( mlt_geometry this )
529 mlt_geometry_clean( this );