2 * \file mlt_animation.c
3 * \brief Property Animation class definition
6 * Copyright (C) 2004-2013 Ushodaya Enterprises Limited
7 * \author Charles Yates <charles.yates@pandora.be>
8 * \author Dan Dennedy <dan@dennedy.org>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "mlt_animation.h"
26 #include "mlt_tokeniser.h"
27 #include "mlt_profile.h"
33 /** \brief animation list node pointer */
34 typedef struct animation_node_s *animation_node;
35 /** \brief private animation list node */
36 struct animation_node_s
38 struct mlt_animation_item_s item;
39 animation_node next, prev;
42 /** \brief Property Animation class
44 * This is the animation engine for a Property object. It is dependent upon
45 * the mlt_property API and used by the various mlt_property_anim_* functions.
48 struct mlt_animation_s
50 char *data; /**< the string representing the animation */
51 int length; /**< the maximum number of frames to use when interpreting negative keyframe positions */
52 double fps; /**< framerate to use when converting time clock strings to frame units */
53 locale_t locale; /**< pointer to a locale to use when converting strings to numeric values */
54 animation_node nodes; /**< a linked list of keyframes (and possibly non-keyframe values) */
57 /** Create a new animation object.
59 * \public \memberof mlt_animation_s
60 * \return an animation object
63 mlt_animation mlt_animation_new( )
65 mlt_animation self = calloc( 1, sizeof( *self ) );
69 /** Re-interpolate non-keyframe nodess after a series of insertions or removals.
71 * \public \memberof mlt_animation_s
72 * \param self an animation
75 void mlt_animation_interpolate( mlt_animation self )
77 // Parse all items to ensure non-keyframes are calculated correctly.
80 animation_node current = self->nodes;
83 if ( !current->item.is_key )
86 mlt_property points[4];
87 animation_node prev = current->prev;
88 animation_node next = current->next;
90 while ( prev && !prev->item.is_key ) prev = prev->prev;
91 while ( next && !next->item.is_key ) next = next->next;
94 current->item.is_key = 1;
95 points[0] = prev->prev? prev->prev->item.property : prev->item.property;
96 points[1] = prev->item.property;
97 points[2] = next->item.property;
98 points[3] = next->next? next->next->item.property : next->item.property;
99 progress = current->item.frame - prev->item.frame;
100 progress /= next->item.frame - prev->item.frame;
101 mlt_property_interpolate( current->item.property, points, progress,
102 self->fps, self->locale, current->item.keyframe_type );
105 // Move to the next item
106 current = current->next;
111 /** Remove a node from the linked list.
113 * \private \memberof mlt_animation_s
114 * \param self an animation
115 * \param node the node to remove
119 static int mlt_animation_drop( mlt_animation self, animation_node node )
121 if ( node == self->nodes )
123 self->nodes = node->next;
125 self->nodes->prev = NULL;
126 self->nodes->item.is_key = 1;
129 else if ( node->next && node->prev )
131 node->prev->next = node->next;
132 node->next->prev = node->prev;
134 else if ( node->next )
136 node->next->prev = node->prev;
138 else if ( node->prev )
140 node->prev->next = node->next;
142 mlt_property_close( node->item.property );
148 /** Reset an animation and free all strings and properties.
150 * \private \memberof mlt_animation_s
151 * \param self an animation
154 static void mlt_animation_clean( mlt_animation self )
159 while ( self->nodes )
160 mlt_animation_drop( self, self->nodes );
163 /** Parse a string representing an animation.
165 * A semicolon is the delimiter between keyframe=value items in the string.
166 * \public \memberof mlt_animation_s
167 * \param self an animation
168 * \param data the string representing an animation
169 * \param length the maximum number of frames when interpreting negative keyframe times,
170 * <=0 if you don't care or need that
171 * \param fps the framerate to use when evaluating time strings
172 * \param locale the locale to use when converting strings to numbers
173 * \return true if there was an error
176 int mlt_animation_parse(mlt_animation self, const char *data, int length, double fps, locale_t locale )
180 struct mlt_animation_item_s item;
181 mlt_tokeniser tokens = mlt_tokeniser_init( );
183 // Clean the existing geometry
184 mlt_animation_clean( self );
186 // Update the info on the data
188 self->data = strdup( data );
189 self->length = length;
191 self->locale = locale;
192 item.property = mlt_property_init();
196 mlt_tokeniser_parse_new( tokens, (char*) data, ";" );
198 // Iterate through each token
199 for ( i = 0; i < mlt_tokeniser_count( tokens ); i++ )
201 char *value = mlt_tokeniser_get_string( tokens, i );
203 // If no data in keyframe, drop it (trailing semicolon)
204 if ( !value || !strcmp( value, "" ) )
208 item.frame = item.is_key = 0;
210 // Now parse the item
211 mlt_animation_parse_item( self, &item, value );
213 // Now insert into place
214 mlt_animation_insert( self, &item );
216 mlt_animation_interpolate( self );
219 mlt_tokeniser_close( tokens );
220 mlt_property_close( item.property );
225 /** Conditionally refresh the animation if it is modified.
227 * \public \memberof mlt_animation_s
228 * \param self an animation
229 * \param data the string representing an animation
230 * \param length the maximum number of frames when interpreting negative keyframe times,
231 * <=0 if you don't care or need that
232 * \return true if there was an error
235 int mlt_animation_refresh( mlt_animation self, const char *data, int length )
237 if ( ( length != self->length )|| ( data && ( !self->data || strcmp( data, self->data ) ) ) )
238 return mlt_animation_parse( self, data, length, self->fps, self->locale );
242 /** Get the length of the animation.
244 * If the animation was initialized with a zero or negative value, then this
245 * gets the maximum frame number from animation's list of nodes.
246 * \public \memberof mlt_animation_s
247 * \param self an animation
248 * \return the number of frames
251 int mlt_animation_get_length( mlt_animation self )
255 if ( self->length > 0 ) {
256 length = self->length;
258 else if ( self->nodes ) {
259 animation_node node = self->nodes;
261 if ( node->item.frame > length )
262 length = node->item.frame;
270 /** Set the length of the animation.
272 * The length is used for interpreting negative keyframe positions as relative
273 * to the length. It is also used when serializing an animation as a string.
274 * \public \memberof mlt_animation_s
275 * \param self an animation
276 * \param length the length of the animation in frame units
279 void mlt_animation_set_length( mlt_animation self, int length )
282 self->length = length;
285 /** Parse a string representing an animation keyframe=value.
287 * This function does not affect the animation itself! But it will use some state
288 * of the animation for the parsing (e.g. fps, locale).
289 * It parses into a mlt_animation_item that you provide.
290 * \p item->frame should be specified if the string does not have an equal sign and time field.
291 * If an exclamation point (!) or vertical bar (|) character preceeds the equal sign, then
292 * the keyframe interpolation is set to discrete. If a tilde (~) preceeds the equal sign,
293 * then the keyframe interpolation is set to smooth (spline).
295 * \public \memberof mlt_animation_s
296 * \param self an animation
297 * \param item an already allocated animation item
298 * \param value the string representing an animation
299 * \return true if there was an error
302 int mlt_animation_parse_item( mlt_animation self, mlt_animation_item item, const char *value )
306 if ( value && strcmp( value, "" ) )
308 // Determine if a position has been specified
309 if ( strchr( value, '=' ) )
311 // Parse an absolute time value.
312 // Null terminate the string at the equal sign to prevent interpreting
313 // a colon in the part to the right of the equal sign as indicative of a
314 // a time value string.
315 char *s = strdup( value );
316 char *p = strchr( s, '=' );
318 mlt_property_set_string( item->property, s );
319 item->frame = mlt_property_get_int( item->property, self->fps, self->locale );
322 // The character preceeding the equal sign indicates interpolation method.
323 p = strchr( value, '=' ) - 1;
324 if ( p[0] == '|' || p[0] == '!' )
325 item->keyframe_type = mlt_keyframe_discrete;
326 else if ( p[0] == '~' )
327 item->keyframe_type = mlt_keyframe_smooth;
329 item->keyframe_type = mlt_keyframe_linear;
333 // Special case - frame < 0
334 if ( item->frame < 0 )
335 item->frame += mlt_animation_get_length( self );
337 // Set remainder of string as item value.
338 mlt_property_set_string( item->property, value );
349 /** Load an animation item for an absolute position.
351 * This performs interpolation if there is no keyframe at the \p position.
352 * \public \memberof mlt_animation_s
353 * \param self an animation
354 * \param item an already allocated animation item that will be filled in
355 * \param position the frame number for the point in time
356 * \return true if there was an error
359 int mlt_animation_get_item( mlt_animation self, mlt_animation_item item, int position )
362 // Need to find the nearest keyframe to the position specifed
363 animation_node node = self->nodes;
365 // Iterate through the keyframes until we reach last or have
366 while ( node && node->next && position >= node->next->item.frame )
371 item->keyframe_type = node->item.keyframe_type;
373 // Position is before the first keyframe.
374 if ( position < node->item.frame )
377 mlt_property_pass( item->property, node->item.property );
380 else if ( position == node->item.frame )
382 item->is_key = node->item.is_key;
383 mlt_property_pass( item->property, node->item.property );
385 // Position is after the last keyframe.
386 else if ( !node->next )
389 mlt_property_pass( item->property, node->item.property );
391 // Interpolation needed.
395 mlt_property points[4];
396 points[0] = node->prev? node->prev->item.property : node->item.property;
397 points[1] = node->item.property;
398 points[2] = node->next->item.property;
399 points[3] = node->next->next? node->next->next->item.property : node->next->item.property;
400 progress = position - node->item.frame;
401 progress /= node->next->item.frame - node->item.frame;
402 mlt_property_interpolate( item->property, points, progress,
403 self->fps, self->locale, item->keyframe_type );
409 item->frame = item->is_key = 0;
412 item->frame = position;
417 /** Insert an animation item.
419 * \public \memberof mlt_animation_s
420 * \param self an animation
421 * \param item an animation item
422 * \return true if there was an error
423 * \see mlt_animation_parse_item
426 int mlt_animation_insert( mlt_animation self, mlt_animation_item item )
429 animation_node node = calloc( 1, sizeof( *node ) );
430 node->item.frame = item->frame;
431 node->item.is_key = 1;
432 node->item.keyframe_type = item->keyframe_type;
433 node->item.property = mlt_property_init();
434 mlt_property_pass( node->item.property, item->property );
436 // Determine if we need to insert or append to the list, or if it's a new list
439 // Get the first item
440 animation_node current = self->nodes;
442 // Locate an existing nearby item
443 while ( current->next && item->frame > current->item.frame )
444 current = current->next;
446 if ( item->frame < current->item.frame )
448 if ( current == self->nodes )
451 current->prev->next = node;
452 node->next = current;
453 node->prev = current->prev;
454 current->prev = node;
456 else if ( item->frame > current->item.frame )
459 current->next->prev = node;
460 node->next = current->next;
461 node->prev = current;
462 current->next = node;
466 // Update matching node.
467 current->item.frame = item->frame;
468 current->item.is_key = 1;
469 current->item.keyframe_type = item->keyframe_type;
470 mlt_property_close( current->item.property );
471 current->item.property = node->item.property;
477 // Set the first item
484 /** Remove the keyframe at the specified position.
486 * \public \memberof mlt_animation_s
487 * \param self an animation
488 * \param position the frame number of the animation node to remove
489 * \return true if there was an error
492 int mlt_animation_remove( mlt_animation self, int position )
495 animation_node node = self->nodes;
497 while ( node && position != node->item.frame )
500 if ( node && position == node->item.frame )
501 error = mlt_animation_drop( self, node );
506 /** Get the keyfame at the position or the next following.
508 * \public \memberof mlt_animation_s
509 * \param self an animation
510 * \param item an already allocated animation item which will be updated
511 * \param position the frame number at which to start looking for the next animation node
512 * \return true if there was an error
515 int mlt_animation_next_key( mlt_animation self, mlt_animation_item item, int position )
517 animation_node node = self->nodes;
519 while ( node && position > node->item.frame )
524 item->frame = node->item.frame;
525 item->is_key = node->item.is_key;
526 item->keyframe_type = node->item.keyframe_type;
527 mlt_property_pass( item->property, node->item.property );
530 return ( node == NULL );
533 /** Get the keyfame at the position or the next preceeding.
535 * \public \memberof mlt_animation_s
536 * \param self an animation
537 * \param item an already allocated animation item which will be updated
538 * \param position the frame number at which to start looking for the previous animation node
539 * \return true if there was an error
542 int mlt_animation_prev_key( mlt_animation self, mlt_animation_item item, int position )
544 animation_node node = self->nodes;
546 while ( node && node->next && position >= node->next->item.frame )
551 item->frame = node->item.frame;
552 item->is_key = node->item.is_key;
553 item->keyframe_type = node->item.keyframe_type;
554 mlt_property_pass( item->property, node->item.property );
557 return ( node == NULL );
560 /** Serialize a cut of the animation.
562 * The caller is responsible for free-ing the returned string.
563 * \public \memberof mlt_animation_s
564 * \param self an animation
565 * \param in the frame at which to start serializing animation nodes
566 * \param out the frame at which to stop serializing nodes
567 * \return a string representing the animation
570 char *mlt_animation_serialize_cut( mlt_animation self, int in, int out )
572 struct mlt_animation_item_s item;
573 char *ret = malloc( 1000 );
577 item.property = mlt_property_init();
581 out = mlt_animation_get_length( self );
593 // If it's the first frame, then it's not necessarily a key
594 if ( item.frame == in )
596 if ( mlt_animation_get_item( self, &item, item.frame ) )
599 // If the first keyframe is larger than the current position
600 // then do nothing here
601 if ( self->nodes->item.frame > item.frame )
607 // To ensure correct seeding
610 // Typically, we move from keyframe to keyframe
611 else if ( item.frame < out )
613 if ( mlt_animation_next_key( self, &item, item.frame ) )
616 // Special case - crop at the out point
617 if ( item.frame > out )
618 mlt_animation_get_item( self, &item, out );
620 // We've handled the last keyframe
626 // Determine length of string to be appended.
627 if ( item.frame - in != 0 )
630 item_len += strlen( mlt_property_get_string_l( item.property, self->locale ) );
632 // Reallocate return string to be long enough.
633 while ( used + item_len + 2 > size ) // +2 for ';' and NULL
636 ret = realloc( ret, size );
639 // Append item delimiter (;) if needed.
640 if ( ret && used > 0 )
647 // Append keyframe time and keyframe/value delimiter (=).
649 switch (item.keyframe_type) {
650 case mlt_keyframe_discrete:
653 case mlt_keyframe_smooth:
660 sprintf( ret + used, "%d%s=", item.frame - in, s );
662 // Append item value.
664 strcat( ret, mlt_property_get_string_l( item.property, self->locale ) );
665 used = strlen( ret );
670 mlt_property_close( item.property );
675 /** Serialize the animation.
677 * The caller is responsible for free-ing the returned string.
678 * \public \memberof mlt_animation_s
679 * \param self an animation
680 * \return a string representing the animation
683 char *mlt_animation_serialize( mlt_animation self )
685 char *ret = mlt_animation_serialize_cut( self, -1, -1 );
692 return strdup( ret );
695 /** Close the animation and deallocate all of its resources.
697 * \public \memberof mlt_animation_s
698 * \param self the animation to destroy
701 void mlt_animation_close( mlt_animation self )
705 mlt_animation_clean( self );