资讯详情

GStreamer 基本教程6:Media formats and Pad Capabilities

目录标题写在这里

  • 目标
  • 介绍
    • Pads
    • Pad 模板
    • Capabilities示例
    • 备注
  • 一个简单的Pad功能示例
  • 演练
  • 总结

目标

Pad Capabilities是GStreamer一个基本元素,虽然大多数时候是看不见的,因为框架会自动处理。这个理论教程显示:

  • 什么是Pad Capabilities
  • 如何检索它们
  • 何时检索它们
  • 你为什么要知道它们?

介绍

Pads

正如前面所示,Pads允许信息输入和离开element。Pad的capability(简称Caps)什么样的信息可以指定?Pad例如,分辨率为320x200像素,每秒30帧RGB视频.一个通道,甚至压缩格式,如mp3或h264。

Pads可以支持多种capability(例如,视频接收器可以支持不同类型的视频接收器RGB或YUV格式视频),capability可指定为范围(例如,音频接收器可支持每秒1到48000个采样率)。但是,从Pad传输到Pad实际信息必须只有明确指定的类型。通过一个叫做协商的过程,两个链接pad就公共类型达成一致,因此pad能力是固定的(只有一种类型,不包括范围)。下面的示例代码练习应该能够清楚地说明这一切。

(否则不能互相理解)。Capabilities主要目标。

作为一名应用程序开发人员,你通常会通过它element一起构建链接 pipelines(你用的是像playbin这样的all-in-all elements的情况 ,则较少)。在这种情况下,你需要知道元素Pad Caps(这些都是常见的名字),或者至少在GStreamer当你拒绝连接这两个元素时,你知道这些错误是什么。

Pad 模板

Pad是由Pad Templates它指出了一个Pad可能拥有的所有可能的Capabilities。创建几个类似的模板Pad,也允许元素在早期拒绝连接:因为如果它们Pad Templates的Capabilities没有公共子集(它们的交集是空的),就没有必要进一步协商。 Pad Templates可视为谈判的第一步。随着过程的发展,实际Pads他们的Capabilities在它们被固定(或谈判失败)之前,会被细化。

Capabilities示例

SINK template: 'sink'   Availability: Always   Capabilities:     audio/x-raw                format: S16LE                  rate: [ 1, 2147483647 ]              channels: [ 1, 2 ]     audio/x-raw                format: U8                  rate: [ 1, 2147483647 ]              channels: [ 1, 2 ] 

这个pad它总是可用于元素sink(我们现在不讨论可用性)。它支持整数格式的原始音频两种媒体(audio/x-raw):有符号的16位小尾数和无符号的8位数。方括号表示一个范围:例如,channels: [ 1, 2 ]表示通道数量从1到2不等。

SRC template: 'src'   Availability: Always   Capabilities:     video/x-raw                 width: [ 1, 2147483647 ]                height: [ 1, 2147483647 ]             framerate: [ 0/1, 2147483647/1 ]
               format: { 
         I420, NV12, NV21, YV12, YUY2, Y42B, Y444, YUV9, YVU9, Y41B, Y800, Y8, GREY, Y16 , UYVY, YVYU, IYU1, v308, AYUV, A420 }

Video /x-raw表示该source pad输出原始视频。它支持广泛的尺寸和帧率,以及一组YUV格式(示例中的花括号表示列表)。所有这些格式都表示图像平面的不同打包和子采样。

备注

您可以使用Basic tutorial 10: GStreamer tools中描述的gst-inspect-1.0工具来了解任何GStreamer元素的Caps。

请记住,一些元素查询底层硬件以获得支持的格式,并相应地提供它们的Pad Caps(它们通常在进入READY状态或更高状态时这样做)。因此,显示的上限可能因平台而异,甚至可能因一次执行而异(尽管这种情况很少见)。

本教程实例化了两个elements(这次是通过它们的factories),显示它们的Pad Templates,链接它们并设置管道播放。在每个状态更改时,将显示接收器元素的Pad的Capabilities,因此您可以观察协商是如何进行的,直到Pad Caps被固定为止。

