]> git.sesse.net Git - mlt/blobdiff - src/framework/mlt_animation.c
race condition fix
[mlt] / src / framework / mlt_animation.c
index b0791bd8dac0e7c8a23d69a7257c92b06b85b75e..5928b0d3cb1bded514866cb1254cf8eb1650ecea 100644 (file)
@@ -1,8 +1,11 @@
-/*
- * mlt_animation.c -- provides the property animation API
+/**
+ * \file mlt_animation.c
+ * \brief Property Animation class definition
+ * \see mlt_animation_s
+ *
  * Copyright (C) 2004-2013 Ushodaya Enterprises Limited
- * Author: Charles Yates <charles.yates@pandora.be>
- * Author: Dan Dennedy <dan@dennedy.org>
+ * \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
 #include <stdlib.h>
 #include <string.h>
 
+/** \brief animation list node pointer */
 typedef struct animation_node_s *animation_node;
+/** \brief private animation list node */
 struct animation_node_s
 {
        struct mlt_animation_item_s item;
        animation_node next, prev;
 };
 
+/** \brief Property Animation class
+ *
+ * This is the animation engine for a Property object. It is dependent upon
+ * the mlt_property API and used by the various mlt_property_anim_* functions.
+ */
+
 struct mlt_animation_s
 {
-       char *data;
-       int length;
-       double fps;
-       locale_t locale;
-       animation_node nodes;
+       char *data;           /**< the string representing the animation */
+       int length;           /**< the maximum number of frames to use when interpreting negative keyframe positions */
+       double fps;           /**< framerate to use when converting time clock strings to frame units */
+       locale_t locale;      /**< pointer to a locale to use when converting strings to numeric values */
+       animation_node nodes; /**< a linked list of keyframes (and possibly non-keyframe values) */
 };
 
-// Create a new geometry structure
+/** Create a new animation object.
+ *
+ * \public \memberof mlt_animation_s
+ * \return an animation object
+ */
+
 mlt_animation mlt_animation_new( )
 {
        mlt_animation self = calloc( 1, sizeof( *self ) );
        return self;
 }
 
+/** Re-interpolate non-keyframe nodess after a series of insertions or removals.
+ *
+ * \public \memberof mlt_animation_s
+ * \param self an animation
+ */
+
 void mlt_animation_interpolate( mlt_animation self )
 {
        // Parse all items to ensure non-keyframes are calculated correctly.
@@ -68,8 +90,13 @@ void mlt_animation_interpolate( mlt_animation self )
                                while ( prev && !prev->item.is_key ) prev = prev->prev;
                                while ( next && !next->item.is_key ) next = next->next;
 
-                               if ( !prev )
+                               if ( !prev ) {
                                        current->item.is_key = 1;
+                                       prev = current;
+                               }
+                               if ( !next ) {
+                                       next = current;
+                               }
                                points[0] = prev->prev? prev->prev->item.property : prev->item.property;
                                points[1] = prev->item.property;
                                points[2] = next->item.property;
@@ -86,6 +113,14 @@ void mlt_animation_interpolate( mlt_animation self )
        }
 }
 
+/** Remove a node from the linked list.
+ *
+ * \private \memberof mlt_animation_s
+ * \param self an animation
+ * \param node the node to remove
+ * \return false
+ */
+
 static int mlt_animation_drop( mlt_animation self, animation_node node )
 {
        if ( node == self->nodes )
@@ -115,6 +150,12 @@ static int mlt_animation_drop( mlt_animation self, animation_node node )
        return 0;
 }
 
+/** Reset an animation and free all strings and properties.
+ *
+ * \private \memberof mlt_animation_s
+ * \param self an animation
+ */
+
 static void mlt_animation_clean( mlt_animation self )
 {
        if ( self->data )
@@ -124,6 +165,19 @@ static void mlt_animation_clean( mlt_animation self )
                mlt_animation_drop( self, self->nodes );
 }
 
