Hi Timon, Thank you for your contribution. This mailing list only discusses kdenlive-specific issues or code, and your patch is essentially a patch to mlt. I would suggest that you open a Pull-Request on their GitHub: https://github.com/mltframework/mlt/pulls. There, it can get reviewed and merged if appropriate.
Then, if your patch is accepted by mlt, we will look into merging you patch to the effect file. Best regards, Nicolas 2017-02-19 12:55 GMT+01:00 Timon <timo...@gmail.com>: > Hi, > > Currently dynamic text is extremely limited, I hacked it up to support > more use-cases, mainly: > - having an in-clip stopwatch (the docs mention this should work but > it didn't for me with 16.12.2) > - negative countdowns (e.g. rocket launch) > > One other case I think would be very useful, but I didn't take a look > at (I don't need it atm): > - scaled time for slow-motion video or time lapse (then you should > also add year-month-day) > > I just added an origin-frame property (that's the frame at which the time > is 0). > The formatting is split into separate keywords for hours, minutes, > seconds, and milliseconds. > These can be chained, so if you set "#time_m#:#time_s#" the seconds > will never go beyond 59 (since minutes count that), but if you only > specify #time_s# the seconds will count arbitrarily large. The main > limitation is that the keywords have to be in most-significant-first > order for this to work. > > There's a few issues with the patches though: > 1. using an origin-time might be better than an origin-frame since it > doesn't depend on the framerate > 2. I wasn't sure what the right type would be to specify the > origin-frame/time, and currently it's primitive and limiting > (min/max), also not very convenient > 3. how is compatibility/versioning handled between mlt and other > programs including kdenlive > 4. getting the profile_fps as part of substitute_keywords is probably not > nice? > > > I'm not very familiar with either kdenlive nor mlt, so I'd appreciate > if someone would take this over and do whatever needs doing, including > discussing and pushing the patch to mlt. > > > From 60f483a6d037bce3a1f99045776ba5a30b987855 Mon Sep 17 00:00:00 2001 > From: timon37 <timo...@gmail.com> > Date: Sun, 19 Feb 2017 11:43:08 +0100 > Subject: [PATCH] extend filter_dynamictext with an origin frame and more > formatting options > > --- > data/effects/dynamictext.xml | 5 ++++- > 1 file changed, 4 insertions(+), 1 deletion(-) > > diff --git a/data/effects/dynamictext.xml b/data/effects/dynamictext.xml > index 3de4570..64911c0 100644 > --- a/data/effects/dynamictext.xml > +++ b/data/effects/dynamictext.xml > @@ -38,9 +38,12 @@ > <paramlistdisplay>Top,Middle,Bottom</paramlistdisplay> > <name>Vertical Alignment</name> > </parameter> > + <parameter type="constant" name="originframe" max="1000000" > min="-1000000" default="0"> > + <name>Origin Frame</name> > + </parameter> > <parameter type="keywords" name="argument" default="#timecode#"> > <name>Text</name> > <keywords>#timecode#;#frame#;#filedate#;#localfiledate#;# > meta.media.0.stream.frame_rate#;#meta.media.0.codec. > name#;#meta.media.0.codec.bit_rate#;#meta.media.width#;# > meta.media.height#;#meta.attr.comment.markup#</keywords> > - <keywordsdisplay>timecode;frame;file date;local file > date;source frame rate;source codec;source bit rate;source > width;source height;source comment</keywordsdisplay> > + <keywordsdisplay>timecode;time_h;time_m;time_s;time_ms; > time_sign;frame;file > date;local file date;source frame rate;source codec;source bit > rate;source width;source height;source comment</keywordsdisplay> > </parameter> > </effect> > -- > 2.10.2 > > > From 385599b3ea7e51ba559d509cc2df108f76db2525 Mon Sep 17 00:00:00 2001 > From: timon37 <timo...@gmail.com> > Date: Sun, 19 Feb 2017 12:28:02 +0100 > Subject: [PATCH] extend filter_dynamictext with an origin frame and more > formatting options > > --- > src/modules/plus/filter_dynamictext.c | 56 > ++++++++++++++++++++++++++++++--- > src/modules/plus/filter_dynamictext.yml | 12 +++++++ > 2 files changed, 63 insertions(+), 5 deletions(-) > > diff --git a/src/modules/plus/filter_dynamictext.c > b/src/modules/plus/filter_dynamictext.c > index 412c13a..d367073 100644 > --- a/src/modules/plus/filter_dynamictext.c > +++ b/src/modules/plus/filter_dynamictext.c > @@ -167,17 +167,59 @@ static void get_resource_str( mlt_filter filter, > mlt_frame frame, char* text ) > > /** Perform substitution for keywords that are enclosed in "# #". > */ > -static void substitute_keywords(mlt_filter filter, char* result, > char* value, mlt_frame frame) > +static void substitute_keywords(mlt_filter filter, char* result, > char* value, mlt_frame frame, mlt_position origin) > { > char keyword[MAX_TEXT_LEN] = ""; > int pos = 0; > int is_keyword = 0; > - > + > + mlt_position frames = mlt_frame_get_position( frame ) - origin; > + int frames_negative = frames < 0 ? 1 : 0; > + frames = abs( frames ); > + > + double fps = 0; > + { > + mlt_profile profile = mlt_properties_get_data( > MLT_FILTER_PROPERTIES( filter ), "_profile", NULL ); > + if ( profile ) > + fps = mlt_profile_fps( profile ); > + } > + > while ( get_next_token(value, &pos, keyword, &is_keyword) ) > { > + size_t len = strlen( result ); > + size_t left = MAX_TEXT_LEN - len; > if(!is_keyword) > { > - strncat( result, keyword, MAX_TEXT_LEN - strlen( > result ) - 1 ); > + strncat( result, keyword, left - 1 ); > + } > + else if ( !strcmp( keyword, "time_sign" ) ) > + { > + if ( frames_negative ) > + strncat( result, "-", left - 1 ); > + } > + else if ( !strcmp( keyword, "time_h" ) ) > + { > + int num = frames / ( fps * 60 * 60 ); > + snprintf( result + len, left, "%02d", num ); > + frames -= num * fps * 60 * 60; > + } > + else if ( !strcmp( keyword, "time_m" ) ) > + { > + int num = frames / ( fps * 60 ); > + snprintf( result + len, left, "%02d", num ); > + frames -= num * fps * 60; > + } > + else if ( !strcmp( keyword, "time_s" ) ) > + { > + int num = frames / fps; > + snprintf( result + len, left, "%02d", num ); > + frames -= num * fps; > + } > + else if ( !strcmp( keyword, "time_ms" ) ) > + { > + int num = ( frames / fps ) * 1000; > + snprintf( result + len, left, "%03d", num ); > + frames -= num / 1000 * fps; > } > else if ( !strcmp( keyword, "timecode" ) || !strcmp( > keyword, "smpte_df" ) ) > { > @@ -214,7 +256,7 @@ static void substitute_keywords(mlt_filter filter, > char* result, char* value, ml > char *frame_value = mlt_properties_get( > frame_properties, keyword ); > if( frame_value ) > { > - strncat( result, frame_value, MAX_TEXT_LEN > - strlen(result) - 1 ); > + strncat( result, frame_value, left - 1 ); > } > } > } > @@ -232,9 +274,12 @@ static int setup_producer( mlt_filter filter, > mlt_producer producer, mlt_frame f > // Check for keywords in dynamic text > if ( dynamic_text ) > { > + int origin = 0; > + if ( mlt_properties_get( my_properties, "originframe" ) ) > + origin = mlt_properties_get_int( my_properties, > "originframe" ); > // Apply keyword substitution before passing the text to > the filter. > char result[MAX_TEXT_LEN] = ""; > - substitute_keywords( filter, result, dynamic_text, frame ); > + substitute_keywords( filter, result, dynamic_text, frame, > origin ); > mlt_properties_set( producer_properties, "text", > (char*)result ); > } > > @@ -386,6 +431,7 @@ mlt_filter filter_dynamictext_init( mlt_profile > profile, mlt_service_type type, > mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), > "eof", "loop" ); > > // Assign default values > + mlt_properties_set( my_properties, "originframe", "0" ); > mlt_properties_set( my_properties, "argument", arg ? arg: > "#timecode#" ); > mlt_properties_set( my_properties, "geometry", > "0%/0%:100%x100%:100" ); > mlt_properties_set( my_properties, "family", "Sans" ); > diff --git a/src/modules/plus/filter_dynamictext.yml > b/src/modules/plus/filter_dynamictext.yml > index 4035ee7..2e4fb90 100644 > --- a/src/modules/plus/filter_dynamictext.yml > +++ b/src/modules/plus/filter_dynamictext.yml > @@ -24,6 +24,11 @@ parameters: > * #smpte_df# - SMPTE drop-frame timecode of the frame > * #smpte_ndf# - SMPTE non-drop-frame timecode of the frame > * #timecode# - same as #smpte_df# > + * #time_h# - time in hours > + * #time_m# - time in minutes > + * #time_s# - time in seconds > + * #time_ms# - time in miliseconds > + * #time_sign# - a minus if the Origin Frame is in the future > * #frame# - frame number of the frame > * #filedate# - modification date of the file (GMT) > * #localfiledate# - modification date of the file (local) > @@ -42,6 +47,13 @@ parameters: > #timecode# > widget: text > > + - identifier: originframe > + title: Origin Frame > + type: integer > + default: 0 > + unit: frames > + widget: spinner > + > - identifier: geometry > title: Geometry > type: geometry > -- > 2.10.2 >