diff --git a/core/mp_core.h b/core/mp_core.h index d2eb8ef296..39a05e0e3b 100644 --- a/core/mp_core.h +++ b/core/mp_core.h @@ -113,7 +113,9 @@ enum { }; typedef struct MPContext { + struct mpv_global *global; struct MPOpts *opts; + struct mp_log *log; struct m_config *mconfig; struct input_ctx *input; struct osd_state *osd; diff --git a/core/mp_msg.c b/core/mp_msg.c index 86a544316e..e9348dbf59 100644 --- a/core/mp_msg.c +++ b/core/mp_msg.c @@ -21,8 +21,12 @@ #include #include #include +#include + +#include "talloc.h" #include "config.h" +#include "core/mpv_global.h" #include "osdep/getch2.h" #include "osdep/io.h" @@ -39,6 +43,25 @@ bool mp_msg_stdout_in_use = 0; +struct mp_log_root { + /* This should, at some point, contain all mp_msg related state, instead + * of having global variables (at least as long as we don't want to + * control the terminal, which is global anyway). But for now, there is + * not much. */ + struct mpv_global *global; +}; + +struct mp_log { + struct mp_log_root *root; + const char *prefix; + const char *verbose_prefix; + int legacy_mod; +}; + +// should not exist +static bool initialized; +static struct mp_log *legacy_logs[MSGT_MAX]; + /* maximum message length of mp_msg */ #define MSGSIZE_MAX 6144 @@ -74,7 +97,7 @@ static int mp_msg_docolor(void) { return mp_msg_cancolor && mp_msg_color; } -void mp_msg_init(void){ +static void mp_msg_do_init(void){ #ifdef _WIN32 CONSOLE_SCREEN_BUFFER_INFO cinfo; DWORD cmode = 0; @@ -121,6 +144,11 @@ int mp_msg_test(int mod, int lev) return lev <= (mp_msg_levels[mod] == -2 ? mp_msg_level_all + verbose : mp_msg_levels[mod]); } +bool mp_msg_test_log(struct mp_log *log, int lev) +{ + return mp_msg_test(log->legacy_mod, lev); +} + static void set_msg_color(FILE* stream, int lev) { static const int v_colors[10] = {9, 1, 3, 3, -1, -1, 2, 8, 8, 8}; @@ -153,78 +181,30 @@ static void set_msg_color(FILE* stream, int lev) } } -static void print_msg_module(FILE* stream, int mod) +static void print_msg_module(FILE* stream, struct mp_log *log) { - static const char *module_text[MSGT_MAX] = { - "GLOBAL", - "CPLAYER", - "GPLAYER", - "VIDEOOUT", - "AUDIOOUT", - "DEMUXER", - "DS", - "DEMUX", - "HEADER", - "AVSYNC", - "AUTOQ", - "CFGPARSER", - "DECAUDIO", - "DECVIDEO", - "SEEK", - "WIN32", - "OPEN", - "DVD", - "PARSEES", - "LIRC", - "STREAM", - "CACHE", - "MENCODER", - "XACODEC", - "TV", - "OSDEP", - "SPUDEC", - "PLAYTREE", - "INPUT", - "VFILTER", - "OSD", - "NETWORK", - "CPUDETECT", - "CODECCFG", - "SWS", - "VOBSUB", - "SUBREADER", - "AFILTER", - "NETST", - "MUXER", - "OSDMENU", - "IDENTIFY", - "RADIO", - "ASS", - "LOADER", - "STATUSLINE", - }; + int mod = log->legacy_mod; int c2 = (mod + 1) % 15 + 1; - if (!mp_msg_module) - return; #ifdef _WIN32 HANDLE *wstream = stream == stderr ? hSTDERR : hSTDOUT; if (mp_msg_docolor()) SetConsoleTextAttribute(wstream, ansi2win32[c2&7] | FOREGROUND_INTENSITY); - fprintf(stream, "%9s", module_text[mod]); + fprintf(stream, "%9s", log->verbose_prefix); if (mp_msg_docolor()) SetConsoleTextAttribute(wstream, stdoutAttrs); #else if (mp_msg_docolor()) fprintf(stream, "\033[%d;3%dm", c2 >> 3, c2 & 7); - fprintf(stream, "%9s", module_text[mod]); + fprintf(stream, "%9s", log->verbose_prefix); if (mp_msg_docolor()) fprintf(stream, "\033[0;37m"); #endif fprintf(stream, ": "); } -void mp_msg_va(int mod, int lev, const char *format, va_list va) +static void mp_msg_log_va(struct mp_log *log, int lev, const char *format, + va_list va) { char tmp[MSGSIZE_MAX]; FILE *stream = @@ -233,7 +213,7 @@ void mp_msg_va(int mod, int lev, const char *format, va_list va) // indicates if last line printed was a status line static int statusline; - if (!mp_msg_test(mod, lev)) return; // do not display + if (!mp_msg_test_log(log, lev)) return; // do not display vsnprintf(tmp, MSGSIZE_MAX, format, va); tmp[MSGSIZE_MAX-2] = '\n'; tmp[MSGSIZE_MAX-1] = 0; @@ -245,9 +225,17 @@ void mp_msg_va(int mod, int lev, const char *format, va_list va) fprintf(stderr, "\n"); statusline = lev == MSGL_STATUS; - if (header) - print_msg_module(stream, mod); set_msg_color(stream, lev); + if (header) { + if (mp_msg_module) { + print_msg_module(stream, log); + set_msg_color(stream, lev); + } else if (lev >= MSGL_V || verbose) { + fprintf(stream, "[%s] ", log->verbose_prefix); + } else if (log->prefix) { + fprintf(stream, "[%s] ", log->prefix); + } + } size_t len = strlen(tmp); header = len && (tmp[len-1] == '\n' || tmp[len-1] == '\r'); @@ -266,6 +254,13 @@ void mp_msg_va(int mod, int lev, const char *format, va_list va) fflush(stream); } +void mp_msg_va(int mod, int lev, const char *format, va_list va) +{ + assert(initialized); + assert(mod >= 0 && mod < MSGT_MAX); + mp_msg_log_va(legacy_logs[mod], lev, format, va); +} + void mp_msg(int mod, int lev, const char *format, ...) { va_list va; @@ -334,3 +329,143 @@ void mp_tmsg(int mod, int lev, const char *format, ...) mp_msg_va(mod, lev, mp_gtext(format), va); va_end(va); } + +// legacy names +static const char *module_text[MSGT_MAX] = { + "global", + "cplayer", + "gplayer", + "vo", + "ao", + "demuxer", + "ds", + "demux", + "header", + "avsync", + "autoq", + "cfgparser", + "decaudio", + "decvideo", + "seek", + "win32", + "open", + "dvd", + "parsees", + "lirc", + "stream", + "cache", + "mencoder", + "xacodec", + "tv", + "osdep", + "spudec", + "playtree", + "input", + "vf", + "osd", + "network", + "cpudetect", + "codeccfg", + "sws", + "vobsub", + "subreader", + "af", + "netst", + "muxer", + "osdmenu", + "identify", + "radio", + "ass", + "loader", + "statusline", + "teletext", +}; + +// Create a new log context, which uses talloc_ctx as talloc parent, and parent +// as logical parent. +// The name is the prefix put before the output. It's usually prefixed by the +// parent's name. If the name starts with "/", the parent's name is not +// prefixed (except in verbose mode), and if it starts with "!", the name is +// printed at all (except in verbose mode). +struct mp_log *mp_log_new(void *talloc_ctx, struct mp_log *parent, + const char *name) +{ + assert(parent); + assert(name); + struct mp_log *log = talloc_zero(talloc_ctx, struct mp_log); + log->root = parent->root; + if (name[0] == '!') { + name = &name[1]; + } else if (name[0] == '/') { + name = &name[1]; + log->prefix = talloc_strdup(log, name); + } else { + log->prefix = parent->prefix + ? talloc_asprintf(log, "%s/%s", parent->prefix, name) + : talloc_strdup(log, name); + } + log->verbose_prefix = parent->prefix + ? talloc_asprintf(log, "%s/%s", parent->prefix, name) + : talloc_strdup(log, name); + if (log->prefix && !log->prefix[0]) + log->prefix = NULL; + if (!log->verbose_prefix[0]) + log->verbose_prefix = "global"; + log->legacy_mod = parent->legacy_mod; + for (int n = 0; n < MSGT_MAX; n++) { + if (module_text[n] && strcmp(name, module_text[n]) == 0) { + log->legacy_mod = n; + break; + } + } + return log; +} + +void mp_msg_init(struct mpv_global *global) +{ + assert(!initialized); + assert(!global->log); + + struct mp_log_root *root = talloc_zero(NULL, struct mp_log_root); + root->global = global; + + struct mp_log dummy = { .root = root }; + struct mp_log *log = mp_log_new(root, &dummy, ""); + for (int n = 0; n < MSGT_MAX; n++) { + char name[80]; + snprintf(name, sizeof(name), "!%s", module_text[n]); + legacy_logs[n] = mp_log_new(root, log, name); + } + mp_msg_do_init(); + + global->log = log; + initialized = true; +} + +struct mpv_global *mp_log_get_global(struct mp_log *log) +{ + return log->root->global; +} + +void mp_msg_uninit(struct mpv_global *global) +{ + talloc_free(global->log->root); + global->log = NULL; + initialized = false; +} + +void mp_msg_log(struct mp_log *log, int lev, const char *format, ...) +{ + va_list va; + va_start(va, format); + mp_msg_log_va(log, lev, format, va); + va_end(va); +} + +void mp_tmsg_log(struct mp_log *log, int lev, const char *format, ...) +{ + va_list va; + va_start(va, format); + mp_msg_log_va(log, lev, mp_gtext(format), va); + va_end(va); +} diff --git a/core/mp_msg.h b/core/mp_msg.h index 392adcf01f..4685668f01 100644 --- a/core/mp_msg.h +++ b/core/mp_msg.h @@ -20,6 +20,9 @@ #define MPLAYER_MP_MSG_H #include +#include + +struct mp_log; // defined in mplayer.c extern int verbose; @@ -126,10 +129,10 @@ extern int verbose; #define MSGT_TELETEXT 46 // Teletext decoder -#define MSGT_MAX 64 +#define MSGT_MAX 47 -void mp_msg_init(void); int mp_msg_test(int mod, int lev); +bool mp_msg_test_log(struct mp_log *log, int lev); #include "config.h" #include "core/mp_common.h" @@ -142,6 +145,34 @@ void mp_msg(int mod, int lev, const char *format, ... ) PRINTF_ATTRIBUTE(3, 4); void mp_tmsg(int mod, int lev, const char *format, ... ) PRINTF_ATTRIBUTE(3, 4); #define mp_dbg mp_msg +struct mp_log *mp_log_new(void *talloc_ctx, struct mp_log *parent, + const char *name); + +void mp_msg_log(struct mp_log *log, int lev, const char *format, ...) + PRINTF_ATTRIBUTE(3, 4); +void mp_tmsg_log(struct mp_log *log, int lev, const char *format, ...) + PRINTF_ATTRIBUTE(3, 4); + +// Convenience macros, typically called with a pointer to a context struct +// as first argument, which has a "struct mp_log log;" member. + +#define MP_MSG(obj, lev, ...) mp_msg_log((obj)->log, lev, __VA_ARGS__) +#define MP_MSGT(obj, lev, ...) mp_msgt_log((obj)->log, lev, __VA_ARGS__) + +#define MP_FATAL(obj, ...) MP_MSG(obj, MSGL_FATAL, __VA_ARGS__) +#define MP_ERR(obj, ...) MP_MSG(obj, MSGL_ERR, __VA_ARGS__) +#define MP_WARN(obj, ...) MP_MSG(obj, MSGL_WARN, __VA_ARGS__) +#define MP_INFO(obj, ...) MP_MSG(obj, MSGL_INFO, __VA_ARGS__) +#define MP_VERBOSE(obj, ...) MP_MSG(obj, MSGL_V, __VA_ARGS__) +#define MP_DBG(obj, ...) MP_MSG(obj, MSGL_DGB2, __VA_ARGS__) +#define MP_TRACE(obj, ...) MP_MSG(obj, MSGL_DGB5, __VA_ARGS__) + +struct mpv_global; +void mp_msg_init(struct mpv_global *global); +void mp_msg_uninit(struct mpv_global *global); + +struct mpv_global *mp_log_get_global(struct mp_log *log); + extern bool mp_msg_stdout_in_use; #endif /* MPLAYER_MP_MSG_H */ diff --git a/core/mplayer.c b/core/mplayer.c index 0238e10be3..626c95111f 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -63,6 +63,7 @@ #include +#include "core/mpv_global.h" #include "core/mp_msg.h" #include "av_log.h" @@ -585,6 +586,8 @@ static MP_NORETURN void exit_player(struct MPContext *mpctx, // must be last since e.g. mp_msg uses option values // that will be freed by this. + + mp_msg_uninit(mpctx->global); talloc_free(mpctx); #ifdef CONFIG_COCOA @@ -4562,8 +4565,6 @@ static void osdep_preinit(int *p_argc, char ***p_argv) if (enable_talloc && strcmp(enable_talloc, "1") == 0) talloc_enable_leak_report(); - GetCpuCaps(&gCpuCaps); - #ifdef __MINGW32__ mp_get_converted_argv(p_argc, p_argv); #endif @@ -4603,10 +4604,6 @@ static int mpv_main(int argc, char *argv[]) .playlist = talloc_struct(mpctx, struct playlist, {0}), }; - mp_msg_init(); - init_libav(); - screenshot_init(mpctx); - // Create the config context and register the options mpctx->mconfig = m_config_new(mpctx, sizeof(struct MPOpts), &mp_default_opts, mp_opts, NULL); @@ -4616,6 +4613,18 @@ static int mpv_main(int argc, char *argv[]) struct MPOpts *opts = mpctx->opts; + + mpctx->global = talloc_zero(mpctx, struct mpv_global); + mpctx->global->opts = opts; + + // Nothing must call mp_msg() before this + mp_msg_init(mpctx->global); + mpctx->log = mp_log_new(mpctx, mpctx->global->log, "!mpv"); + + init_libav(); + GetCpuCaps(&gCpuCaps); + screenshot_init(mpctx); + // Preparse the command line m_config_preparse_command_line(mpctx->mconfig, argc, argv); diff --git a/core/mpv_global.h b/core/mpv_global.h new file mode 100644 index 0000000000..546c585294 --- /dev/null +++ b/core/mpv_global.h @@ -0,0 +1,12 @@ +#ifndef MPV_MPV_H +#define MPV_MPV_H + +// This should be accessed by glue code only, never normal code. +// The only purpose of this is to make mpv library-safe. +// Think hard before adding new members. +struct mpv_global { + struct MPOpts *opts; + struct mp_log *log; +}; + +#endif