zoukankan      html  css  js  c++  java
  • GStreamer基础教程13

    摘要

      在很多情况下,我们需要对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 列出当前所注册的模块名,模块名由插件注册。在安装的插件改变时,此命令输出结果也会变化。

    使用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
    ",
                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
    本文版权归作者所有,欢迎转载。商业转载请联系作者获得授权,非商业转载请在文章页面明显位置给出原文连接.
  • 相关阅读:
    软件工程结对编程作业
    软件工程第1次作业
    阅读一篇文章,培养一个习惯
    OpenvSwitch系列之五 网桥特性功能配置
    读《阿里工程师的自我修养》我学到这几点
    OpenvSwitch系列之四 ovs-ofctl命令使用
    OpenvSwitch系列之三 ovs-vsctl命令使用
    python进阶之垃圾回收
    OpenDaylight开发hello-world项目之功能实现
    python进阶之内存模型
  • 原文地址:https://www.cnblogs.com/xleng/p/12228720.html
Copyright © 2011-2022 走看看