|
|
|
@ -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,15 +1046,78 @@ 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"; |
|
|
|
|
const char *fmt_begin = fmt; |
|
|
|
|
int64_t unow; |
|
|
|
|
time_t now; |
|
|
|
|
struct tm tm; |
|
|
|
|
const char *begin; |
|
|
|
|
const char *tmp; |
|
|
|
|
int len; |
|
|
|
|
int div; |
|
|
|
|
AVBPrint fmt_bp; |
|
|
|
|
|
|
|
|
|
time(&now); |
|
|
|
|
if (tag == 'L') |
|
|
|
|
av_bprint_init(&fmt_bp, 0, AV_BPRINT_SIZE_UNLIMITED); |
|
|
|
|
|
|
|
|
|
unow = av_gettime(); |
|
|
|
|
now = unow / 1000000; |
|
|
|
|
if (tag == 'L' || tag == 'm') |
|
|
|
|
localtime_r(&now, &tm); |
|
|
|
|
else |
|
|
|
|
tm = *gmtime_r(&now, &tm); |
|
|
|
|
av_bprint_strftime(bp, fmt, &tm); |
|
|
|
|
|
|
|
|
|
// manually parse format for %N (fractional seconds)
|
|
|
|
|
begin = fmt; |
|
|
|
|
while ((begin = strchr(begin, '%'))) { |
|
|
|
|
tmp = begin + 1; |
|
|
|
|
len = 0; |
|
|
|
|
|
|
|
|
|
// skip escaped "%%"
|
|
|
|
|
if (*tmp == '%') { |
|
|
|
|
begin = tmp + 1; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 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 digit given, expect [1,6], warn & clamp otherwise
|
|
|
|
|
if (len == 1) { |
|
|
|
|
num_digits = av_clip(*(begin + 1) - '0', 1, 6); |
|
|
|
|
} else if (len > 1) { |
|
|
|
|
av_log(ctx, AV_LOG_WARNING, "Invalid number of decimals for %%N, using default of %i\n", num_digits); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
len += 2; // add % and N to get length of string part
|
|
|
|
|
|
|
|
|
|
div = pow(10, 6 - num_digits); |
|
|
|
|
|
|
|
|
|
av_bprintf(&fmt_bp, "%.*s%0*d", (int)(begin - fmt_begin), fmt_begin, num_digits, (int)(unow % 1000000) / div); |
|
|
|
|
|
|
|
|
|
begin += len; |
|
|
|
|
fmt_begin = begin; |
|
|
|
|
|
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
begin = tmp; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
av_bprintf(&fmt_bp, "%s", fmt_begin); |
|
|
|
|
if (!av_bprint_is_complete(&fmt_bp)) { |
|
|
|
|
av_log(ctx, AV_LOG_WARNING, "Format string truncated at %u/%u.", fmt_bp.size, fmt_bp.len); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
av_bprint_strftime(bp, fmt_bp.str, &tm); |
|
|
|
|
|
|
|
|
|
av_bprint_finalize(&fmt_bp, NULL); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|