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=2,audiotestsrc:6 只會將audiotestsrc的日志級別設置為6,其他的模塊仍然使用級別2。
  這樣,GST_DEBUG的值是以逗號分隔的”模塊名:級別“的鍵值對,可以在最開始增加其他未指定模塊的默認日志級別,多個模塊名可以使用逗號隔開。同時,GST_DEBUG的值還支持”*“通配符。
  例如:GST_DEBUG=2,audio*:6會將模塊名以audio開始的模塊的日志級別設置為6,其他的默認為2。
  同樣,GST_DEBUG=*:2 會匹配所有的模塊,與GST_DEBUG=2等同。
  我們可以通過gst-launch-1.0 --gst-debug-help 列出當前所注冊的模塊名,模塊名由插件注冊。在安裝的插件改變時,此命令輸出結果也會變化。

 在Windows中,需要按照Windows的方式設置環境變量

  •   Windows cmd使用以下命令設置:
D:\gstreamer\1.0\msvc_x86_64\bin>  set GST_DEBUG=*:2

查看設置的值
D:\gstreamer\1.0\msvc_x86_64\bin> set GST_DEBUG GST_DEBUG=*:2
  •   Windows PowerShell使用以下命令設置:
PS D:\Tools\gstreamer\1.0\msvc_x86_64\bin> $env:GST_DEBUG="*:2"

查看設置的值
PS D:\Tools\gstreamer\1.0\msvc_x86_64\bin> $env:GST_DEBUG
*:2

PS D:\Tools\gstreamer\1.0\msvc_x86_64\bin> $env:GST_DEBUG="souphttpsrc:6"
PS D:\Tools\gstreamer\1.0\msvc_x86_64\bin> $env:GST_DEBUG
souphttpsrc:6

 

 

使用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
本文版權歸作者所有,歡迎轉載。商業轉載請聯系作者獲得授權,非商業轉載請在文章頁面明顯位置給出原文連接.
查看設置的值

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM