在调测VLC源码时经常需要借助日志打印其中核心变量、临时变量的值,方便学习和定位问题,但是遇到像src\input\clock.c中的函数,因缺少vlc_object_t *obj对象,无法打印日志。一般可以通过增加函数参数,从调用方传入,本文提供更简单的方法,可以将以下源码加入到工程里即可使用。
本文基于vlc-2.2.1.32-2013工程修改,源码目录https://github.com/sunqueen/vlc-2.2.1.32-2013。
修改源码:
1、在include\vlc_messages.h函数中增加代码
// add by yagerfgcs:增加msg_Output打印方式
VLC_API void vlc_Debug(vlc_object_t *, int,
const char *, const char *, ...) VLC_FORMAT( 4, 5 );
VLC_API void vlc_vaDebug(vlc_object_t *, int,
const char *, const char *, va_list);
#define msg_Output(p_this,...) \
vlc_Debug(VLC_OBJECT(p_this), VLC_MSG_DBG, MODULE_STRING, __VA_ARGS__ )
// end
2、在src\misc\messages.c中增加代码
a、定义静态变量,存放vlc_object_t对象
// add by yagerfgcs
static libvlc_priv_t *s_priv = NULL;
// end
b、在vlc_LogSet被调用时,更新s_priv值
void vlc_LogSet (libvlc_int_t *vlc, vlc_log_cb cb, void *opaque)
{
libvlc_priv_t *priv = libvlc_priv (vlc);
if (cb == NULL)
{
#ifdef __ANDROID__
cb = AndroidPrintMsg;
#else
#if defined (HAVE_ISATTY) && !defined (_WIN32)
if (isatty (STDERR_FILENO) && var_InheritBool (vlc, "color"))
cb = PrintColorMsg;
else
#endif
cb = PrintMsg;
#endif // __ANDROID__
opaque = (void *)(intptr_t)priv->log.verbose;
}
vlc_rwlock_wrlock (&priv->log.lock);
priv->log.cb = cb;
priv->log.opaque = opaque;
vlc_rwlock_unlock (&priv->log.lock);
// add by yagerfgcs for:增加在无vlc_object_t对象的情况下也能调用msg_Output打印debug调试日志
s_priv = priv;
// end
/* Announce who we are */
msg_Dbg (vlc, "VLC media player - %s", VERSION_MESSAGE);
msg_Dbg (vlc, "%s", COPYRIGHT_MESSAGE);
msg_Dbg (vlc, "revision %s", psz_vlc_changeset);
msg_Dbg (vlc, "configured with %s", CONFIGURE_LINE);
}
c、在vlc_LogDeinit中清理s_priv
void vlc_LogDeinit (libvlc_int_t *vlc)
{
libvlc_priv_t *priv = libvlc_priv (vlc);
vlc_rwlock_destroy (&priv->log.lock);
// add by yagerfgcs
s_priv = NULL;
// end
}
d、在messages.c文件末尾粘贴以下代码
// add by yagerfgcs:增加在无vlc_object_t对象的情况下也能调用msg_Output打印debug调试日志
void vlc_Debug(vlc_object_t *obj, int type, const char *module,
const char *format, ...)
{
va_list args;
va_start(args, format);
vlc_vaDebug(obj, type, module, format, args);
va_end(args);
}
#ifdef _WIN32
static void Win32DebugOutputMsgnoObj(int, const vlc_log_t *,
const char *, va_list);
#endif
/**
* Emit a log message. This function is the variable argument list equivalent
* to vlc_Log().
*/
void vlc_vaDebug(vlc_object_t *obj, int type, const char *module,
const char *format, va_list args)
{
/*if (obj != NULL && obj->i_flags & OBJECT_FLAGS_QUIET)
return;*/
/* Get basename from the module filename */
char *p = strrchr(module, '/');
if (p != NULL)
module = p;
p = strchr(module, '.');
size_t modlen = (p != NULL) ? (p - module) : 1;
// char modulebuf[modlen + 1];
char *modulebuf = (char *)malloc(modlen + 1); // sunqueen modify
if (p != NULL)
{
memcpy(modulebuf, module, modlen);
modulebuf[modlen] = '\0';
module = modulebuf;
}
/* Fill message information fields */
vlc_log_t msg;
msg.i_object_id = (uintptr_t)obj;
msg.psz_object_type = "generic";
msg.psz_module = module;
msg.psz_header = NULL;
for (vlc_object_t *o = obj; o != NULL; o = o->p_parent)
if (o->psz_header != NULL)
{
msg.psz_header = o->psz_header;
break;
}
/* Pass message to the callback */
// libvlc_priv_t *priv = obj ? libvlc_priv(obj->p_libvlc) : NULL;
#ifdef _WIN32
va_list ap;
va_copy(ap, args);
Win32DebugOutputMsgnoObj(type, &msg, format, ap);
va_end(ap);
#endif
if (s_priv)
{
vlc_rwlock_rdlock(&s_priv->log.lock);
s_priv->log.cb(s_priv->log.opaque, type, &msg, format, args);
vlc_rwlock_unlock(&s_priv->log.lock);
}
free(modulebuf);
}
#ifdef _WIN32
static void Win32DebugOutputMsgnoObj(int type, const vlc_log_t *p_item,
const char *format, va_list dol)
{
VLC_UNUSED(p_item);
va_list dol2;
va_copy(dol2, dol);
int msg_len = vsnprintf(NULL, 0, format, dol2);
va_end(dol2);
if (msg_len <= 0)
return;
char *msg = malloc(msg_len + 1 + 1);
if (!msg)
return;
msg_len = vsnprintf(msg, msg_len + 1, format, dol);
if (msg_len > 0){
if (msg[msg_len - 1] != '\n'){
msg[msg_len] = '\n';
msg[msg_len + 1] = '\0';
}
char* psz_msg = NULL;
if (asprintf(&psz_msg, "%s %s%s: %s", p_item->psz_module,
p_item->psz_object_type, msg_type[type], msg) > 0) {
wchar_t* wmsg = ToWide(psz_msg);
OutputDebugStringW(wmsg);
free(wmsg);
free(psz_msg);
}
}
free(msg);
}
#endif
// end by yagerfgcs
3、在需要打印日志的地方调用msg_Output方法即可,以下两种方式都可以。
vlc_object_t *debug = NULL;
msg_Output(debug, "AvgInit average_t{i_value[%llu] i_residue[%d] i_count[%d] i_divider[%d]} i_divider[%d]", p_avg->i_value, p_avg->i_residue, p_avg->i_count, p_avg->i_divider, i_divider);
msg_Output(NULL, "ClockData i_ts_buffering[%llu] i_ts_delay[%llu]", i_ts_buffering, i_ts_delay);
效果:
备注:如果是VS2010版本的老VLC源码,可以参考http://blog.csdn.net/c_m_deng/article/details/8209310