+}
+
+/** Get the real number at a frame position.
+ *
+ * \public \memberof mlt_property_s
+ * \param self a property
+ * \param fps the frame rate, which may be needed for converting a time string to frame units
+ * \param locale the locale, which may be needed for converting a string to a real number
+ * \param position the frame number
+ * \param length the maximum number of frames when interpreting negative keyframe times,
+ * <=0 if you don't care or need that
+ * \return the real number
+ */
+
+double mlt_property_anim_get_double( mlt_property self, double fps, locale_t locale, int position, int length )
+{
+ pthread_mutex_lock( &self->mutex );
+ double result;
+ if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
+ {
+ struct mlt_animation_item_s item;
+ item.property = mlt_property_init();
+
+ refresh_animation( self, fps, locale, length );
+ mlt_animation_get_item( self->animation, &item, position );
+ result = mlt_property_get_double( item.property, fps, locale );
+
+ mlt_property_close( item.property );
+ }
+ else
+ {
+ result = mlt_property_get_double( self, fps, locale );
+ }
+ pthread_mutex_unlock( &self->mutex );
+ return result;
+}
+
+/** Get the property as an integer number at a frame position.
+ *
+ * \public \memberof mlt_property_s
+ * \param self a property
+ * \param fps the frame rate, which may be needed for converting a time string to frame units
+ * \param locale the locale, which may be needed for converting a string to a real number
+ * \param position the frame number
+ * \param length the maximum number of frames when interpreting negative keyframe times,
+ * <=0 if you don't care or need that
+ * \return an integer value
+ */
+
+int mlt_property_anim_get_int( mlt_property self, double fps, locale_t locale, int position, int length )
+{
+ pthread_mutex_lock( &self->mutex );
+ int result;
+ if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
+ {
+ struct mlt_animation_item_s item;
+ item.property = mlt_property_init();
+
+ refresh_animation( self, fps, locale, length );
+ mlt_animation_get_item( self->animation, &item, position );
+ result = mlt_property_get_int( item.property, fps, locale );
+
+ mlt_property_close( item.property );
+ }
+ else
+ {
+ result = mlt_property_get_int( self, fps, locale );
+ }
+ pthread_mutex_unlock( &self->mutex );
+ return result;
+}
+
+/** Get the string at certain a frame position.
+ *
+ * \public \memberof mlt_property_s
+ * \param self a property
+ * \param fps the frame rate, which may be needed for converting a time string to frame units
+ * \param locale the locale, which may be needed for converting a string to a real number
+ * \param position the frame number
+ * \param length the maximum number of frames when interpreting negative keyframe times,
+ * <=0 if you don't care or need that
+ * \return the string representation of the property or NULL if failed
+ */
+
+char* mlt_property_anim_get_string( mlt_property self, double fps, locale_t locale, int position, int length )
+{
+ pthread_mutex_lock( &self->mutex );
+ char *result;
+ if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
+ {
+ struct mlt_animation_item_s item;
+ item.property = mlt_property_init();
+
+ if ( !self->animation )
+ refresh_animation( self, fps, locale, length );
+ mlt_animation_get_item( self->animation, &item, position );
+
+ if ( self->prop_string )
+ free( self->prop_string );
+ self->prop_string = mlt_property_get_string_l( item.property, locale );
+ if ( self->prop_string )
+ self->prop_string = strdup( self->prop_string );
+ self->types |= mlt_prop_string;
+
+ result = self->prop_string;
+ mlt_property_close( item.property );
+ }
+ else
+ {
+ result = mlt_property_get_string_l( self, locale );
+ }
+ pthread_mutex_unlock( &self->mutex );
+ 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
+ * \param fps the frame rate, which may be needed for converting a time string to frame units
+ * \param locale the locale, which may be needed for converting a string to a real number
+ * \param position the frame number
+ * \param length the maximum number of frames when interpreting negative keyframe times,
+ * <=0 if you don't care or need that
+ * \param keyframe_type the interpolation method for this keyframe
+ * \return false if successful, true to indicate error
+ */
+
+int mlt_property_anim_set_double( mlt_property self, double value, double fps, locale_t locale,
+ int position, int length, mlt_keyframe_type keyframe_type )
+{
+ 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 an integer
+ * \param fps the frame rate, which may be needed for converting a time string to frame units
+ * \param locale the locale, which may be needed for converting a string to a real number
+ * \param position the frame number
+ * \param length the maximum number of frames when interpreting negative keyframe times,
+ * <=0 if you don't care or need that
+ * \param keyframe_type the interpolation method for this keyframe
+ * \return false if successful, true to indicate error
+ */
+
+int mlt_property_anim_set_int( mlt_property self, int value, double fps, locale_t locale,
+ int position, int length, mlt_keyframe_type keyframe_type )
+{
+ 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;
+}
+
+/** Set a property animation keyframe to a string.
+ *
+ * Strings only support discrete animation. Do not use this to set a property's
+ * animation string that contains a semicolon-delimited set of values; use
+ * mlt_property_set() for that.
+ * \public \memberof mlt_property_s
+ * \param self a property
+ * \param value a string
+ * \param fps the frame rate, which may be needed for converting a time string to frame units
+ * \param locale the locale, which may be needed for converting a string to a real number
+ * \param position the frame number
+ * \param length the maximum number of frames when interpreting negative keyframe times,
+ * <=0 if you don't care or need that
+ * \return false if successful, true to indicate error
+ */
+
+int mlt_property_anim_set_string( mlt_property self, const char *value, double fps, locale_t locale, int position, int length )
+{
+ int result;
+ struct mlt_animation_item_s item;
+
+ item.property = mlt_property_init();
+ item.frame = position;
+ item.keyframe_type = mlt_keyframe_discrete;
+ mlt_property_set_string( 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;
+}
+
+/** Get an object's animation object.
+ *
+ * You might need to call another mlt_property_anim_ function to actually construct
+ * the animation, as this is a simple accessor function.
+ * \public \memberof mlt_property_s
+ * \param self a property
+ * \return the animation object or NULL if there is no animation
+ */
+
+mlt_animation mlt_property_get_animation( mlt_property self )
+{
+ return self->animation;
+}
+
+/** Convert a rectangle value into a string.
+ *
+ * Unlike the deprecated mlt_geometry API, the canonical form of a mlt_rect
+ * is a space delimited "x y w h o" even though many kinds of field delimiters
+ * may be used to convert a string to a rectangle.
+ * \private \memberof mlt_property_s
+ * \param rect the rectangle to convert
+ * \param length not used
+ * \return the string representation of a rectangle
+ */
+
+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 rectangle
+ * \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 rectangle.
+ *
+ * You can use any non-numeric character(s) as a field delimiter.
+ * If the number has a '%' immediately following it, the number is divided by
+ * 100 to convert it into a real number.
+ * \public \memberof mlt_property_s
+ * \param self a property
+ * \param locale the locale to use for when converting from a string
+ * \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 );
+ else
+#endif
+ temp = strtod( value, &p );
+ if ( p != value )
+ {
+ if ( p[0] == '%' )
+ {
+ temp /= 100.0;
+ p ++;
+ }
+
+ // Chomp the delimiter.
+ if ( *p ) p ++;
+
+ // Assign the value to appropriate field.
+ 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
+ * \param fps the frame rate, which may be needed for converting a time string to frame units
+ * \param locale the locale, which may be needed for converting a string to a real number
+ * \param position the frame number
+ * \param length the maximum number of frames when interpreting negative keyframe times,
+ * <=0 if you don't care or need that
+ * \param keyframe_type the interpolation method for this keyframe
+ * \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,
+ int position, int length, mlt_keyframe_type keyframe_type )
+{
+ 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;
+}
+
+/** Get a rectangle at a frame position.
+ *
+ * \public \memberof mlt_property_s
+ * \param self a property
+ * \param fps the frame rate, which may be needed for converting a time string to frame units
+ * \param locale the locale, which may be needed for converting a string to a real number
+ * \param position the frame number
+ * \param length the maximum number of frames when interpreting negative keyframe times,
+ * <=0 if you don't care or need that
+ * \return the rectangle
+ */
+
+mlt_rect mlt_property_anim_get_rect( mlt_property self, double fps, locale_t locale, int position, int length )
+{
+ pthread_mutex_lock( &self->mutex );
+ 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