Gstreamer插件教程2.9—编写一个插件(Writing a Plugin):构建一个测试应用(Building a Test Application)

英文原文:https://gstreamer.freedesktop.org/documentation/plugin-development/basics/testapp.html

你将经常想用尽可能小的设置来测试你新写的插件。通常,gst-launch-1.0是用于测试插件的第一步。如果你还未在Gstreamer的搜索目录上安装你的插件,你将需要设置插件路径。或者设置GST_PLUGIN_PATH变量为包含你插件的目录路径,或者用命令行选项--gst-plugin-path。如果你的插件基于gst-plugin模板,它将类似于gst-launch-1.0 --gst-plugin-path=$HOME/gst-template/gst-plugin/src/.libs TESTPIPELINE一样查找。然而,你将经常需要更多的测试特性,而不仅仅是gst-launch-1,0提供的,如seeking, events, interactivity等更多。为了实现这些,写一个你自己的小型的测试程序是最简单的方式。这部分会以非常少的内容来描述如何实现。对于一个完整的应用开发教程,请见应用开发手册

首先,你需要通过调用gst_init()函数来初始化Gstreamer的核心库。你也可以通过调用gst_init_get_option_group()函数来实现,这个函数将返回一个指向GOptionGroup的指针,然后,你可以用GOption来处理初始化工作,这将完成Gstreamer的初始化。

你可以使用gst_element_factory_make()函数来创建elemens,其中第一个参数是你想创建的element类型,第二个参数是一个任取的名称。例子使用了一个简单的filesource - decoder - soundcard output pipeline,但是,如果需要的话,你可以使用特殊的需调试的element。例如,一个identity element可以作用在pipeline的中间,作为应用中的一个数据传送者。在你的应用中,它可用于检查数据的不正当性和正确性。同样的,你可在pipeline的最后面用一个fakesink element来下载你的数据到标准输出(为了实现这个,请设置dump的属性为TRUE)。最后,你可以用valgrind来检查内存错误。

在链接期间,你的测试应用可以用过滤caps来驱动一个特殊类型的数据从你的element输出或输入到你的element中。在你的element中,这是一个非常简单且有效的检测多种输入输出类型的方式。

注意到在运行期间,为了正确的处理,你应该在总线和/或你的插件/element上监听至少"error"和"eos"信息。同样的,你应该添加event到pipeline中,并确保你的插件会正确地处理这些event(关于clocking, internal caching等)。

永远别忘记在你的插件和应用中清理内存。当进入NULL状态时,你的element应该清理已分配的内存和caches。同样的,应该关闭任何引用到可能支持的库。你的应用程序应该unref() pipeline并确保它不会崩溃。

#include <gst/gst.h>

static gboolean
bus_call (GstBus     *bus,
      GstMessage *msg,
      gpointer    data)
{
  GMainLoop *loop = data;

  switch (GST_MESSAGE_TYPE (msg)) {
    case GST_MESSAGE_EOS:
      g_print ("End-of-stream\n");
      g_main_loop_quit (loop);
      break;
    case GST_MESSAGE_ERROR: {
      gchar *debug = NULL;
      GError *err = NULL;

      gst_message_parse_error (msg, &err, &debug);

      g_print ("Error: %s\n", err->message);
      g_error_free (err);

      if (debug) {
        g_print ("Debug details: %s\n", debug);
        g_free (debug);
      }

      g_main_loop_quit (loop);
      break;
    }
    default:
      break;
  }

  return TRUE;
}

gint
main (gint   argc,
      gchar *argv[])
{
  GstStateChangeReturn ret;
  GstElement *pipeline, *filesrc, *decoder, *filter, *sink;
  GstElement *convert1, *convert2, *resample;
  GMainLoop *loop;
  GstBus *bus;
  guint watch_id;

  /* initialization */
  gst_init (&argc, &argv);
  loop = g_main_loop_new (NULL, FALSE);
  if (argc != 2) {
    g_print ("Usage: %s <mp3 filename>\n", argv[0]);
    return 01;
  }

  /* create elements */
  pipeline = gst_pipeline_new ("my_pipeline");

  /* watch for messages on the pipeline's bus (note that this will only
   * work like this when a GLib main loop is running) */
  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  watch_id = gst_bus_add_watch (bus, bus_call, loop);
  gst_object_unref (bus);

  filesrc  = gst_element_factory_make ("filesrc", "my_filesource");
  decoder  = gst_element_factory_make ("mad", "my_decoder");

  /* putting an audioconvert element here to convert the output of the
   * decoder into a format that my_filter can handle (we are assuming it
   * will handle any sample rate here though) */
  convert1 = gst_element_factory_make ("audioconvert", "audioconvert1");

  /* use "identity" here for a filter that does nothing */
  filter   = gst_element_factory_make ("my_filter", "my_filter");

  /* there should always be audioconvert and audioresample elements before
   * the audio sink, since the capabilities of the audio sink usually vary
   * depending on the environment (output used, sound card, driver etc.) */
  convert2 = gst_element_factory_make ("audioconvert", "audioconvert2");
  resample = gst_element_factory_make ("audioresample", "audioresample");
  sink     = gst_element_factory_make ("pulsesink", "audiosink");

  if (!sink || !decoder) {
    g_print ("Decoder or output could not be found - check your install\n");
    return -1;
  } else if (!convert1 || !convert2 || !resample) {
    g_print ("Could not create audioconvert or audioresample element, "
             "check your installation\n");
    return -1;
  } else if (!filter) {
    g_print ("Your self-written filter could not be found. Make sure it "
             "is installed correctly in $(libdir)/gstreamer-1.0/ or "
             "~/.gstreamer-1.0/plugins/ and that gst-inspect-1.0 lists it. "
             "If it doesn't, check with 'GST_DEBUG=*:2 gst-inspect-1.0' for "
             "the reason why it is not being loaded.");
    return -1;
  }

  g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);

  gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, convert1, filter,
                    convert2, resample, sink, NULL);

  /* link everything together */
  if (!gst_element_link_many (filesrc, decoder, convert1, filter, convert2,
                              resample, sink, NULL)) {
    g_print ("Failed to link one or more elements!\n");
    return -1;
  }

  /* run */
  ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
  if (ret == GST_STATE_CHANGE_FAILURE) {
    GstMessage *msg;

    g_print ("Failed to start up pipeline!\n");

    /* check if there is an error message with details on the bus */
    msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0);
    if (msg) {
      GError *err = NULL;

      gst_message_parse_error (msg, &err, NULL);
      g_print ("ERROR: %s\n", err->message);
      g_error_free (err);
      gst_message_unref (msg);
    }
    return -1;
  }

  g_main_loop_run (loop);

  /* clean up */
  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_object_unref (pipeline);
  g_source_remove (watch_id);
  g_main_loop_unref (loop);

  return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值