Thilo Borgmann: > Am 20.01.22 um 13:04 schrieb Thilo Borgmann: >> Am 19.01.22 um 04:16 schrieb "zhilizhao(赵志立)": >>> >>> >>>> On Jan 18, 2022, at 8:52 PM, Thilo Borgmann <thilo.borgm...@mail.de> >>>> wrote: >>>> >>>> Am 16.01.22 um 12:06 schrieb Nicolas George: >>>>> Thilo Borgman (12022-01-14): >>>>>> v6 does: >>>>>> >>>>>> $> ffmpeg ... drawtext="fontfile=...:text='%{localtime \:%a %b >>>>>> %d %Y %S}'" (seconds) >>>>>> $> ffmpeg ... drawtext="fontfile=...:text='%{localtime_ms\:%a %b >>>>>> %d %Y %S}'" (milliseconds) >>>>>> >>>>>> I suggest v7 should according to your remark: >>>>>> >>>>>> $> ffmpeg ... drawtext="fontfile=...:text='%{localtime \:%a %b >>>>>> %d %Y %S}'" (seconds) >>>>>> $> ffmpeg ... drawtext="fontfile=...:text='%{localtime \:%a %b >>>>>> %d %Y %S}':show_ms=1" (milliseconds) >>>>>> >>>>>> Good? >>>>> >>>>> I dislike both versions, from a user interface point of view: if there >>>>> is a format string, then it stands to reason, for the user, that the >>>>> resulting text is governed by the format string, not by an extra >>>>> option >>>>> somewhere else. >>>>> >>>>> There is no "use_four_digit_year=1" option, there is %Y instead of %y. >>>>> >>>>> There is no "use_slashes=1" option, you write %Y/%m/%d instead of >>>>> %Y-%m-%d. >>>>> >>>>> There are no "omit_date=1" and "omit_hour=1" options, you just write >>>>> what you want in the format string. >>>>> >>>>> My proposal goes the same way: >>>>> >>>>> $> ffmpeg ... drawtext="fontfile=...:text='%{localtime \:%a %b %d >>>>> %Y %S.%3N}'" >>>>> >>>>> It has several merits over your proposal: >>>>> >>>>> - It can be extended later to support printing the milliseconds at >>>>> another place than the end (for example to put the time in >>>>> brackets). >>>>> >>>>> - It can be extended to support microseconds or centiseconds (%6N, >>>>> %2N). >>>>> >>>>> - It is somewhat compatible with GNU date and possibly a few others. >>>>> >>>>> And I do not think it is harder to implement. >>>> >>>> Ok, did introduce a variable: %[1-6]N >>>> Parsing and clipping value to valid range of 1-6. >>>> Default 3. >>>> >>>> That way it is position independent and can show any number of >>>> decimals from 1 to 6. >>>> >>> >>>> diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c >>>> index 2a88692cbd..448b174dbb 100644 >>>> --- a/libavfilter/vf_drawtext.c >>>> +++ b/libavfilter/vf_drawtext.c >>>> @@ -51,6 +51,7 @@ >>>> #include "libavutil/opt.h" >>>> #include "libavutil/random_seed.h" >>>> #include "libavutil/parseutils.h" >>>> +#include "libavutil/time.h" >>>> #include "libavutil/timecode.h" >>>> #include "libavutil/time_internal.h" >>>> #include "libavutil/tree.h" >>>> @@ -1045,14 +1046,82 @@ static int func_strftime(AVFilterContext >>>> *ctx, AVBPrint *bp, >>>> char *fct, unsigned argc, char **argv, >>>> int tag) >>>> { >>>> const char *fmt = argc ? argv[0] : "%Y-%m-%d %H:%M:%S"; >>>> + int64_t unow; >>>> time_t now; >>>> struct tm tm; >>>> - >>>> - time(&now); >>>> - if (tag == 'L') >>>> + char *begin; >>>> + char *tmp; >>>> + int len; >>>> + char *fmt_new; >>>> + const char *fmt_tmp; >>>> + int div; >>>> + >>>> + unow = av_gettime(); >>>> + now = unow / 1000000; >>>> + if (tag == 'L' || tag == 'm') >>>> localtime_r(&now, &tm); >>>> else >>>> tm = *gmtime_r(&now, &tm); >>>> + >>>> + // manually parse format for %N (fractional seconds) >>>> + begin = (char*)fmt; >>> >>> Make begin and tmp const char *, so the cast can be removed. >>> >>>> + while ((begin = av_stristr(begin, "%"))) { >>> >>> How about strstr() since ‘%’ is caseless? >>> >>>> + tmp = begin + 1; >>>> + len = 0; >>>> + // count digits between % and possible N >>>> + while (*tmp != '\0' && av_isdigit((int)*tmp)) { >>>> + len++; >>>> + tmp++; >>>> + } >>>> + // N encountered, insert time >>>> + if (*tmp == 'N') { >>>> + int num_digits = 3; // default show millisecond [1,6] >>>> + >>>> + // if digits given, parse as number in [1,6] >>>> + if (len > 0) { >>>> + av_sscanf(begin + 1, "%i", &num_digits); >>>> + num_digits = av_clip(num_digits, 1, 6); // ensure >>>> valid value >>> >>> We can ignore len > 1, then the code can be simplified as >>> >>> if (len == 1) >>> num_digits = av_clip(*(begin + 1) - ‘\0’, 1, 6) >>> >>> >>>> + } >>>> + >>>> + len += 2; // add % and N to get length of string part >>>> + >>>> + switch(num_digits) { >>>> + case 1: >>>> + fmt_tmp = "%.*s%01d%s"; >>>> + div = 100000; >>>> + break; >>>> + case 2: >>>> + fmt_tmp = "%.*s%02d%s"; >>>> + div = 10000; >>>> + break; >>>> + case 3: >>>> + fmt_tmp = "%.*s%03d%s"; >>>> + div = 1000; >>>> + break; >>>> + case 4: >>>> + fmt_tmp = "%.*s%04d%s"; >>>> + div = 100; >>>> + break; >>>> + case 5: >>>> + fmt_tmp = "%.*s%05d%s"; >>>> + div = 10; >>>> + break; >>>> + case 6: >>>> + fmt_tmp = "%.*s%06d%s"; >>>> + div = 1; >>>> + break; >>>> + } >>> >>> The switch-case can be replaced by “%0*d” and pow(10, 6 - num_digits). >> >> Indeed, simplified. >> >> >>>> + >>>> + fmt_new = av_asprintf(fmt_tmp, begin - fmt, fmt, >>>> (int)(unow % 1000000) / div, begin + len); >>>> + if (!fmt_new) >>>> + return AVERROR(ENOMEM); >>>> + av_bprint_strftime(bp, fmt_new, &tm); >>>> + av_freep(&fmt_new); >>>> + return 0; >>>> + } >>>> + begin++; >>> >>> Progress faster by taking account of len. >> >> As well, also added to skip "%%". >> >> >>>> + } >>>> + >>>> av_bprint_strftime(bp, fmt, &tm); >>>> return 0; >>>> } >>>> -- >> >> v8 attached. > > Fixed off-by-one bug. > Allows for several occurrences of %N parameter now. > > v9 attached. > > Thanks, > Thilo > > > + // manually parse format for %N (fractional seconds) > + begin = fmt; > + while ((begin = av_stristr(begin, "%"))) { > + tmp = begin + 1;
begin = strchr(begin, '%') - Andreas _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".