]> git.sesse.net Git - mlt/commitdiff
Add support for discrete animation including strings.
authorDan Dennedy <dan@dennedy.org>
Fri, 17 May 2013 05:38:16 +0000 (22:38 -0700)
committerDan Dennedy <dan@dennedy.org>
Fri, 31 May 2013 23:58:12 +0000 (16:58 -0700)
src/framework/mlt_animation.c
src/framework/mlt_animation.h
src/framework/mlt_property.c
src/tests/test_properties/test_properties.cpp

index 195b1af2ed62ac3ba45c18fbae4ccd68411a9682..449ee2fe0daceb8e4b46476af3dca43b57e4a9ea 100644 (file)
@@ -68,11 +68,18 @@ void mlt_animation_interpolate( mlt_animation self )
 
                                if ( !prev )
                                        current->item.is_key = 1;
-                               mlt_property_interpolate( current->item.property,
-                                       prev->item.property, next->item.property,
-                                       current->item.frame - prev->item.frame,
-                                       next->item.frame - prev->item.frame,
-                                       self->fps, self->locale );
+                               if ( current->item.keyframe_type == mlt_keyframe_discrete )
+                               {
+                                       mlt_property_pass( current->item.property, prev->item.property );
+                               }
+                               else
+                               {
+                                       mlt_property_interpolate( current->item.property,
+                                               prev->item.property, next->item.property,
+                                               current->item.frame - prev->item.frame,
+                                               next->item.frame - prev->item.frame,
+                                               self->fps, self->locale );
+                               }
                        }
 
                        // Move to the next item
@@ -219,9 +226,14 @@ int mlt_animation_parse_item( mlt_animation self, mlt_animation_item item, const
                                mlt_property_set_string( item->property, value );
                                item->frame = mlt_property_get_int( item->property, self->fps, self->locale );
                        }
-                       value = strchr( value, '=' ) + 1;
 
-                       // TODO the character preceeding the equal sign indicates method of interpolation.
+                       // The character preceeding the equal sign indicates interpolation method.
+                       p = strchr( value, '=' ) - 1;
+                       if ( p[0] == '|' )
+                               item->keyframe_type = mlt_keyframe_discrete;
+                       else
+                               item->keyframe_type = mlt_keyframe_linear;
+                       value = &p[2];
                }
 
                // Special case - frame < 0
