]> git.sesse.net Git - mlt/commitdiff
Add mlt_rect and mlt_properties_set/get_rect.
authorDan Dennedy <dan@dennedy.org>
Mon, 27 May 2013 05:28:17 +0000 (22:28 -0700)
committerDan Dennedy <dan@dennedy.org>
Fri, 31 May 2013 23:58:12 +0000 (16:58 -0700)
src/framework/mlt_properties.c
src/framework/mlt_properties.h
src/framework/mlt_property.c
src/framework/mlt_property.h
src/framework/mlt_types.h
src/mlt++/MltProperties.cpp
src/mlt++/MltProperties.h
src/tests/test_properties/test_properties.cpp

index e96a1307e08a54ce65a83f5ad9bd0e6d6f4cbbb0..156316af7f624574365b5a47c6402bf914b200c8 100644 (file)
@@ -39,6 +39,7 @@
 #include <sys/stat.h>
 #include <errno.h>
 #include <locale.h>
+#include <float.h>
 
 #define PRESETS_DIR "/presets"
 
@@ -2107,3 +2108,48 @@ int mlt_properties_set_int_pos( mlt_properties self, const char *name, int value
        return error;
 }
 
+/** Set a property to a rectangle value.
+ *
+ * \public \memberof mlt_properties_s
+ * \param self a properties list
+ * \param name the property to set
+ * \param value the rectangle
+ * \return true if error
+ */
+
+extern int mlt_properties_set_rect( mlt_properties self, const char *name, mlt_rect value )
+{
+       int error = 1;
+
+       if ( !self || !name ) return error;
+
+       // Fetch the property to work with
+       mlt_property property = mlt_properties_fetch( self, name );
+
+       // Set it if not NULL
+       if ( property != NULL )
+       {
+               error = mlt_property_set_rect( property, value );
+               mlt_properties_do_mirror( self, name );
+       }
+
+       mlt_events_fire( self, "property-changed", name, NULL );
+
+       return error;
+}
+
+/** Get a rectangle associated to the name.
+ *
+ * \public \memberof mlt_properties_s
+ * \param self a properties list
+ * \param name the property to get
+ * \return The rectangle value, the rectangle fields will be DBL_MIN if not found
+ */
+
+extern mlt_rect mlt_properties_get_rect( mlt_properties self, const char* name )
+{
+       property_list *list = self->local;
+       mlt_property value = mlt_properties_find( self, name );
+       mlt_rect rect = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN };
+       return value == NULL ? rect : mlt_property_get_rect( value, list->locale );
+}
index 8aaa8a4b2ec64d88f90b5951733592aa12f5ad8a..45bbca1b751b31dbe82359583ab71054ded9f8db 100644 (file)
@@ -93,4 +93,7 @@ extern char *mlt_properties_get_time( mlt_properties, const char* name, mlt_time
 extern int mlt_properties_get_int_pos( mlt_properties self, const char *name, int position, int length );
 extern int mlt_properties_set_int_pos( mlt_properties self, const char *name, int value, mlt_keyframe_type keyframe_type, int position, int length );
 
+extern int mlt_properties_set_rect( mlt_properties self, const char *name, mlt_rect value );
+extern mlt_rect mlt_properties_get_rect( mlt_properties self, const char *name );
+
 #endif
index 8604e31f1a5aa60b6c7084f4a3db0fd92bac2745..e86f2f1c1e332a081f15e2d89b478cecacb17f48 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;
@@ -484,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;
@@ -509,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;
@@ -549,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;
@@ -752,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;
@@ -932,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 )
@@ -974,24 +995,96 @@ int mlt_property_interpolate( mlt_property self, mlt_property p[],
        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 )
