]> git.sesse.net Git - mlt/blobdiff - src/framework/mlt_geometry.c
Add mlt_properties_set_color().
[mlt] / src / framework / mlt_geometry.c
index 4e894fcccb3246405e7604cb43e15133e80dc82a..301963ddca24b0fe0ed0eea7796b8d11ae09bd4b 100644 (file)
@@ -3,29 +3,29 @@
  * Copyright (C) 2004-2005 Ushodaya Enterprises Limited
  * Author: Charles Yates <charles.yates@pandora.be>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful,
+ * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include "mlt_geometry.h"
 #include "mlt_tokeniser.h"
 #include "mlt_factory.h"
+#include "mlt_profile.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <math.h>
 
 typedef struct geometry_item_s
 {
@@ -47,27 +47,23 @@ geometry_s, *geometry;
 // Create a new geometry structure
 mlt_geometry mlt_geometry_init( )
 {
-       mlt_geometry this = calloc( 1, sizeof( struct mlt_geometry_s ) );
-       if ( this != NULL )
+       mlt_geometry self = calloc( 1, sizeof( struct mlt_geometry_s ) );
+       if ( self != NULL )
        {
-               this->local = calloc( 1, sizeof( geometry_s ) );
-               if ( this->local != NULL )
+               self->local = calloc( 1, sizeof( geometry_s ) );
+               if ( self->local != NULL )
                {
-                       geometry self = this->local;
-                       char *normalisation = mlt_environment( "MLT_NORMALISATION" );
-                       self->nw = 720;
-                       if ( normalisation == NULL || strcmp( normalisation, "NTSC" ) )
-                               self->nh = 576;
-                       else
-                               self->nh = 480;
+                       geometry g = self->local;
+                       g->nw = 720;
+                       g->nh = 576;
                }
                else
                {
-                       free( this );
-                       this = NULL;
+                       free( self );
+                       self = NULL;
                }
        }
-       return this;
+       return self;
 }
 
 /** A linear step
@@ -79,17 +75,17 @@ static inline double linearstep( double start, double end, double position, int
        return start + position * o;
 }
 
-static void mlt_geometry_virtual_refresh( mlt_geometry this )
+void mlt_geometry_interpolate( mlt_geometry self )
 {
-       geometry self = this->local;
+       geometry g = self->local;
 
        // Parse of all items to ensure unspecified keys are calculated correctly
-       if ( self->item != NULL )
+       if ( g->item != NULL )
        {
                int i = 0;
                for ( i = 0; i < 5; i ++ )
                {
-                       geometry_item current = self->item;
+                       geometry_item current = g->item;
                        while( current != NULL )
                        {
                                int fixed = current->data.f[ i ];
@@ -98,9 +94,9 @@ static void mlt_geometry_virtual_refresh( mlt_geometry this )
                                        geometry_item prev = current->prev;
                                        geometry_item next = current->next;
 
-                                       float prev_value = 0;
-                                       float next_value = 0;
-                                       float value = 0;
+                                       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;
@@ -154,23 +150,23 @@ static void mlt_geometry_virtual_refresh( mlt_geometry this )
        }
 }
 
-static int mlt_geometry_drop( mlt_geometry this, geometry_item item )
+static int mlt_geometry_drop( mlt_geometry self, geometry_item item )
 {
-       geometry self = this->local;
+       geometry g = self->local;
 
-       if ( item == self->item )
+       if ( item == g->item )
        {
-               self->item = item->next;
-               if ( self->item != NULL )
-                       self->item->prev = NULL;
+               g->item = item->next;
+               if ( g->item != NULL )
+                       g->item->prev = NULL;
                // To ensure correct seeding, ensure all values are fixed
-               if ( self->item != NULL )
+               if ( g->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;
+                       g->item->data.f[0] = 1;
+                       g->item->data.f[1] = 1;
+                       g->item->data.f[2] = 1;
+                       g->item->data.f[3] = 1;
+                       g->item->data.f[4] = 1;
                }
        }
        else if ( item->next != NULL && item->prev != NULL )
@@ -192,19 +188,21 @@ static int mlt_geometry_drop( mlt_geometry this, geometry_item item )
        return 0;
 }
 
-static void mlt_geometry_clean( mlt_geometry this )
+static void mlt_geometry_clean( mlt_geometry self )
 {
-       geometry self = this->local;
-       free( self->data );
-       self->data = NULL;
-       while( self->item )
-               mlt_geometry_drop( this, self->item );
+       geometry g = self->local;
+       if ( g->data )
+               free( g->data );
+       g->data = NULL;
+       while( g->item )
+               mlt_geometry_drop( self, g->item );
 }
 
 // Parse the geometry specification for a given length and normalised width/height (-1 for default)
-// data is constructed as: [frame=]X,Y:WxH[:mix][;[frame=]X,Y:WxH[:mix]]*
+// data is constructed as: [frame=]X/Y:WxH[:mix][!][;[frame=]X/Y:WxH[:mix][!]]*
 // and X, Y, W and H can have trailing % chars to indicate percentage of normalised size
-int mlt_geometry_parse( mlt_geometry this, char *data, int length, int nw, int nh )
+// Append a pair's value with ! to enable distort.
+int mlt_geometry_parse( mlt_geometry self, char *data, int length, int nw, int nh )
 {
        int i = 0;
 
@@ -212,20 +210,20 @@ int mlt_geometry_parse( mlt_geometry this, char *data, int length, int nw, int n
        mlt_tokeniser tokens = mlt_tokeniser_init( );
 
        // Get the local/private structure
-       geometry self = this->local;
+       geometry g = self->local;
 
        // Clean the existing geometry
-       mlt_geometry_clean( this );
+       mlt_geometry_clean( self );
 
        // Update the info on the data
        if ( length != -1 )
-               self->length = length;
+               g->length = length;
        if ( nw != -1 )
-               self->nw = nw;
+               g->nw = nw;
        if ( nh != -1 )
-               self->nh = nh;
+               g->nh = nh;
        if ( data != NULL )
-               self->data = strdup( data );
+               g->data = strdup( data );
 
        // Tokenise
        if ( data != NULL )
@@ -237,15 +235,20 @@ int mlt_geometry_parse( mlt_geometry this, char *data, int length, int nw, int n
                struct mlt_geometry_item_s item;
                char *value = mlt_tokeniser_get_string( tokens, i );
 
+               // If no data in keyframe, drop it (trailing semicolon)
+               if ( value == NULL || !strcmp( value, "" ) )
+                       continue;
+
                // Set item to 0
                memset( &item, 0, sizeof( struct mlt_geometry_item_s ) );
 
                // Now parse the item
-               mlt_geometry_parse_item( this, &item, value );
+               mlt_geometry_parse_item( self, &item, value );
 
                // Now insert into place
-               mlt_geometry_insert( this, &item );
+               mlt_geometry_insert( self, &item );
        }
+       mlt_geometry_interpolate( self );
 
        // Remove the tokeniser
        mlt_tokeniser_close( tokens );
@@ -255,42 +258,42 @@ int mlt_geometry_parse( mlt_geometry this, char *data, int length, int nw, int n
 }
 
 // Conditionally refresh in case of a change
-int mlt_geometry_refresh( mlt_geometry this, char *data, int length, int nw, int nh )
+int mlt_geometry_refresh( mlt_geometry self, char *data, int length, int nw, int nh )
 {
-       geometry self = this->local;
-       int changed = ( length != -1 && length != self->length );
-       changed = changed || ( nw != -1 && nw != self->nw );
-       changed = changed || ( nh != -1 && nh != self->nh );
-       changed = changed || ( data != NULL && ( self->data == NULL || strcmp( data, self->data ) ) );
+       geometry g = self->local;
+       int changed = ( length != -1 && length != g->length );
+       changed = changed || ( nw != -1 && nw != g->nw );
+       changed = changed || ( nh != -1 && nh != g->nh );
+       changed = changed || ( data != NULL && ( g->data == NULL || strcmp( data, g->data ) ) );
        if ( changed )
-               return mlt_geometry_parse( this, data, length, nw, nh );
+               return mlt_geometry_parse( self, data, length, nw, nh );
        return -1;
 }
 
-int mlt_geometry_get_length( mlt_geometry this )
+int mlt_geometry_get_length( mlt_geometry self )
 {
        // Get the local/private structure
-       geometry self = this->local;
+       geometry g = self->local;
 
        // return the length
-       return self->length;
+       return g->length;
 }
 
-void mlt_geometry_set_length( mlt_geometry this, int length )
+void mlt_geometry_set_length( mlt_geometry self, int length )
 {
        // Get the local/private structure
-       geometry self = this->local;
+       geometry g = self->local;
 
        // set the length
-       self->length = length;
+       g->length = length;
 }
 
-int mlt_geometry_parse_item( mlt_geometry this, mlt_geometry_item item, char *value )
+int mlt_geometry_parse_item( mlt_geometry self, mlt_geometry_item item, char *value )
 {
        int ret = 0;
 
        // Get the local/private structure
-       geometry self = this->local;
+       geometry g = self->local;
 
        if ( value != NULL && strcmp( value, "" ) )
        {
@@ -303,7 +306,7 @@ int mlt_geometry_parse_item( mlt_geometry this, mlt_geometry_item item, char *va
                {
                        temp = atof( value );
                        if ( temp > -1 && temp < 1 )
-                               item->frame = temp * self->length;
+                               item->frame = temp * g->length;
                        else
                                item->frame = temp;
                        value = p + 1;
@@ -311,11 +314,11 @@ int mlt_geometry_parse_item( mlt_geometry this, mlt_geometry_item item, char *va
 
                // Special case - frame < 0
                if ( item->frame < 0 )
-                       item->frame += self->length;
+                       item->frame += g->length;
 
-               // Obtain the current value at this position - this allows new
+               // Obtain the current value at this position - self allows new
                // frames to be created which don't specify all values
-               mlt_geometry_fetch( this, item, item->frame );
+               mlt_geometry_fetch( self, 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...
@@ -341,9 +344,9 @@ int mlt_geometry_parse_item( mlt_geometry this, mlt_geometry_item item, char *va
                                if ( *p == '%' )
                                {
                                        if ( count == 0 || count == 2 )
-                                               temp *= self->nw / 100.0;
+                                               temp *= g->nw / 100.0;
                                        else if ( count == 1 || count == 3 )
-                                               temp *= self->nh / 100.0;
+                                               temp *= g->nh / 100.0;
                                        p ++;
                                }
 
@@ -386,13 +389,13 @@ int mlt_geometry_parse_item( mlt_geometry this, mlt_geometry_item item, char *va
 }
 
 // Fetch a geometry item for an absolute position
-int mlt_geometry_fetch( mlt_geometry this, mlt_geometry_item item, float position )
+int mlt_geometry_fetch( mlt_geometry self, mlt_geometry_item item, float position )
 {
        // Get the local geometry
-       geometry self = this->local;
+       geometry g = self->local;
 
        // Need to find the nearest key to the position specifed
-       geometry_item key = self->item;
+       geometry_item key = g->item;
 
        // Iterate through the keys until we reach last or have 
        while( key != NULL && key->next != NULL && position >= key->next->data.frame )
@@ -450,21 +453,21 @@ int mlt_geometry_fetch( mlt_geometry this, mlt_geometry_item item, float positio
 }
 
 // Specify a geometry item at an absolute position
-int mlt_geometry_insert( mlt_geometry this, mlt_geometry_item item )
+int mlt_geometry_insert( mlt_geometry self, mlt_geometry_item item )
 {
        // Get the local/private geometry structure
-       geometry self = this->local;
+       geometry g = self->local;
 
-       // Create a new local item (this may be removed if a key already exists at this position)
-       geometry_item new = calloc( 1, sizeof( struct geometry_item_s ) );
-       memcpy( &new->data, item, sizeof( struct mlt_geometry_item_s ) );
-       new->data.key = 1;
+       // Create a new local item (this may be removed if a key already exists at self position)
+       geometry_item gi = calloc( 1, sizeof( struct geometry_item_s ) );
+       memcpy( &gi->data, item, sizeof( struct mlt_geometry_item_s ) );
+       gi->data.key = 1;
 
        // Determine if we need to insert or append to the list, or if it's a new list
-       if ( self->item != NULL )
+       if ( g->item != NULL )
        {
                // Get the first item
-               geometry_item place = self->item;
+               geometry_item place = g->item;
 
                // Locate an existing nearby item
                while ( place->next != NULL && item->frame > place->data.frame )
@@ -472,79 +475,73 @@ int mlt_geometry_insert( mlt_geometry this, mlt_geometry_item item )
 
                if ( item->frame < place->data.frame )
                {
-                       if ( place == self->item )
-                               self->item = new;
+                       if ( place == g->item )
+                               g->item = gi;
                        if ( place->prev )
-                               place->prev->next = new;
-                       new->next = place;
-                       new->prev = place->prev;
-                       place->prev = new;
+                               place->prev->next = gi;
+                       gi->next = place;
+                       gi->prev = place->prev;
+                       place->prev = gi;
                }
                else if ( item->frame > place->data.frame )
                {
                        if ( place->next )
-                               place->next->prev = new;
-                       new->next = place->next;
-                       new->prev = place;
-                       place->next = new;
+                               place->next->prev = gi;
+                       gi->next = place->next;
+                       gi->prev = place;
+                       place->next = gi;
                }
                else
                {
-                       memcpy( &place->data, &new->data, sizeof( struct mlt_geometry_item_s ) );
-                       free( new );
+                       memcpy( &place->data, &gi->data, sizeof( struct mlt_geometry_item_s ) );
+                       free( gi );
                }
        }
        else
        {
                // Set the first item
-               self->item = new;
+               g->item = gi;
 
                // 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;
+               g->item->data.f[0] = 1;
+               g->item->data.f[1] = 1;
+               g->item->data.f[2] = 1;
+               g->item->data.f[3] = 1;
+               g->item->data.f[4] = 1;
        }
 
-       // Refresh all geometries
-       mlt_geometry_virtual_refresh( this );
-
        // TODO: Error checking
        return 0;
 }
 
 // Remove the key at the specified position
-int mlt_geometry_remove( mlt_geometry this, int position )
+int mlt_geometry_remove( mlt_geometry self, int position )
 {
        int ret = 1;
 
        // Get the local/private geometry structure
-       geometry self = this->local;
+       geometry g = self->local;
 
        // Get the first item
-       geometry_item place = self->item;
+       geometry_item place = g->item;
 
        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 );
+               ret = mlt_geometry_drop( self, place );
 
        return ret;
 }
 
 // Get the key at the position or the next following
-int mlt_geometry_next_key( mlt_geometry this, mlt_geometry_item item, int position )
+int mlt_geometry_next_key( mlt_geometry self, mlt_geometry_item item, int position )
 {
        // Get the local/private geometry structure
-       geometry self = this->local;
+       geometry g = self->local;
 
        // Get the first item
-       geometry_item place = self->item;
+       geometry_item place = g->item;
 
        while( place != NULL && position > place->data.frame )
                place = place->next;
@@ -556,13 +553,13 @@ int mlt_geometry_next_key( mlt_geometry this, mlt_geometry_item item, int positi
 }
 
 // Get the key at the position or the previous key
-int mlt_geometry_prev_key( mlt_geometry this, mlt_geometry_item item, int position )
+int mlt_geometry_prev_key( mlt_geometry self, mlt_geometry_item item, int position )
 {
        // Get the local/private geometry structure
-       geometry self = this->local;
+       geometry g = self->local;
 
        // Get the first item
-       geometry_item place = self->item;
+       geometry_item place = g->item;
 
        while( place != NULL && place->next != NULL && position >= place->next->data.frame )
                place = place->next;
@@ -573,9 +570,9 @@ int mlt_geometry_prev_key( mlt_geometry this, mlt_geometry_item item, int positi
        return place == NULL;
 }
 
-char *mlt_geometry_serialise_cut( mlt_geometry this, int in, int out )
+char *mlt_geometry_serialise_cut( mlt_geometry self, int in, int out )
 {
-       geometry self = this->local;
+       geometry g = self->local;
        struct mlt_geometry_item_s item;
        char *ret = malloc( 1000 );
        int used = 0;
@@ -584,7 +581,7 @@ char *mlt_geometry_serialise_cut( mlt_geometry this, int in, int out )
        if ( in == -1 )
                in = 0;
        if ( out == -1 )
-               out = mlt_geometry_get_length( this );
+               out = mlt_geometry_get_length( self );
 
        if ( ret != NULL )
        {
@@ -601,12 +598,12 @@ char *mlt_geometry_serialise_cut( mlt_geometry this, int in, int out )
                        // If it's the first frame, then it's not necessarily a key
                        if ( item.frame == in )
                        {
-                               if ( mlt_geometry_fetch( this, &item, item.frame ) )
+                               if ( mlt_geometry_fetch( self, &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 )
+                               if ( g->item->data.frame > item.frame )
                                {
                                        item.frame ++;
                                        continue;
@@ -622,12 +619,12 @@ char *mlt_geometry_serialise_cut( mlt_geometry this, int in, int out )
                        // Typically, we move from key to key
                        else if ( item.frame < out )
                        {
-                               if ( mlt_geometry_next_key( this, &item, item.frame ) )
+                               if ( mlt_geometry_next_key( self, &item, item.frame ) )
                                        break;
 
                                // Special case - crop at the out point
                                if ( item.frame > out )
-                                       mlt_geometry_fetch( this, &item, out );
+                                       mlt_geometry_fetch( self, &item, out );
                        }
                        // We've handled the last key
                        else
@@ -638,21 +635,26 @@ char *mlt_geometry_serialise_cut( mlt_geometry this, int in, int out )
                        if ( item.frame - in != 0 )
                                sprintf( temp, "%d=", item.frame - in );
 
-                       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 )
+                       if ( item.f[0] )
+                               sprintf( temp + strlen( temp ), "%g", item.x );
+                       if ( item.f[1] ) {
+                               strcat( temp, "/" );
+                               sprintf( temp + strlen( temp ), "%g", item.y );
+                       }
+                       if ( item.f[2] ) {
+                               strcat( temp, ":" );
+                               sprintf( temp + strlen( temp ), "%g", item.w );
+                       }
+                       if ( item.f[3] ) {
+                               strcat( temp, "x" );
+                               sprintf( temp + strlen( temp ), "%g", item.h );
+                       }
+                       if ( item.f[4] ) {
+                               strcat( temp, ":" );
+                               sprintf( temp + strlen( temp ), "%g", item.mix );
+                       }
+
+                       if ( used + strlen( temp ) + 2 > size ) // +2 for ';' and NULL
                        {
                                size += 1000;
                                ret = realloc( ret, size );
@@ -677,26 +679,27 @@ char *mlt_geometry_serialise_cut( mlt_geometry this, int in, int out )
 }
 
 // Serialise the current geometry
-char *mlt_geometry_serialise( mlt_geometry this )
+char *mlt_geometry_serialise( mlt_geometry self )
 {
-       geometry self = this->local;
-       char *ret = mlt_geometry_serialise_cut( this, 0, self->length );
+       geometry g = self->local;
+       char *ret = mlt_geometry_serialise_cut( self, 0, g->length );
        if ( ret )
        {
-               free( self->data );
-               self->data = ret;
+               if ( g->data )
+                       free( g->data );
+               g->data = ret;
        }
-       return ret;
+       return strdup( ret );
 }
 
 // Close the geometry
-void mlt_geometry_close( mlt_geometry this )
+void mlt_geometry_close( mlt_geometry self )
 {
-       if ( this != NULL )
+       if ( self != NULL )
        {
-               mlt_geometry_clean( this );
-               free( this->local );
-               free( this );
+               mlt_geometry_clean( self );
+               free( self->local );
+               free( self );
        }
 }