[vlc-commits] [Git][videolan/vlc][master] 9 commits: core: add tracing API

Thomas Guillem (@tguillem) gitlab at videolan.org
Tue Aug 31 14:38:15 UTC 2021



Thomas Guillem pushed to branch master at VideoLAN / VLC


Commits:
ee52a2e1 by Nicolas LeQuec at 2021-08-31T12:35:56+00:00
core: add tracing API

Tracing system is independant from the logging system and load modules with a "tracer" capability.
The tracer module is loaded at the initialisation of a libvlc instance.

- - - - -
fa32b560 by Nicolas LeQuec at 2021-08-31T12:35:56+00:00
src/object: add vlc_object_get_tracer function

- - - - -
d66f36af by Nicolas LeQuec at 2021-08-31T12:35:56+00:00
libvlc: integrate vlc_tracer API

- - - - -
0bf5330a by Nicolas LeQuec at 2021-08-31T12:35:56+00:00
src/clock: add a tracer field to the main clock

- - - - -
fcafe8a5 by Nicolas LeQuec at 2021-08-31T12:35:56+00:00
logger: add new trace module

Add a trace module that stores the traces in a file or displays them
in stdout with a json notation.

- - - - -
66fe08f3 by Nicolas LeQuec at 2021-08-31T12:35:56+00:00
libvlc-module: add the tracer module

- - - - -
a7edba07 by Nicolas LeQuec at 2021-08-31T12:35:56+00:00
src/decoder: add new field psz_id

In traces, it's useful to have the id of the decoder used.

- - - - -
8218c474 by Nicolas LeQuec at 2021-08-31T12:35:56+00:00
src/clock: add new field track_str_id

In traces, it's useful to have the str_id of the elementary stream read.
It can be obtained through the clock.

- - - - -
f55348fd by Nicolas LeQuec at 2021-08-31T12:35:56+00:00
logs: fit trace messages with the new trace API

Use of the previouly created trace API to collect data from demuxer, decoder and video_output.
Fields "type", "id", and "stream" are then used by a script to identify data and name curves to
display.
Here is the link of the script project: https://gitlab.com/videolabs/public/vlc-pa

- - - - -


16 changed files:

- include/vlc_objects.h
- + include/vlc_tracer.h
- modules/logger/Makefile.am
- + modules/logger/json.c
- src/Makefile.am
- src/clock/clock.c
- src/clock/clock.h
- src/input/decoder.c
- src/input/decoder.h
- src/input/es_out.c
- src/libvlc-module.c
- src/libvlc.c
- src/libvlc.h
- src/libvlccore.sym
- src/misc/objects.c
- + src/misc/tracer.c


Changes:

=====================================
include/vlc_objects.h
=====================================
@@ -29,6 +29,7 @@
  */
 
 struct vlc_logger;
+struct vlc_tracer;
 struct vlc_object_internals;
 struct vlc_object_marker;
 
@@ -161,6 +162,13 @@ static inline struct vlc_logger *vlc_object_logger(vlc_object_t *obj)
 }
 #define vlc_object_logger(o) vlc_object_logger(VLC_OBJECT(o))
 