一个简单的Pad功能示例

将此代码复制到一个名为basic-tutorial-6.c的文本文件中(或在GStreamer安装中找到它)。

#include <gst/gst.h>

/* Functions below print the Capabilities in a human-friendly format */
static gboolean print_field (GQuark field, const GValue * value, gpointer pfx) { 
        
  gchar *str = gst_value_serialize (value);

  g_print ("%s %15s: %s\n", (gchar *) pfx, g_quark_to_string (field), str);
  g_free (str);
  return TRUE;
}

static void print_caps (const GstCaps * caps, const gchar * pfx) { 
        
  guint i;

  g_return_if_fail (caps != NULL);

  if (gst_caps_is_any (caps)) { 
        
    g_print ("%sANY\n", pfx);
    return;
  }
  if (gst_caps_is_empty (caps)) { 
        
    g_print ("%sEMPTY\n", pfx);
    return;
  }

  for (i = 0; i < gst_caps_get_size (caps); i++) { 
        
    GstStructure *structure = gst_caps_get_structure (caps, i);

    g_print ("%s%s\n", pfx, gst_structure_get_name (structure));
    gst_structure_foreach (structure, print_field, (gpointer) pfx);
  }
}

/* Prints information about a Pad Template, including its Capabilities */
static void print_pad_templates_information (GstElementFactory * factory) { 
        
  const GList *pads;
  GstStaticPadTemplate *padtemplate;

  g_print ("Pad Templates for %s:\n", gst_element_factory_get_longname (factory));
  if (!gst_element_factory_get_num_pad_templates (factory)) { 
        
    g_print (" none\n");
    return;
  }

  pads = gst_element_factory_get_static_pad_templates (factory);
  while (pads) { 
        
    padtemplate = pads->data;
    pads = g_list_next (pads);

    if (padtemplate->direction == GST_PAD_SRC)
      g_print (" SRC template: '%s'\n", padtemplate->name_template);
    else if (padtemplate->direction == GST_PAD_SINK)
      g_print (" SINK template: '%s'\n", padtemplate->name_template);
    else
      g_print (" UNKNOWN!!! template: '%s'\n", padtemplate->name_template);

    if (padtemplate->presence == GST_PAD_ALWAYS)
      g_print (" Availability: Always\n");
    else if (padtemplate->presence == GST_PAD_SOMETIMES)
      g_print (" Availability: Sometimes\n");
    else if (padtemplate->presence == GST_PAD_REQUEST)
      g_print (" Availability: On request\n");
    else
      g_print (" Availability: UNKNOWN!!!\n");

    if (padtemplate->static_caps.string) { 
        
      GstCaps *caps;
      g_print (" Capabilities:\n");
      caps = gst_static_caps_get (&padtemplate->static_caps);
      print_caps (caps, " ");
      gst_caps_unref (caps);

    }

    g_print ("\n");
  }
}

/* Shows the CURRENT capabilities of the requested pad in the given element */
static void print_pad_capabilities (GstElement *element, gchar *pad_name) { 
        
  GstPad *pad = NULL;
  GstCaps *caps = NULL;

  /* Retrieve pad */
  pad = gst_element_get_static_pad (element, pad_name);
  if (!pad) { 
        
    g_printerr ("Could not retrieve pad '%s'\n", pad_name);
    return;
  }

  /* Retrieve negotiated caps (or acceptable caps if negotiation is not finished yet) */
  caps = gst_pad_get_current_caps (pad);
  if (!caps)
    caps = gst_pad_query_caps (pad, NULL);

  /* Print and free */
  g_print ("Caps for the %s pad:\n", pad_name);
  print_caps (caps, " ");
  gst_caps_unref (caps);
  gst_object_unref (pad);
}

