/*
- * mlt_geometry.h -- provides the geometry API
+ * mlt_geometry.c -- provides the geometry API
* Copyright (C) 2004-2005 Ushodaya Enterprises Limited
* Author: Charles Yates <charles.yates@pandora.be>
*
return this;
}
+/** A linear step
+*/
+
+static inline double linearstep( double start, double end, double position, int length )
+{
+ double o = ( end - start ) / length;
+ return start + position * o;
+}
+
+static void mlt_geometry_virtual_refresh( mlt_geometry this )
+{
+ geometry self = this->local;
+
+ // Parse of all items to ensure unspecified keys are calculated correctly
+ if ( self->item != NULL )
+ {
+ int i = 0;
+ for ( i = 0; i < 5; i ++ )
+ {
+ geometry_item current = self->item;
+ while( current != NULL )
+ {
+ int fixed = current->data.f[ i ];
+ if ( !fixed )
+ {
+ geometry_item prev = current->prev;
+ geometry_item next = current->next;
+
+ double prev_value = 0;
+ double next_value = 0;
+ double value = 0;
+
+ while( prev != NULL && !prev->data.f[ i ] ) prev = prev->prev;
+ while( next != NULL && !next->data.f[ i ] ) next = next->next;
+
+ switch( i )
+ {
+ case 0:
+ if ( prev ) prev_value = prev->data.x;
+ if ( next ) next_value = next->data.x;
+ break;
+ case 1:
+ if ( prev ) prev_value = prev->data.y;
+ if ( next ) next_value = next->data.y;
+ break;
+ case 2:
+ if ( prev ) prev_value = prev->data.w;
+ if ( next ) next_value = next->data.w;
+ break;
+ case 3:
+ if ( prev ) prev_value = prev->data.h;
+ if ( next ) next_value = next->data.h;
+ break;
+ case 4:
+ if ( prev ) prev_value = prev->data.mix;
+ if ( next ) next_value = next->data.mix;
+ break;
+ }
+
+ // This should never happen
+ if ( prev == NULL )
+ current->data.f[ i ] = 1;
+ else if ( next == NULL )
+ value = prev_value;
+ else
+ value = linearstep( prev_value, next_value, current->data.frame - prev->data.frame, next->data.frame - prev->data.frame );
+
+ switch( i )
+ {
+ case 0: current->data.x = value; break;
+ case 1: current->data.y = value; break;
+ case 2: current->data.w = value; break;
+ case 3: current->data.h = value; break;
+ case 4: current->data.mix = value; break;
+ }
+ }
+
+ // Move to the next item
+ current = current->next;
+ }
+ }
+ }
+}
+
static int mlt_geometry_drop( mlt_geometry this, geometry_item item )
{
geometry self = this->local;
self->item = item->next;
if ( self->item != NULL )
self->item->prev = NULL;
+ // To ensure correct seeding, ensure all values are fixed
+ if ( self->item != NULL )
+ {
+ self->item->data.f[0] = 1;
+ self->item->data.f[1] = 1;
+ self->item->data.f[2] = 1;
+ self->item->data.f[3] = 1;
+ self->item->data.f[4] = 1;
+ }
+ }
+ else if ( item->next != NULL && item->prev != NULL )
+ {
+ item->prev->next = item->next;
+ item->next->prev = item->prev;
}
else if ( item->next != NULL )
{
else if ( item->prev != NULL )
{
item->prev->next = item->next;
- item->next->prev = item->prev;
}
free( item );
// Get the local/private structure
geometry self = this->local;
- // return the length
+ // set the length
self->length = length;
}
{
char *p = strchr( value, '=' );
int count = 0;
- float temp;
+ double temp;
// Determine if a position has been specified
if ( p != NULL )
{
- item->frame = atoi( value );
+ temp = atof( value );
+ if ( temp > -1 && temp < 1 )
+ item->frame = temp * self->length;
+ else
+ item->frame = temp;
value = p + 1;
}
// frames to be created which don't specify all values
mlt_geometry_fetch( this, item, item->frame );
+ // Special case - when an empty string is specified, all values are fixed
+ // TODO: Check if this is logical - it's convenient, but it's also odd...
+ if ( !*value )
+ {
+ item->f[0] = 1;
+ item->f[1] = 1;
+ item->f[2] = 1;
+ item->f[3] = 1;
+ item->f[4] = 1;
+ }
+
// Iterate through the remainder of value
while( *value )
{
}
// Special case - distort token
- if ( *p == '!' )
+ if ( *p == '!' || *p == '*' )
{
p ++;
item->distort = 1;
// Assign to the item
switch( count )
{
- case 0: item->x = temp; break;
- case 1: item->y = temp; break;
- case 2: item->w = temp; break;
- case 3: item->h = temp; break;
- case 4: item->mix = temp; break;
+ case 0: item->x = temp; item->f[0] = 1; break;
+ case 1: item->y = temp; item->f[1] = 1; break;
+ case 2: item->w = temp; item->f[2] = 1; break;
+ case 3: item->h = temp; item->f[3] = 1; break;
+ case 4: item->mix = temp; item->f[4] = 1; break;
}
}
else
return ret;
}
-/** A linear step
-*/
-
-static inline float linearstep( float start, float end, float position, int length )
-{
- float o = ( end - start ) / length;
- return start + position * o + 0.5;
-}
-
// Fetch a geometry item for an absolute position
int mlt_geometry_fetch( mlt_geometry this, mlt_geometry_item item, float position )
{
{
memcpy( item, &key->data, sizeof( struct mlt_geometry_item_s ) );
item->key = 0;
+ item->f[ 0 ] = 0;
+ item->f[ 1 ] = 0;
+ item->f[ 2 ] = 0;
+ item->f[ 3 ] = 0;
+ item->f[ 4 ] = 0;
}
// Interpolation is needed - position > key and there is a following key
else
else
{
memset( item, 0, sizeof( struct mlt_geometry_item_s ) );
+ item->frame = position;
item->mix = 100;
}
}
else if ( item->frame > place->data.frame )
{
+ if ( place->next )
+ place->next->prev = new;
new->next = place->next;
new->prev = place;
place->next = new;
}
else
{
+ // Set the first item
self->item = new;
+
+ // To ensure correct seeding, ensure all values are fixed
+ self->item->data.f[0] = 1;
+ self->item->data.f[1] = 1;
+ self->item->data.f[2] = 1;
+ self->item->data.f[3] = 1;
+ self->item->data.f[4] = 1;
}
+ // Refresh all geometries
+ mlt_geometry_virtual_refresh( this );
+
// TODO: Error checking
return 0;
}
// Get the first item
geometry_item place = self->item;
- while( place != NULL && position < place->data.frame )
+ while( place != NULL && position != place->data.frame )
place = place->next;
if ( place != NULL && position == place->data.frame )
ret = mlt_geometry_drop( this, place );
+ // Refresh all geometries
+ mlt_geometry_virtual_refresh( this );
+
return ret;
}
// Get the key at the position or the next following
-int mlt_geometry_key( mlt_geometry this, mlt_geometry_item item, int position )
+int mlt_geometry_next_key( mlt_geometry this, mlt_geometry_item item, int position )
{
// Get the local/private geometry structure
geometry self = this->local;
return place == NULL;
}
+// Get the key at the position or the previous key
+int mlt_geometry_prev_key( mlt_geometry this, mlt_geometry_item item, int position )
+{
+ // Get the local/private geometry structure
+ geometry self = this->local;
+
+ // Get the first item
+ geometry_item place = self->item;
+
+ while( place != NULL && place->next != NULL && position >= place->next->data.frame )
+ place = place->next;
+
+ if ( place != NULL )
+ memcpy( item, &place->data, sizeof( struct mlt_geometry_item_s ) );
+
+ return place == NULL;
+}
+
char *mlt_geometry_serialise_cut( mlt_geometry this, int in, int out )
{
+ geometry self = this->local;
struct mlt_geometry_item_s item;
char *ret = malloc( 1000 );
int used = 0;
{
if ( mlt_geometry_fetch( this, &item, item.frame ) )
break;
+
+ // If the first key is larger than the current position
+ // then do nothing here
+ if ( self->item->data.frame > item.frame )
+ {
+ item.frame ++;
+ continue;
+ }
+
+ // To ensure correct seeding, ensure all values are fixed
+ item.f[0] = 1;
+ item.f[1] = 1;
+ item.f[2] = 1;
+ item.f[3] = 1;
+ item.f[4] = 1;
}
// Typically, we move from key to key
else if ( item.frame < out )
{
- if ( mlt_geometry_key( this, &item, item.frame ) )
+ if ( mlt_geometry_next_key( this, &item, item.frame ) )
break;
// Special case - crop at the out point
if ( item.frame - in != 0 )
sprintf( temp, "%d=", item.frame - in );
- sprintf( temp + strlen( temp ), "%.0f,%.0f:%.0fx%.0f%s", item.x, item.y, item.w, item.h, item.distort ? "!" : "" );
-
- if ( item.mix )
+ if ( item.f[0] )
+ sprintf( temp + strlen( temp ), "%.0f", item.x );
+ strcat( temp, "," );
+ if ( item.f[1] )
+ sprintf( temp + strlen( temp ), "%.0f", item.y );
+ strcat( temp, ":" );
+ if ( item.f[2] )
+ sprintf( temp + strlen( temp ), "%.0f", item.w );
+ strcat( temp, "x" );
+ if ( item.f[3] )
+ sprintf( temp + strlen( temp ), "%.0f", item.h );
+ if ( item.f[4] )
sprintf( temp + strlen( temp ), ":%.0f", item.mix );
if ( used + strlen( temp ) > size )