Gstreamer - 自动插件

自动插件

在您的第一个应用程序中,您已经学会了为 Ogg/Vorbis 文件构建一个简单的媒体播放器。通过使用替代element,您可以为其他媒体类型构建媒体播放器,例如 Ogg/Speex、MP3 甚至视频格式。但是,您更愿意构建一个应用程序,该应用程序可以自动检测流的媒体类型,并通过查看系统中的所有可用element来自动生成可能的最佳pipeline。这个过程称为自动插件,GStreamer 包含高质量的自动插件器。如果您正在寻找自动插件程序,请不要继续阅读并转到<播放组件>。本章将解释自动插件和类型查找的概念。它将解释 GStreamer 包含哪些系统来动态检测媒体流的类型,以及如何生成解码器element的pipeline来播放此媒体。相同的原理也可用于转码。由于这个概念的完全动态性,GStreamer 可以自动扩展以支持新的媒体类型,而无需对其自动插件进行任何调整。

我们将首先介绍媒体类型的概念,作为识别媒体流的一种动态且可扩展的方式。之后,我们将介绍类型查找的概念来查找媒体流的类型。最后,我们将解释如何使用自动插件和 GStreamer 注册表来设置将媒体从一种媒体类型转换为另一种媒体类型的pipeline,例如用于媒体解码。

媒体类型作为识别流的一种方式

我们之前介绍过capabilities 的概念,当数据从一个element流到另一个element时,capabilities是element之间(或者更确切地说,是pad)在媒体类型上达成一致的一种方式(参见pad的capabilities)。我们已经解释过,capabilities 是媒体类型和一组属性的组合。对于大多数容器格式(那些是你在硬盘上找到的文件;例如,Ogg 是一种容器格式),不需要任何属性来描述流。只需要一种媒体类型。可以在<插件编写指南>中找到媒体类型和附带属性的完整列表。

当一个element被加载到系统中时,它必须将一个媒体类型与其source pad 和sink pad 相关联。 GStreamer 通过 GStreamer 的注册表了解不同的element以及它们期望的数据类型和发出的数据类型。正如我们将看到的,这允许创建非常动态和可扩展的element。

在您的第一个应用程序中,我们学习了为 Ogg/Vorbis 文件构建音乐播放器。让我们看看与此pipeline中的每个pad关联的媒体类型。带有媒体类型的 Hello world pipeline显示了该pipeline中每个 pad 的媒体类型。

 

现在我们已经了解了GStreamer如何识别已知的媒体流,我们可以看看GStreamer用来设置用于媒体处理和媒体类型检测的pipeline的方法。

媒体流类型检测

通常,在加载媒体流时,流的类型是未知的。这意味着在我们可以选择一个pipeline来解码流之前,我们首先需要检测流类型。 GStreamer 为此使用了类型查找的概念。类型查找是pipeline的正常部分,只要流的类型未知,它就会读取数据。在此期间,它将向所有实现类型查找器的插件提供数据。当其中一个 typefinder 识别到流时,typefind element将发出一个信号,并从那时起充当 passthrough 模块。如果未找到任何类型,它将发出错误并停止进一步的媒体处理。

一旦 typefind element找到一个类型,应用程序就可以使用它来插入pipeline以解码媒体流。这将在下一节中讨论。

如前所述,GStreamer 中的插件可以实现类型查找器功能。实现此功能的插件将提交一个媒体类型,可选的一组通常用于该媒体类型的文件扩展名,以及一个 typefind 函数。一旦调用了插件内部的这个 typefind 函数,插件就会查看这个媒体流中的数据是否与标记由该媒体类型标识的媒体类型的特定模式匹配。如果是,它会通知 typefind element这个事实,告诉我们识别了哪个媒体类型以及我们有多确定这个流确实是那个媒体类型。一旦为实现 typefind 功能的所有插件完成此运行,typefind element将告诉应用程序它认为已识别的媒体流类型。

下面的代码应该解释如何使用 typefind element。它将打印检测到的媒体类型,或告诉媒体类型未找到。下一节将介绍更多有用的行为,例如将解码pipeline连接在一起。

#include <gst/gst.h>

[.. my_bus_callback goes here ..]

static gboolean
idle_exit_loop (gpointer data)
{
  g_main_loop_quit ((GMainLoop *) data);

  /* once */
  return FALSE;
}

static void
cb_typefound (GstElement *typefind,
          guint       probability,
          GstCaps    *caps,
          gpointer    data)
{
  GMainLoop *loop = data;
  gchar *type;

  type = gst_caps_to_string (caps);
  g_print ("Media type %s found, probability %d%%\n", type, probability);
  g_free (type);

  /* since we connect to a signal in the pipeline thread context, we need
   * to set an idle handler to exit the main loop in the mainloop context.
   * Normally, your app should not need to worry about such things. */
  g_idle_add (idle_exit_loop, loop);
}

gint
main (gint   argc,
      gchar *argv[])
{
  GMainLoop *loop;
  GstElement *pipeline, *filesrc, *typefind, *fakesink;
  GstBus *bus;

  /* init GStreamer */
  gst_init (&argc, &argv);
  loop = g_main_loop_new (NULL, FALSE);

  /* check args */
  if (argc != 2) {
    g_print ("Usage: %s <filename>\n", argv[0]);
    return -1;
  }

  /* create a new pipeline to hold the elements */
  pipeline = gst_pipeline_new ("pipe");

  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  gst_bus_add_watch (bus, my_bus_callback, NULL);
  gst_object_unref (bus);

  /* create file source and typefind element */
  filesrc = gst_element_factory_make ("filesrc", "source");
  g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
  typefind = gst_element_factory_make ("typefind", "typefinder");
  g_signal_connect (typefind, "have-type", G_CALLBACK (cb_typefound), loop);
  fakesink = gst_element_factory_make ("fakesink", "sink");

  /* setup */
  gst_bin_add_many (GST_BIN (pipeline), filesrc, typefind, fakesink, NULL);
  gst_element_link_many (filesrc, typefind, fakesink, NULL);
  gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
  g_main_loop_run (loop);

  /* unset */
  gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
  gst_object_unref (GST_OBJECT (pipeline));

  return 0;
}

检测到媒体类型后,您可以将一个element(例如分流器或解码器)插入 typefind element的source pad,然后媒体流的解码将立即开始。

动态自动插件pipeline

请参阅播放组件以使用可用于动态构建pipeline的高级对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值