int main(int argc, char *argv[]) { 
        
  GstElement *pipeline, *source, *sink;
  GstElementFactory *source_factory, *sink_factory;
  GstBus *bus;
  GstMessage *msg;
  GstStateChangeReturn ret;
  gboolean terminate = FALSE;

  /* Initialize GStreamer */
  gst_init (&argc, &argv);

  /* Create the element factories */
  source_factory = gst_element_factory_find ("audiotestsrc");
  sink_factory = gst_element_factory_find ("autoaudiosink");
  if (!source_factory || !sink_factory) { 
        
    g_printerr ("Not all element factories could be created.\n");
    return -1;
  }

  /* Print information about the pad templates of these factories */
  print_pad_templates_information (source_factory);
  print_pad_templates_information (sink_factory);

  /* Ask the factories to instantiate actual elements */
  source = gst_element_factory_create (source_factory, "source");
  sink = gst_element_factory_create (sink_factory, "sink");

  /* Create the empty pipeline */
  pipeline = gst_pipeline_new ("test-pipeline");

  if (!pipeline || !source || !sink) { 
        
    g_printerr ("Not all elements could be created.\n");
    return -1;
  }

  /* Build the pipeline */
  gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
  if (gst_element_link (source, sink) != TRUE) { 
        
    g_printerr ("Elements could not be linked.\n");
    gst_object_unref (pipeline);
    return -1;
  }

  /* Print initial negotiated caps (in NULL state) */
  g_print ("In NULL state:\n");
  print_pad_capabilities (sink, "sink");

  /* Start playing */
  ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
  if (ret == GST_STATE_CHANGE_FAILURE) { 
        
    g_printerr ("Unable to set the pipeline to the playing state (check the bus for error messages).\n");
  }

  /* Wait until error, EOS or State Change */
  bus = gst_element_get_bus (pipeline);
  do { 
        
    msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS |
        GST_MESSAGE_STATE_CHANGED);

    /* Parse message */
    if (msg != NULL) { 
        
      GError *err;
      gchar *debug_info;

      switch (GST_MESSAGE_TYPE (msg)) { 
        
        case GST_MESSAGE_ERROR:
          gst_message_parse_error (msg, &err, &debug_info);
          g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);
          g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");
          g_clear_error (&err);
          g_free (debug_info);
          terminate = TRUE;
          break;
        case GST_MESSAGE_EOS:
          g_print ("End-Of-Stream reached.\n");
          terminate = TRUE;
          break;
        case GST_MESSAGE_STATE_CHANGED:
          /* We are only interested in state-changed messages from the pipeline */
          if (GST_MESSAGE_SRC (msg) == GST_OBJECT (pipeline)) { 
        
            GstState old_state, new_state, pending_state;
            gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);
            g_print ("\nPipeline state changed from %s to %s:\n",
                gst_element_state_get_name (old_state), gst_element_state_get_name (new_state));
            /* Print the current capabilities of the sink element */
            print_pad_capabilities (sink, "sink");
          }
          break;
        default:
          /* We should not reach here because we only asked for ERRORs, EOS and STATE_CHANGED */
          g_printerr ("Unexpected message received.\n");
          break;
      }
      gst_message_unref (msg);
    }
  } while (!terminate);

  /* Free resources */
  gst_object_unref (bus);
  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_object_unref (pipeline);
  gst_object_unref (source_factory);
  gst_object_unref (sink_factory);
  return 0;
}

需要帮忙吗?

如果你需要帮助来编译这些代码,请参考构建你的平台的教程部分:Linux, Mac OS X或Windows,或者在Linux上使用这个特定的命令:

GCC basic-tutorial-6.c -o basic-tutorial-6 ' pkg-config——cflags——libs gstreamer-1.0 '

如果您需要帮助来运行此代码,请参考针对您的平台运行教程一节:Linux、Mac OS X或Windows。 本教程只是简单地显示有关Pad能力在不同的时间瞬间的信息。 必需的库:gstreamer - 1.0*

演练

print_field、print_caps和print_pad_templates只是以一种人性化的格式显示功能结构。如果您想了解GstCaps结构的内部组织,请阅读关于Pad Caps的GStreamer文档。

