[FFmpeg-devel] Add option to log timing

Submitted by Soft Works on Sept. 4, 2019, 6:53 p.m.

Details

Message ID MN2PR13MB275270278979806652ED6597BAB80@MN2PR13MB2752.namprd13.prod.outlook.com
State New
Headers show

Commit Message

Soft Works Sept. 4, 2019, 6:53 p.m.
This commit adds two logging flags: 'timing' and 'datetiming'.

Usage: ffmpeg -logleve +timing

Timing information will only be added to log lines once transcoding has started.
---
fftools/cmdutils.c | 14 ++++++++++++++
fftools/ffmpeg.c   |  3 +++
libavutil/log.c    | 37 ++++++++++++++++++++++++++++++++-----
libavutil/log.h    | 17 +++++++++++++++++
4 files changed, 66 insertions(+), 5 deletions(-)

Comments

Bodecs Bela Sept. 4, 2019, 7:12 p.m.
Hi,

2019.09.04. 20:53 keltezéssel, Soft Works írta:
> This commit adds two logging flags: 'timing' and 'datetiming'.
>
> Usage: ffmpeg -logleve +timing
>
> Timing information will only be added to log lines once transcoding has started.

Why this restriction? I think all log lines should be start with 
time/date if corresponding flag is present. This makes the log to be 
easy to parse by scripts.