+ /**
+ * Get tracer of a vlc instance from an object.
+ *
+ * \return the tracer of a vlc instance from an object (NULL if none).
+ */
+VLC_API struct vlc_tracer *vlc_object_get_tracer(vlc_object_t *obj);
+
 /**
  * Tries to get the name of module bound to an object.
  *


=====================================
include/vlc_tracer.h
=====================================
@@ -0,0 +1,188 @@
+/*****************************************************************************
+ * vlc_tracer.h: tracing interface
+ * This library provides basic functions for threads to interact with user
+ * interface, such as trace output.
+ *****************************************************************************
+ * Copyright (C) 2021 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef VLC_TRACES_H
+#define VLC_TRACES_H
+
+#include <stdarg.h>
+
+/**
+ * \defgroup traces Tracing
+ * \ingroup os
+ * \brief Message traces
+ *
+ * Functions for modules to emit traces.
+ *
+ * @{
+ * \file
+ * Tracing functions
+ */
+
+/**
+ * Trace message values
+ */
+enum vlc_tracer_value
+{
+    VLC_TRACER_INT,
+    VLC_TRACER_STRING
+};
+
+typedef union
+{
+    int64_t integer;
+    const char *string;
+} vlc_tracer_value_t;
+
+/**
+ * Trace message
+ */
+struct vlc_tracer_entry
+{
+    const char *key;            /**< Key to identify the value */
+    vlc_tracer_value_t value;   /**< Trace value */
+    enum vlc_tracer_value type; /**< Type of the value */
+};
+
+struct vlc_tracer;
+
+/**
+ * Trace logging callback signature.
+ *
+ * va-args can only be \ref vlc_tracer_entry and the va-args list
+ * should be ended by a \ref vlc_tracer_entry with a NULL key.
+ * \param data data pointer as provided to vlc_tracer_Trace().
+ */
+typedef void (*vlc_trace_cb) (void *data, va_list entries);
+
+struct vlc_tracer_operations
+{
+    vlc_trace_cb trace;
+    void (*destroy)(void *data);
+};
+
+/**
+ * Emit traces
+ *
+ * va-args are a list of key / value parameters.
+ * Key must be a not NULL string.
+ * Value has to be defined with one of the type defined
+ * in the \ref vlc_tracer_entry union.
+ * \param tracer tracer emitting the traces
+ */
+VLC_API void vlc_tracer_Trace(struct vlc_tracer *tracer, ...);
+
+/**
+ * \defgroup tracer Tracer
+ * \brief Tracing back-end.
+ *
+ * @{
+ */
+
+static inline struct vlc_tracer_entry vlc_tracer_entry_FromTick(const char *key, vlc_tick_t value)
+{
+    vlc_tracer_value_t tracer_value;
+    tracer_value.integer = value;
+    struct vlc_tracer_entry trace = { key, tracer_value, VLC_TRACER_INT };
+    return trace;
+}
+
+static inline struct vlc_tracer_entry vlc_tracer_entry_FromString(const char *key, const char *value)
+{
+    vlc_tracer_value_t tracer_value;
+    tracer_value.string = value;
+    struct vlc_tracer_entry trace = { key, tracer_value, VLC_TRACER_STRING };
+    return trace;
+}
+
+#ifndef __cplusplus
+#define VLC_TRACE_END \
+        vlc_tracer_entry_FromString(NULL, NULL)
+
+#define VLC_TRACE(key, value) \
+        _Generic((value), \
+        vlc_tick_t: vlc_tracer_entry_FromTick, \
+        char *: vlc_tracer_entry_FromString, \
+        const char *: vlc_tracer_entry_FromString) (key, value)
+#else
+#define VLC_TRACE_END \
+        vlc_tracer_entry_FromString(nullptr, nullptr)
+
+static inline struct vlc_tracer_entry VLC_TRACE(const char *key, vlc_tick_t value)
+{
+    return vlc_tracer_entry_FromTick(key, value);
+}
+
+static inline struct vlc_tracer_entry VLC_TRACE(const char *key, char *value)
+{
+    return vlc_tracer_entry_FromString(key, value);
+}
+
+static inline struct vlc_tracer_entry VLC_TRACE(const char *key, const char *value)
+{
+    return vlc_tracer_entry_FromString(key, value);
+}
+#endif
+
+/*
+ * Helper trace functions
+ */
+
+static inline void vlc_tracer_TraceStreamPTS(struct vlc_tracer *tracer, const char *type,
+                                const char *id, const char* stream,
+                                vlc_tick_t pts)
+{
+    vlc_tracer_Trace(tracer, VLC_TRACE("type", type), VLC_TRACE("id", id),
+                     VLC_TRACE("stream", stream), VLC_TRACE("pts", NS_FROM_VLC_TICK(pts)),
+                     VLC_TRACE_END);
+}
+
+static inline void vlc_tracer_TraceStreamDTS(struct vlc_tracer *tracer, const char *type,
+                                const char *id, const char* stream,
+                                vlc_tick_t pts, vlc_tick_t dts)
+{
+    vlc_tracer_Trace(tracer, VLC_TRACE("type", type), VLC_TRACE("id", id),
+                     VLC_TRACE("stream", stream), VLC_TRACE("pts", NS_FROM_VLC_TICK(pts)),
+                     VLC_TRACE("dts", NS_FROM_VLC_TICK(dts)), VLC_TRACE_END);
+}
+
+static inline void vlc_tracer_TraceRender(struct vlc_tracer *tracer, const char *type,
+                                const char *id, vlc_tick_t pts, vlc_tick_t now)
+{
+    vlc_tracer_Trace(tracer, VLC_TRACE("type", type), VLC_TRACE("id", id),
+                     VLC_TRACE("pts", NS_FROM_VLC_TICK(pts)),
+                     VLC_TRACE("render_ts", NS_FROM_VLC_TICK(now)), VLC_TRACE_END);
+}
+
+static inline void vlc_tracer_TracePCR( struct vlc_tracer *tracer, const char *type,
+                                    const char *id, vlc_tick_t pcr)
+{
+    vlc_tracer_Trace(tracer, VLC_TRACE("type", type), VLC_TRACE("id", id),
+                     VLC_TRACE("pcr", NS_FROM_VLC_TICK(pcr)), VLC_TRACE_END);
+}
+
+/**
+ * @}
+ */
+/**
+ * @}
+ */
+#endif


=====================================
modules/logger/Makefile.am
=====================================
@@ -22,3 +22,6 @@ libandroid_logger_plugin_la_LIBADD = -llog
 if HAVE_ANDROID
 logger_LTLIBRARIES += libandroid_logger_plugin.la
 endif
+
+libjson_tracer_plugin_la_SOURCES = logger/json.c
+logger_LTLIBRARIES += libjson_tracer_plugin.la