/* Shows the CURRENT capabilities of the requested pad in the given element */
static void print_pad_capabilities (GstElement *element, gchar *pad_name) { 
        
  GstPad *pad = NULL;
  GstCaps *caps = NULL;

  /* Retrieve pad */
  pad = gst_element_get_static_pad (element, pad_name);
  if (!pad) { 
        
    g_printerr ("Could not retrieve pad '%s'\n", pad_name);
    return;
  }

  /* Retrieve negotiated caps (or acceptable caps if negotiation is not finished yet) */
  caps = gst_pad_get_current_caps (pad);
  if (!caps)
    caps = gst_pad_query_caps (pad, NULL);

  /* Print and free */
  g_print ("Caps for the %s pad:\n", pad_name);
  print_caps (caps, " ");
  gst_caps_unref (caps);
  gst_object_unref (pad);
}

gst_element_get_static_pad()从给定元素检索命名的Pad。这个Pad是静态的,因为它总是出现在元素中。要了解关于Pad可用性的更多信息,请阅读关于Pad的GStreamer文档。

然后我们调用gst_pad_get_current_caps()来检索Pad的当前能力,它可以是固定的,也可以不是,这取决于协商过程的状态。它们甚至可能不存在,在这种情况下,我们调用gst_pad_query_caps()来检索当前可接受的Pad Capabilities。当前可接受的Caps将是在NULL状态下的Pad模板的Caps,但是在以后的状态中可能会改变,因为实际的硬件能力可能会被查询。

然后我们打印这些 Capabilities。

/* Create the element factories */
source_factory = gst_element_factory_find ("audiotestsrc");
sink_factory = gst_element_factory_find ("autoaudiosink");
if (!source_factory || !sink_factory) { 
        
  g_printerr ("Not all element factories could be created.\n");
  return -1;
}

/* Print information about the pad templates of these factories */
print_pad_templates_information (source_factory);
print_pad_templates_information (sink_factory);

/* Ask the factories to instantiate actual elements */
source = gst_element_factory_create (source_factory, "source");
sink = gst_element_factory_create (sink_factory, "sink");

在前面的教程中,我们直接使用gst_element_factory_make()创建元素,跳过了factory的讨论,但是我们现在要做的是。GstElementFactory负责实例化由其factory名称标识的特定类型的元素。

您可以使用gst_element_factory_find()来创建一个“videotestsrc”类型的factory,然后使用gst_element_factory_create()来实例化多个“videotestsrc”元素。Gst_element_factory_make()实际上是gst_element_factory_find()+ gst_element_factory_create()的快捷方式。

Pad模板已经可以通过factory访问,所以一旦factory创建,它们就会被打印出来。

我们跳过管道的创建和启动,进入State-Changed消息处理:

case GST_MESSAGE_STATE_CHANGED:
  /* We are only interested in state-changed messages from the pipeline */
  if (GST_MESSAGE_SRC (msg) == GST_OBJECT (pipeline)) { 
        
    GstState old_state, new_state, pending_state;
    gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);
    g_print ("\nPipeline state changed from %s to %s:\n",
        gst_element_state_get_name (old_state), gst_element_state_get_name (new_state));
    /* Print the current capabilities of the sink element */
    print_pad_capabilities (sink, "sink");
  }
  break;

每当管道的状态发生变化时,它就简单地打印当前的Pad Caps。您应该在输出中看到,如何逐步细化初始caps (Pad Template的caps),直到它们完全固定(它们包含一个没有范围的单一类型)。

总结

本教程显示了:

  • 什么是Pad Capabilities 和 Pad Template Capabilities.
  • 如何使用gst_pad_get_current_caps()或gst_pad_query_caps()检索它们。
  • 它们根据管道的状态有不同的含义(最初它们表示所有可能的能力,后来它们表示Pad当前协商的Caps)。
  • 事先知道两个元素是否可以连接在一起是很重要的。
  • Pad Caps可以使用gst-inspect-1.0工具找到,在Basic tutorial 10: GStreamer tools中有描述。

下一个教程将展示如何将数据手动注入到GStreamer管道中并从该管道中提取数据。

原教程链接:https://gstreamer.freedesktop.org/documentation/tutorials/basic/media-formats-and-pad-capabilities.html?gi-language=c

标签: 连接器y16hy16连接器y16p

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台