ffmpg,av_log

Ffmpeg developers' guide

-----------------by Alan Wang

1Debug

        ffmpeg的源码上进行调试自然免不了打log,在ffmpeg中打log可以使用Ffmpeg中的API 

/**
 * 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 av_vlog callback
 * function.
 *
 * @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, lower values signifying
 * higher importance.
 * @param fmt The format string (printf-compatible) that specifies how
 * subsequent arguments are converted to output.
 * @see av_vlog
 */

//注意默认情况下,所有的logging msg都被输出到stderr上。
void av_log(void *avcl, int level, const char *fmt, ...) av_printf_format(3, 4);
Ffmpeglogging system的调用关系主要如下图:












其中这三个函数的原型如下:
1void av_log(void *avcl, int level, const char *fmt, ...) av_printf_format(3, 4);  //av_printf_format(3,4) ???
2void av_vlog(void *avcl, int level, const char *fmt, va_list);
//注意va_list是一个依赖编译器实现的c宏,va_list代表一个指向参数列表的指针(char *)
3void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl);

默认的情况下,av_vlog函数会调用默认的回调函数 av_log_default_callback来完成log的输出,其实这个函数内部调用的就是fprintf(stderr,....),所以默认的log都会输出到stderr,通过API
void av_log_set_callback(void (*)(void*, int, const char*, va_list));
来设置一个新的回调函数指针例如my_logging_callback,那么在这个函数的实现中可以自定义把函数输出到其他地方入stdoutmy_logging_callback的实现自然可以用fprintf

Ffmpeg强烈推荐使用av_log APIDebug,但是这样确实带来的不便性,开发者自然会想到使用printf()来打log调试。但是Ffmpeg做了一定的限制,有时候使用printf()会带来错误信息。原因是Ffmpeglibavutil/internal.h文件中将 printf ,fprintf, malloc, free,exit....等等这些函数都重新define过了事例如下:

#undef  printf
#define printf please_use_av_log_instead_of_printf
#undef  fprintf
#define fprintf please_use_av_log_instead_of_fprintf
#undef  puts
#define puts please_use_av_log_instead_of_puts

所以如果向使用printf函数,需要在使用前重新 #undef一下。

#undef printf
printf(“Msg you want to sent to stdout”);

需要补充的是如果 ffplay.c ffmpeg.c ...这些测试程序中之间用printf来打log是没问题的,但是在这些程序中打log没有太大意义。Debug ffmpeg主要目的是取debug libavformatlibavcodec...这些库,在这些库中用printf会得到下面的编译阶段错误信息:
libavformat/sbgdec.c:347: error: implicit declaration of function ‘please_use_av_log_instead_of_printf’
libavformat/sbgdec.c:348: warning: ISO C90 forbids mixed declarations and code
make: *** [libavformat/sbgdec.o] Error 1



这里补充一个知识点:

//下面是av_log的函数原型,后面的av_printf_format(3, 4)实际上是一个宏。
void av_log(void *avcl, int level, const char *fmt, ...) av_printf_format(3, 4);  //av_printf_format(3,4) ???

//该宏定义的文件位于 libavutil/attributes.h
av_printf_format(3,4) 这个宏展开后的结果是 :__attribute__((__format__(__printf__, fmtpos, attrpos)))
#ifdef __GNUC__
#    define av_builtin_constant_p __builtin_constant_p
#    define av_printf_format(fmtpos, attrpos) __attribute__((__format__(__printf__, fmtpos, attrpos)))
#else
#    define av_builtin_constant_p(x) 0
#    define av_printf_format(fmtpos, attrpos)
#endif 

可以看到这个__attribute__属性是一个gun c编译器的一个特色,这个attribute告诉编译器对这个av_log函数进行format检查,怎么检查?按照 printf函数的格式化方式进行参数检查。其中fmtpos(3) 代表需要格式化的字符串在av_log函数中的参数的位置是第3个,attrpos(4)表示第一个被格式化的变量值(可能是%s%d)出现在av_log函数中的参数的位置是第4个。Gnu c__attribute__作用是可以告诉编译器,让编译器做进一步的检查。

那么av_log的函数声明就可以被解释了。
Void av_log(void *avcl, int level, const char *fmt, …) __attribute__((_format_(_printf_, 3, 4)));













你可能感兴趣的:(视频编解码)