=====================================
modules/logger/json.c
=====================================
@@ -0,0 +1,270 @@
+/*****************************************************************************
+ * json.c: JSON tracer plugin
+ *****************************************************************************
+ * Copyright © 2021 Videolabs
+ *
+ * Authors : Nicolas Le Quec
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_fs.h>
+#include <vlc_charset.h>
+#include <vlc_tracer.h>
+#include <vlc_memstream.h>
+
+#include <stdbool.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+#include <ctype.h>
+
+#define JSON_FILENAME "vlc-log.json"
+
+typedef struct
+{
+    FILE *stream;
+} vlc_tracer_sys_t;
+
+static void PrintUTF8Char(FILE *stream, uint32_t character)
+{
+    /* If the character is in the Basic Multilingual Plane (U+0000 through U+FFFF),
+       then it may be represented as a six-character sequence: \uxxxx */
+    if (character < 0x10000)
+    {
+        fprintf(stream, "\\u%04x", character);
+    }
+    /* To escape an extended character that is not in the Basic Multilingual
+      Plane, the character is represented as a 12-character sequence, encoding
+      the UTF-16 surrogate pair. */
+
+    else if (0x10000 <= character && character <= 0x10FFFF) {
+        unsigned int code;
+        uint16_t units[2];
+
+        code = (character - 0x10000);
+        units[0] = 0xD800 | (code >> 10);
+        units[1] = 0xDC00 | (code & 0x3FF);
+
+        fprintf(stream, "\\u%04x\\u%04x", units[0], units[1]);
+    }
+}
+
+static void JsonPrintString(FILE *stream, const char *str)
+{
+    if (!IsUTF8(str))
+    {
+        fputs("\"invalid string\"", stream);
+        return;
+    }
+
+    fputc('\"', stream);
+
+    unsigned char byte;
+    while (*str != '\0')
+    {
+        switch (*str)
+        {
+        case '/':
+            fputs("\\/", stream);
+            break;
+        case '\b':
+            fputs("\\b", stream);
+            break;
+        case '\f':
+            fputs("\\f", stream);
+            break;
+        case '\n':
+            fputs("\\n", stream);
+            break;
+        case '\r':
+            fputs("\\r", stream);
+            break;
+        case '\t':
+            fputs("\\t", stream);
+            break;
+        case '\\':
+        case '\"':
+            fprintf(stream, "\\%c", *str);
+            break;
+        default:
+            byte = *str;
+            if (byte <= 0x1F || byte == 0x7F)
+            {
+                fprintf(stream, "\\u%04x", byte);
+            }
+            else if (byte < 0x80)
+            {
+                fputc(byte, stream);
+            }
+            else
+            {
+                uint32_t bytes;
+                size_t len = vlc_towc(str, &bytes);
+                PrintUTF8Char(stream, bytes);
+                str += len - 1;
+            }
+        }
+        str++;
+    }
+    fputc('\"', stream);
+}
+
+static void JsonPrintKeyValueNumber(FILE *stream, const char *key, int64_t value)
+{
+    JsonPrintString(stream, key);
+    fprintf(stream, ": \"%"PRId64"\"", value);
+}
+
+static void JsonPrintKeyValueLabel(FILE *stream, const char *key, const char *value)
+{
+    JsonPrintString(stream, key);
+    fputs(": ", stream);
+    JsonPrintString(stream, value);
+}
+
+static void JsonStartObjectSection(FILE *stream, const char* name)
+{
+    if (name != NULL)
+        fprintf(stream, "\"%s\": {", name);
+    else
+        fputc('{', stream);
+}
+
+static void JsonEndObjectSection(FILE *stream)
+{
+    fputc('}', stream);
+}
+
+static void TraceJson(void *opaque, va_list entries)
+{
+    vlc_tracer_sys_t *sys = opaque;
+    FILE* stream = sys->stream;
+
+    flockfile(stream);
+    JsonStartObjectSection(stream, NULL);
+    JsonPrintKeyValueNumber(stream, "Timestamp", US_FROM_VLC_TICK(vlc_tick_now()));
+    fputc(',', stream);
+
+    JsonStartObjectSection(stream, "Body");
+
+    struct vlc_tracer_entry entry = va_arg(entries, struct vlc_tracer_entry);
+    while (entry.key != NULL)
+    {
+        switch (entry.type)
+        {
+            case VLC_TRACER_INT:
+                JsonPrintKeyValueNumber(stream, entry.key, entry.value.integer);
+                break;
+            case VLC_TRACER_STRING:
+                JsonPrintKeyValueLabel(stream, entry.key, entry.value.string);
+                break;
+            default:
+                vlc_assert_unreachable();
+                break;
+        }
+        entry = va_arg(entries, struct vlc_tracer_entry);
+        if (entry.key != NULL)
+        {
+            fputc(',', stream);
+        }
+    }
+    JsonEndObjectSection(stream);
+    JsonEndObjectSection(stream);
+    fputc('\n', stream);
+    funlockfile(stream);
+}
+
+static void Close(void *opaque)
+{
+    vlc_tracer_sys_t *sys = opaque;
+
+    free(sys);
+}
+
+static const struct vlc_tracer_operations json_ops =
+{
+    TraceJson,
+    Close
+};
+
+static const struct vlc_tracer_operations *Open(vlc_object_t *obj,
+                                               void **restrict sysp)
+{
+    vlc_tracer_sys_t *sys = malloc(sizeof (*sys));
+    if (unlikely(sys == NULL))
+        return NULL;
+
+    const struct vlc_tracer_operations *ops = &json_ops;
+
+    const char *filename = JSON_FILENAME;
+
+    char *path = var_InheritString(obj, "json-tracer-file");
+#ifdef __APPLE__
+    if (path == NULL)
+    {
+        char *home = config_GetUserDir(VLC_HOME_DIR);
+        if (home != NULL)
+        {
+            if (asprintf(&path, "%s/Library/Logs/"JSON_FILENAME, home) == -1)
+                path = NULL;
+            free(home);
+        }
+    }
+#endif
+    if (path != NULL)
+        filename = path;
+
+    /* Open the log file and remove any buffering for the stream */
+    msg_Dbg(obj, "opening logfile `%s'", filename);
+    sys->stream = vlc_fopen(filename, "at");
+    if (sys->stream == NULL)
+    {
+        msg_Err(obj, "error opening log file `%s': %s", filename,
+            vlc_strerror_c(errno) );
+        free(path);
+        free(sys);
+        return NULL;
+    }
+    free(path);
+
+    setvbuf(sys->stream, NULL, _IOLBF, 0);
+
+    *sysp = sys;
+    return ops;
+}
+
+#define FILE_LOG_TEXT N_("Log to file")
+#define FILE_LOG_LONGTEXT N_("Log all VLC traces to a json file.")
+
+#define LOGFILE_NAME_TEXT N_("Log filename")
+#define LOGFILE_NAME_LONGTEXT N_("Specify the log filename.")
+
+vlc_module_begin()
+    set_shortname(N_("Tracer"))
+    set_description(N_("JSON tracer"))
+    set_category(CAT_ADVANCED)
+    set_subcategory(SUBCAT_ADVANCED_MISC)
+    set_capability("tracer", 0)
+    set_callback(Open)
+
+    add_savefile("json-tracer-file", NULL, LOGFILE_NAME_TEXT, LOGFILE_NAME_LONGTEXT)
+vlc_module_end()


