概述
在日常Android開發中,我們都是通過Logcat來查看日誌,但是將FFmpeg移植到Android上,無法在Logcat中查看調試信息而無法分析錯誤。本文將介紹如何配置來將FFmpeg的信息輸出到Logcat。
avlogset_callback
FFmpeg中的avlogset_callback函數用來註冊FFmpeg日誌輸出的回調接口。
在FFmpeg源碼中的ffmpeg.c文件的main函數中有avlogsetcallback的調用,而logcallback_null是個空的回調函數,一個思路是可以直接在該回調函數寫打印代碼:
int main(int argc, char **argv) { // 省略其他代碼... av_log_set_callback(log_callback_null); // 省略其他代碼... } static void log_callback_null(void *ptr, int level, const char *fmt, va_list vl) { }
編寫android_log.h頭文件
#include <android/log.h> static int use_log_report = 0; #define FF_LOG_TAG "FFmpeg_VideoEditor" #define FF_LOG_UNKNOWN ANDROID_LOG_UNKNOWN #define FF_LOG_DEFAULT ANDROID_LOG_DEFAULT #define FF_LOG_VERBOSE ANDROID_LOG_VERBOSE #define FF_LOG_DEBUG ANDROID_LOG_DEBUG #define FF_LOG_INFO ANDROID_LOG_INFO #define FF_LOG_WARN ANDROID_LOG_WARN #define FF_LOG_ERROR ANDROID_LOG_ERROR #define FF_LOG_FATAL ANDROID_LOG_FATAL #define FF_LOG_SILENT ANDROID_LOG_SILENT // 打印可變參數 #define VLOG(level, TAG, ...) ((void)__android_log_vprint(level, TAG, __VA_ARGS__)) #define VLOGV(...) VLOG(FF_LOG_VERBOSE, FF_LOG_TAG, __VA_ARGS__) #define VLOGD(...) VLOG(FF_LOG_DEBUG, FF_LOG_TAG, __VA_ARGS__) #define VLOGI(...) VLOG(FF_LOG_INFO, FF_LOG_TAG, __VA_ARGS__) #define VLOGW(...) VLOG(FF_LOG_WARN, FF_LOG_TAG, __VA_ARGS__) #define VLOGE(...) VLOG(FF_LOG_ERROR, FF_LOG_TAG, __VA_ARGS__) #define ALOG(level, TAG, ...) ((void)__android_log_print(level, TAG, __VA_ARGS__)) #define ALOGV(...) ALOG(FF_LOG_VERBOSE, FF_LOG_TAG, __VA_ARGS__) #define ALOGD(...) ALOG(FF_LOG_DEBUG, FF_LOG_TAG, __VA_ARGS__) #define ALOGI(...) ALOG(FF_LOG_INFO, FF_LOG_TAG, __VA_ARGS__) #define ALOGW(...) ALOG(FF_LOG_WARN, FF_LOG_TAG, __VA_ARGS__) #define ALOGE(...) ALOG(FF_LOG_ERROR, FF_LOG_TAG, __VA_ARGS__) #define LOGE(format, ...) __android_log_print(ANDROID_LOG_ERROR, FF_LOG_TAG, format, ##__VA_ARGS__) #define LOGI(format, ...) __android_log_print(ANDROID_LOG_INFO, FF_LOG_TAG, format, ##__VA_ARGS__) // 原樣輸出FFmpeg日誌 static void ffp_log_callback_brief(void *ptr, int level, const char *fmt, va_list vl) { int ffplv = FF_LOG_VERBOSE; if (level <= AV_LOG_ERROR) ffplv = FF_LOG_ERROR; else if (level <= AV_LOG_WARNING) ffplv = FF_LOG_WARN; else if (level <= AV_LOG_INFO) ffplv = FF_LOG_INFO; else if (level <= AV_LOG_VERBOSE) ffplv = FF_LOG_VERBOSE; else ffplv = FF_LOG_DEBUG; if (level <= AV_LOG_INFO) VLOG(ffplv, FF_LOG_TAG, fmt, vl); } // 對FFmpeg日誌進行格式化 static void ffp_log_callback_report(void *ptr, int level, const char *fmt, va_list vl) { int ffplv = FF_LOG_VERBOSE; if (level <= AV_LOG_ERROR) ffplv = FF_LOG_ERROR; else if (level <= AV_LOG_WARNING) ffplv = FF_LOG_WARN; else if (level <= AV_LOG_INFO) ffplv = FF_LOG_INFO; else if (level <= AV_LOG_VERBOSE) ffplv = FF_LOG_VERBOSE; else ffplv = FF_LOG_DEBUG; va_list vl2; char line[1024]; static int print_prefix = 1; va_copy(vl2, vl); // av_log_default_callback(ptr, level, fmt, vl); av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix); va_end(vl2); // ALOG(ffplv, FF_LOG_TAG, "%s", line); }
在實踐中發現輸出的日誌都一樣,只是 ffp_log_callback_report
函數可以在輸出的日誌添加額外信息,如ALOG(ffplv, FFLOGTAG, "額外信息:%s", line);
在ffmpeg.c的main方法中註冊
#include "android_log.h" int main(int argc, char **argv) { // 省略其他代碼... if(use_log_report) { av_log_set_callback(ffp_log_callback_report); } else { av_log_set_callback(ffp_log_callback_brief); } // 省略其他代碼 }
日誌
通過日誌,我們可以看到FFmpeg的版本信息,還有配置信息。
在 configuration
日誌行中可以看到我在編譯時的配置項,當我們在拿到一個別人編譯好的庫,如果我們不知道他的編譯腳本,通過這日誌信息也可以知道。
參考鏈接
- https://blog.csdn.net/matrix_laboratory/article/details/57080891
- https://blog.csdn.net/u012027644/article/details/56666608