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
+ 0.5;
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 );