=====================================
src/Makefile.am
=====================================
@@ -70,6 +70,7 @@ pluginsinclude_HEADERS = \
 	../include/vlc_media_source.h \
 	../include/vlc_memstream.h \
 	../include/vlc_messages.h \
+	../include/vlc_tracer.h \
 	../include/vlc_meta.h \
 	../include/vlc_meta_fetcher.h \
 	../include/vlc_mime.h \
@@ -378,6 +379,7 @@ libvlccore_la_SOURCES = \
 	misc/events.c \
 	misc/image.c \
 	misc/messages.c \
+	misc/tracer.c \
 	misc/mime.c \
 	misc/objects.c \
 	misc/objres.c \


=====================================
src/clock/clock.c
=====================================
@@ -25,12 +25,14 @@
 #include <vlc_aout.h>
 #include <assert.h>
 #include <limits.h>
+#include <vlc_tracer.h>
 #include "clock.h"
 #include "clock_internal.h"
 
 struct vlc_clock_main_t
 {
     struct vlc_logger *logger;
+    struct vlc_tracer *tracer;
     vlc_mutex_t lock;
     vlc_cond_t cond;
 
@@ -72,6 +74,7 @@ struct vlc_clock_t
     vlc_clock_main_t *owner;
     vlc_tick_t delay;
     unsigned priority;
+    const char *track_str_id;
 
     const struct vlc_clock_cbs *cbs;
     void *cbs_data;
@@ -105,9 +108,15 @@ static inline void vlc_clock_on_update(vlc_clock_t *clock,
                                        unsigned frame_rate,
                                        unsigned frame_rate_base)
 {
+    vlc_clock_main_t *main_clock = clock->owner;
     if (clock->cbs)
         clock->cbs->on_update(system_now, ts, rate, frame_rate, frame_rate_base,
                               clock->cbs_data);
+
+    if (main_clock->tracer != NULL && clock->track_str_id)
+    {
+        vlc_tracer_TraceRender(main_clock->tracer, "RENDER", clock->track_str_id, ts, system_now);
+    }
 }
 
 static vlc_tick_t vlc_clock_master_update(vlc_clock_t *clock,
@@ -385,7 +394,7 @@ void vlc_clock_Wake(vlc_clock_t *clock)
     vlc_cond_broadcast(&main_clock->cond);
 }
 
-vlc_clock_main_t *vlc_clock_main_New(struct vlc_logger *parent_logger)
+vlc_clock_main_t *vlc_clock_main_New(struct vlc_logger *parent_logger, struct vlc_tracer *parent_tracer)
 {
     vlc_clock_main_t *main_clock = malloc(sizeof(vlc_clock_main_t));
 
@@ -398,6 +407,7 @@ vlc_clock_main_t *vlc_clock_main_New(struct vlc_logger *parent_logger)
         free(main_clock);
         return NULL;
     }
+    main_clock->tracer = parent_tracer;
 
     vlc_mutex_init(&main_clock->lock);
     vlc_cond_init(&main_clock->cond);
@@ -547,6 +557,7 @@ static void vlc_clock_set_slave_callbacks(vlc_clock_t *clock)
 }
 
 static vlc_clock_t *vlc_clock_main_Create(vlc_clock_main_t *main_clock,
+                                          const char* track_str_id,
                                           unsigned priority,
                                           const struct vlc_clock_cbs *cbs,
                                           void *cbs_data)
