int mlt_animation_parse_item( mlt_animation self, mlt_animation_item item, const char *value ) { int error = 0; if ( value && strcmp( value, "" ) ) { // Determine if a position has been specified if ( strchr( value, '=' ) ) { // 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; 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 += mlt_animation_get_length( self ); // Set remainder of string as item value. mlt_property_set_string( item->property, value ); item->is_key = 1; } else { error = 1; } return error; }
static mlt_position repeat_position(mlt_properties properties, const char* name, mlt_position position, int length) { // Make mlt_properties parse and refresh animation. mlt_properties_anim_get_double(properties, name, position, length); mlt_animation animation = mlt_properties_get_animation(properties, name); if (animation) { // Apply repeat and mirror options. int anim_length = mlt_animation_get_length(animation); int repeat_off = mlt_properties_get_int(properties, "repeat_off"); if (!repeat_off && position >= anim_length && anim_length != 0) { int section = position / anim_length; int mirror_off = mlt_properties_get_int(properties, "mirror_off"); position -= section * anim_length; if (!mirror_off && section % 2 == 1) position = anim_length - position; } } return position; }
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; }