if ( !prev )
current->item.is_key = 1;
- mlt_property_interpolate( current->item.property,
- prev->item.property, next->item.property,
- current->item.frame - prev->item.frame,
- next->item.frame - prev->item.frame,
- self->fps, self->locale );
+ if ( current->item.keyframe_type == mlt_keyframe_discrete )
+ {
+ mlt_property_pass( current->item.property, prev->item.property );
+ }
+ else
+ {
+ mlt_property_interpolate( current->item.property,
+ prev->item.property, next->item.property,
+ current->item.frame - prev->item.frame,
+ next->item.frame - prev->item.frame,
+ self->fps, self->locale );
+ }
}
// Move to the next item
mlt_property_set_string( item->property, value );
item->frame = mlt_property_get_int( item->property, self->fps, self->locale );
}
- value = strchr( value, '=' ) + 1;
- // TODO the character preceeding the equal sign indicates method of interpolation.
+ // The character preceeding the equal sign indicates interpolation method.
+ p = strchr( value, '=' ) - 1;
+ if ( p[0] == '|' )
+ item->keyframe_type = mlt_keyframe_discrete;
+ else
+ item->keyframe_type = mlt_keyframe_linear;
+ value = &p[2];
}
// Special case - frame < 0
if ( node )
{
+ item->keyframe_type = node->item.keyframe_type;
+
// Position is before the first keyframe.
if ( position < node->item.frame )
{
else
{
item->is_key = 0;
- mlt_property_interpolate( item->property, node->item.property, node->next->item.property,
- position - node->item.frame, node->next->item.frame - node->item.frame,
- self->fps, self->locale );
+ if ( node->item.keyframe_type == mlt_keyframe_discrete )
+ {
+ mlt_property_pass( item->property, node->item.property );
+ }
+ else
+ {
+ mlt_property_interpolate( item->property, node->item.property, node->next->item.property,
+ position - node->item.frame, node->next->item.frame - node->item.frame,
+ self->fps, self->locale );
+ }
}
}
else
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 );
// 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 );
{
item->frame = node->item.frame;
item->is_key = node->item.is_key;
+ item->keyframe_type = node->item.keyframe_type;
mlt_property_pass( item->property, node->item.property );
}
{
item->frame = node->item.frame;
item->is_key = node->item.is_key;
+ item->keyframe_type = node->item.keyframe_type;
mlt_property_pass( item->property, node->item.property );
}
{
// Append keyframe time and keyframe/value delimiter (=).
if ( item.frame - in != 0 )
- sprintf( ret + used, "%d=", item.frame - in );
+ {
+ const char *s;
+ switch (item.keyframe_type) {
+ case mlt_keyframe_discrete:
+ 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 ) );
return self->prop_string;
}
+static int is_property_numeric( mlt_property self, locale_t locale )
+{
+ int result = ( self->types & mlt_prop_int ) ||
+ ( self->types & mlt_prop_int64 ) ||
+ ( self->types & mlt_prop_double ) ||
+ ( self->types & mlt_prop_position );
+
+ // If not already numeric but string is numeric.
+ if ( ( !result && self->types & mlt_prop_string ) && self->prop_string )
+ {
+ double temp;
+ char *p = NULL;
+#if defined(__GLIBC__) || defined(__DARWIN__)
+ if ( locale )
+ temp = strtod_l( self->prop_string, &p, locale );
+ else
+#endif
+ temp = strtod( self->prop_string, &p );
+ result = ( p != self->prop_string );
+ }
+ return result;
+}
+
static inline double linearstep( double start, double end, double position, int length )
{
double o = ( end - start ) / length;
double position, int length, double fps, locale_t locale )
{
int error = 0;
-
- if ( fps > 0 )
+ if ( fps > 0 && is_property_numeric( previous, locale ) && is_property_numeric( next, locale ) )
{
double start = previous? mlt_property_get_double( previous, fps, locale ) : 0;
double end = next? mlt_property_get_double( next, fps, locale ) : 0;
}
else
{
- error = 1;
+ mlt_property_pass( self, previous );
}
return error;
}
mlt_animation_close(a);
}
+ void IntAnimation()
+ {
+ locale_t locale;
+#if defined(__linux__) || defined(__DARWIN__)
+ locale = newlocale( LC_NUMERIC_MASK, "POSIX", NULL );
+#endif
+ double fps = 25.0;
+ mlt_animation a = mlt_animation_new();
+ struct mlt_animation_item_s item;
+
+ mlt_animation_parse(a, "50=100; 60=60; 100=0", 100, fps, locale);
+ mlt_animation_remove(a, 60);
+ char *a_serialized = mlt_animation_serialize(a);
+ QCOMPARE(a_serialized, "50=100;100=0");
+ if (a_serialized) free(a_serialized);
+ item.property = mlt_property_init();
+
+ mlt_animation_get_item(a, &item, 10);
+ QCOMPARE(mlt_property_get_int(item.property, fps, locale), 100);
+ QCOMPARE(item.is_key, 0);
+
+ mlt_animation_get_item(a, &item, 50);
+ QCOMPARE(mlt_property_get_int(item.property, fps, locale), 100);
+ QCOMPARE(item.is_key, 1);
+
+ mlt_animation_get_item(a, &item, 75);
+ QCOMPARE(mlt_property_get_int(item.property, fps, locale), 50);
+ QCOMPARE(item.is_key, 0);
+
+ mlt_animation_get_item(a, &item, 100);
+ QCOMPARE(mlt_property_get_int(item.property, fps, locale), 0);
+ QCOMPARE(item.is_key, 1);
+
+ mlt_animation_get_item(a, &item, 110);
+ QCOMPARE(mlt_property_get_int(item.property, fps, locale), 0);
+ QCOMPARE(item.is_key, 0);
+
+ mlt_property_close(item.property);
+ mlt_animation_close(a);
+ }
+
void AnimationWithTimeValueKeyframes()
{
locale_t locale;
mlt_property_close(item.property);
mlt_animation_close(a);
}
+
+ void DiscreteIntAnimation()
+ {
+ locale_t locale;
+#if defined(__linux__) || defined(__DARWIN__)
+ locale = newlocale( LC_NUMERIC_MASK, "POSIX", NULL );
+#endif
+ double fps = 25.0;
+ mlt_animation a = mlt_animation_new();
+ struct mlt_animation_item_s item;
+
+ mlt_animation_parse(a, "50|=100; 60|=60; 100|=0", 100, fps, locale);
+ char *a_serialized = mlt_animation_serialize(a);
+ QCOMPARE(a_serialized, "50|=100;60|=60;100|=0");
+ if (a_serialized) free(a_serialized);
+ item.property = mlt_property_init();
+
+ mlt_animation_get_item(a, &item, 10);
+ QCOMPARE(mlt_property_get_int(item.property, fps, locale), 100);
+ QCOMPARE(item.is_key, 0);
+
+ mlt_animation_get_item(a, &item, 50);
+ QCOMPARE(mlt_property_get_int(item.property, fps, locale), 100);
+ QCOMPARE(item.is_key, 1);
+
+ mlt_animation_get_item(a, &item, 55);
+ QCOMPARE(mlt_property_get_int(item.property, fps, locale), 100);
+ QCOMPARE(item.is_key, 0);
+
+ mlt_animation_get_item(a, &item, 60);
+ QCOMPARE(mlt_property_get_int(item.property, fps, locale), 60);
+ QCOMPARE(item.is_key, 1);
+
+ mlt_animation_get_item(a, &item, 75);
+ QCOMPARE(mlt_property_get_int(item.property, fps, locale), 60);
+ QCOMPARE(item.is_key, 0);
+
+ mlt_animation_get_item(a, &item, 100);
+ QCOMPARE(mlt_property_get_int(item.property, fps, locale), 0);
+ QCOMPARE(item.is_key, 1);
+
+ mlt_animation_get_item(a, &item, 110);
+ QCOMPARE(mlt_property_get_int(item.property, fps, locale), 0);
+ QCOMPARE(item.is_key, 0);
+
+ mlt_property_close(item.property);
+ mlt_animation_close(a);
+ }
+
+ void StringAnimation()
+ {
+ locale_t locale;
+#if defined(__linux__) || defined(__DARWIN__)
+ locale = newlocale( LC_NUMERIC_MASK, "POSIX", NULL );
+#endif
+ double fps = 25.0;
+ mlt_animation a = mlt_animation_new();
+ struct mlt_animation_item_s item;
+
+ mlt_animation_parse(a, "50=hello world; 60=\"good night\"; 100=bar", 100, fps, locale);
+ char *a_serialized = mlt_animation_serialize(a);
+ QCOMPARE(a_serialized, "50=hello world;60=\"good night\";100=bar");
+ if (a_serialized) free(a_serialized);
+ item.property = mlt_property_init();
+
+ mlt_animation_get_item(a, &item, 10);
+ QCOMPARE(mlt_property_get_string(item.property), "hello world");
+ QCOMPARE(item.is_key, 0);
+
+ mlt_animation_get_item(a, &item, 50);
+ QCOMPARE(mlt_property_get_string(item.property), "hello world");
+ QCOMPARE(item.is_key, 1);
+
+ mlt_animation_get_item(a, &item, 75);
+ QCOMPARE(mlt_property_get_string(item.property), "\"good night\"");
+ QCOMPARE(item.is_key, 0);
+
+ mlt_animation_get_item(a, &item, 100);
+ QCOMPARE(mlt_property_get_string(item.property), "bar");
+ QCOMPARE(item.is_key, 1);
+
+ mlt_animation_get_item(a, &item, 110);
+ QCOMPARE(mlt_property_get_string(item.property), "bar");
+ QCOMPARE(item.is_key, 0);
+
+ mlt_property_close(item.property);
+ mlt_animation_close(a);
+ }
};
QTEST_APPLESS_MAIN(TestProperties)