VLC调试:增加messages.c日志函数,在无vlc_object_t下打印日志

在调测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);

效果:

VLC调试:增加messages.c日志函数,在无vlc_object_t下打印日志

备注:如果是VS2010版本的老VLC源码,可以参考http://blog.csdn.net/c_m_deng/article/details/8209310

上一篇:基础能力-加解锁


下一篇:VLC已知问题及解决办法,欢迎拍砖