summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-12-21 20:06:36 +0100
committerwm4 <wm4@nowhere>2013-12-21 21:43:16 +0100
commitd57eaa7e30a2faada712b60e75b7b2eb734cca3c (patch)
tree247ac75074c3b6a226aeeb625bb20f616c1519a2
parent7bdee8f35ed0aa19c83377b7c264c51696f9653f (diff)
downloadmpv-d57eaa7e30a2faada712b60e75b7b2eb734cca3c.tar.bz2
mpv-d57eaa7e30a2faada712b60e75b7b2eb734cca3c.tar.xz
av_log: mp_msg conversion
This is pretty nasty, because FFmpeg/Libav is yet another library with a global message callback. We do something with mutexes trying to get it done, but of course we can't actually solve this problem. If more than one library in a process use FFmpeg/Libav, only one of them will get log messages.
-rw-r--r--common/av_log.c96
-rw-r--r--common/av_log.h7
-rw-r--r--player/main.c4
3 files changed, 73 insertions, 34 deletions
diff --git a/common/av_log.c b/common/av_log.c
index b007062d1e..0ee39b3022 100644
--- a/common/av_log.c
+++ b/common/av_log.c
@@ -21,11 +21,16 @@
*/
#include <stdlib.h>
+#include <stdio.h>
#include <stdbool.h>
+#include <pthread.h>
#include "av_log.h"
#include "config.h"
+#include "common/common.h"
+#include "common/global.h"
#include "common/msg.h"
+
#include <libavutil/avutil.h>
#include <libavutil/log.h>
@@ -48,6 +53,19 @@
#include <libswresample/swresample.h>
#endif
+#if LIBAVCODEC_VERSION_MICRO >= 100
+#define LIB_PREFIX "ffmpeg"
+#else
+#define LIB_PREFIX "libav"
+#endif
+
+// Needed because the av_log callback does not provide a library-safe message
+// callback.
+static pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
+static struct mpv_global *log_mpv_instance;
+static struct mp_log *log_root, *log_decaudio, *log_decvideo, *log_demuxer;
+static bool log_print_prefix = true;
+
static int av_log_level_to_mp_level(int av_level)
{
if (av_level > AV_LOG_VERBOSE)
@@ -63,17 +81,17 @@ static int av_log_level_to_mp_level(int av_level)
return MSGL_FATAL;
}
-static int extract_msg_type_from_ctx(void *ptr)
+static struct mp_log *get_av_log(void *ptr)
{
if (!ptr)
- return MSGT_FIXME;
+ return log_root;
AVClass *avc = *(AVClass **)ptr;
if (!avc) {
- mp_msg(MSGT_FIXME, MSGL_WARN,
+ mp_warn(log_root,
"av_log callback called with bad parameters (NULL AVClass).\n"
"This is a bug in one of Libav/FFmpeg libraries used.\n");
- return MSGT_FIXME;
+ return log_root;
}
if (!strcmp(avc->class_name, "AVCodecContext")) {
@@ -81,59 +99,65 @@ static int extract_msg_type_from_ctx(void *ptr)
if (s->codec) {
if (s->codec->type == AVMEDIA_TYPE_AUDIO) {
if (s->codec->decode)
- return MSGT_DECAUDIO;
+ return log_decaudio;
} else if (s->codec->type == AVMEDIA_TYPE_VIDEO) {
if (s->codec->decode)
- return MSGT_DECVIDEO;
+ return log_decvideo;
}
- // FIXME subtitles, encoders
- // What msgt for them? There is nothing appropriate...
}
- return MSGT_FIXME;
}
if (!strcmp(avc->class_name, "AVFormatContext")) {
AVFormatContext *s = ptr;
if (s->iformat)
- return MSGT_DEMUXER;
- else if (s->oformat)
- return MSGT_MUXER;
- return MSGT_FIXME;
+ return log_demuxer;
}
- return MSGT_FIXME;
+ return log_root;
}
-#if LIBAVCODEC_VERSION_MICRO >= 100
-#define LIB_PREFIX "ffmpeg"
-#else
-#define LIB_PREFIX "libav"
-#endif
-
-static bool print_prefix = true;
-
static void mp_msg_av_log_callback(void *ptr, int level, const char *fmt,
va_list vl)
{
AVClass *avc = ptr ? *(AVClass **)ptr : NULL;
int mp_level = av_log_level_to_mp_level(level);
- int type = extract_msg_type_from_ctx(ptr);
- if (!mp_msg_test(type, mp_level))
+ // Note: mp_log is thread-safe, but destruction of the log instances is not.
+ pthread_mutex_lock(&log_lock);
+
+ if (!log_mpv_instance) {
+ pthread_mutex_unlock(&log_lock);
+ // Fallback to stderr
+ vfprintf(stderr, fmt, vl);
return;
+ }
+
+ struct mp_log *log = get_av_log(ptr);
+
+ if (mp_msg_test_log(log, mp_level)) {
+ if (log_print_prefix)
+ mp_msg_log(log, mp_level, "%s: ", avc ? avc->item_name(ptr) : "?");
+ log_print_prefix = fmt[strlen(fmt) - 1] == '\n';
- if (print_prefix) {
- mp_msg(type, mp_level, "[%s/%s] ", LIB_PREFIX,
- avc ? avc->item_name(ptr) : "?");
+ mp_msg_log_va(log, mp_level, fmt, vl);
}
- print_prefix = fmt[strlen(fmt) - 1] == '\n';
- mp_msg_va(type, mp_level, fmt, vl);
+ pthread_mutex_unlock(&log_lock);
}
-void init_libav(void)
+void init_libav(struct mpv_global *global)
{
- av_log_set_callback(mp_msg_av_log_callback);
+ pthread_mutex_lock(&log_lock);
+ if (!log_mpv_instance) {
+ log_mpv_instance = global;
+ log_root = mp_log_new(NULL, global->log, LIB_PREFIX);
+ log_decaudio = mp_log_new(log_root, log_root, "audio");
+ log_decvideo = mp_log_new(log_root, log_root, "video");
+ log_demuxer = mp_log_new(log_root, log_root, "demuxer");
+ av_log_set_callback(mp_msg_av_log_callback);
+ }
+ pthread_mutex_unlock(&log_lock);
+
avcodec_register_all();
av_register_all();
avformat_network_init();
@@ -146,6 +170,16 @@ void init_libav(void)
#endif
}
+void uninit_libav(struct mpv_global *global)
+{
+ pthread_mutex_lock(&log_lock);
+ if (log_mpv_instance == global) {
+ log_mpv_instance = NULL;
+ talloc_free(log_root);
+ }
+ pthread_mutex_unlock(&log_lock);
+}
+
#define V(x) (x)>>16, (x)>>8 & 255, (x) & 255
static void print_version(struct mp_log *log, int v, char *name,
unsigned buildv, unsigned runv)
diff --git a/common/av_log.h b/common/av_log.h
index e941220a11..17326b609f 100644
--- a/common/av_log.h
+++ b/common/av_log.h
@@ -1,3 +1,8 @@
-void init_libav(void);
+#ifndef MP_AV_LOG_H
+#define MP_AV_LOG_H
+struct mpv_global;
struct mp_log;
+void init_libav(struct mpv_global *global);
+void uninit_libav(struct mpv_global *global);
void print_libav_versions(struct mp_log *log, int v);
+#endif
diff --git a/player/main.c b/player/main.c
index db2794c1ad..b1d5d8163e 100644
--- a/player/main.c
+++ b/player/main.c
@@ -140,6 +140,7 @@ static MP_NORETURN void exit_player(struct MPContext *mpctx,
#endif
getch2_disable();
+ uninit_libav(mpctx->global);
if (how != EXIT_NONE) {
const char *reason;
@@ -310,8 +311,7 @@ static int mpv_main(int argc, char *argv[])
struct MPOpts *opts = mpctx->opts;
mpctx->global->opts = opts;
-
- init_libav();
+ init_libav(mpctx->global);
GetCpuCaps(&gCpuCaps);
screenshot_init(mpctx);
mpctx->mixer = mixer_init(mpctx, mpctx->global);