@@ -257,6 +269,8 @@ int mlt_animation_get_item( mlt_animation self, mlt_animation_item item, int pos
 
        if ( node )
        {
+               item->keyframe_type = node->item.keyframe_type;
+
                // Position is before the first keyframe.
                if ( position < node->item.frame )
                {
@@ -279,9 +293,16 @@ int mlt_animation_get_item( mlt_animation self, mlt_animation_item item, int pos
                else
                {
                        item->is_key = 0;
-                       mlt_property_interpolate( item->property, node->item.property, node->next->item.property,
-                               position - node->item.frame, node->next->item.frame - node->item.frame,
-                               self->fps, self->locale );
+                       if ( node->item.keyframe_type == mlt_keyframe_discrete )
+                       {
+                               mlt_property_pass( item->property, node->item.property );
+                       }
+                       else
+                       {
+                               mlt_property_interpolate( item->property, node->item.property, node->next->item.property,
+                                       position - node->item.frame, node->next->item.frame - node->item.frame,
+                                       self->fps, self->locale );
+                       }
                }
        }
        else
@@ -301,6 +322,7 @@ int mlt_animation_insert( mlt_animation self, mlt_animation_item item )
        animation_node node = calloc( 1, sizeof( *node ) );
        node->item.frame = item->frame;
        node->item.is_key = 1;
+       node->item.keyframe_type = item->keyframe_type;
        node->item.property = mlt_property_init();
        mlt_property_pass( node->item.property, item->property );
 
@@ -337,6 +359,7 @@ int mlt_animation_insert( mlt_animation self, mlt_animation_item item )
                        // Update matching node.
                        current->item.frame = item->frame;
                        current->item.is_key = 1;
+                       current->item.keyframe_type = item->keyframe_type;
                        mlt_property_close( current->item.property );
                        current->item.property = node->item.property;
                        free( node );
@@ -378,6 +401,7 @@ int mlt_animation_next_key( mlt_animation self, mlt_animation_item item, int pos
        {
                item->frame = node->item.frame;
                item->is_key = node->item.is_key;
+               item->keyframe_type = node->item.keyframe_type;
                mlt_property_pass( item->property, node->item.property );
        }
 
@@ -396,6 +420,7 @@ int mlt_animation_prev_key( mlt_animation self, mlt_animation_item item, int pos
        {
                item->frame = node->item.frame;
                item->is_key = node->item.is_key;
+               item->keyframe_type = node->item.keyframe_type;
                mlt_property_pass( item->property, node->item.property );
        }
 
@@ -481,7 +506,18 @@ char *mlt_animation_serialize_cut( mlt_animation self, int in, int out )
                        {
                                // Append keyframe time and keyframe/value delimiter (=).
                                if ( item.frame - in != 0 )
-                                       sprintf( ret + used, "%d=", item.frame - in );
+                               {
+                                       const char *s;
+                                       switch (item.keyframe_type) {
+                                       case mlt_keyframe_discrete:
+                                               s = "|";
+                                               break;
+                                       default:
+                                               s = "";
+                                               break;
+                                       }
+                                       sprintf( ret + used, "%d%s=", item.frame - in, s );
+                               }
                                // Append item value.
                                if ( item.is_key )
                                        strcat( ret, mlt_property_get_string_l( item.property, self->locale ) );
index 313e193b779882d7a1cc3f472a53ea757513eecb..a0bb06292e1e625c0ba7ab6d695e1bea01e4c1e7 100644 (file)
 #include "mlt_types.h"
 #include "mlt_property.h"
 
+typedef enum {
+       mlt_keyframe_discrete,
+       mlt_keyframe_linear
+} mlt_keyframe_type;
+
 struct mlt_animation_item_s
 {
-
        int is_key; /**< = whether this is a key frame or an interpolated item */
        int frame; /**< The actual frame this corresponds to */
        mlt_property property;
+       mlt_keyframe_type keyframe_type;
 };
 typedef struct mlt_animation_item_s *mlt_animation_item;
 
index da41726eae20f4a0e53abf6abb74d365266092e8..21c6e08c7cd4f81c6e48ab47bbbdac5d64d7530d 100644 (file)
@@ -925,6 +925,29 @@ char *mlt_property_get_time( mlt_property self, mlt_time_format format, double f
        return self->prop_string;
 }
 
+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 );
+
+       // If not already numeric but string is numeric.
+       if ( ( !result && self->types & mlt_prop_string ) && self->prop_string )
+       {
+               double temp;
+               char *p = NULL;
+#if defined(__GLIBC__) || defined(__DARWIN__)
+               if ( locale )
+                       temp = strtod_l( self->prop_string, &p, locale );
+               else
+#endif
+               temp = strtod( self->prop_string, &p );
+               result = ( p != self->prop_string );
+       }
+       return result;
+}
+
 static inline double linearstep( double start, double end, double position, int length )
 {
        double o = ( end - start ) / length;
@@ -935,8 +958,7 @@ int mlt_property_interpolate(mlt_property self, mlt_property previous, mlt_prope
        double position, int length, double fps, locale_t locale )
 {
        int error = 0;
-
-       if ( fps > 0 )
+       if ( fps > 0 && is_property_numeric( previous, locale ) && is_property_numeric( next, locale ) )
        {
                double start = previous? mlt_property_get_double( previous, fps, locale ) : 0;
                double end = next? mlt_property_get_double( next, fps, locale ) : 0;
@@ -945,7 +967,7 @@ int mlt_property_interpolate(mlt_property self, mlt_property previous, mlt_prope
        }
        else
        {
-               error = 1;
+               mlt_property_pass( self, previous );
        }
        return error;
 }
index 35a01cdb4fa1839199fd8e717b20de139f12eac0..b8eb494cbd6c1eaab07ab71ee6d385b947b8d4b9 100644 (file)
@@ -352,6 +352,47 @@ private Q_SLOTS:
         mlt_animation_close(a);
     }
 
+    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;
+
+        mlt_animation_parse(a, "50=100; 60=60; 100=0", 100, fps, locale);
+        mlt_animation_remove(a, 60);
+        char *a_serialized = mlt_animation_serialize(a);
+        QCOMPARE(a_serialized, "50=100;100=0");
+        if (a_serialized) free(a_serialized);
+        item.property = mlt_property_init();
+
+        mlt_animation_get_item(a, &item, 10);
+        QCOMPARE(mlt_property_get_int(item.property, fps, locale), 100);
+        QCOMPARE(item.is_key, 0);
+
+        mlt_animation_get_item(a, &item, 50);
+        QCOMPARE(mlt_property_get_int(item.property, fps, locale), 100);
+        QCOMPARE(item.is_key, 1);
+
+        mlt_animation_get_item(a, &item, 75);
+        QCOMPARE(mlt_property_get_int(item.property, fps, locale), 50);
+        QCOMPARE(item.is_key, 0);
+
+        mlt_animation_get_item(a, &item, 100);
+        QCOMPARE(mlt_property_get_int(item.property, fps, locale), 0);
+        QCOMPARE(item.is_key, 1);
+
+        mlt_animation_get_item(a, &item, 110);
+        QCOMPARE(mlt_property_get_int(item.property, fps, locale), 0);
+        QCOMPARE(item.is_key, 0);
+
+        mlt_property_close(item.property);
+        mlt_animation_close(a);
+    }
+
     void AnimationWithTimeValueKeyframes()
     {
         locale_t locale;
@@ -392,6 +433,94 @@ private Q_SLOTS:
         mlt_property_close(item.property);
         mlt_animation_close(a);
     }
+
+    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;
+
+        mlt_animation_parse(a, "50|=100; 60|=60; 100|=0", 100, fps, locale);
+        char *a_serialized = mlt_animation_serialize(a);
+        QCOMPARE(a_serialized, "50|=100;60|=60;100|=0");
+        if (a_serialized) free(a_serialized);
+        item.property = mlt_property_init();
+
+        mlt_animation_get_item(a, &item, 10);
+        QCOMPARE(mlt_property_get_int(item.property, fps, locale), 100);
+        QCOMPARE(item.is_key, 0);
+
+        mlt_animation_get_item(a, &item, 50);
+        QCOMPARE(mlt_property_get_int(item.property, fps, locale), 100);
+        QCOMPARE(item.is_key, 1);
+
+        mlt_animation_get_item(a, &item, 55);
+        QCOMPARE(mlt_property_get_int(item.property, fps, locale), 100);
+        QCOMPARE(item.is_key, 0);
+
+        mlt_animation_get_item(a, &item, 60);
+        QCOMPARE(mlt_property_get_int(item.property, fps, locale), 60);
+        QCOMPARE(item.is_key, 1);
+
+        mlt_animation_get_item(a, &item, 75);
+        QCOMPARE(mlt_property_get_int(item.property, fps, locale), 60);
+        QCOMPARE(item.is_key, 0);
+
+        mlt_animation_get_item(a, &item, 100);
+        QCOMPARE(mlt_property_get_int(item.property, fps, locale), 0);
+        QCOMPARE(item.is_key, 1);
+
+        mlt_animation_get_item(a, &item, 110);
+        QCOMPARE(mlt_property_get_int(item.property, fps, locale), 0);
+        QCOMPARE(item.is_key, 0);
+
+        mlt_property_close(item.property);
+        mlt_animation_close(a);
+    }
+
+    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;
+
+        mlt_animation_parse(a, "50=hello world; 60=\"good night\"; 100=bar", 100, fps, locale);
+        char *a_serialized = mlt_animation_serialize(a);
+        QCOMPARE(a_serialized, "50=hello world;60=\"good night\";100=bar");
+        if (a_serialized) free(a_serialized);
+        item.property = mlt_property_init();
+
+        mlt_animation_get_item(a, &item, 10);
+        QCOMPARE(mlt_property_get_string(item.property), "hello world");
+        QCOMPARE(item.is_key, 0);
+
+        mlt_animation_get_item(a, &item, 50);
+        QCOMPARE(mlt_property_get_string(item.property), "hello world");
+        QCOMPARE(item.is_key, 1);
+
+        mlt_animation_get_item(a, &item, 75);
+        QCOMPARE(mlt_property_get_string(item.property), "\"good night\"");
+        QCOMPARE(item.is_key, 0);
+
+        mlt_animation_get_item(a, &item, 100);
+        QCOMPARE(mlt_property_get_string(item.property), "bar");
+        QCOMPARE(item.is_key, 1);
+
+        mlt_animation_get_item(a, &item, 110);
+        QCOMPARE(mlt_property_get_string(item.property), "bar");
+        QCOMPARE(item.is_key, 0);
+
+        mlt_property_close(item.property);
+        mlt_animation_close(a);
+    }
 };
 
 QTEST_APPLESS_MAIN(TestProperties)