ffmpeg日誌系統

日誌系統

PS:

在當前的計算機系統中, I/O操作相比其它環節是最耗費資源浪費時間的,所以大家要慎重, 儘量減少不必要的I/O操作。

使用一般步驟:

  1. 頭文件: #include <libavutil/log.h>
  2. 設置log級別: av_log_set_level(AV_LOG_DEBUG);
  3. 輸出log: av_log(nullptr, AV_LOG_INFO, “this is log output”);

設置日誌級別

設置日誌級別的意義:作者可以預設標識了級別的輸出日誌, 然後通過設置日誌級別來控制那些日誌信息需要輸出, 方便進行調試。而不需要到處去修改,和設置DEBUG宏異曲同工之妙。

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

函數代碼實現:

static int av_log_level = AV_LOG_INFO;

顯然,設置日誌輸出等級就是操作靜態全局變量av_log_level。該變量用於存儲當前系統Log的級別。
設置了日誌輸出級別之後, 比此級別嚴重的日誌都會輸出
exp:

int main()
{
    av_log_set_level(AV_LOG_INFO);
    av_log(nullptr, AV_LOG_INFO, "AV_LOG_INFO = %d\n", AV_LOG_INFO);
    av_log(nullptr, AV_LOG_ERROR, "AV_LOG_ERROR = %d\n", AV_LOG_ERROR);
    av_log(nullptr, AV_LOG_TRACE, "AV_LOG_TRACE = %d\n", AV_LOG_TRACE);
    return 0;
}

out put

int main()
{
    av_log_set_level(AV_LOG_ERROR);
    av_log(nullptr, AV_LOG_INFO, "AV_LOG_INFO = %d\n", AV_LOG_INFO);
    av_log(nullptr, AV_LOG_ERROR, "AV_LOG_ERROR = %d\n", AV_LOG_ERROR);
    av_log(nullptr, AV_LOG_TRACE, "AV_LOG_TRACE = %d\n", AV_LOG_TRACE);
    return 0;
}

在這裏插入圖片描述

常用的日誌級別

 // 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

每個級別定義的數值代表了嚴重程度,數值越小代表越嚴重
默認av_log()輸出的級別是AV_LOG_INFO。

獲取當前日誌級別

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

日誌輸出函數

/**
 * 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 or NULL if general log.
 * @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, ...)

第一個參數指定該log所屬的結構體,例如AVFormatContext、AVCodecContext等等。
第二個參數指定log的級別,第三個參數爲要輸出的內容。

PS: 結合之前的內容,所謂的輸出log, 其實是設定了具有一定log級別的輸出, 系統會根據作者設置的日誌閾值, 來自動篩選那些日誌是需要輸出的, 那些是不需要輸出的。

自定義log輸出函數

av_log()調用了av_vlog(),av_log()調用了一個函數指針av_log_callback。av_log_callback是一個全局靜態變量,定義如下所示:

static void (*av_log_callback)(void*, int, const char*, va_list) = av_log_default_callback;

從代碼中可以看出,av_log_callback指針默認指向一個函數av_log_default_callback()。av_log_default_callback()即FFmpeg默認的Log函數。
需要注意的是,這個Log函數是可以自定義的。按照指定的參數定義一個自定義的函數後,可以通過FFmpeg的另一個API函數av_log_set_callback()設定爲Log函數。
查看源碼,可以看到 av_log_set_callback() 的聲明如下:

/**
 * Set the logging callback
 *
 * @note The callback must be thread safe, even if the application does not use
 *       threads itself as some codecs are multithreaded.
 *
 * @see av_log_default_callback
 *
 * @param callback A logging function with a compatible signature.
 */
void av_log_set_callback(void (*callback)(void*, int, const char*, va_list));

從聲明中可以看出,需要指定一個參數爲(void*, int, const char*, va_list),返回值爲void的函數作爲Log函數。

查看av_log_set_callback() 源碼,可以看到此方法只是做了一個函數指針賦值的工作,代碼如下:

void av_log_set_callback(void (*callback)(void*, int, const char*, va_list)) {
    av_log_callback = callback;
}

這樣我們可以自定義一個my_logoutput()函數作爲Log的輸出函數:

void selfDefineLogOutPut(void* ptr, int level, const char* fmt,va_list vl){
    *******(omit....}

編輯好函數之後,使用av_log_set_callback()函數設置該函數爲Log輸出函數即可。

av_log_set_callback(selfDefineLogOutPut);

For Example:

void selfDefineLogOutPut(void* ptr, int level, const char* fmt,va_list vl){
    cout << fmt;
    return;
}

int main()
{
    av_log_set_level(AV_LOG_INFO);
    av_log_set_callback(selfDefineLogOutPut);
    av_log(nullptr, AV_LOG_ERROR, "My self out put\n");
    av_log_get_level();
    return 0;
}

輸出結果:
在這裏插入圖片描述
ps: 如果有需要, 還得恢復默認的log輸出行爲, 不要拍拍屁股就走人了:

av_log_set_callback(av_log_default_callback);

把日誌輸出到日誌文件:

大家務必注意,上文的所有騷操作, 一頓操作猛如虎,一看結果250,所有的log都輸出在屏幕上,也即是標準輸出或者標準出錯。怎麼把日誌輸出到log文件裏呢??
這裏就需要結合上一條的操作, 既然能夠自定義log輸出函數, 那就好辦了:

void selfDefineLogOutPut(void* ptr, int level, const char* fmt, va_list vl){
    char buff[1024] = "";
    sprintf(buff, fmt, vl[0]);
    FILE *file = fopen("D:\\ZLJ\\stuff\\a.txt", "wb+");
    fwrite(buff, 1, strlen(buff), file);
    fclose(file);
    return;
}

int main()
{
    av_log_set_level(AV_LOG_INFO);
    av_log_set_callback(selfDefineLogOutPut);
    av_log(nullptr, AV_LOG_ERROR, "My self out put abc = %d \n", 123);
    av_log_get_level();
    return 0;
}

上面的方法完全可以實現把log輸出到日誌裏。但是,因爲va_list 實在是一個愚蠢到頂的數據結構,不知道那個白癡想出來的可變參數。用起來還是有些不方便。但是有總比沒有要強的多吧,哈哈哈哈

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章