+/** Parse a string representing an animation.
+ *
+ * A semicolon is the delimiter between keyframe=value items in the string.
+ * \public \memberof mlt_animation_s
+ * \param self an animation
+ * \param data the string representing an animation
+ * \param length the maximum number of frames when interpreting negative keyframe times,
+ *  <=0 if you don't care or need that
+ * \param fps the framerate to use when evaluating time strings
+ * \param locale the locale to use when converting strings to numbers
+ * \return true if there was an error
+ */
+
 int mlt_animation_parse(mlt_animation self, const char *data, int length, double fps, locale_t locale )
 {
        int error = 0;
@@ -173,28 +227,83 @@ int mlt_animation_parse(mlt_animation self, const char *data, int length, double
        return error;
 }
 
-// Conditionally refresh in case of a change
-int mlt_animation_refresh(mlt_animation self, const char *data, int length)
+/** Conditionally refresh the animation if it is modified.
+ *
+ * \public \memberof mlt_animation_s
+ * \param self an animation
+ * \param data the string representing an animation
+ * \param length the maximum number of frames when interpreting negative keyframe times,
+ *  <=0 if you don't care or need that
+ * \return true if there was an error
+ */
+
+int mlt_animation_refresh( mlt_animation self, const char *data, int length )
 {
        if ( ( length != self->length )|| ( data && ( !self->data || strcmp( data, self->data ) ) ) )
                return mlt_animation_parse( self, data, length, self->fps, self->locale );
        return 0;
 }
 
+/** Get the length of the animation.
+ *
+ * If the animation was initialized with a zero or negative value, then this
+ * gets the maximum frame number from animation's list of nodes.
+ * \public \memberof mlt_animation_s
+ * \param self an animation
+ * \return the number of frames
+ */
+
 int mlt_animation_get_length( mlt_animation self )
 {
-       if ( self )
-               return self->length;
-       else
-               return 0;
+       int length = 0;
+       if ( self ) {
+               if ( self->length > 0 ) {
+                       length = self->length;
+               }
+               else if ( self->nodes ) {
+                       animation_node node = self->nodes;
+                       while ( node ) {
+                               if ( node->item.frame > length )
+                                       length = node->item.frame;
+                               node = node->next;
+                       }
+               }
+       }
+       return length;
 }
 
+/** Set the length of the animation.
+ *
+ * The length is used for interpreting negative keyframe positions as relative
+ * to the length. It is also used when serializing an animation as a string.
+ * \public \memberof mlt_animation_s
+ * \param self an animation
+ * \param length the length of the animation in frame units
+ */
+
 void mlt_animation_set_length( mlt_animation self, int length )
 {
        if ( self )
                self->length = length;
 }
 
+/** Parse a string representing an animation keyframe=value.
+ *
+ * This function does not affect the animation itself! But it will use some state
+ * of the animation for the parsing (e.g. fps, locale).
+ * It parses into a mlt_animation_item that you provide.
+ * \p item->frame should be specified if the string does not have an equal sign and time field.
+ * If an exclamation point (!) or vertical bar (|) character preceeds the equal sign, then
+ * the keyframe interpolation is set to discrete. If a tilde (~) preceeds the equal sign,
+ * then the keyframe interpolation is set to smooth (spline).
+ *
+ * \public \memberof mlt_animation_s
+ * \param self an animation
+ * \param item an already allocated animation item
+ * \param value the string representing an animation
+ * \return true if there was an error
+ */
+
 int mlt_animation_parse_item( mlt_animation self, mlt_animation_item item, const char *value )
 {
        int error = 0;
@@ -204,26 +313,16 @@ int mlt_animation_parse_item( mlt_animation self, mlt_animation_item item, const
                // Determine if a position has been specified
                if ( strchr( value, '=' ) )
                {
-                       double temp;
-                       char *p = NULL;
-#if defined(__GLIBC__) || defined(__DARWIN__)
-                       if ( self->locale )
-                               temp = strtod_l( value, &p, self->locale );
-                       else
-#endif
-                       temp = strtod( value, &p );
-                       // If p == value then it is likely a time clock or time code.
-                       if ( temp > -1.0 && temp < 1.0 && p != value )
-                       {
-                               // Parse a relative time (-1, 1).
-                               item->frame = temp * self->length;
-                       }
-                       else
-                       {
-                               // Parse an absolute time value.
-                               mlt_property_set_string( item->property, value );
-                               item->frame = mlt_property_get_int( item->property, self->fps, self->locale );
-                       }
+                       // Parse an absolute time value.
+                       // Null terminate the string at the equal sign to prevent interpreting
+                       // a colon in the part to the right of the equal sign as indicative of a
+                       // a time value string.
+                       char *s = strdup( value );
+                       char *p = strchr( s, '=' );
+                       p[0] = '\0';
+                       mlt_property_set_string( item->property, s );
+                       item->frame = mlt_property_get_int( item->property, self->fps, self->locale );
+                       free( s );
 
                        // The character preceeding the equal sign indicates interpolation method.
                        p = strchr( value, '=' ) - 1;
@@ -238,7 +337,7 @@ int mlt_animation_parse_item( mlt_animation self, mlt_animation_item item, const
 
                // Special case - frame < 0
                if ( item->frame < 0 )
-                       item->frame += self->length;
+                       item->frame += mlt_animation_get_length( self );
 
                // Set remainder of string as item value.
                mlt_property_set_string( item->property, value );
@@ -252,7 +351,16 @@ int mlt_animation_parse_item( mlt_animation self, mlt_animation_item item, const
        return error;
 }
 
-// Fetch a geometry item for an absolute position
+/** Load an animation item for an absolute position.
+ *
+ * This performs interpolation if there is no keyframe at the \p position.
+ * \public \memberof mlt_animation_s
+ * \param self an animation
+ * \param item an already allocated animation item that will be filled in
+ * \param position the frame number for the point in time
+ * \return true if there was an error
+ */
+
 int mlt_animation_get_item( mlt_animation self, mlt_animation_item item, int position )
 {
        int error = 0;
@@ -311,7 +419,15 @@ int mlt_animation_get_item( mlt_animation self, mlt_animation_item item, int pos
        return error;
 }
 
-// Specify an animation item at an absolute position
+/** Insert an animation item.
+ *
+ * \public \memberof mlt_animation_s
+ * \param self an animation
+ * \param item an animation item
+ * \return true if there was an error
+ * \see mlt_animation_parse_item
+ */
+
 int mlt_animation_insert( mlt_animation self, mlt_animation_item item )
 {
        int error = 0;
@@ -370,7 +486,14 @@ int mlt_animation_insert( mlt_animation self, mlt_animation_item item )
        return error;
 }
 
-// Remove the keyframe at the specified position
+/** Remove the keyframe at the specified position.
+ *
+ * \public \memberof mlt_animation_s
+ * \param self an animation
+ * \param position the frame number of the animation node to remove
+ * \return true if there was an error
+ */
+
 int mlt_animation_remove( mlt_animation self, int position )
 {
        int error = 1;
@@ -385,7 +508,15 @@ int mlt_animation_remove( mlt_animation self, int position )
        return error;
 }
 
-// Get the keyfame at the position or the next following
+/** Get the keyfame at the position or the next following.
+ *
+ * \public \memberof mlt_animation_s
+ * \param self an animation
+ * \param item an already allocated animation item which will be updated
+ * \param position the frame number at which to start looking for the next animation node
+ * \return true if there was an error
+ */
+
 int mlt_animation_next_key( mlt_animation self, mlt_animation_item item, int position )
 {
        animation_node node = self->nodes;
@@ -404,7 +535,15 @@ int mlt_animation_next_key( mlt_animation self, mlt_animation_item item, int pos
        return ( node == NULL );
 }
 
-// Get the keyframe at the position or the previous key
+/** Get the keyfame at the position or the next preceeding.
+ *
+ * \public \memberof mlt_animation_s
+ * \param self an animation
+ * \param item an already allocated animation item which will be updated
+ * \param position the frame number at which to start looking for the previous animation node
+ * \return true if there was an error
+ */
+
 int mlt_animation_prev_key( mlt_animation self, mlt_animation_item item, int position )
 {
        animation_node node = self->nodes;
@@ -423,6 +562,16 @@ int mlt_animation_prev_key( mlt_animation self, mlt_animation_item item, int pos
        return ( node == NULL );
 }
 
+/** Serialize a cut of the animation.
+ *
+ * The caller is responsible for free-ing the returned string.
+ * \public \memberof mlt_animation_s
+ * \param self an animation
+ * \param in the frame at which to start serializing animation nodes
+ * \param out the frame at which to stop serializing nodes
+ * \return a string representing the animation
+ */
+
 char *mlt_animation_serialize_cut( mlt_animation self, int in, int out )
 {
        struct mlt_animation_item_s item;
@@ -528,20 +677,33 @@ char *mlt_animation_serialize_cut( mlt_animation self, int in, int out )
        return ret;
 }
 
-// Serialise the current geometry
+/** Serialize the animation.
+ *
+ * The caller is responsible for free-ing the returned string.
+ * \public \memberof mlt_animation_s
+ * \param self an animation
+ * \return a string representing the animation
+ */
+
 char *mlt_animation_serialize( mlt_animation self )
 {
-       char *ret = mlt_animation_serialize_cut( self, 0, self->length );
+       char *ret = mlt_animation_serialize_cut( self, -1, -1 );
        if ( ret )
        {
                if ( self->data )
                        free( self->data );
                self->data = ret;
+               ret = strdup( ret );
        }
-       return strdup( ret );
+       return ret;
 }
 
-// Close the geometry
+/** Close the animation and deallocate all of its resources.
+ *
+ * \public \memberof mlt_animation_s
+ * \param self the animation to destroy
+ */
+
 void mlt_animation_close( mlt_animation self )
 {
        if ( self )