2 * mlt_animation.c -- provides the property animation API
3 * Copyright (C) 2004-2013 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
5 * Author: Dan Dennedy <dan@dennedy.org>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "mlt_animation.h"
23 #include "mlt_tokeniser.h"
24 #include "mlt_profile.h"
30 /** \brief animation list node pointer */
31 typedef struct animation_node_s *animation_node;
32 /** \brief private animation list node */
33 struct animation_node_s
35 struct mlt_animation_item_s item;
36 animation_node next, prev;
39 /** \brief Property Animation class
41 * This is the animation engine for a Property object. It is dependent upon
42 * the mlt_property API and used by the various mlt_property_anim_* functions.
45 struct mlt_animation_s
47 char *data; /**< the string representing the animation */
48 int length; /**< the maximum number of frames to use when interpreting negative keyframe positions */
49 double fps; /**< framerate to use when converting time clock strings to frame units */
50 locale_t locale; /**< pointer to a locale to use when converting strings to numeric values */
51 animation_node nodes; /**< a linked list of keyframes (and possibly non-keyframe values) */
54 /** Create a new animation object.
56 * \public \memberof mlt_animation_s
57 * \return an animation object
60 mlt_animation mlt_animation_new( )
62 mlt_animation self = calloc( 1, sizeof( *self ) );
66 /** Re-interpolate non-keyframe nodess after a series of insertions or removals.
68 * \public \memberof mlt_animation_s
69 * \param self an animation
72 void mlt_animation_interpolate( mlt_animation self )
74 // Parse all items to ensure non-keyframes are calculated correctly.
77 animation_node current = self->nodes;
80 if ( !current->item.is_key )
83 mlt_property points[4];
84 animation_node prev = current->prev;
85 animation_node next = current->next;
87 while ( prev && !prev->item.is_key ) prev = prev->prev;
88 while ( next && !next->item.is_key ) next = next->next;
91 current->item.is_key = 1;
92 points[0] = prev->prev? prev->prev->item.property : prev->item.property;
93 points[1] = prev->item.property;
94 points[2] = next->item.property;
95 points[3] = next->next? next->next->item.property : next->item.property;
96 progress = current->item.frame - prev->item.frame;
97 progress /= next->item.frame - prev->item.frame;
98 mlt_property_interpolate( current->item.property, points, progress,
99 self->fps, self->locale, current->item.keyframe_type );
102 // Move to the next item
103 current = current->next;
108 /** Remove a node from the linked list.
110 * \private \memberof mlt_animation_s
111 * \param self an animation
112 * \param node the node to remove
116 static int mlt_animation_drop( mlt_animation self, animation_node node )
118 if ( node == self->nodes )
120 self->nodes = node->next;
122 self->nodes->prev = NULL;
123 self->nodes->item.is_key = 1;
126 else if ( node->next && node->prev )
128 node->prev->next = node->next;
129 node->next->prev = node->prev;
131 else if ( node->next )
133 node->next->prev = node->prev;
135 else if ( node->prev )
137 node->prev->next = node->next;
139 mlt_property_close( node->item.property );
145 /** Reset an animation and free all strings and properties.
147 * \private \memberof mlt_animation_s
148 * \param self an animation
151 static void mlt_animation_clean( mlt_animation self )
156 while ( self->nodes )
157 mlt_animation_drop( self, self->nodes );
160 /** Parse a string representing an animation.
162 * A semicolon is the delimiter between keyframe=value items in the string.
163 * \public \memberof mlt_animation_s
164 * \param self an animation
165 * \param data the string representing an animation
166 * \param length the maximum number of frames when interpreting negative keyframe times,
167 * <=0 if you don't care or need that
168 * \param fps the framerate to use when evaluating time strings
169 * \param locale the locale to use when converting strings to numbers
170 * \return true if there was an error
173 int mlt_animation_parse(mlt_animation self, const char *data, int length, double fps, locale_t locale )
177 struct mlt_animation_item_s item;
178 mlt_tokeniser tokens = mlt_tokeniser_init( );
180 // Clean the existing geometry
181 mlt_animation_clean( self );
183 // Update the info on the data
185 self->data = strdup( data );
186 self->length = length;
188 self->locale = locale;
189 item.property = mlt_property_init();
193 mlt_tokeniser_parse_new( tokens, (char*) data, ";" );
195 // Iterate through each token
196 for ( i = 0; i < mlt_tokeniser_count( tokens ); i++ )
198 char *value = mlt_tokeniser_get_string( tokens, i );
200 // If no data in keyframe, drop it (trailing semicolon)
201 if ( !value || !strcmp( value, "" ) )
205 item.frame = item.is_key = 0;
207 // Now parse the item
208 mlt_animation_parse_item( self, &item, value );
210 // Now insert into place
211 mlt_animation_insert( self, &item );
213 mlt_animation_interpolate( self );
216 mlt_tokeniser_close( tokens );
217 mlt_property_close( item.property );
222 /** Conditionally refresh the animation if it is modified.
224 * \public \memberof mlt_animation_s
225 * \param self an animation
226 * \param data the string representing an animation
227 * \param length the maximum number of frames when interpreting negative keyframe times,
228 * <=0 if you don't care or need that
229 * \return true if there was an error
232 int mlt_animation_refresh( mlt_animation self, const char *data, int length )
234 if ( ( length != self->length )|| ( data && ( !self->data || strcmp( data, self->data ) ) ) )
235 return mlt_animation_parse( self, data, length, self->fps, self->locale );
239 /** Get the length of the animation.
241 * If the animation was initialized with a zero or negative value, then this
242 * gets the maximum frame number from animation's list of nodes.
243 * \public \memberof mlt_animation_s
244 * \param self an animation
245 * \return the number of frames
248 int mlt_animation_get_length( mlt_animation self )
252 if ( self->length > 0 ) {
253 length = self->length;
255 else if ( self->nodes ) {
256 animation_node node = self->nodes;
258 if ( node->item.frame > length )
259 length = node->item.frame;
267 /** Set the length of the animation.
269 * The length is used for interpreting negative keyframe positions as relative
270 * to the length. It is also used when serializing an animation as a string.
271 * \public \memberof mlt_animation_s
272 * \param self an animation
273 * \param length the length of the animation in frame units
276 void mlt_animation_set_length( mlt_animation self, int length )
279 self->length = length;
282 /** Parse a string representing an animation keyframe=value.
284 * This function does not affect the animation itself! But it will use some state
285 * of the animation for the parsing (e.g. fps, locale).
286 * It parses into a mlt_animation_item that you provide.
287 * \p item->frame should be specified if the string does not have an equal sign and time field.
288 * If an exclamation point (!) or vertical bar (|) character preceeds the equal sign, then
289 * the keyframe interpolation is set to discrete. If a tilde (~) preceeds the equal sign,
290 * then the keyframe interpolation is set to smooth (spline).
292 * \public \memberof mlt_animation_s
293 * \param self an animation
294 * \param item an already allocated animation item
295 * \param value the string representing an animation
296 * \return true if there was an error
299 int mlt_animation_parse_item( mlt_animation self, mlt_animation_item item, const char *value )
303 if ( value && strcmp( value, "" ) )
305 // Determine if a position has been specified
306 if ( strchr( value, '=' ) )
308 // Parse an absolute time value.
309 // Null terminate the string at the equal sign to prevent interpreting
310 // a colon in the part to the right of the equal sign as indicative of a
311 // a time value string.
312 char *s = strdup( value );
313 char *p = strchr( s, '=' );
315 mlt_property_set_string( item->property, s );
316 item->frame = mlt_property_get_int( item->property, self->fps, self->locale );
319 // The character preceeding the equal sign indicates interpolation method.
320 p = strchr( value, '=' ) - 1;
321 if ( p[0] == '|' || p[0] == '!' )
322 item->keyframe_type = mlt_keyframe_discrete;
323 else if ( p[0] == '~' )
324 item->keyframe_type = mlt_keyframe_smooth;
326 item->keyframe_type = mlt_keyframe_linear;
330 // Special case - frame < 0
331 if ( item->frame < 0 )
332 item->frame += mlt_animation_get_length( self );
334 // Set remainder of string as item value.
335 mlt_property_set_string( item->property, value );
346 /** Load an animation item for an absolute position.
348 * This performs interpolation if there is no keyframe at the \p position.
349 * \public \memberof mlt_animation_s
350 * \param self an animation
351 * \param item an already allocated animation item that will be filled in
352 * \param position the frame number for the point in time
353 * \return true if there was an error
356 int mlt_animation_get_item( mlt_animation self, mlt_animation_item item, int position )
359 // Need to find the nearest keyframe to the position specifed
360 animation_node node = self->nodes;
362 // Iterate through the keyframes until we reach last or have
363 while ( node && node->next && position >= node->next->item.frame )
368 item->keyframe_type = node->item.keyframe_type;
370 // Position is before the first keyframe.
371 if ( position < node->item.frame )
374 mlt_property_pass( item->property, node->item.property );
377 else if ( position == node->item.frame )
379 item->is_key = node->item.is_key;
380 mlt_property_pass( item->property, node->item.property );
382 // Position is after the last keyframe.
383 else if ( !node->next )
386 mlt_property_pass( item->property, node->item.property );
388 // Interpolation needed.
392 mlt_property points[4];
393 points[0] = node->prev? node->prev->item.property : node->item.property;
394 points[1] = node->item.property;
395 points[2] = node->next->item.property;
396 points[3] = node->next->next? node->next->next->item.property : node->next->item.property;
397 progress = position - node->item.frame;
398 progress /= node->next->item.frame - node->item.frame;
399 mlt_property_interpolate( item->property, points, progress,
400 self->fps, self->locale, item->keyframe_type );
406 item->frame = item->is_key = 0;
409 item->frame = position;
414 /** Insert an animation item.
416 * \public \memberof mlt_animation_s
417 * \param self an animation
418 * \param item an animation item
419 * \return true if there was an error
420 * \see mlt_animation_parse_item
423 int mlt_animation_insert( mlt_animation self, mlt_animation_item item )
426 animation_node node = calloc( 1, sizeof( *node ) );
427 node->item.frame = item->frame;
428 node->item.is_key = 1;
429 node->item.keyframe_type = item->keyframe_type;
430 node->item.property = mlt_property_init();
431 mlt_property_pass( node->item.property, item->property );
433 // Determine if we need to insert or append to the list, or if it's a new list
436 // Get the first item
437 animation_node current = self->nodes;
439 // Locate an existing nearby item
440 while ( current->next && item->frame > current->item.frame )
441 current = current->next;
443 if ( item->frame < current->item.frame )
445 if ( current == self->nodes )
448 current->prev->next = node;
449 node->next = current;
450 node->prev = current->prev;
451 current->prev = node;
453 else if ( item->frame > current->item.frame )
456 current->next->prev = node;
457 node->next = current->next;
458 node->prev = current;
459 current->next = node;
463 // Update matching node.
464 current->item.frame = item->frame;
465 current->item.is_key = 1;
466 current->item.keyframe_type = item->keyframe_type;
467 mlt_property_close( current->item.property );
468 current->item.property = node->item.property;
474 // Set the first item
481 /** Remove the keyframe at the specified position.
483 * \public \memberof mlt_animation_s
484 * \param self an animation
485 * \param position the frame number of the animation node to remove
486 * \return true if there was an error
489 int mlt_animation_remove( mlt_animation self, int position )
492 animation_node node = self->nodes;
494 while ( node && position != node->item.frame )
497 if ( node && position == node->item.frame )
498 error = mlt_animation_drop( self, node );
503 /** Get the keyfame at the position or the next following.
505 * \public \memberof mlt_animation_s
506 * \param self an animation
507 * \param item an already allocated animation item which will be updated
508 * \param position the frame number at which to start looking for the next animation node
509 * \return true if there was an error
512 int mlt_animation_next_key( mlt_animation self, mlt_animation_item item, int position )
514 animation_node node = self->nodes;
516 while ( node && position > node->item.frame )
521 item->frame = node->item.frame;
522 item->is_key = node->item.is_key;
523 item->keyframe_type = node->item.keyframe_type;
524 mlt_property_pass( item->property, node->item.property );
527 return ( node == NULL );
530 /** Get the keyfame at the position or the next preceeding.
532 * \public \memberof mlt_animation_s
533 * \param self an animation
534 * \param item an already allocated animation item which will be updated
535 * \param position the frame number at which to start looking for the previous animation node
536 * \return true if there was an error
539 int mlt_animation_prev_key( mlt_animation self, mlt_animation_item item, int position )
541 animation_node node = self->nodes;
543 while ( node && node->next && position >= node->next->item.frame )
548 item->frame = node->item.frame;
549 item->is_key = node->item.is_key;
550 item->keyframe_type = node->item.keyframe_type;
551 mlt_property_pass( item->property, node->item.property );
554 return ( node == NULL );
557 /** Serialize a cut of the animation.
559 * The caller is responsible for free-ing the returned string.
560 * \public \memberof mlt_animation_s
561 * \param self an animation
562 * \param in the frame at which to start serializing animation nodes
563 * \param out the frame at which to stop serializing nodes
564 * \return a string representing the animation
567 char *mlt_animation_serialize_cut( mlt_animation self, int in, int out )
569 struct mlt_animation_item_s item;
570 char *ret = malloc( 1000 );
574 item.property = mlt_property_init();
578 out = mlt_animation_get_length( self );
590 // If it's the first frame, then it's not necessarily a key
591 if ( item.frame == in )
593 if ( mlt_animation_get_item( self, &item, item.frame ) )
596 // If the first keyframe is larger than the current position
597 // then do nothing here
598 if ( self->nodes->item.frame > item.frame )
604 // To ensure correct seeding
607 // Typically, we move from keyframe to keyframe
608 else if ( item.frame < out )
610 if ( mlt_animation_next_key( self, &item, item.frame ) )
613 // Special case - crop at the out point
614 if ( item.frame > out )
615 mlt_animation_get_item( self, &item, out );
617 // We've handled the last keyframe
623 // Determine length of string to be appended.
624 if ( item.frame - in != 0 )
627 item_len += strlen( mlt_property_get_string_l( item.property, self->locale ) );
629 // Reallocate return string to be long enough.
630 while ( used + item_len + 2 > size ) // +2 for ';' and NULL
633 ret = realloc( ret, size );
636 // Append item delimiter (;) if needed.
637 if ( ret && used > 0 )
644 // Append keyframe time and keyframe/value delimiter (=).
646 switch (item.keyframe_type) {
647 case mlt_keyframe_discrete:
650 case mlt_keyframe_smooth:
657 sprintf( ret + used, "%d%s=", item.frame - in, s );
659 // Append item value.
661 strcat( ret, mlt_property_get_string_l( item.property, self->locale ) );
662 used = strlen( ret );
667 mlt_property_close( item.property );
672 /** Serialize the animation.
674 * The caller is responsible for free-ing the returned string.
675 * \public \memberof mlt_animation_s
676 * \param self an animation
677 * \return a string representing the animation
680 char *mlt_animation_serialize( mlt_animation self )
682 char *ret = mlt_animation_serialize_cut( self, -1, -1 );
689 return strdup( ret );
692 /** Close the animation and deallocate all of its resources.
694 * \public \memberof mlt_animation_s
695 * \param self the animation to destroy
698 void mlt_animation_close( mlt_animation self )
702 mlt_animation_clean( self );