GStreamer基礎教程13 - 除錯Pipeline
摘要
在很多情況下,我們需要對GStreamer建立的Pipeline進行除錯,來了解其執行機制以解決所遇到的問題。為此,GStreamer提供了相應的除錯機制,方便我們快速定位問題。
檢視除錯日誌
使用GST_DEBUG環境變數檢視日誌
GStreamer框架以及其外掛提供了不同級別的日誌資訊,日誌中包含時間戳,程序ID,執行緒ID,型別,原始碼行數,函式名,Element資訊以及相應的日誌訊息。例如:
$ GST_DEBUG=2 gst-launch-1.0 playbin uri=file:///x.mp3 Setting pipeline to PAUSED ... 0:00:00.014898047 47333 0x2159d80 WARN filesrc gstfilesrc.c:530:gst_file_src_start:<source> error: No such file "/x.mp3" ...
我們可以發現,只需要在執行時指定GST_DEBUG環境變數,並設定日誌級別,即可得到相應的日誌。由於GStreamer提供了豐富的日誌,如果我們開啟所有的日誌,必定會對程式的效能有所影響,所以我們需要對日誌進行分級,GStreamer提供了8種級別,用於輸出不同型別的日誌。
- 級別0:不輸出任何日誌資訊。
- 級別1:ERROR資訊。
- 級別2:WARNING資訊。
- 級別3:FIXME資訊。
- 級別4:INFO資訊。
- 級別5:DEBUG資訊
- 級別6:LOG資訊。
- 級別7:TRACE資訊。
- 級別8:MEMDUMP資訊,最高級別日誌。
在使用時,我們只需將GST_DEBUG設定為相應級別,所有小於其級別的資訊都會被輸出,例如:設定GST_DEBUG=2,我們會得到ERROR及WARNING級別的日誌。
這樣,GST_DEBUG的值是以逗號分隔的”模組名:級別“的鍵值對,可以在最開始增加其他未指定模組的預設日誌級別,多個模組名可以使用逗號隔開。同時,GST_DEBUG的值還支援”*“萬用字元。
例如:GST_DEBUG=2,audio*:6會將模組名以audio開始的模組的日誌級別設定為6,其他的預設為2。
同樣,GST_DEBUG=*:2 會匹配所有的模組,與GST_DEBUG=2等同。
使用GST_DEBUG_FILE將日誌輸出到檔案
在實際中,我們通常將日誌儲存在檔案中,便於後續分析。我們可以使用GST_DEBUG_FILE環境變數,指定日誌檔名,GStreamer會自動將日誌寫入檔案中,由於GStreamer日誌包含終端色彩程式碼,我們通常使用 GST_DEBUG_NO_COLOR=1 環境變數將其禁用,方便檢視。使用方式如下:
$ GST_DEBUG_NO_COLOR=1 GST_DEBUG_FILE=pipeline.log GST_DEBUG=5 gst-launch-1.0 audiotestsrc ! autoaudiosink
使用自定義日誌介面
在實際專案中,不同應用可能採用不同的日誌介面,為此,GStreamer提供了相應的介面,應用程式可以在初始化時,通過gst_debug_add_log_function()增加自定義日誌介面。相關介面如下:
//Add customized log function to GStreamer log system. void gst_debug_add_log_function (GstLogFunction func, gpointer user_data, GDestroyNotify notify); // Function prototype for a logging function that can be registered with // gst_debug_add_log_function() // Use G_GNUC_NO_INSTRUMENT on that function. typedef void (*GstLogFunction) (GstDebugCategory * category, GstDebugLevel level, const gchar * file, const gchar * function, gint line, GObject * object, GstDebugMessage * message, gpointer user_data); // Enable log if set to true. void gst_debug_set_active (gboolean active); // Set the default log level. void gst_debug_set_default_threshold (GstDebugLevel level);
示例程式碼如下:
#include <gst/gst.h> #include <stdio.h> /* declare log function with the required attribute */ void my_log_func(GstDebugCategory * category, GstDebugLevel level, const gchar * file, const gchar * function, gint line, GObject * object, GstDebugMessage * message, gpointer user_data) G_GNUC_NO_INSTRUMENT; void my_log_func(GstDebugCategory * category, GstDebugLevel level, const gchar * file, const gchar * function, gint line, GObject * object, GstDebugMessage * message, gpointer user_data) { printf("MyLogFunc: [Level:%d] %s:%s:%d %s\n", level, file, function, line, gst_debug_message_get(message)); } int main(int argc, char *argv[]) { GstPipeline *pipeline = NULL; GMainLoop *main_loop = NULL; /* set log function and remove the default one */ gst_debug_add_log_function(my_log_func, NULL, NULL); gst_debug_set_active(TRUE); gst_debug_set_default_threshold(GST_LEVEL_INFO); /* Initialize GStreamer */ gst_init (&argc, &argv); /* default log function is added by gst_init, so we need remove it after that. */ gst_debug_remove_log_function(gst_debug_log_default); pipeline = (GstPipeline *)gst_parse_launch("audiotestsrc ! autoaudiosink", NULL); /* Start playing */ gst_element_set_state (GST_ELEMENT(pipeline), GST_STATE_PLAYING); main_loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (main_loop); /* Free resources */ g_main_loop_unref (main_loop); gst_element_set_state (GST_ELEMENT(pipeline), GST_STATE_NULL); gst_object_unref (pipeline); return 0; }
編譯執行後,會得到指定函式輸出的log。
$ gcc basic-tutorial-13a.c -o basic-tutorial-13a `pkg-config --cflags --libs gstreamer-1.0`
使用GStreamer日誌系統
如果不想使用自定義介面,我們同樣可以使用Gstreamer提供的日誌系統來由Gstreamer框架統一管理日誌。
使用GStreamer的日誌系統時,我們需要首先定義我們的category,並定義GST_CAT_DEFAULT 巨集為我們的category:
GST_DEBUG_CATEGORY_STATIC (my_category); #define GST_CAT_DEFAULT my_category
然後在gst_init後初始化我們的category:
GST_DEBUG_CATEGORY_INIT (my_category, "my category", 0, "This is my very own");
最後使用GST_ERROR(), GST_WARNING(), GST_INFO(), GST_LOG() 或GST_DEBUG() 巨集輸出日誌,這些巨集所接受的引數型別與printf相同。
示例程式碼如下:
#include <gst/gst.h> #include <stdio.h> GST_DEBUG_CATEGORY_STATIC (my_category); #define GST_CAT_DEFAULT my_category int main(int argc, char *argv[]) { /* Initialize GStreamer */ gst_init (&argc, &argv); GST_DEBUG_CATEGORY_INIT (my_category, "my category", 0, "This is my very own"); GST_ERROR("My msg: %d", 0); GST_WARNING("My msg: %d", 1); GST_INFO("My msg: %d", 2); GST_DEBUG("My msg: %d", 3); return 0; }
編譯後,設定相應的log等級即可看到我們所新增的log。
$ gcc basic-tutorial-13b.c -o basic-tutorial-13b `pkg-config --cflags --libs gstreamer-1.0` $ GST_DEBUG=5 ./basic-tutorial-13b ... 0:00:00.135957434 6189 0x21c4600 ERROR my category basic-tutorial-13b.c:13:main: My msg: 0 0:00:00.135967528 6189 0x21c4600 WARN my category basic-tutorial-13b.c:14:main: My msg: 1 0:00:00.135976899 6189 0x21c4600 INFO my category basic-tutorial-13b.c:15:main: My msg: 2 0:00:00.135985622 6189 0x21c4600 DEBUG my category basic-tutorial-13b.c:16:main: My msg: 3
獲取Pipeline執行時的Element關係圖
在Pipeline變得很複雜時,我們需要知道Pipeline是否按預期執行、使用到哪些Element,尤其是使用playbin 或uridecodebin時。為此,GStreamer提供了相應的功能,能夠將Pipeline在當前狀態下所有的Elements及其關係輸出成dot檔案,再通過 Graphviz等工具可以將其轉換成圖片檔案。
為了得到.dot檔案,我們只需通過GST_DEBUG_DUMP_DOT_DIR 環境變數,指定輸出目錄即可,gst-launch-1.0會在各狀態分別生成一個.dot檔案。 例如:通過下列命令,我們可以得到使用playbin播放網路檔案時生成的Pipeline:
$ GST_DEBUG_DUMP_DOT_DIR=. gst-launch-1.0 playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm $ ls *.dot 0.00.00.013715494-gst-launch.NULL_READY.dot 0.00.00.170999259-gst-launch.PAUSED_PLAYING.dot 0.00.07.642049256-gst-launch.PAUSED_READY.dot 0.00.00.162033239-gst-launch.READY_PAUSED.dot 0.00.07.606477348-gst-launch.PLAYING_PAUSED.dot $ dot 0.00.00.170999259-gst-launch.PAUSED_PLAYING.dot -Tpng -o play.png
生成的play.png如下(結果會根據安裝的外掛不同而不同):
需要注意的是,如果需要在自己的應用中加入此功能,那就需要在想要生成dot檔案的時候顯式地在相應事件發生時呼叫GST_DEBUG_BIN_TO_DOT_FILE() 或GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(),否則即使設定了GST_DEBUG_DUMP_DOT_DIR 環境變數也無法生成dot檔案。
總結
通過本文,我們學習了:
- 如何通過GST_DEBUG環境變數獲取GStreamer詳細的日誌資訊。
- 如何使用自定義GStreamer的日誌輸出函式。
- 如何使用GStreamer日誌系統。
- 如何獲得GStreamer執行時的Element關係圖。
作者:John.Leng 出處:http://www.cnblogs.com/xleng/ 本文版權歸作者所有,歡迎轉載。商業轉載請聯絡作者獲得授權,非商業轉載請在文章頁面明顯位置給出原文連線.