> ---
> fftools/cmdutils.c | 14 ++++++++++++++
> fftools/ffmpeg.c   |  3 +++
> libavutil/log.c    | 37 ++++++++++++++++++++++++++++++++-----
> libavutil/log.h    | 17 +++++++++++++++++
> 4 files changed, 66 insertions(+), 5 deletions(-)
>
> diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c
> index fdcd376b76..7805058f8b 100644
> --- a/fftools/cmdutils.c
> +++ b/fftools/cmdutils.c
> @@ -912,6 +912,20 @@ int opt_loglevel(void *optctx, const char *opt, const char *arg)
>                   flags |= AV_LOG_PRINT_LEVEL;
>               }
>               arg = token + 5;
> +        } else if (!strncmp(token, "timing", 6)) {
> +            if (cmd == '-') {
> +                flags &= ~AV_LOG_PRINT_TIME;
> +            } else {
> +                flags |= AV_LOG_PRINT_TIME;
> +            }
> +            arg = token + 6;
> +        } else if (!strncmp(token, "datetiming", 10)) {
> +            if (cmd == '-') {
> +                flags &= ~AV_LOG_PRINT_DATETIME;
> +            } else {
> +                flags |= AV_LOG_PRINT_DATETIME;
> +            }
> +            arg = token + 10;
>           } else {
>               break;
>           }
> diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
> index 01f04103cf..ed1c6ab6fc 100644
> --- a/fftools/ffmpeg.c
> +++ b/fftools/ffmpeg.c
> @@ -4668,6 +4668,9 @@ static int transcode(void)
>           av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n");
>       }
> +    /* Enable log timestamps if configured */
> +    av_log_set_flags(av_log_get_flags() | AV_LOG_PRINT_STARTUPCOMPLETE);
> +
>       timer_start = av_gettime_relative();
>   #if HAVE_THREADS
> diff --git a/libavutil/log.c b/libavutil/log.c
> index 93a156b8e4..a374a68c4e 100644
> --- a/libavutil/log.c
> +++ b/libavutil/log.c
> @@ -40,6 +40,8 @@
> #include "internal.h"
> #include "log.h"
> #include "thread.h"
> +#include "time.h"
> +#include "time_internal.h"
>   static AVMutex mutex = AV_MUTEX_INITIALIZER;
> @@ -243,14 +245,32 @@ static const char *get_level_str(int level)
>       }
> }
> +static void format_date_now(AVBPrint* timeBuf, int include_date)
> +{
> +    struct tm *ptm, tmbuf;
> +    int64_t time_us = av_gettime();
> +    int64_t time_ms = time_us / 1000;
> +    const time_t time_s = time_ms / 1000;
> +    int millisec = time_ms - (time_s * 1000);
> +    ptm = localtime_r(&time_s, &tmbuf);
> +    if (ptm) {
> +        if (include_date)
> +            av_bprint_strftime(timeBuf, "%Y-%m-%d ", ptm);
> +
> +        av_bprint_strftime(timeBuf, "%H:%M:%S", ptm);
> +        av_bprintf(timeBuf, ".%03d ", millisec);
> +    }
> +}
> +
> static void format_line(void *avcl, int level, const char *fmt, va_list vl,
> -                        AVBPrint part[4], int *print_prefix, int type[2])
> +                        AVBPrint part[5], int *print_prefix, int type[2])
> {
>       AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
>       av_bprint_init(part+0, 0, AV_BPRINT_SIZE_AUTOMATIC);
>       av_bprint_init(part+1, 0, AV_BPRINT_SIZE_AUTOMATIC);
>       av_bprint_init(part+2, 0, AV_BPRINT_SIZE_AUTOMATIC);
>       av_bprint_init(part+3, 0, 65536);
> +    av_bprint_init(part+4, 0, AV_BPRINT_SIZE_AUTOMATIC);
>       if(type) type[0] = type[1] = AV_CLASS_CATEGORY_NA + 16;
>       if (*print_prefix && avc) {
> @@ -277,6 +297,10 @@ static void format_line(void *avcl, int level, const char *fmt, va_list vl,
>           char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0;
>           *print_prefix = lastc == '\n' || lastc == '\r';
>       }
> +
> +    if (*print_prefix && part[3].len > 1 && (flags & AV_LOG_PRINT_STARTUPCOMPLETE)
> +        && ((flags & AV_LOG_PRINT_TIME) || (flags & AV_LOG_PRINT_DATETIME)))
> +        format_date_now(&part[4], flags & AV_LOG_PRINT_DATETIME);
> }
>   void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl,
> @@ -288,12 +312,12 @@ void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl,
> int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl,
>                           char *line, int line_size, int *print_prefix)
> {
> -    AVBPrint part[4];
> +    AVBPrint part[5];
>       int ret;
>       format_line(ptr, level, fmt, vl, part, print_prefix, NULL);
>       ret = snprintf(line, line_size, "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
> -    av_bprint_finalize(part+3, NULL);
> +    av_bprint_finalize(part+4, NULL);
>       return ret;
> }
> @@ -302,7 +326,7 @@ void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl)
>       static int print_prefix = 1;
>       static int count;
>       static char prev[LINE_SZ];
> -    AVBPrint part[4];
> +    AVBPrint part[5];
>       char line[LINE_SZ];
>       static int is_atty;
>       int type[2];
> @@ -337,6 +361,9 @@ void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl)
>           count = 0;
>       }
>       strcpy(prev, line);
> +
> +    sanitize(part[4].str);
> +    colored_fputs(7, 0, part[4].str);
>       sanitize(part[0].str);
>       colored_fputs(type[0], 0, part[0].str);
>       sanitize(part[1].str);
> @@ -351,7 +378,7 @@ void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl)
>           VALGRIND_PRINTF_BACKTRACE("%s", "");
> #endif
> end:
> -    av_bprint_finalize(part+3, NULL);
> +    av_bprint_finalize(part+4, NULL);
>       ff_mutex_unlock(&mutex);
> }
> diff --git a/libavutil/log.h b/libavutil/log.h
> index d9554e609d..a4a750de74 100644
> --- a/libavutil/log.h
> +++ b/libavutil/log.h
> @@ -352,6 +352,23 @@ int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl,
>    */
> #define AV_LOG_PRINT_LEVEL 2
> +/**
> + * Include system time in log output.
> + */
> +#define AV_LOG_PRINT_TIME 4
> +
> +/**
> + * Include system date and time in log output.
> + */
> +#define AV_LOG_PRINT_DATETIME 8
> +
> +/**
> + * Internal flag indicating that transcoding has started
> + * and subsequent log output should include timing when
> + * AV_LOG_PRINT_TIME or AV_LOG_PRINT_DATETIME is set.
> + */
> +#define AV_LOG_PRINT_STARTUPCOMPLETE 65536
> +
> void av_log_set_flags(int arg);
> int av_log_get_flags(void);
> --
> 2.17.1.windows.2
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> f
bb
> fmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Soft Works Sept. 4, 2019, 7:35 p.m.
> Why this restriction? I think all log lines should be start with
> time/date if corresponding flag is present. This makes the log to be
> easy to parse by scripts.

Initially I didn’t have this restriction, but it doesn’t work well together with some multi-line logging.
See below for an example.

To get this nice, it would require a larger amount of changes, and probably result in something that nobody wants to merge in.

Anyway, there’s a flag controlling this behavior and if you really want, you can set it.
Then you’ll see something like this:


18:59:04.449 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'file:xxxxxxx.mp4':
18:59:04.449   Metadata:
    major_brand     : isom18:59:04.449
    minor_version   : 51218:59:04.449
    compatible_brands: isomiso2avc1mp4118:59:04.449
    encoder         : Lavf58.12.10018:59:04.449
  Duration: 00:20:52.72, start: 0.000000, bitrate: 1386 kb/s18:59:04.449
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 640x360 [SAR 1:1 DAR 16:9], 612 kb/s, Level 30, 25 fps, 25 tbr, 12800 tbn, 50 tbc (default)18:59:04.449
18:59:04.449     Metadata:
      handler_name    : VideoHandler18:59:04.449
    Stream #0:1(ger): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 5.1, fltp, 381 kb/s (default)18:59:04.449