@@ -556,6 +567,7 @@ static vlc_clock_t *vlc_clock_main_Create(vlc_clock_main_t *main_clock,
         return NULL;
 
     clock->owner = main_clock;
+    clock->track_str_id = track_str_id;
     clock->delay = 0;
     clock->cbs = cbs;
     clock->cbs_data = cbs_data;
@@ -566,11 +578,12 @@ static vlc_clock_t *vlc_clock_main_Create(vlc_clock_main_t *main_clock,
 }
 
 vlc_clock_t *vlc_clock_main_CreateMaster(vlc_clock_main_t *main_clock,
+                                         const char *track_str_id,
                                          const struct vlc_clock_cbs *cbs,
                                          void *cbs_data)
 {
     /* The master has always the 0 priority */
-    vlc_clock_t *clock = vlc_clock_main_Create(main_clock, 0, cbs, cbs_data);
+    vlc_clock_t *clock = vlc_clock_main_Create(main_clock, track_str_id, 0, cbs, cbs_data);
     if (!clock)
         return NULL;
 
@@ -592,7 +605,7 @@ vlc_clock_t *vlc_clock_main_CreateMaster(vlc_clock_main_t *main_clock,
 vlc_clock_t *vlc_clock_main_CreateInputMaster(vlc_clock_main_t *main_clock)
 {
     /* The master has always the 0 priority */
-    vlc_clock_t *clock = vlc_clock_main_Create(main_clock, 0, NULL, NULL);
+    vlc_clock_t *clock = vlc_clock_main_Create(main_clock, NULL, 0, NULL, NULL);
     if (!clock)
         return NULL;
 
@@ -616,6 +629,7 @@ vlc_clock_t *vlc_clock_main_CreateInputMaster(vlc_clock_main_t *main_clock)
 }
 
 vlc_clock_t *vlc_clock_main_CreateSlave(vlc_clock_main_t *main_clock,
+                                        const char* track_str_id,
                                         enum es_format_category_e cat,
                                         const struct vlc_clock_cbs *cbs,
                                         void *cbs_data)
@@ -637,7 +651,7 @@ vlc_clock_t *vlc_clock_main_CreateSlave(vlc_clock_main_t *main_clock,
             break;
     }
 
-    vlc_clock_t *clock = vlc_clock_main_Create(main_clock, priority, cbs,
+    vlc_clock_t *clock = vlc_clock_main_Create(main_clock, track_str_id, priority, cbs,
                                                cbs_data);
     if (!clock)
         return NULL;
@@ -653,7 +667,7 @@ vlc_clock_t *vlc_clock_main_CreateSlave(vlc_clock_main_t *main_clock,
 vlc_clock_t *vlc_clock_CreateSlave(const vlc_clock_t *clock,
                                    enum es_format_category_e cat)
 {
-    return vlc_clock_main_CreateSlave(clock->owner, cat, NULL, NULL);
+    return vlc_clock_main_CreateSlave(clock->owner, clock->track_str_id, cat, NULL, NULL);
 }
 
 void vlc_clock_Delete(vlc_clock_t *clock)


=====================================
src/clock/clock.h
=====================================
@@ -58,7 +58,7 @@ struct vlc_clock_cbs
 /**
  * This function creates the vlc_clock_main_t of the program
  */
-vlc_clock_main_t *vlc_clock_main_New(struct vlc_logger *parent_logger);
+vlc_clock_main_t *vlc_clock_main_New(struct vlc_logger *parent_logger, struct vlc_tracer *parent_tracer);
 
 /**
  * Destroy the clock main
@@ -97,6 +97,7 @@ void vlc_clock_main_ChangePause(vlc_clock_main_t *clock, vlc_tick_t system_now,
  * You must use vlc_clock_Delete to free it.
  */
 vlc_clock_t *vlc_clock_main_CreateMaster(vlc_clock_main_t *main_clock,
+                                         const char *track_str_id,
                                          const struct vlc_clock_cbs *cbs,
                                          void *cbs_data);
 
@@ -118,6 +119,7 @@ vlc_clock_t *vlc_clock_main_CreateInputMaster(vlc_clock_main_t *main_clock);
  * You must use vlc_clock_Delete to free it.
  */
 vlc_clock_t *vlc_clock_main_CreateSlave(vlc_clock_main_t *main_clock,
+                                        const char *track_str_id,
                                         enum es_format_category_e cat,
                                         const struct vlc_clock_cbs *cbs,
                                         void *cbs_data);


=====================================
src/input/decoder.c
=====================================
@@ -43,6 +43,7 @@
 #include <vlc_modules.h>
 #include <vlc_decoder.h>
 #include <vlc_picture_pool.h>
+#include <vlc_tracer.h>
 
 #include "audio_output/aout_internal.h"
 #include "stream_output/stream_output.h"
@@ -68,6 +69,7 @@ struct vlc_input_decoder_t
     decoder_t        dec;
     input_resource_t*p_resource;
     vlc_clock_t     *p_clock;
+    const char *psz_id;
 
     const struct vlc_input_decoder_callbacks *cbs;
     void *cbs_userdata;
@@ -1113,7 +1115,13 @@ static void ModuleThread_QueueVideo( decoder_t *p_dec, picture_t *p_pic )
 {
     assert( p_pic );
     vlc_input_decoder_t *p_owner = dec_get_owner( p_dec );
+    struct vlc_tracer *tracer = vlc_object_get_tracer( &p_dec->obj );
 
+    if ( tracer != NULL )
+    {
+        vlc_tracer_TraceStreamPTS( tracer, "DEC", p_owner->psz_id,
+                            "OUT", p_pic->date );
+    }
     int success = ModuleThread_PlayVideo( p_owner, p_pic );
 
     ModuleThread_UpdateStatVideo( p_owner, success != VLC_SUCCESS );
@@ -1242,7 +1250,13 @@ static void ModuleThread_UpdateStatAudio( vlc_input_decoder_t *p_owner,
 static void ModuleThread_QueueAudio( decoder_t *p_dec, block_t *p_aout_buf )
 {
     vlc_input_decoder_t *p_owner = dec_get_owner( p_dec );
+    struct vlc_tracer *tracer = vlc_object_get_tracer( &p_dec->obj );
 
+    if ( tracer != NULL && p_aout_buf != NULL )
+    {
+        vlc_tracer_TraceStreamDTS( tracer, "DEC", p_owner->psz_id, "OUT",
+                            p_aout_buf->i_pts, p_aout_buf->i_dts );
+    }
     int success = ModuleThread_PlayAudio( p_owner, p_aout_buf );
 
     ModuleThread_UpdateStatAudio( p_owner, success != VLC_SUCCESS );
@@ -1280,6 +1294,13 @@ static void ModuleThread_QueueSpu( decoder_t *p_dec, subpicture_t *p_spu )
 {
     assert( p_spu );
     vlc_input_decoder_t *p_owner = dec_get_owner( p_dec );
+    struct vlc_tracer *tracer = vlc_object_get_tracer( &p_dec->obj );
+
+    if ( tracer != NULL && p_spu != NULL )
+    {
+        vlc_tracer_TraceStreamPTS( tracer, "DEC", p_owner->psz_id,
+                            "OUT", p_spu->i_start );
+    }
 
     /* The vout must be created from a previous decoder_NewSubpicture call. */
     assert( p_owner->p_vout );
@@ -1304,6 +1325,13 @@ static void DecoderThread_ProcessInput( vlc_input_decoder_t *p_owner, block_t *p
 static void DecoderThread_DecodeBlock( vlc_input_decoder_t *p_owner, block_t *p_block )
 {
     decoder_t *p_dec = &p_owner->dec;
+    struct vlc_tracer *tracer = vlc_object_get_tracer( &p_dec->obj );
+
+    if ( tracer != NULL && p_block != NULL )
+    {
+        vlc_tracer_TraceStreamDTS( tracer, "DEC", p_owner->psz_id, "IN",
+                            p_block->i_pts, p_block->i_dts );
+    }
 
     int ret = p_dec->pf_decode( p_dec, p_block );
     switch( ret )
@@ -1769,8 +1797,8 @@ static const struct decoder_owner_callbacks dec_spu_cbs =
  * \return the decoder object
  */
 static vlc_input_decoder_t *
-CreateDecoder( vlc_object_t *p_parent,
-               const es_format_t *fmt, vlc_clock_t *p_clock,
+CreateDecoder( vlc_object_t *p_parent, const es_format_t *fmt,
+               const char *psz_id, vlc_clock_t *p_clock,
                input_resource_t *p_resource, sout_stream_t *p_sout,
                bool b_thumbnailing, const struct vlc_input_decoder_callbacks *cbs,
                void *cbs_userdata )
@@ -1785,6 +1813,7 @@ CreateDecoder( vlc_object_t *p_parent,
         return NULL;
     p_dec = &p_owner->dec;
 
+    p_owner->psz_id = psz_id;
     p_owner->p_clock = p_clock;
     p_owner->i_preroll_end = PREROLL_NONE;
     p_owner->p_resource = p_resource;
@@ -2028,7 +2057,7 @@ static void DecoderUnsupportedCodec( decoder_t *p_dec, const es_format_t *fmt, b
 
 /* TODO: pass p_sout through p_resource? -- Courmisch */
 static vlc_input_decoder_t *
-decoder_New( vlc_object_t *p_parent, const es_format_t *fmt,
+decoder_New( vlc_object_t *p_parent, const es_format_t *fmt, const char *psz_id,
              vlc_clock_t *p_clock, input_resource_t *p_resource,
              sout_stream_t *p_sout, bool thumbnailing,
              const struct vlc_input_decoder_callbacks *cbs, void *userdata)
@@ -2038,7 +2067,7 @@ decoder_New( vlc_object_t *p_parent, const es_format_t *fmt,
 
     /* Create the decoder configuration structure */
     vlc_input_decoder_t *p_owner =
-        CreateDecoder( p_parent, fmt, p_clock, p_resource, p_sout,
+        CreateDecoder( p_parent, fmt, psz_id, p_clock, p_resource, p_sout,
                        thumbnailing, cbs, userdata );
     if( p_owner == NULL )
     {
@@ -2102,12 +2131,13 @@ decoder_New( vlc_object_t *p_parent, const es_format_t *fmt,
  */
 vlc_input_decoder_t *
 vlc_input_decoder_New( vlc_object_t *parent, es_format_t *fmt,
-                  vlc_clock_t *p_clock, input_resource_t *resource,
+                  const char *psz_id, vlc_clock_t *p_clock,
+                  input_resource_t *resource,
                   sout_stream_t *p_sout, bool thumbnailing,
                   const struct vlc_input_decoder_callbacks *cbs,
                   void *cbs_userdata)
 {
-    return decoder_New( parent, fmt, p_clock, resource, p_sout, thumbnailing,
+    return decoder_New( parent, fmt, psz_id, p_clock, resource, p_sout, thumbnailing,
                         cbs, cbs_userdata );
 }
 
@@ -2118,7 +2148,7 @@ vlc_input_decoder_t *
 vlc_input_decoder_Create( vlc_object_t *p_parent, const es_format_t *fmt,
                      input_resource_t *p_resource )
 {
-    return decoder_New( p_parent, fmt, NULL, p_resource, NULL, false, NULL,
+    return decoder_New( p_parent, fmt, NULL, NULL, p_resource, NULL, false, NULL,
                         NULL );
 }
 
@@ -2371,9 +2401,9 @@ int vlc_input_decoder_SetCcState( vlc_input_decoder_t *p_owner, vlc_fourcc_t cod
         es_format_Init( &fmt, SPU_ES, codec );
         fmt.subs.cc.i_channel = i_channel;
         fmt.subs.cc.i_reorder_depth = p_owner->cc.desc.i_reorder_depth;
-        p_ccowner = vlc_input_decoder_New( VLC_OBJECT(p_dec), &fmt, p_owner->p_clock,
-                                      p_owner->p_resource, p_owner->p_sout, false,
-                                      NULL, NULL );
+        p_ccowner = vlc_input_decoder_New( VLC_OBJECT(p_dec), &fmt, p_owner->psz_id,
+                                      p_owner->p_clock, p_owner->p_resource, p_owner->p_sout,
+                                      false, NULL, NULL );
         if( !p_ccowner )
         {
             msg_Err( p_dec, "could not create decoder" );


=====================================
src/input/decoder.h
=====================================
@@ -51,7 +51,7 @@ struct vlc_input_decoder_callbacks {
 };
 
 vlc_input_decoder_t *
-vlc_input_decoder_New( vlc_object_t *parent, es_format_t *, vlc_clock_t *,
+vlc_input_decoder_New( vlc_object_t *parent, es_format_t *, const char *psz_id, vlc_clock_t *,
                        input_resource_t *, sout_stream_t *, bool thumbnailing,
                        const struct vlc_input_decoder_callbacks *cbs,
                        void *userdata ) VLC_USED;


=====================================
src/input/es_out.c
=====================================
@@ -40,6 +40,7 @@
 #include <vlc_list.h>
 #include <vlc_decoder.h>
 #include <vlc_memstream.h>
+#include <vlc_tracer.h>
 
 #include "input_internal.h"
 #include "../clock/input_clock.h"
@@ -845,7 +846,8 @@ static int EsOutSetRecord(  es_out_t *out, bool b_record )
                 continue;
 
             p_es->p_dec_record =
-                vlc_input_decoder_New( VLC_OBJECT(p_input), &p_es->fmt, NULL,
+                vlc_input_decoder_New( VLC_OBJECT(p_input), &p_es->fmt,
+                                       p_es->id.str_id, NULL,
                                        input_priv(p_input)->p_resource,
                                        p_sys->p_sout_record, false,
                                        &decoder_cbs, p_es );
@@ -1498,7 +1500,8 @@ static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, input_source_t *source, in
     p_pgrm->p_master_es_clock = NULL;
     p_pgrm->active_clock_source = VLC_CLOCK_MASTER_AUTO;
 
-    p_pgrm->p_main_clock = vlc_clock_main_New( p_input->obj.logger );
+    struct vlc_tracer *tracer = vlc_object_get_tracer( &p_input->obj );
+    p_pgrm->p_main_clock = vlc_clock_main_New( p_input->obj.logger, tracer );
     if( !p_pgrm->p_main_clock )
     {
         free( p_pgrm );
@@ -2313,12 +2316,14 @@ static void EsOutCreateDecoder( es_out_t *out, es_out_id_t *p_es )
         p_es->master = true;
         p_es->p_pgrm->p_master_es_clock = p_es->p_clock =
             vlc_clock_main_CreateMaster( p_es->p_pgrm->p_main_clock,
+                                         p_es->id.str_id,
                                          &clock_cbs, p_es );
     }
     else
     {
         p_es->master = false;
         p_es->p_clock = vlc_clock_main_CreateSlave( p_es->p_pgrm->p_main_clock,
+                                                    p_es->id.str_id,
                                                     p_es->fmt.i_cat,
                                                     &clock_cbs, p_es );
     }
@@ -2330,7 +2335,8 @@ static void EsOutCreateDecoder( es_out_t *out, es_out_id_t *p_es )
     }
 
     input_thread_private_t *priv = input_priv(p_input);
-    dec = vlc_input_decoder_New( VLC_OBJECT(p_input), &p_es->fmt, p_es->p_clock,
+    dec = vlc_input_decoder_New( VLC_OBJECT(p_input), &p_es->fmt,
+                                 p_es->id.str_id, p_es->p_clock,
                                  priv->p_resource, priv->p_sout,
                                  priv->b_thumbnailing, &decoder_cbs, p_es );
     if( dec != NULL )
@@ -2343,7 +2349,8 @@ static void EsOutCreateDecoder( es_out_t *out, es_out_id_t *p_es )
         if( !p_es->p_master && p_sys->p_sout_record )
         {
             p_es->p_dec_record =
-                vlc_input_decoder_New( VLC_OBJECT(p_input), &p_es->fmt, NULL,
+                vlc_input_decoder_New( VLC_OBJECT(p_input), &p_es->fmt,
+                                       p_es->id.str_id, NULL,
                                        priv->p_resource, p_sys->p_sout_record,
                                        false, &decoder_cbs, p_es );
             if( p_es->p_dec_record && p_sys->b_buffering )
@@ -2895,6 +2902,13 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
     input_thread_t *p_input = p_sys->p_input;
 
     assert( p_block->p_next == NULL );
+    struct vlc_tracer *tracer = vlc_object_get_tracer( &p_input->obj );
+
+    if ( tracer != NULL )
+    {
+        vlc_tracer_TraceStreamDTS( tracer, "DEMUX", es->id.str_id, "OUT",
+                            p_block->i_pts, p_block->i_dts);
+    }
 
     struct input_stats *stats = input_priv(p_input)->stats;
     if( stats != NULL )
@@ -3342,6 +3356,11 @@ static int EsOutVaControlLocked( es_out_t *out, input_source_t *source,
 
         p_pgrm->i_last_pcr = i_pcr;
 
+        struct vlc_tracer *tracer = vlc_object_get_tracer( &p_sys->p_input->obj );
+        if ( tracer != NULL )
+        {
+            vlc_tracer_TracePCR(tracer, "DEMUX", "PCR", i_pcr);
+        }
         input_thread_private_t *priv = input_priv(p_sys->p_input);
 
         /* TODO do not use vlc_tick_now() but proper stream acquisition date */


=====================================
src/libvlc-module.c
=====================================
@@ -1085,6 +1085,10 @@ static const char* const ppsz_restore_playback_desc[] = {
     "You can select which VoD server module you want to use. Set this " \
     "to 'vod_rtsp' to switch back to the old, legacy module." )
 
+#define TRACER_TEXT N_("Tracer module")
+#define TRACER_LONGTEXT N_( \
+    "This allow to select which tracer module you want to use." )
+
 #define VLM_CONF_TEXT N_("VLM configuration file")
 #define VLM_CONF_LONGTEXT N_( \
     "Read a VLM configuration file as soon as VLM is started." )
@@ -2058,6 +2062,8 @@ vlc_module_begin ()
     set_section( N_("Special modules"), NULL )
     add_module("vod-server", "vod server", NULL,
                VOD_SERVER_TEXT, VOD_SERVER_LONGTEXT)
+    add_module("tracer", "tracer", NULL,
+               TRACER_TEXT, TRACER_LONGTEXT)
 
     set_section( N_("Plugins" ), NULL )
 #ifdef HAVE_DYNAMIC_PLUGINS


=====================================
src/libvlc.c
=====================================
@@ -179,6 +179,7 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
         goto error;
 
     vlc_LogInit(p_libvlc);
+    vlc_tracer_Init(p_libvlc);
 
     /*
      * Support for gettext
@@ -389,6 +390,7 @@ void libvlc_InternalCleanup( libvlc_int_t *p_libvlc )
         config_AutoSaveConfigFile( VLC_OBJECT(p_libvlc) );
 
     vlc_LogDestroy(p_libvlc->obj.logger);
+    vlc_tracer_Destroy(p_libvlc);
     /* Free module bank. It is refcounted, so we call this each time  */
     module_EndBank (true);
 #if defined(_WIN32) || defined(__OS2__)


=====================================
src/libvlc.h
=====================================
@@ -59,6 +59,14 @@ typedef struct vlc_logger vlc_logger_t;
 int vlc_LogPreinit(libvlc_int_t *) VLC_USED;
 void vlc_LogInit(libvlc_int_t *);
 
+/*
+ * Tracing
+ */
+typedef struct vlc_tracer vlc_tracer_t;
+
+void vlc_tracer_Init(libvlc_int_t *);
+void vlc_tracer_Destroy(libvlc_int_t *);
+
 /*
  * LibVLC exit event handling
  */
@@ -185,6 +193,7 @@ typedef struct libvlc_priv_t
     vlc_actions_t *actions; ///< Hotkeys handler
     struct vlc_medialibrary_t *p_media_library; ///< Media library instance
     struct vlc_thumbnailer_t *p_thumbnailer; ///< Lazily instantiated media thumbnailer
+    struct vlc_tracer *tracer; ///< Tracer callbacks
 
     /* Exit callback */
     vlc_exit_t       exit;


=====================================
src/libvlccore.sym
=====================================
@@ -279,6 +279,7 @@ vlc_memstream_printf
 vlc_Log
 vlc_LogSet
 vlc_vaLog
+vlc_tracer_Trace
 vlc_LogHeaderCreate
 vlc_LogDestroy
 vlc_strerror
@@ -642,6 +643,7 @@ vlc_object_create
 vlc_object_delete
 vlc_object_typename
 vlc_object_parent
+vlc_object_get_tracer
 vlc_object_Log
 vlc_object_vaLog
 vlc_once


=====================================
src/misc/objects.c
=====================================
@@ -116,6 +116,13 @@ vlc_object_t *(vlc_object_parent)(vlc_object_t *obj)
     return vlc_internals(obj)->parent;
 }
 
+struct vlc_tracer *vlc_object_get_tracer(vlc_object_t *obj)
+{
+    libvlc_int_t *vlc = vlc_object_instance(obj);
+    libvlc_priv_t *vlc_priv = libvlc_priv(vlc);
+    return vlc_priv->tracer;
+}
+
 void vlc_object_deinit(vlc_object_t *obj)
 {
     vlc_object_internals_t *priv = vlc_internals(obj);


=====================================
src/misc/tracer.c
=====================================
@@ -0,0 +1,118 @@
+/*****************************************************************************
+ * tracer.c: tracing interface
+ * This library provides an interface to the traces to be used by other
+ * modules. See vlc_config.h for output configuration.
+ *****************************************************************************
+ * Copyright (C) 2021 VLC authors and VideoLAN
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include <vlc_common.h>
+#include <vlc_modules.h>
+#include <vlc_tracer.h>
+#include "../libvlc.h"
+
+struct vlc_tracer {
+    const struct vlc_tracer_operations *ops;
+};
+
+/**
+ * Module-based message trace.
+ */
+struct vlc_tracer_module {
+    struct vlc_object_t obj;
+    struct vlc_tracer tracer;
+    void *opaque;
+};
+
+void vlc_tracer_Trace(struct vlc_tracer *tracer, ...)
+{
+    assert(tracer->ops->trace != NULL);
+    struct vlc_tracer_module *module =
+            container_of(tracer, struct vlc_tracer_module, tracer);
+
+    /* Pass message to the callback */
+    va_list entries;
+    va_start(entries, tracer);
+    tracer->ops->trace(module->opaque, entries);
+    va_end(entries);
+}
+
+static int vlc_tracer_load(void *func, bool forced, va_list ap)
+{
+    const struct vlc_tracer_operations *(*activate)(vlc_object_t *,
+                                                    void **) = func;
+    struct vlc_tracer_module *module = va_arg(ap, struct vlc_tracer_module *);
+
+    (void) forced;
+    module->tracer.ops = activate(VLC_OBJECT(module), &module->opaque);
+    return (module->tracer.ops != NULL) ? VLC_SUCCESS : VLC_EGENERIC;
+}
+
+static struct vlc_tracer *vlc_TraceModuleCreate(vlc_object_t *parent)
+{
+    struct vlc_tracer_module *module;
+
+    module = vlc_custom_create(parent, sizeof (*module), "tracer");
+    if (unlikely(module == NULL))
+        return NULL;
+
+    char *module_name = var_InheritString(parent, "tracer");
+    if (vlc_module_load(VLC_OBJECT(module), "tracer", module_name, false,
+                        vlc_tracer_load, module) == NULL) {
+        vlc_object_delete(VLC_OBJECT(module));
+        if (module_name)
+            free(module_name);
+        return NULL;
+    }
+    if (module_name)
+        free(module_name);
+
+    return &module->tracer;
+}
+
+/**
+ * Initializes the messages tracing system */
+void vlc_tracer_Init(libvlc_int_t *vlc)
+{
+    struct vlc_tracer *tracer = vlc_TraceModuleCreate(VLC_OBJECT(vlc));
+    libvlc_priv_t *vlc_priv = libvlc_priv(vlc);
+    vlc_priv->tracer = tracer;
+}
+
+void vlc_tracer_Destroy(libvlc_int_t *vlc)
+{
+    libvlc_priv_t *vlc_priv = libvlc_priv(vlc);
+
+    if (vlc_priv->tracer != NULL)
+    {
+        struct vlc_tracer_module *module =
+            container_of(vlc_priv->tracer, struct vlc_tracer_module, tracer);
+
+        if (module->tracer.ops->destroy != NULL)
+            module->tracer.ops->destroy(module->opaque);
+
+        vlc_object_delete(VLC_OBJECT(module));
+    }
+}



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/50728ae64510294784371335fafe8f7d575251fb...f55348fd9b90335ae39669c77de493954fb763ce

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/50728ae64510294784371335fafe8f7d575251fb...f55348fd9b90335ae39669c77de493954fb763ce
You're receiving this email because of your account on code.videolan.org.




More information about the vlc-commits mailing list