+                       {
+                               int i = 5;
+                               mlt_rect points[2];
+                               mlt_rect zero = {0, 0, 0, 0, 0};
+                               points[0] = p[1]? mlt_property_get_rect( p[1], locale ) : zero;
+                               points[1] = p[2]? mlt_property_get_rect( p[2], locale ) : zero;
+                               while ( i-- ) switch ( i )
+                               {
+                                       case 0: value.x = p[2]?
+                                                       linear_interpolate( points[0].x, points[1].x, progress ):
+                                                       points[0].x;
+                                               break;
+                                       case 1: value.y = p[2]?
+                                                       linear_interpolate( points[0].y, points[1].y, progress ):
+                                                       points[0].y;
+                                               break;
+                                       case 2: value.w = p[2]?
+                                                       linear_interpolate( points[0].w, points[1].w, progress ):
+                                                       points[0].w;
+                                               break;
+                                       case 3: value.h = p[2]?
+                                                       linear_interpolate( points[0].h, points[1].h, progress ):
+                                                       points[0].h;
+                                               break;
+                                       case 4: value.o = p[2]?
+                                                       linear_interpolate( points[0].o, points[1].o, progress ):
+                                                       points[0].o;
+                                               break;
+                               }
+                       }
+                       else if ( interp == mlt_keyframe_smooth )
+                       {
+                               int i = 5;
+                               mlt_rect points[4];
+                               mlt_rect zero = {0, 0, 0, 0, 0};
+                               points[0] = p[0]? mlt_property_get_rect( p[0], locale ) : zero;
+                               points[1] = p[1]? mlt_property_get_rect( p[1], 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;
+                               while ( i-- ) switch ( i )
+                               {
+                                       case 0: value.x = p[2]?
+                                                       catmull_rom_interpolate( points[0].x, points[1].x, points[2].x, points[3].x, progress ):
+                                                       points[1].x;
+                                               break;
+                                       case 1: value.y = p[2]?
+                                                       catmull_rom_interpolate( points[0].y, points[1].y, points[2].y, points[3].y, progress ):
+                                                       points[1].y;
+                                               break;
+                                       case 2: value.w = p[2]?
+                                                       catmull_rom_interpolate( points[0].w, points[1].w, points[2].w, points[3].w, progress ):
+                                                       points[1].w;
+                                               break;
+                                       case 3: value.h = p[2]?
+                                                       catmull_rom_interpolate( points[0].h, points[1].h, points[2].h, points[3].h, progress ):
+                                                       points[1].h;
+                                               break;
+                                       case 4: value.o = p[2]?
+                                                       catmull_rom_interpolate( points[0].o, points[1].o, points[2].o, points[3].o, progress ):
+                                                       points[1].o;
+                                               break;
+                               }
+                       }
+                       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
        {
@@ -1118,3 +1211,101 @@ int mlt_property_set_int_pos( mlt_property self, int value, double fps, locale_t
 
        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 ) 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;
+}
index 07fe6631b3a5268e0db1e59b391183637e05ffc9..e520389022b80c5a0057e823ad59f51696f55149 100644 (file)
@@ -62,5 +62,6 @@ extern int mlt_property_set_double_pos( mlt_property self, double value, double
                                         mlt_keyframe_type keyframe_type, int position, int length );
 extern int mlt_property_set_int_pos( mlt_property self, int value, double fps, locale_t locale,
                                      mlt_keyframe_type keyframe_type, int position, int length );
-
+extern int mlt_property_set_rect( mlt_property self, mlt_rect value );
+extern mlt_rect mlt_property_get_rect( mlt_property self, locale_t locale );
 #endif
index 41e42c8d83e6b6bd477027a54e0559f3a1d48860..fbd41900b30fbd8c465614b6237e591117d320eb 100644 (file)
@@ -123,6 +123,14 @@ typedef double mlt_position;
 typedef int32_t mlt_position;
 #endif
 
+typedef struct {
+       double x; /**< X coordinate */
+       double y; /**< Y coordinate */
+       double w; /**< width */
+       double h; /**< height */
+       double o; /**< opacity / mix-level */
+} mlt_rect;
+
 typedef struct mlt_frame_s *mlt_frame, **mlt_frame_ptr; /**< pointer to Frame object */
 typedef struct mlt_property_s *mlt_property;            /**< pointer to Property object */
 typedef struct mlt_properties_s *mlt_properties;        /**< pointer to Properties object */
index 734d2c3babf1954acf6f64b750aa3016318d62c0..9657600a01b8cc63f5d293355ec19287f905f352 100644 (file)
@@ -346,3 +346,19 @@ int Properties::set( const char *name, int value, int position, int length, mlt_
 {
        return mlt_properties_set_int_pos( get_properties(), name, value, keyframe_type, position, length );
 }
+
+int Properties::set( const char *name, mlt_rect value )
+{
+       return mlt_properties_set_rect( get_properties(), name, value );
+}
+
+int Properties::set( const char *name, double x, double y, double w, double h, double opacity )
+{
+       mlt_rect value = { x, y, w, h, opacity };
+       return mlt_properties_set_rect( get_properties(), name, value );
+}
+
+mlt_rect Properties::get_rect( const char *name )
+{
+       return mlt_properties_get_rect( get_properties(), name );
+}
index a174708abf071bd9956856e78dca1414f6744268..d867f67e82d4d5d64b6206d598421547033d6426 100644 (file)
@@ -100,6 +100,9 @@ namespace Mlt
                        int get_int( const char *name, int position, int length );
                        int set( const char *name, int value, int position, int length,
                                mlt_keyframe_type keyframe_type = mlt_keyframe_linear );
+                       int set( const char *name, mlt_rect value );
+                       int set( const char *name, double x, double y, double w, double h, double opacity = 1.0 );
+                       mlt_rect get_rect( const char* name );
        };
 }
 