18:59:04.449     Metadata:
      handler_name    : SoundHandler18:59:04.449
    Stream #0:2(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 5.1, fltp, 382 kb/s18:59:04.449
18:59:04.449     Metadata:
      handler_name    : SoundHandler18:59:04.449
18:59:04.737 Stream mapping:
  Stream #0:0 (h264_cuvid) -> scale_cuda (graph 0)18:59:04.737
  scale_cuda (graph 0)18:59:04.737  -> Stream #0:0 (h264_nvenc)
  Stream #0:1 -> #0:1 (aac (native) -> mp3 (libmp3lame))18:59:04.737
Michael Niedermayer Sept. 4, 2019, 7:45 p.m.
On Wed, Sep 04, 2019 at 06:53:28PM +0000, Soft Works wrote:
> This commit adds two logging flags: 'timing' and 'datetiming'.
> 
> Usage: ffmpeg -logleve +timing
> 
> Timing information will only be added to log lines once transcoding has started.
> ---
> fftools/cmdutils.c | 14 ++++++++++++++
> fftools/ffmpeg.c   |  3 +++
> libavutil/log.c    | 37 ++++++++++++++++++++++++++++++++-----
> libavutil/log.h    | 17 +++++++++++++++++
> 4 files changed, 66 insertions(+), 5 deletions(-)

Applying: Add option to log timing
error: corrupt patch at line 45
...

[...]
Michael Niedermayer Sept. 4, 2019, 7:48 p.m.
On Wed, Sep 04, 2019 at 07:35:11PM +0000, Soft Works wrote:
> 
> > Why this restriction? I think all log lines should be start with
> > time/date if corresponding flag is present. This makes the log to be
> > easy to parse by scripts.
> 
> Initially I didn’t have this restriction, but it doesn’t work well together with some multi-line logging.
> See below for an example.
> 
> To get this nice, it would require a larger amount of changes, and probably result in something that nobody wants to merge in.
> 
> Anyway, there’s a flag controlling this behavior and if you really want, you can set it.
> Then you’ll see something like this:

how hard would it be to fix this ?

because nothing stops a codec from doing whatever the code outside transcode
did here causing this ...

[...]
Soft Works Sept. 4, 2019, 8:01 p.m.
> Michael Niedermayer wrote:
> >
> > > Why this restriction? I think all log lines should be start with
> > > time/date if corresponding flag is present. This makes the log to be
> > > easy to parse by scripts.
> >
> > Initially I didn’t have this restriction, but it doesn’t work well together with some multi-line logging.
> > See below for an example.
> >
> > To get this nice, it would require a larger amount of changes, and probably result in something that nobody wants to merge in.
> >
> > Anyway, there’s a flag controlling this behavior and if you really want, you can set it.
> > Then you’ll see something like this:
>
> how hard would it be to fix this ?
>
> because nothing stops a codec from doing whatever the code outside transcode
> did here causing this ...

Hi Michael,

it follows the same logic as the class prefixes do (those in square braces),
that's why the codec outputs are normally not doing those things that happen during startup.

If there is a normal line break in a codec output, that's ok and won't lead to the
nasty outputs I've shown. It will just don't have a timing in the second line, which is
just right imo, because then it's not a new log event but just continued output of
the previous line. A parser needs to check for this and will add the line content to the
previous log entry instead of parsing it as a new one.

softworkz

Patch hide | download patch | download mbox

diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c
index fdcd376b76..7805058f8b 100644
--- a/fftools/cmdutils.c
+++ b/fftools/cmdutils.c
@@ -912,6 +912,20 @@  int opt_loglevel(void *optctx, const char *opt, const char *arg)
                 flags |= AV_LOG_PRINT_LEVEL;
             }
             arg = token + 5;
+        } else if (!strncmp(token, "timing", 6)) {
+            if (cmd == '-') {
+                flags &= ~AV_LOG_PRINT_TIME;
+            } else {
+                flags |= AV_LOG_PRINT_TIME;
+            }
+            arg = token + 6;
+        } else if (!strncmp(token, "datetiming", 10)) {
+            if (cmd == '-') {
+                flags &= ~AV_LOG_PRINT_DATETIME;
+            } else {
+                flags |= AV_LOG_PRINT_DATETIME;
+            }
+            arg = token + 10;
         } else {
             break;
         }
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 01f04103cf..ed1c6ab6fc 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -4668,6 +4668,9 @@  static int transcode(void)
         av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n");
     }
+    /* Enable log timestamps if configured */
+    av_log_set_flags(av_log_get_flags() | AV_LOG_PRINT_STARTUPCOMPLETE);
+
     timer_start = av_gettime_relative();
 #if HAVE_THREADS
