]> git.sesse.net Git - mlt/blobdiff - src/framework/mlt_property.c
Add mlt_properties_anim_set/get_double().
[mlt] / src / framework / mlt_property.c
index e09959f36a88139d1f20558032680c612263fa05..b00cc56382efb182ba637b389e51e719fa9ae67e 100644 (file)
@@ -34,6 +34,7 @@
 #include <string.h>
 #include <locale.h>
 #include <pthread.h>
+#include <float.h>
 
 
 /** Bit pattern used internally to indicated representations available.
@@ -47,7 +48,8 @@ typedef enum
        mlt_prop_position = 4,//!< set as a position
        mlt_prop_double = 8,  //!< set as a floating point
        mlt_prop_data = 16,   //!< set as opaque binary
-       mlt_prop_int64 = 32   //!< set as a 64-bit integer
+       mlt_prop_int64 = 32,  //!< set as a 64-bit integer
+       mlt_prop_rect = 64    //!< set as a mlt_rect
 }
 mlt_property_type;
 
@@ -422,6 +424,8 @@ int mlt_property_get_int( mlt_property self, double fps, locale_t locale )
                return ( int )self->prop_position;
        else if ( self->types & mlt_prop_int64 )
                return ( int )self->prop_int64;
+       else if ( self->types & mlt_prop_rect && self->data )
+               return ( int ) ( (mlt_rect*) self->data )->x;
        else if ( ( self->types & mlt_prop_string ) && self->prop_string )
                return mlt_property_atoi( self->prop_string, fps, locale );
        return 0;
@@ -432,6 +436,8 @@ int mlt_property_get_int( mlt_property self, double fps, locale_t locale )
  * If the string contains a colon it is interpreted as a time value. If it also
  * contains a period or comma character, the string is parsed as a clock value:
  * HH:MM:SS. Otherwise, the time value is parsed as a SMPTE timecode: HH:MM:SS:FF.
+ * If the numeric string ends with '%' then the value is divided by 100 to convert
+ * it into a ratio.
  * \private \memberof mlt_property_s
  * \param value the string to convert
  * \param fps frames per second, used when converting from time value
@@ -449,11 +455,17 @@ static double mlt_property_atof( const char *value, double fps, locale_t locale
        }
        else
        {
+               char *end = NULL;
+               double result;
 #if defined(__GLIBC__) || defined(__DARWIN__)
                if ( locale )
-                       return strtod_l( value, NULL, locale );
+                       result = strtod_l( value, &end, locale );
 #endif
-               return strtod( value, NULL );
+               else
+                       result = strtod( value, &end );
+               if ( end && end[0] == '%' )
+                       result /= 100.0;
+               return result;
        }
 }
 
@@ -476,6 +488,8 @@ double mlt_property_get_double( mlt_property self, double fps, locale_t locale )
                return ( double )self->prop_position;
        else if ( self->types & mlt_prop_int64 )
                return ( double )self->prop_int64;
+       else if ( self->types & mlt_prop_rect && self->data )
+               return ( (mlt_rect*) self->data )->x;
        else if ( ( self->types & mlt_prop_string ) && self->prop_string )
                return mlt_property_atof( self->prop_string, fps, locale );
        return 0;
@@ -501,6 +515,8 @@ mlt_position mlt_property_get_position( mlt_property self, double fps, locale_t
                return ( mlt_position )self->prop_double;
        else if ( self->types & mlt_prop_int64 )
                return ( mlt_position )self->prop_int64;
+       else if ( self->types & mlt_prop_rect && self->data )
+               return ( mlt_position ) ( (mlt_rect*) self->data )->x;
        else if ( ( self->types & mlt_prop_string ) && self->prop_string )
                return ( mlt_position )mlt_property_atoi( self->prop_string, fps, locale );
        return 0;
@@ -541,6 +557,8 @@ int64_t mlt_property_get_int64( mlt_property self )
                return ( int64_t )self->prop_double;
        else if ( self->types & mlt_prop_position )
                return ( int64_t )self->prop_position;
+       else if ( self->types & mlt_prop_rect && self->data )
+               return ( int64_t ) ( (mlt_rect*) self->data )->x;
        else if ( ( self->types & mlt_prop_string ) && self->prop_string )
                return mlt_property_atoll( self->prop_string );
        return 0;
@@ -573,7 +591,7 @@ char *mlt_property_get_string( mlt_property self )
                {
                        self->types |= mlt_prop_string;
                        self->prop_string = malloc( 32 );
-                       sprintf( self->prop_string, "%f", self->prop_double );
+                       sprintf( self->prop_string, "%g", self->prop_double );
                }
                else if ( self->types & mlt_prop_position )
                {
@@ -649,7 +667,7 @@ char *mlt_property_get_string_l( mlt_property self, locale_t locale )
                {
                        self->types |= mlt_prop_string;
                        self->prop_string = malloc( 32 );
-                       sprintf( self->prop_string, "%f", self->prop_double );
+                       sprintf( self->prop_string, "%g", self->prop_double );
                }
                else if ( self->types & mlt_prop_position )
                {
@@ -744,6 +762,16 @@ void mlt_property_pass( mlt_property self, mlt_property that )
                if ( that->prop_string != NULL )
                        self->prop_string = strdup( that->prop_string );
        }
+       else if ( that->types & mlt_prop_rect )
+       {
+               mlt_property_clear( self );
+               self->types = mlt_prop_rect | mlt_prop_data;
+               self->length = that->length;
+               self->data = calloc( 1, self->length );
+               memcpy( self->data, that->data, self->length );
+               self->destructor = free;
+               self->serialiser = that->serialiser;
+       }
        else if ( self->types & mlt_prop_data && self->serialiser != NULL )
        {
                self->types = mlt_prop_string;
@@ -924,7 +952,8 @@ static int is_property_numeric( mlt_property self, locale_t locale )
        int result = ( self->types & mlt_prop_int ) ||
                        ( self->types & mlt_prop_int64 ) ||
                        ( self->types & mlt_prop_double ) ||
-                       ( self->types & mlt_prop_position );
+                       ( self->types & mlt_prop_position ) ||
+                       ( self->types & mlt_prop_rect );
 
        // If not already numeric but string is numeric.
        if ( ( !result && self->types & mlt_prop_string ) && self->prop_string )
@@ -963,27 +992,75 @@ int mlt_property_interpolate( mlt_property self, mlt_property p[],
        double progress, double fps, locale_t locale, mlt_keyframe_type interp )
 {
        int error = 0;
-       if ( interp != mlt_keyframe_discrete && fps > 0 &&
+       if ( interp != mlt_keyframe_discrete &&
                is_property_numeric( p[1], locale ) && is_property_numeric( p[2], locale ) )
        {
-               double value;
-               if ( interp == mlt_keyframe_linear )
+               if ( self->types & mlt_prop_rect )
                {
-                       double points[2];
-                       points[0] = p[1]? mlt_property_get_double( p[1], fps, locale ) : 0;
-                       points[1] = p[2]? mlt_property_get_double( p[2], fps, locale ) : 0;
-                       value = p[2]? linear_interpolate( points[0], points[1], progress ) : points[0];
+                       mlt_rect value = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN };
+                       if ( interp == mlt_keyframe_linear )
+                       {
+                               mlt_rect points[2];
+                               mlt_rect zero = {0, 0, 0, 0, 0};
+                               points[0] = p[1]? mlt_property_get_rect( p[1], locale ) : zero;
+                               if ( p[2] )
+                               {
+                                       points[1] = mlt_property_get_rect( p[2], locale );
+                                       value.x = linear_interpolate( points[0].x, points[1].x, progress );
+                                       value.y = linear_interpolate( points[0].y, points[1].y, progress );
+                                       value.w = linear_interpolate( points[0].w, points[1].w, progress );
+                                       value.h = linear_interpolate( points[0].h, points[1].h, progress );
+                                       value.o = linear_interpolate( points[0].o, points[1].o, progress );
+                               }
+                               else
+                               {
+                                       value = points[0];
+                               }
+                       }
+                       else if ( interp == mlt_keyframe_smooth )
+                       {
+                               mlt_rect points[4];
+                               mlt_rect zero = {0, 0, 0, 0, 0};
+                               points[1] = p[1]? mlt_property_get_rect( p[1], locale ) : zero;
+                               if ( p[2] )
+                               {
+                                       points[0] = p[0]? mlt_property_get_rect( p[0], locale ) : zero;
+                                       points[2] = p[2]? mlt_property_get_rect( p[2], locale ) : zero;
+                                       points[3] = p[3]? mlt_property_get_rect( p[3], locale ) : zero;
+                                       value.x = catmull_rom_interpolate( points[0].x, points[1].x, points[2].x, points[3].x, progress );
+                                       value.y = catmull_rom_interpolate( points[0].y, points[1].y, points[2].y, points[3].y, progress );
+                                       value.w = catmull_rom_interpolate( points[0].w, points[1].w, points[2].w, points[3].w, progress );
+                                       value.h = catmull_rom_interpolate( points[0].h, points[1].h, points[2].h, points[3].h, progress );
+                                       value.o = catmull_rom_interpolate( points[0].o, points[1].o, points[2].o, points[3].o, progress );
+                               }
+                               else
+                               {
+                                       value = points[1];
+                               }
+                       }
+                       error = mlt_property_set_rect( self, value );
                }
-               else if ( interp == mlt_keyframe_smooth )
+               else
                {
-                       double points[4];
-                       points[0] = p[0]? mlt_property_get_double( p[0], fps, locale ) : 0;
-                       points[1] = p[1]? mlt_property_get_double( p[1], fps, locale ) : 0;
-                       points[2] = p[2]? mlt_property_get_double( p[2], fps, locale ) : 0;
-                       points[3] = p[3]? mlt_property_get_double( p[3], fps, locale ) : 0;
-                       value = p[2]? catmull_rom_interpolate( points[0], points[1], points[2], points[3], progress ) : points[1];
+                       double value;
+                       if ( interp == mlt_keyframe_linear )
+                       {
+                               double points[2];
+                               points[0] = p[1]? mlt_property_get_double( p[1], fps, locale ) : 0;
+                               points[1] = p[2]? mlt_property_get_double( p[2], fps, locale ) : 0;
+                               value = p[2]? linear_interpolate( points[0], points[1], progress ) : points[0];
+                       }
+                       else if ( interp == mlt_keyframe_smooth )
+                       {
+                               double points[4];
+                               points[0] = p[0]? mlt_property_get_double( p[0], fps, locale ) : 0;
+                               points[1] = p[1]? mlt_property_get_double( p[1], fps, locale ) : 0;
+                               points[2] = p[2]? mlt_property_get_double( p[2], fps, locale ) : 0;
+                               points[3] = p[3]? mlt_property_get_double( p[3], fps, locale ) : 0;
+                               value = p[2]? catmull_rom_interpolate( points[0], points[1], points[2], points[3], progress ) : points[1];
+                       }
+                       error = mlt_property_set_double( self, value );
                }
-               error = mlt_property_set_double( self, value );
        }
        else
        {
@@ -997,18 +1074,28 @@ static void refresh_animation( mlt_property self, double fps, locale_t locale, i
        if ( !self->animation )
        {
                self->animation = mlt_animation_new();
-               mlt_animation_parse( self->animation, self->prop_string, length, fps, locale );
+               if ( self->prop_string )
+               {
+                       mlt_animation_parse( self->animation, self->prop_string, length, fps, locale );
+               }
+               else
+               {
+                       mlt_animation_set_length( self->animation, length );
+                       self->types |= mlt_prop_data;
+                       self->data = self->animation;
+                       self->serialiser = (mlt_serialiser) mlt_animation_serialize;
+               }
        }
-       else
+       else if ( self->prop_string )
        {
                mlt_animation_refresh( self->animation, self->prop_string, length );
        }
 }
 
-double mlt_property_get_double_pos( mlt_property self, double fps, locale_t locale, int position, int length )
+double mlt_property_anim_get_double( mlt_property self, double fps, locale_t locale, int position, int length )
 {
        double result;
-       if ( ( self->types & mlt_prop_string ) && self->prop_string )
+       if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
        {
                struct mlt_animation_item_s item;
                item.property = mlt_property_init();
@@ -1026,10 +1113,10 @@ double mlt_property_get_double_pos( mlt_property self, double fps, locale_t loca
        return result;
 }
 
-int mlt_property_get_int_pos( mlt_property self, double fps, locale_t locale, int position, int length )
+int mlt_property_anim_get_int( mlt_property self, double fps, locale_t locale, int position, int length )
 {
        int result;
-       if ( ( self->types & mlt_prop_string ) && self->prop_string )
+       if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
        {
                struct mlt_animation_item_s item;
                item.property = mlt_property_init();
@@ -1046,3 +1133,206 @@ int mlt_property_get_int_pos( mlt_property self, double fps, locale_t locale, in
        }
        return result;
 }
+
+/** Set a property animation keyframe to a real number.
+ *
+ * \public \memberof mlt_property_s
+ * \param self a property
+ * \param value a double precision floating point value
+ * \return false if successful, true to indicate error
+ */
+
+int mlt_property_anim_set_double( mlt_property self, double value, double fps, locale_t locale,
+       mlt_keyframe_type keyframe_type, int position, int length )
+{
+       int result;
+       struct mlt_animation_item_s item;
+
+       item.property = mlt_property_init();
+       item.frame = position;
+       item.keyframe_type = keyframe_type;
+       mlt_property_set_double( item.property, value );
+
+       refresh_animation( self, fps, locale, length );
+       result = mlt_animation_insert( self->animation, &item );
+       mlt_animation_interpolate( self->animation );
+       mlt_property_close( item.property );
+
+       return result;
+}
+
+/** Set a property animation keyframe to an integer value.
+ *
+ * \public \memberof mlt_property_s
+ * \param self a property
+ * \param value a double precision floating point value
+ * \return false if successful, true to indicate error
+ */
+
+int mlt_property_anim_set_int( mlt_property self, int value, double fps, locale_t locale,
+       mlt_keyframe_type keyframe_type, int position, int length )
+{
+       int result;
+       struct mlt_animation_item_s item;
+
+       item.property = mlt_property_init();
+       item.frame = position;
+       item.keyframe_type = keyframe_type;
+       mlt_property_set_int( item.property, value );
+
+       refresh_animation( self, fps, locale, length );
+       result = mlt_animation_insert( self->animation, &item );
+       mlt_animation_interpolate( self->animation );
+       mlt_property_close( item.property );
+
+       return result;
+}
+
+static char* serialise_mlt_rect( mlt_rect *rect, int length )
+{
+       char* result = calloc( 1, 100 );
+       if ( rect->x != DBL_MIN )
+               sprintf( result + strlen( result ), "%g", rect->x );
+       if ( rect->y != DBL_MIN )
+               sprintf( result + strlen( result ), " %g", rect->y );
+       if ( rect->w != DBL_MIN )
+               sprintf( result + strlen( result ), " %g", rect->w );
+       if ( rect->h != DBL_MIN )
+               sprintf( result + strlen( result ), " %g", rect->h );
+       if ( rect->o != DBL_MIN )
+               sprintf( result + strlen( result ), " %g", rect->o );
+       return result;
+}
+
+/** Set a property to a mlt_rect rectangle.
+ *
+ * \public \memberof mlt_property_s
+ * \param self a property
+ * \param value a mlt_rect
+ * \return false
+ */
+
+int mlt_property_set_rect( mlt_property self, mlt_rect value )
+{
+       pthread_mutex_lock( &self->mutex );
+       mlt_property_clear( self );
+       self->types = mlt_prop_rect | mlt_prop_data;
+       self->length = sizeof(value);
+       self->data = calloc( 1, self->length );
+       memcpy( self->data, &value, self->length );
+       self->destructor = free;
+       self->serialiser = (mlt_serialiser) serialise_mlt_rect;
+       pthread_mutex_unlock( &self->mutex );
+       return 0;
+}
+
+/** Get the property as a floating point.
+ *
+ * \public \memberof mlt_property_s
+ * \param self a property
+ * \param fps frames per second, used when converting from time value
+ * \param locale the locale to use for this conversion
+ * \return a rectangle value
+ */
+
+mlt_rect mlt_property_get_rect( mlt_property self, locale_t locale )
+{
+       mlt_rect rect = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN };
+       if ( self->types & mlt_prop_rect )
+               rect = *( (mlt_rect*) self->data );
+       else if ( self->types & mlt_prop_double )
+               rect.x = self->prop_double;
+       else if ( self->types & mlt_prop_int )
+               rect.x = ( double )self->prop_int;
+       else if ( self->types & mlt_prop_position )
+               rect.x = ( double )self->prop_position;
+       else if ( self->types & mlt_prop_int64 )
+               rect.x = ( double )self->prop_int64;
+       else if ( ( self->types & mlt_prop_string ) && self->prop_string )
+       {
+               //return mlt_property_atof( self->prop_string, fps, locale );
+               char *value = self->prop_string;
+               char *p = NULL;
+               int count = 0;
+               while ( *value )
+               {
+                       double temp;
+#if defined(__GLIBC__) || defined(__DARWIN__)
+                       if ( locale )
+                               temp = strtod_l( value, &p, locale );
+#endif
+                       else
+                               temp = strtod( value, &p );
+                       if ( p != value )
+                       {
+                               if ( p[0] == '%' )
+                                       temp /= 100.0;
+                               if ( *p ) p ++;
+                               switch( count )
+                               {
+                                       case 0: rect.x = temp; break;
+                                       case 1: rect.y = temp; break;
+                                       case 2: rect.w = temp; break;
+                                       case 3: rect.h = temp; break;
+                                       case 4: rect.o = temp; break;
+                               }
+                       }
+                       else
+                       {
+                               p++;
+                       }
+                       value = p;
+                       count ++;
+               }
+       }
+       return rect;
+}
+
+/** Set a property animation keyframe to a rectangle.
+ *
+ * \public \memberof mlt_property_s
+ * \param self a property
+ * \param value a rectangle
+ * \return false if successful, true to indicate error
+ */
+
+int mlt_property_anim_set_rect( mlt_property self, mlt_rect value, double fps, locale_t locale,
+       mlt_keyframe_type keyframe_type, int position, int length )
+{
+       int result;
+       struct mlt_animation_item_s item;
+
+       item.property = mlt_property_init();
+       item.frame = position;
+       item.keyframe_type = keyframe_type;
+       mlt_property_set_rect( item.property, value );
+
+       refresh_animation( self, fps, locale, length );
+       result = mlt_animation_insert( self->animation, &item );
+       mlt_animation_interpolate( self->animation );
+       mlt_property_close( item.property );
+
+       return result;
+}
+
+mlt_rect mlt_property_anim_get_rect( mlt_property self, double fps, locale_t locale, int position, int length )
+{
+       mlt_rect result;
+       if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
+       {
+               struct mlt_animation_item_s item;
+               item.property = mlt_property_init();
+               item.property->types = mlt_prop_rect;
+
+               refresh_animation( self, fps, locale, length );
+               mlt_animation_get_item( self->animation, &item, position );
+               result = mlt_property_get_rect( item.property, locale );
+
+               mlt_property_close( item.property );
+       }
+       else
+       {
+               result = mlt_property_get_rect( self, locale );
+       }
+       return result;
+}