index 296b7f35834b86d406ce2a7d30991bbf122bbec4..5ce0228786bd876d189d8a48383fc44254cfbd11 100644 (file)
@@ -27,13 +27,19 @@ extern "C" {
 #include <framework/mlt_property.h>
 #include <framework/mlt_animation.h>
 }
+#include <cfloat>
 
 class TestProperties: public QObject
 {
     Q_OBJECT
+    locale_t locale;
 
 public:
-    TestProperties() {}
+    TestProperties() {
+#if defined(__linux__) || defined(__DARWIN__)
+        locale = newlocale( LC_NUMERIC_MASK, "POSIX", NULL );
+#endif
+    }
 
 private Q_SLOTS:
     void InstantiationIsAReference()
@@ -313,10 +319,6 @@ private Q_SLOTS:
 
     void DoubleAnimation()
     {
-        locale_t locale;
-#if defined(__linux__) || defined(__DARWIN__)
-        locale = newlocale( LC_NUMERIC_MASK, "POSIX", NULL );
-#endif
         double fps = 25.0;
         mlt_animation a = mlt_animation_new();
         struct mlt_animation_item_s item;
@@ -354,10 +356,6 @@ private Q_SLOTS:
 
     void IntAnimation()
     {
-        locale_t locale;
-#if defined(__linux__) || defined(__DARWIN__)
-        locale = newlocale( LC_NUMERIC_MASK, "POSIX", NULL );
-#endif
         double fps = 25.0;
         mlt_animation a = mlt_animation_new();
         struct mlt_animation_item_s item;
@@ -395,10 +393,6 @@ private Q_SLOTS:
 
     void AnimationWithTimeValueKeyframes()
     {
-        locale_t locale;
-#if defined(__linux__) || defined(__DARWIN__)
-        locale = newlocale( LC_NUMERIC_MASK, "POSIX", NULL );
-#endif
         double fps = 25.0;
         mlt_animation a = mlt_animation_new();
         struct mlt_animation_item_s item;
@@ -436,10 +430,6 @@ private Q_SLOTS:
 
     void DiscreteIntAnimation()
     {
-        locale_t locale;
-#if defined(__linux__) || defined(__DARWIN__)
-        locale = newlocale( LC_NUMERIC_MASK, "POSIX", NULL );
-#endif
         double fps = 25.0;
         mlt_animation a = mlt_animation_new();
         struct mlt_animation_item_s item;
@@ -484,10 +474,6 @@ private Q_SLOTS:
 
     void StringAnimation()
     {
-        locale_t locale;
-#if defined(__linux__) || defined(__DARWIN__)
-        locale = newlocale( LC_NUMERIC_MASK, "POSIX", NULL );
-#endif
         double fps = 25.0;
         mlt_animation a = mlt_animation_new();
         struct mlt_animation_item_s item;
@@ -524,10 +510,6 @@ private Q_SLOTS:
 
     void test_property_get_double_pos()
     {
-        locale_t locale;
-#if defined(__linux__) || defined(__DARWIN__)
-        locale = newlocale( LC_NUMERIC_MASK, "POSIX", NULL );
-#endif
         double fps = 25.0;
         mlt_property p = mlt_property_init();
         mlt_property_set_string(p, "10=100; 20=200");
@@ -545,10 +527,6 @@ private Q_SLOTS:
 
     void test_property_get_int_pos()
     {
-        locale_t locale;
-#if defined(__linux__) || defined(__DARWIN__)
-        locale = newlocale( LC_NUMERIC_MASK, "POSIX", NULL );
-#endif
         double fps = 25.0;
         mlt_property p = mlt_property_init();
         mlt_property_set_string(p, "10=100; 20=200");
@@ -566,10 +544,6 @@ private Q_SLOTS:
 
     void SmoothIntAnimation()
     {
-        locale_t locale;
-#if defined(__linux__) || defined(__DARWIN__)
-        locale = newlocale( LC_NUMERIC_MASK, "POSIX", NULL );
-#endif
         double fps = 25.0;
         mlt_animation a = mlt_animation_new();
         struct mlt_animation_item_s item;
@@ -614,10 +588,6 @@ private Q_SLOTS:
 
     void test_property_set_double_pos()
     {
-        locale_t locale;
-#if defined(__linux__) || defined(__DARWIN__)
-        locale = newlocale( LC_NUMERIC_MASK, "POSIX", NULL );
-#endif
         double fps = 25.0;
         mlt_property p = mlt_property_init();
         mlt_property_set_string(p, "10=100; 20=200");
@@ -633,10 +603,6 @@ private Q_SLOTS:
 
     void test_property_set_int_pos()
     {
-        locale_t locale;
-#if defined(__linux__) || defined(__DARWIN__)
-        locale = newlocale( LC_NUMERIC_MASK, "POSIX", NULL );
-#endif
         double fps = 25.0;
         mlt_property p = mlt_property_init();
         mlt_property_set_string(p, "10=100; 20=200");
@@ -688,6 +654,83 @@ private Q_SLOTS:
         QCOMPARE(p.get_int("foo", 25, len), 150);
         QCOMPARE(p.get_int("foo", 50, len), 200);
     }
+
+    void test_mlt_rect()
+    {
+        mlt_property p = mlt_property_init();
+        mlt_rect r = { 1, 2, 3, 4, 5 };
+
+        mlt_property_set_rect( p, r );
+        QCOMPARE(mlt_property_get_string(p), "1 2 3 4 5");
+        r.o = DBL_MIN;
+        mlt_property_set_rect( p, r );
+        QCOMPARE(mlt_property_get_string(p), "1 2 3 4");
+        r.w = DBL_MIN;
+        r.h = DBL_MIN;
+        mlt_property_set_rect( p, r );
+        QCOMPARE(mlt_property_get_string(p), "1 2");
+
+        mlt_property_set_string(p, "1.1/2.2:3.3x4.4:5.5");
+        r = mlt_property_get_rect(p, locale);
+        QCOMPARE(r.x, 1.1);
+        QCOMPARE(r.y, 2.2);
+        QCOMPARE(r.w, 3.3);
+        QCOMPARE(r.h, 4.4);
+        QCOMPARE(r.o, 5.5);
+
+        mlt_property_set_string(p, "1.1 2.2");
+        r = mlt_property_get_rect(p, locale);
+        QCOMPARE(r.x, 1.1);
+        QCOMPARE(r.y, 2.2);
+        QCOMPARE(r.w, DBL_MIN);
+
+        mlt_property_set_int64(p, UINT_MAX);
+        r = mlt_property_get_rect(p, locale);
+        QCOMPARE(r.x, double(UINT_MAX));
+
+        mlt_property_close(p);
+    }
+
+    void SetAndGetRect()
+    {
+        Properties p;
+        mlt_rect r;
+        r.x = 1.1;
+        r.y = 2.2;
+        r.w = 3.3;
+        r.h = 4.4;
+        r.o = 5.5;
+        p.set("key", r);
+        mlt_rect q = p.get_rect("key");
+        QCOMPARE(q.x, 1.1);
+        QCOMPARE(q.y, 2.2);
+        QCOMPARE(q.w, 3.3);
+        QCOMPARE(q.h, 4.4);
+        QCOMPARE(q.o, 5.5);
+        p.set("key", 10, 20, 30, 40);
+        q = p.get_rect("key");
+        QCOMPARE(q.x, 10.0);
+        QCOMPARE(q.y, 20.0);
+        QCOMPARE(q.w, 30.0);
+        QCOMPARE(q.h, 40.0);
+    }
+
+    void RectFromString()
+    {
+        Properties p;
+        p.set_lcnumeric("POSIX");
+        const char *s = "1.1 2.2 3.3 4.4 5.5";
+        mlt_rect r = { 1.1, 2.2, 3.3, 4.4, 5.5 };
+        p.set("key", r);
+        QCOMPARE(p.get("key"), s);
+        p.set("key", s);
+        r = p.get_rect("key");
+        QCOMPARE(r.x, 1.1);
+        QCOMPARE(r.y, 2.2);
+        QCOMPARE(r.w, 3.3);
+        QCOMPARE(r.h, 4.4);
+        QCOMPARE(r.o, 5.5);
+    }
 };
 
 QTEST_APPLESS_MAIN(TestProperties)