diff --git a/libavutil/log.c b/libavutil/log.c
index 93a156b8e4..a374a68c4e 100644
--- a/libavutil/log.c
+++ b/libavutil/log.c
@@ -40,6 +40,8 @@ 
#include "internal.h"
#include "log.h"
#include "thread.h"
+#include "time.h"
+#include "time_internal.h"
 static AVMutex mutex = AV_MUTEX_INITIALIZER;
@@ -243,14 +245,32 @@  static const char *get_level_str(int level)
     }
}
+static void format_date_now(AVBPrint* timeBuf, int include_date)
+{
+    struct tm *ptm, tmbuf;
+    int64_t time_us = av_gettime();
+    int64_t time_ms = time_us / 1000;
+    const time_t time_s = time_ms / 1000;
+    int millisec = time_ms - (time_s * 1000);
+    ptm = localtime_r(&time_s, &tmbuf);
+    if (ptm) {
+        if (include_date)
+            av_bprint_strftime(timeBuf, "%Y-%m-%d ", ptm);
+
+        av_bprint_strftime(timeBuf, "%H:%M:%S", ptm);
+        av_bprintf(timeBuf, ".%03d ", millisec);
+    }
+}
+
static void format_line(void *avcl, int level, const char *fmt, va_list vl,
-                        AVBPrint part[4], int *print_prefix, int type[2])
+                        AVBPrint part[5], int *print_prefix, int type[2])
{
     AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
     av_bprint_init(part+0, 0, AV_BPRINT_SIZE_AUTOMATIC);
     av_bprint_init(part+1, 0, AV_BPRINT_SIZE_AUTOMATIC);
     av_bprint_init(part+2, 0, AV_BPRINT_SIZE_AUTOMATIC);
     av_bprint_init(part+3, 0, 65536);
+    av_bprint_init(part+4, 0, AV_BPRINT_SIZE_AUTOMATIC);
     if(type) type[0] = type[1] = AV_CLASS_CATEGORY_NA + 16;
     if (*print_prefix && avc) {
@@ -277,6 +297,10 @@  static void format_line(void *avcl, int level, const char *fmt, va_list vl,
         char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0;
         *print_prefix = lastc == '\n' || lastc == '\r';
     }
+
+    if (*print_prefix && part[3].len > 1 && (flags & AV_LOG_PRINT_STARTUPCOMPLETE)
+        && ((flags & AV_LOG_PRINT_TIME) || (flags & AV_LOG_PRINT_DATETIME)))
+        format_date_now(&part[4], flags & AV_LOG_PRINT_DATETIME);
}
 void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl,
@@ -288,12 +312,12 @@  void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl,
int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl,
                         char *line, int line_size, int *print_prefix)
{
-    AVBPrint part[4];
+    AVBPrint part[5];
     int ret;
     format_line(ptr, level, fmt, vl, part, print_prefix, NULL);
     ret = snprintf(line, line_size, "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
-    av_bprint_finalize(part+3, NULL);
+    av_bprint_finalize(part+4, NULL);
     return ret;
}
@@ -302,7 +326,7 @@  void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl)
     static int print_prefix = 1;
     static int count;
     static char prev[LINE_SZ];
-    AVBPrint part[4];
+    AVBPrint part[5];
     char line[LINE_SZ];
     static int is_atty;
     int type[2];
@@ -337,6 +361,9 @@  void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl)
         count = 0;
     }
     strcpy(prev, line);
+
+    sanitize(part[4].str);
+    colored_fputs(7, 0, part[4].str);
     sanitize(part[0].str);
     colored_fputs(type[0], 0, part[0].str);
     sanitize(part[1].str);
@@ -351,7 +378,7 @@  void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl)
         VALGRIND_PRINTF_BACKTRACE("%s", "");
#endif
end:
-    av_bprint_finalize(part+3, NULL);
+    av_bprint_finalize(part+4, NULL);
     ff_mutex_unlock(&mutex);
}
diff --git a/libavutil/log.h b/libavutil/log.h
index d9554e609d..a4a750de74 100644
--- a/libavutil/log.h
+++ b/libavutil/log.h
@@ -352,6 +352,23 @@  int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl,
  */
#define AV_LOG_PRINT_LEVEL 2
+/**
+ * Include system time in log output.
+ */
+#define AV_LOG_PRINT_TIME 4
+
+/**
+ * Include system date and time in log output.
+ */
+#define AV_LOG_PRINT_DATETIME 8
+
+/**
+ * Internal flag indicating that transcoding has started
+ * and subsequent log output should include timing when
+ * AV_LOG_PRINT_TIME or AV_LOG_PRINT_DATETIME is set.
+ */
+#define AV_LOG_PRINT_STARTUPCOMPLETE 65536
+
void av_log_set_flags(int arg);
int av_log_get_flags(void);
--
2.17.1.windows.2