]> git.sesse.net Git - mlt/blobdiff - src/framework/mlt_animation.c
Add Catmull-Rom spline smooth animation interpolation.
[mlt] / src / framework / mlt_animation.c
index 195b1af2ed62ac3ba45c18fbae4ccd68411a9682..b0791bd8dac0e7c8a23d69a7257c92b06b85b75e 100644 (file)
@@ -60,6 +60,8 @@ void mlt_animation_interpolate( mlt_animation self )
                {
                        if ( !current->item.is_key )
                        {
+                               double progress;
+                               mlt_property points[4];
                                animation_node prev = current->prev;
                                animation_node next = current->next;
 
@@ -68,11 +70,14 @@ 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 );
+                               points[0] = prev->prev? prev->prev->item.property : prev->item.property;
+                               points[1] = prev->item.property;
+                               points[2] = next->item.property;
+                               points[3] = next->next? next->next->item.property : next->item.property;
+                               progress = current->item.frame - prev->item.frame;
+                               progress /= next->item.frame - prev->item.frame;
+                               mlt_property_interpolate( current->item.property, points, progress,
+                                       self->fps, self->locale, current->item.keyframe_type );
                        }
 
                        // Move to the next item
@@ -219,19 +224,22 @@ 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] == '|' || p[0] == '!' )
+                               item->keyframe_type = mlt_keyframe_discrete;
+                       else if ( p[0] == '~' )
+                               item->keyframe_type = mlt_keyframe_smooth;
+                       else
+                               item->keyframe_type = mlt_keyframe_linear;
+                       value = &p[2];
                }
 
                // Special case - frame < 0
                if ( item->frame < 0 )
                        item->frame += self->length;
 
-               // Obtain the current value at this position - this allows new
-               // frames to be created which don't specify all values
-               mlt_animation_get_item( self, item, item->frame );
-
                // Set remainder of string as item value.
                mlt_property_set_string( item->property, value );
                item->is_key = 1;
@@ -257,6 +265,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 )
                {
@@ -278,10 +288,17 @@ int mlt_animation_get_item( mlt_animation self, mlt_animation_item item, int pos
                // Interpolation needed.
                else
                {
+                       double progress;
+                       mlt_property points[4];
+                       points[0] = node->prev? node->prev->item.property : node->item.property;
+                       points[1] = node->item.property;
+                       points[2] = node->next->item.property;
+                       points[3] = node->next->next? node->next->next->item.property : node->next->item.property;
+                       progress = position - node->item.frame;
+                       progress /= node->next->item.frame - node->item.frame;
+                       mlt_property_interpolate( item->property, points, progress,
+                               self->fps, self->locale, item->keyframe_type );
                        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 );
                }
        }
        else
@@ -301,6 +318,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 +355,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 +397,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 +416,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 );
        }
 
@@ -480,8 +501,20 @@ char *mlt_animation_serialize_cut( mlt_animation self, int in, int out )
                        if ( ret )
                        {
                                // 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;
+                               case mlt_keyframe_smooth:
+                                       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 ) );