]> git.sesse.net Git - mlt/blobdiff - src/framework/mlt_property.c
Restrict auto-profile frame rate to a sane value.
[mlt] / src / framework / mlt_property.c
index 1f847b5af381f0634568d8a969e84b5e1ef5ce01..ab8730f4cbfb978293b3dcb867d47f5b675fd25b 100644 (file)
@@ -3,8 +3,9 @@
  * \brief Property class definition
  * \see mlt_property_s
  *
- * Copyright (C) 2003-2009 Ushodaya Enterprises Limited
+ * Copyright (C) 2003-2013 Ushodaya Enterprises Limited
  * \author Charles Yates <charles.yates@pandora.be>
+ * \author Dan Dennedy <dan@dennedy.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -264,13 +265,14 @@ int mlt_property_set_data( mlt_property self, void *value, int length, mlt_destr
 /** Parse a SMIL clock value.
  *
  * \private \memberof mlt_property_s
+ * \param self a property
  * \param s the string to parse
  * \param fps frames per second
  * \param locale the locale to use for parsing a real number value
  * \return position in frames
  */
 
-static int time_clock_to_frames( const char *s, double fps, locale_t locale )
+static int time_clock_to_frames( mlt_property self, const char *s, double fps, locale_t locale )
 {
        char *pos, *copy = strdup( s );
        int hours = 0, minutes = 0;
@@ -278,6 +280,22 @@ static int time_clock_to_frames( const char *s, double fps, locale_t locale )
 
        s = copy;
        pos = strrchr( s, ':' );
+
+#if !defined(__GLIBC__) && !defined(__DARWIN__)
+       char *orig_localename = NULL;
+       if ( locale )
+       {
+               // Protect damaging the global locale from a temporary locale on another thread.
+               pthread_mutex_lock( &self->mutex );
+               
+               // Get the current locale
+               orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
+               
+               // Set the new locale
+               setlocale( LC_NUMERIC, locale );
+       }
+#endif
+
        if ( pos ) {
 #if defined(__GLIBC__) || defined(__DARWIN__)
                if ( locale )
@@ -304,6 +322,16 @@ static int time_clock_to_frames( const char *s, double fps, locale_t locale )
 #endif
                        seconds = strtod( s, NULL );
        }
+
+#if !defined(__GLIBC__) && !defined(__DARWIN__)
+       if ( locale ) {
+               // Restore the current locale
+               setlocale( LC_NUMERIC, orig_localename );
+               free( orig_localename );
+               pthread_mutex_unlock( &self->mutex );
+       }
+#endif
+
        free( copy );
 
        return lrint( fps * ( (hours * 3600) + (minutes * 60) + seconds ) );
@@ -312,12 +340,13 @@ static int time_clock_to_frames( const char *s, double fps, locale_t locale )
 /** Parse a SMPTE timecode string.
  *
  * \private \memberof mlt_property_s
+ * \param self a property
  * \param s the string to parse
  * \param fps frames per second
  * \return position in frames
  */
 
-static int time_code_to_frames( const char *s, double fps )
+static int time_code_to_frames( mlt_property self, const char *s, double fps )
 {
        char *pos, *copy = strdup( s );
        int hours = 0, minutes = 0, seconds = 0, frames;
@@ -373,13 +402,15 @@ static int time_code_to_frames( const char *s, double fps )
  * 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.
  * \private \memberof mlt_property_s
- * \param value a string to convert
+ * \param self a property
  * \param fps frames per second, used when converting from time value
  * \param locale the locale to use when converting from time clock value
  * \return the resultant integer
  */
-static int mlt_property_atoi( const char *value, double fps, locale_t locale )
+static int mlt_property_atoi( mlt_property self, double fps, locale_t locale )
 {
+       const char *value = self->prop_string;
+       
        // Parse a hex color value as #RRGGBB or #AARRGGBB.
        if ( value[0] == '#' )
        {
@@ -396,9 +427,9 @@ static int mlt_property_atoi( const char *value, double fps, locale_t locale )
        else if ( fps > 0 && strchr( value, ':' ) )
        {
                if ( strchr( value, '.' ) || strchr( value, ',' ) )
-                       return time_clock_to_frames( value, fps, locale );
+                       return time_clock_to_frames( self, value, fps, locale );
                else
-                       return time_code_to_frames( value, fps );
+                       return time_code_to_frames( self, value, fps );
        }
        else
        {
@@ -428,7 +459,7 @@ int mlt_property_get_int( mlt_property self, double fps, locale_t locale )
        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 mlt_property_atoi( self, fps, locale );
        return 0;
 }
 
@@ -440,32 +471,58 @@ int mlt_property_get_int( mlt_property self, double fps, locale_t locale )
  * 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 self a property
  * \param fps frames per second, used when converting from time value
  * \param locale the locale to use when converting from time clock value
  * \return the resultant real number
  */
-static double mlt_property_atof( const char *value, double fps, locale_t locale )
+static double mlt_property_atof( mlt_property self, double fps, locale_t locale )
 {
-       if ( fps > 0 && strchr( value, ':' ) )
+       const char *value = self->prop_string;
+
+    if ( fps > 0 && strchr( value, ':' ) )
        {
                if ( strchr( value, '.' ) || strchr( value, ',' ) )
-                       return time_clock_to_frames( value, fps, locale );
+                       return time_clock_to_frames( self, value, fps, locale );
                else
-                       return time_code_to_frames( value, fps );
+                       return time_code_to_frames( self, value, fps );
        }
        else
        {
                char *end = NULL;
                double result;
+
 #if defined(__GLIBC__) || defined(__DARWIN__)
                if ( locale )
                        result = strtod_l( value, &end, locale );
-#endif
                else
+#else
+               char *orig_localename = NULL;
+               if ( locale ) {
+                       // Protect damaging the global locale from a temporary locale on another thread.
+                       pthread_mutex_lock( &self->mutex );
+                       
+                       // Get the current locale
+                       orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
+                       
+                       // Set the new locale
+                       setlocale( LC_NUMERIC, locale );
+               }
+#endif
+
                        result = strtod( value, &end );
                if ( end && end[0] == '%' )
                        result /= 100.0;
+
+#if !defined(__GLIBC__) && !defined(__DARWIN__)
+               if ( locale ) {
+                       // Restore the current locale
+                       setlocale( LC_NUMERIC, orig_localename );
+                       free( orig_localename );
+                       pthread_mutex_unlock( &self->mutex );
+               }
+#endif
+
                return result;
        }
 }
@@ -492,7 +549,7 @@ double mlt_property_get_double( mlt_property self, double fps, locale_t locale )
        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 mlt_property_atof( self, fps, locale );
        return 0;
 }
 
@@ -519,7 +576,7 @@ mlt_position mlt_property_get_position( mlt_property self, double fps, locale_t
        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 ( mlt_position )mlt_property_atoi( self, fps, locale );
        return 0;
 }
 
@@ -646,8 +703,7 @@ char *mlt_property_get_string_l( mlt_property self, locale_t locale )
 #elif defined(__GLIBC__)
                const char *localename = locale->__names[ LC_NUMERIC ];
 #else
-               // TODO: not yet sure what to do on other platforms
-               const char *localename = "";
+               const char *localename = locale;
 #endif
                // Protect damaging the global locale from a temporary locale on another thread.
                pthread_mutex_lock( &self->mutex );
@@ -773,10 +829,10 @@ void mlt_property_pass( mlt_property self, mlt_property that )
                self->destructor = free;
                self->serialiser = that->serialiser;
        }
-       else if ( self->types & mlt_prop_data && self->serialiser != NULL )
+       else if ( self->types & mlt_prop_data && that->serialiser != NULL )
        {
                self->types = mlt_prop_string;
-               self->prop_string = self->serialiser( self->data, self->length );
+               self->prop_string = that->serialiser( that->data, that->length );
        }
        pthread_mutex_unlock( &self->mutex );
 }
@@ -856,7 +912,7 @@ static void time_clock_from_frames( int frames, double fps, char *s )
 char *mlt_property_get_time( mlt_property self, mlt_time_format format, double fps, locale_t locale )
 {
        char *orig_localename = NULL;
-       const char *localename = "";
+       const char *localename = "C";
 
        // Optimization for mlt_time_frames
        if ( format == mlt_time_frames )
@@ -948,6 +1004,14 @@ char *mlt_property_get_time( mlt_property self, mlt_time_format format, double f
        return self->prop_string;
 }
 
+/** Determine if the property holds a numeric or numeric string value.
+ *
+ * \private \memberof mlt_property_s
+ * \param self a property
+ * \param locale the locale to use for string evaluation
+ * \return true if it is numeric
+ */
+
 static int is_property_numeric( mlt_property self, locale_t locale )
 {
        int result = ( self->types & mlt_prop_int ) ||
@@ -961,24 +1025,58 @@ static int is_property_numeric( mlt_property self, locale_t locale )
        {
                double temp;
                char *p = NULL;
+               
 #if defined(__GLIBC__) || defined(__DARWIN__)
                if ( locale )
                        temp = strtod_l( self->prop_string, &p, locale );
                else
+#else
+               char *orig_localename = NULL;
+               if ( locale ) {
+                       // Protect damaging the global locale from a temporary locale on another thread.
+                       pthread_mutex_lock( &self->mutex );
+                       
+                       // Get the current locale
+                       orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
+                       
+                       // Set the new locale
+                       setlocale( LC_NUMERIC, locale );
+               }
 #endif
+
                temp = strtod( self->prop_string, &p );
+
+#if !defined(__GLIBC__) && !defined(__DARWIN__)
+               if ( locale ) {
+                       // Restore the current locale
+                       setlocale( LC_NUMERIC, orig_localename );
+                       free( orig_localename );
+                       pthread_mutex_unlock( &self->mutex );
+               }
+#endif
+
                result = ( p != self->prop_string );
        }
        return result;
 }
 
+/** A linear interpolation function for animation.
+ *
+ * \private \memberof mlt_property_s
+ */
+
 static inline double linear_interpolate( double y1, double y2, double t )
 {
        return y1 + ( y2 - y1 ) * t;
 }
 
-//  For non-closed curves, you need to also supply the tangent vector at the first and last control point.
-// This is commonly done: T(P[0]) = P[1] - P[0] and T(P[n]) = P[n] - P[n-1].
+/** A smooth spline interpolation for animation.
+ *
+ * For non-closed curves, you need to also supply the tangent vector at the first and last control point.
+ * This is commonly done: T(P[0]) = P[1] - P[0] and T(P[n]) = P[n] - P[n-1].
+ * \private \memberof mlt_property_s
+ */
+
 static inline double catmull_rom_interpolate( double y0, double y1, double y2, double y3, double t )
 {
        double t2 = t * t;
@@ -989,6 +1087,20 @@ static inline double catmull_rom_interpolate( double y0, double y1, double y2, d
        return a0 * t * t2 + a1 * t2 + a2 * t + a3;
 }
 
+/** Interpolate a new property value given a set of other properties.
+ *
+ * \public \memberof mlt_property_s
+ * \param self the property onto which to set the computed value
+ * \param p an array of at least 1 value in p[1] if \p interp is discrete,
+ *  2 values in p[1] and p[2] if \p interp is linear, or
+ *  4 values in p[0] - p[3] if \p interp is smooth
+ * \param progress a ratio in the range [0, 1] to indicate how far between p[1] and p[2]
+ * \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 interp the interpolation method to use
+ * \return true if there was an error
+ */
+
 int mlt_property_interpolate( mlt_property self, mlt_property p[],
        double progress, double fps, locale_t locale, mlt_keyframe_type interp )
 {
@@ -1043,7 +1155,7 @@ int mlt_property_interpolate( mlt_property self, mlt_property p[],
                }
                else
                {
-                       double value;
+                       double value = 0.0;
                        if ( interp == mlt_keyframe_linear )
                        {
                                double points[2];
@@ -1070,6 +1182,16 @@ int mlt_property_interpolate( mlt_property self, mlt_property p[],
        return error;
 }
 
+/** Create a new animation or refresh an existing one.
+ *
+ * \private \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 length the maximum number of frames when interpreting negative keyframe times,
+ *  <=0 if you don't care or need that
+ */
+
 static void refresh_animation( mlt_property self, double fps, locale_t locale, int length  )
 {
        if ( !self->animation )
@@ -1082,9 +1204,11 @@ static void refresh_animation( mlt_property self, double fps, locale_t locale, i
                else
                {
                        mlt_animation_set_length( self->animation, length );
+                       pthread_mutex_lock( &self->mutex );
                        self->types |= mlt_prop_data;
                        self->data = self->animation;
                        self->serialiser = (mlt_serialiser) mlt_animation_serialize;
+                       pthread_mutex_unlock( &self->mutex );
                }
        }
        else if ( self->prop_string )
@@ -1093,8 +1217,21 @@ static void refresh_animation( mlt_property self, double fps, locale_t locale, i
        }
 }
 
+/** 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 ) )
        {
@@ -1111,11 +1248,25 @@ double mlt_property_anim_get_double( mlt_property self, double fps, locale_t loc
        {
                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 ) )
        {
@@ -1132,11 +1283,25 @@ int mlt_property_anim_get_int( mlt_property self, double fps, locale_t locale, i
        {
                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 ) )
        {
@@ -1147,14 +1312,12 @@ char* mlt_property_anim_get_string( mlt_property self, double fps, locale_t loca
                        refresh_animation( self, fps, locale, length );
                mlt_animation_get_item( self->animation, &item, position );
 
-               pthread_mutex_lock( &self->mutex );
                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;
-               pthread_mutex_unlock( &self->mutex );
 
                result = self->prop_string;
                mlt_property_close( item.property );
@@ -1163,6 +1326,7 @@ char* mlt_property_anim_get_string( mlt_property self, double fps, locale_t loca
        {
                result = mlt_property_get_string_l( self, locale );
        }
+       pthread_mutex_unlock( &self->mutex );
        return result;
 }
 
@@ -1171,6 +1335,12 @@ char* mlt_property_anim_get_string( mlt_property self, double fps, locale_t loca
  * \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
  */
 
@@ -1197,7 +1367,13 @@ int mlt_property_anim_set_double( mlt_property self, double value, double fps, l
  *
  * \public \memberof mlt_property_s
  * \param self a property
- * \param value a double precision floating point value
+ * \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
  */
 
@@ -1220,6 +1396,22 @@ int mlt_property_anim_set_int( mlt_property self, int value, double fps, locale_
        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;
@@ -1238,11 +1430,31 @@ int mlt_property_anim_set_string( mlt_property self, const char *value, double f
        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;
+    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 );
@@ -1263,7 +1475,7 @@ static char* serialise_mlt_rect( mlt_rect *rect, int length )
  *
  * \public \memberof mlt_property_s
  * \param self a property
- * \param value a mlt_rect
+ * \param value a rectangle
  * \return false
  */
 
@@ -1281,12 +1493,14 @@ int mlt_property_set_rect( mlt_property self, mlt_rect value )
        return 0;
 }
 
-/** Get the property as a floating point.
+/** 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 fps frames per second, used when converting from time value
- * \param locale the locale to use for this conversion
+ * \param locale the locale to use for when converting from a string
  * \return a rectangle value
  */
 
@@ -1305,24 +1519,45 @@ mlt_rect mlt_property_get_rect( mlt_property self, locale_t locale )
                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;
+
+#if !defined(__GLIBC__) && !defined(__DARWIN__)
+               char *orig_localename = NULL;
+               if ( locale ) {
+                       // Protect damaging the global locale from a temporary locale on another thread.
+                       pthread_mutex_lock( &self->mutex );
+                       
+                       // Get the current locale
+                       orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
+                       
+                       // Set the new locale
+                       setlocale( LC_NUMERIC, locale );
+               }
+#endif
+
                while ( *value )
                {
                        double temp;
 #if defined(__GLIBC__) || defined(__DARWIN__)
                        if ( locale )
                                temp = strtod_l( value, &p, locale );
+            else
 #endif
-                       else
                                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;
@@ -1339,7 +1574,16 @@ mlt_rect mlt_property_get_rect( mlt_property self, locale_t locale )
                        value = p;
                        count ++;
                }
-       }
+
+#if !defined(__GLIBC__) && !defined(__DARWIN__)
+               if ( locale ) {
+                       // Restore the current locale
+                       setlocale( LC_NUMERIC, orig_localename );
+                       free( orig_localename );
+                       pthread_mutex_unlock( &self->mutex );
+               }
+#endif
+    }
        return rect;
 }
 
@@ -1348,6 +1592,12 @@ mlt_rect mlt_property_get_rect( mlt_property self, locale_t locale )
  * \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
  */
 
@@ -1370,8 +1620,21 @@ int mlt_property_anim_set_rect( mlt_property self, mlt_rect value, double fps, l
        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 ) )
        {
@@ -1389,5 +1652,6 @@ mlt_rect mlt_property_anim_get_rect( mlt_property self, double fps, locale_t loc
        {
                result = mlt_property_get_rect( self, locale );
        }
+       pthread_mutex_unlock( &self->mutex );
        return result;
 }