【FFmpeg】FFmpeg日志输出系统av_log的移植

FFmpeg日志输出系统av_log的移植

av_log()函数是FFmpeg日志输出的核心函数,在FFmpeg内部的所有打印信息全部采用的都是av_log()接口进行打印的.

在一开始的时候,我记得ffmpeg里是无法使用printf函数的,如果你在代码里加了一句打印,那么他会屏蔽掉,但现在忘记是在什么地方限制了

av_log()函数原型:

/**
 * Send the specified message to the log if the level is less than or equal
 * to the current av_log_level. By default, all logging messages are sent to
 * stderr. This behavior can be altered by setting a different logging callback
 * function.
 * @see av_log_set_callback
 *
 * @param avcl A pointer to an arbitrary struct of which the first field is a
 *        pointer to an AVClass struct.
 * @param level The importance level of the message expressed using a @ref
 *        lavu_log_constants "Logging Constant".
 * @param fmt The format string (printf-compatible) that specifies how
 *        subsequent arguments are converted to output.
 */
void av_log(void *avcl, int level, const char *fmt, ...) av_printf_format(3, 4);

FFmpeg里的av_log()的特性:

  • 引入AVClass,能够打印是哪个模块那个部分作出的打印,并能够影响level的值从而实现颜色的变化
 level += *(int *) (((uint8_t *) avcl) + avc->log_level_offset_offset);
  • 可控制是否颜色输出,可以根据不同打印等级,显示出不同的颜色,易于区分

第二个参数,它决定了是否输出字符串,同时还可以根据level输出不同的颜色.

是否输出颜色由use_color控制:

use_color = 0时: 无色彩输出;

use_color = 1时: 有色彩输出,但此时输出的字符串背景是无色;

use_color = 256时: 有色彩输出,但此时输出的字符串背景是可配置的;

  • 可控制对重复信息的重复打印,浪费打印资源

打印级别

/**
 * Print no output.
 */
#define AV_LOG_QUIET    -8

/**
 * Something went really wrong and we will crash now.
 */
#define AV_LOG_PANIC     0

/**
 * Something went wrong and recovery is not possible.
 * For example, no header was found for a format which depends
 * on headers or an illegal combination of parameters is used.
 */
#define AV_LOG_FATAL     8

/**
 * Something went wrong and cannot losslessly be recovered.
 * However, not all future data is affected.
 */
#define AV_LOG_ERROR    16

/**
 * Something somehow does not look correct. This may or may not
 * lead to problems. An example would be the use of '-vstrict -2'.
 */
#define AV_LOG_WARNING  24

/**
 * Standard information.
 */
#define AV_LOG_INFO     32

/**
 * Detailed information.
 */
#define AV_LOG_VERBOSE  40

/**
 * Stuff which is only useful for libav* developers.
 */
#define AV_LOG_DEBUG    48

/**
 * Extremely verbose debugging, useful for libav* development.
 */
#define AV_LOG_TRACE    56

#define AV_LOG_MAX_OFFSET (AV_LOG_TRACE - AV_LOG_QUIET)

从定义可以看出,不同打印等级后都有一个数值.数值越小说明越严重,系统默认的级别是AV_LOG_INFO.

可以通过av_log_get_level()获得当前Log的级别,通过另一个函数av_log_set_level()设置当前的Log级别。

/**
 * Get the current log level
 *
 * @see lavu_log_constants
 *
 * @return Current log level
 */
int av_log_get_level(void);

/**
 * Set the log level
 *
 * @see lavu_log_constants
 *
 * @param level Logging level
 */
void av_log_set_level(int level);

有关av_log的介绍就到这里,详细的av_log介绍还是雷霄骅大佬写的全面,这里就不做过多介绍了.

请移步:FFmpeg源代码简单分析:日志输出系统(av_log()等)



下面主要说明如何将av_log移植出来化为自己所用的.

由于上述所说的ffmpegav_log的特性.认为不同以往的日志输出框架,比较有趣,所以这次将其移植出来进行使用以及日志框架的搭建学习.

但是在移植完之后,也不得不去思考所面临的一些问题,认为移植出来的log虽可以使用,但在某些嵌入式系统里,还是欠缺实用性.

