static int mlt_animation_drop( mlt_animation self, animation_node node ) { if ( node == self->nodes ) { self->nodes = node->next; if ( self->nodes ) { self->nodes->prev = NULL; self->nodes->item.is_key = 1; } } else if ( node->next && node->prev ) { node->prev->next = node->next; node->next->prev = node->prev; } else if ( node->next ) { node->next->prev = node->prev; } else if ( node->prev ) { node->prev->next = node->next; } mlt_property_close( node->item.property ); free( node ); return 0; }
int mlt_animation_insert( mlt_animation self, mlt_animation_item item ) { int error = 0; 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 ); // Determine if we need to insert or append to the list, or if it's a new list if ( self->nodes ) { // Get the first item animation_node current = self->nodes; // Locate an existing nearby item while ( current->next && item->frame > current->item.frame ) current = current->next; if ( item->frame < current->item.frame ) { if ( current == self->nodes ) self->nodes = node; if ( current->prev ) current->prev->next = node; node->next = current; node->prev = current->prev; current->prev = node; } else if ( item->frame > current->item.frame ) { if ( current->next ) current->next->prev = node; node->next = current->next; node->prev = current; current->next = node; } else { // 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 ); } } else { // Set the first item self->nodes = node; } return error; }
static void serialize_localmotions(StabData* data, LocalMotions &vectors, mlt_position pos) { mlt_animation_item_s item; // Initialize animation item item.is_key = 1; item.frame = data->md.frameNum; item.keyframe_type = mlt_keyframe_discrete; item.property = mlt_property_init(); mlt_property_set_data(item.property, &vectors, 1, lm_destructor, (mlt_serialiser) lm_serializer); mlt_animation_insert(data->animation, &item); mlt_property_close(item.property); }
int mlt_animation_parse(mlt_animation self, const char *data, int length, double fps, locale_t locale ) { int error = 0; int i = 0; struct mlt_animation_item_s item; mlt_tokeniser tokens = mlt_tokeniser_init( ); // Clean the existing geometry mlt_animation_clean( self ); // Update the info on the data if ( data ) self->data = strdup( data ); self->length = length; self->fps = fps; self->locale = locale; item.property = mlt_property_init(); // Tokenise if ( data ) mlt_tokeniser_parse_new( tokens, (char*) data, ";" ); // Iterate through each token for ( i = 0; i < mlt_tokeniser_count( tokens ); i++ ) { char *value = mlt_tokeniser_get_string( tokens, i ); // If no data in keyframe, drop it (trailing semicolon) if ( !value || !strcmp( value, "" ) ) continue; // Reset item item.frame = item.is_key = 0; // Now parse the item mlt_animation_parse_item( self, &item, value ); // Now insert into place mlt_animation_insert( self, &item ); } mlt_animation_interpolate( self ); // Cleanup mlt_tokeniser_close( tokens ); mlt_property_close( item.property ); return error; }
char *mlt_animation_serialize_cut( mlt_animation self, int in, int out ) { struct mlt_animation_item_s item; char *ret = malloc( 1000 ); size_t used = 0; size_t size = 1000; item.property = mlt_property_init(); if ( in == -1 ) in = 0; if ( out == -1 ) out = mlt_animation_get_length( self ); if ( ret ) { strcpy( ret, "" ); item.frame = in; while ( 1 ) { size_t item_len = 0; // If it's the first frame, then it's not necessarily a key if ( item.frame == in ) { if ( mlt_animation_get_item( self, &item, item.frame ) ) break; // If the first keyframe is larger than the current position // then do nothing here if ( self->nodes->item.frame > item.frame ) { item.frame ++; continue; } // To ensure correct seeding item.is_key = 1; } // Typically, we move from keyframe to keyframe else if ( item.frame <= out ) { if ( mlt_animation_next_key( self, &item, item.frame ) ) break; // Special case - crop at the out point if ( item.frame > out ) mlt_animation_get_item( self, &item, out ); } // We've handled the last keyframe else { break; } // Determine length of string to be appended. if ( item.frame - in != 0 ) item_len += 20; if ( item.is_key ) item_len += strlen( mlt_property_get_string_l( item.property, self->locale ) ); // Reallocate return string to be long enough. while ( used + item_len + 2 > size ) // +2 for ';' and NULL { size += 1000; ret = realloc( ret, size ); } // Append item delimiter (;) if needed. if ( ret && used > 0 ) { used ++; strcat( ret, ";" ); } if ( ret ) { // Append keyframe time and keyframe/value delimiter (=). 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 ) ); used = strlen( ret ); } item.frame ++; } } mlt_property_close( item.property ); return ret; }