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

简介: 在调测VLC源码时经常需要借助日志打印其中核心变量、临时变量的值,方便学习和定位问题,但是遇到像src\input\clock.c中的函数,因缺少vlc_object_t *obj对象,无法打印日志。
在调测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

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
4月前
|
Kubernetes Shell Linux
linux|shell脚本|有趣的知识---格式化输出日志和脚本调试方法以及kubernetes集群核心服务重启和集群证书备份脚本
linux|shell脚本|有趣的知识---格式化输出日志和脚本调试方法以及kubernetes集群核心服务重启和集群证书备份脚本
60 0
|
1月前
|
前端开发 开发工具 iOS开发
mPaaS常见问题之真机预览与调试扫码调式 release包开启日志如何解决
mPaaS(移动平台即服务,Mobile Platform as a Service)是阿里巴巴集团提供的一套移动开发解决方案,它包含了一系列移动开发、测试、监控和运营的工具和服务。以下是mPaaS常见问题的汇总,旨在帮助开发者和企业用户解决在使用mPaaS产品过程中遇到的各种挑战
23 0
|
3月前
|
存储 监控 Serverless
在处理阿里云函数计算3.0版本的函数时,如果遇到报错但没有日志信息的情况
在处理阿里云函数计算3.0版本的函数时,如果遇到报错但没有日志信息的情况【1月更文挑战第23天】【1月更文挑战第114篇】
63 5
|
3月前
|
IDE 开发工具 Python
|
4月前
|
SQL Python BI
Django实践-07日志调试,Django-Debug-Toolbar配置与sql优化
Django实践-07日志调试,Django-Debug-Toolbar配置与sql优化
Django实践-07日志调试,Django-Debug-Toolbar配置与sql优化
|
7月前
|
C语言
3D打印Marlin2.0固件源代码分析之如何使用LOG接口调试代码
3D打印Marlin2.0固件源代码分析之如何使用LOG接口调试代码
187 0
|
7月前
|
数据采集 网络安全
syslog日志接口调试方法
日志数据采集,比较方便常用的就是通过syslog来进行数据采集,syslog可以通过udp协议来进行高效的数据传输。一般来说在工程实施的过程中需要对接对端系统的数据采集源可以通过以下步骤来进行syslog日志接口的调试。主要是验证syslog日志是否能正常送到指定的日志服务器的指定端口,日志服务器的指定端口是否能正常收到对端发过来的日志。
197 0
syslog日志接口调试方法
|
10月前
|
存储 编译器 C语言
C语言进阶学习日志:文件操作函数 及 使用(三)
C语言进阶学习日志:文件操作函数 及 使用(三)
74 1
|
10月前
|
C语言
C语言进阶学习日志:文件操作函数 及 使用(二)
C语言进阶学习日志:文件操作函数 及 使用(二)
89 0

热门文章

最新文章