相信看到这里的时候,你已经将上面大神雷霄骅的日志输出系统做一个简单的学习.

有关本次移植的代码已经上传至:https://github.com/Tschome/log,有需要的可以下载使用.

函数原型:
void log(void *name, int level, const char *fmt, ...) printf_format(3, 4);
  1. 为了区别于av_log(),移植后的代码将移除av_,AV_前缀为log()
  2. 为了简易使用,索性将第一个参数AVClass删去,直接用name的使用字段替代.且若执行log()代码之后会发现打印信息里会有reserve,这个字段是作为保留选项,现在还没想好如何利用好这个位置,或者说第一个参数暂做保留设计,以后有什么好的参数选项,可以再进行优化修改.
  3. 第二个参数level打印等级只使用AV_LOG_PANICAV_LOG_FATALAV_LOG_ERRORAV_LOG_WARNINGAV_LOG_INFOAV_LOG_VERBOSEAV_LOG_DEBUG,其他等级暂无打算使用.
示例代码:
#include <stdlib.h>
#include <string.h>

#include "log.h"

#define TAG "main"

void main(int argc, char **argv)
{
        log_set_flags(LOG_SKIP_REPEATED | LOG_PRINT_LEVEL);//跳过重复的信息 + 显示打印级别

        log_set_level(LOG_DEBUG);
        int i = 0;
        //for(i = 0; i < 10; i++)
        log(TAG, LOG_QUIET, "LOG_QUIET\n");
        //for(i = 0; i < 10; i++)
        log(TAG, LOG_PANIC, "LOG_PANIC\n");
        //for(i = 0; i < 10; i++)
        log(TAG, LOG_FATAL, "LOG_FATAL\n");
        //for(i = 0; i < 10; i++)
        log(TAG, LOG_ERROR, "LOG_ERROR\n");
        //for(i = 0; i < 10; i++)
        log(TAG, LOG_WARNING, "LOG_WARNING\n");
        //for(i = 0; i < 10; i++)
        log(TAG, LOG_INFO, "LOG_INFO\n");
        //for(i = 0; i < 10; i++)
        log(TAG, LOG_VERBOSE, "LOG_VERBOSE\n");
        //for(i = 0; i < 10; i++)
        log(TAG, LOG_DEBUG, "LOG_DEBUG\n");
        //for(i = 0; i < 10; i++)
        log(TAG, LOG_TRACE, "LOG_TRACE\n");
        log(TAG, LOG_MAX_OFFSET, "LOG_MAX_OFFSET\n");

        return;
}

测试结果:

测试结果

问题:

1.在移植之后,在编译后,这个vlog()在原先的逻辑下出现了段错误.截至目前没有找到是什么原因,遂直接调用内部的log回调函数,但这样造成的后果就是:无法自定义自己的log函数了

所以这个问题后续也得解决

//log.c
void vlog(void *name, int level, const char *fmt, va_list vl)
{
#if 0
    //原先的实现逻辑
    void (*log_callback)(void*, int, const char*, va_list) = log_callback;
    if (log_callback){
        log_callback(name, level, fmt, vl);
    }
#else
    //临时的替代方案
    log_default_callback(name, level, fmt, vl);
#endif
}

2.无法输出颜色效果.本次移植也依旧使用临时替代方案,后面需要使用合适的方式代替它

//log.c
static void colored_fputs(int level, int tint, const char *str)
{
    int local_use_color;
    if (!*str)
        return;

    if (use_color < 0)
        check_color_terminal();

    if (level == LOG_INFO/8) local_use_color = 0;
    else                        local_use_color = use_color;

#if 1
        //临时替代方案
        use_color = 256;
        local_use_color = 256;
#endif

#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE && HAVE_GETSTDHANDLE
    if (con != INVALID_HANDLE_VALUE) {
        if (local_use_color)
            SetConsoleTextAttribute(con, background | color[level]);
        win_console_puts(str);
        if (local_use_color)
            SetConsoleTextAttribute(con, attr_orig);
    } else {
        ansi_fputs(level, tint, str, local_use_color);
    }
#else
    ansi_fputs(level, tint, str, local_use_color);
#endif

}

本文作为本次移植的记录,内容尚简,欢迎交流指导

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Van.Ghylivan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值