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.
_______________________________________________ vlc-commits mailing list vlc-commits@videolan.org https://mailman.videolan.org/listinfo/vlc-commits