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