目标

      Pad的Capabilities是一个GStreamer element的基础,因为framework大部分时间是自动处理的,所以我们几乎感觉不到它的存在。本教程比较偏向原理,介绍了:

      什么是Pad Capabilities

      如何获得这个东西

      什么时候应该去获得这个东西

      为什么你需要了解他们



介绍

Pads

      Pads允许信息进入或者离开一个element——就像曾经展示过得一样。这个Capabilities(或者简单地叫做Caps)就是指定哪些信息可以通过Pad来传输。例如:“”RGB视频,尺寸为320x200并且每秒30帧“或者”16位的音频采样,5.1声道,每秒采样44.1k“甚至可以是类似于mp3/h264之类的压缩格式。

      Pads支持多重Capabilities(比如,一个视频的sink可以支持RGB输出或者YUV输出),Capabilities可以指定一个范围而不必须是一个特定值(比如,一个音频sink可以支持从1~48000的采样率)。然而,数据从一个pad流向另一个pad的时候,必须是一个双方都能支持的格式。某一种数据形式是两个pad都能支持的,这样Pads的Capabilities就固定下来(只有一个钟个数,并且不再是一个数据区间了),这个过程被称为协商。下面的例子会更清楚的说明这一点。

      为了两个element可以连接,他们必须有一个共同的Capabilities子集(否则它们肯定不能互相连接)。这就是Capabilities存在的主要目的。

      作为一个应用开发者,我们通常都是用连接一个个element的方法来建立pipeline的。在这个例子中,你需要了解你使用的element的Pad的Caps。

Pad模板

      Pad是由Pad模板创建的,模板里面会列出一个Pad所有可能的Capabilities。模板对于创建几个相似的Pad是很有帮助的,但也会比较早就判断出两个element是否可以相连:如果连两个Pad的模板都不具备共同的子集的化,就没必要进行更深层的协商了。

      Pad模板检查是协商流程的第一步。随着流程的逐步深入,Pad会正式初始化,也会确定他们的Capability(除非协商失败了)。

Capabilities例子

[plain] view
plain
 copy

  1. SINK template: 'sink'
  2. Availability: Always
  3. Capabilities:
  4. audio/x-raw-int
  5. signed: true
  6. width: 16
  7. depth: 16
  8. rate: [ 1, 2147483647 ]
  9. channels: [ 1, 2 ]
  10. audio/x-raw-int
  11. signed: false
  12. width: 8
  13. depth: 8
  14. rate: [ 1, 2147483647 ]
  15. channels: [ 1, 2 ]

这是一个element的永久sink pad。它支持2种媒体格式,都是音频的原始数据(audio/x-raw-int),16位的符号数和8位的无符号数。方括号表示一个范围,例如,频道(channels)的范围是1到2.

[plain] view
plain
 copy

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

video/x-raw-yur表示这个source pad用YUV格式输出视频。它支持一个很广的维数和帧率,一系列的YUV格式(用花括号列出了)。所有这些格式都显示不同的图像打包和子采样程度。

最后的总结

你可以使用gst-inspect-0.10这个工具(在后面教程中会介绍)来查看一下element的Caps。

记住有些element会查看底层的硬件来确定支持的格式和能提供的Pad的Caps(通常在进入READY或更后面的状态)。因此,这个显示的Caps由于平台的不同是不一样的,甚至可能在每一次运行都不相同(这种情况很少)。

本教程会创建2个element,显示它们各自的Pad模板,连接起来并把pipeline设置成PLAY状态。在每个状态切换的过程中,sink element的Pad的Capabilities会显示出来,这样你就可以观察到协商过程是如何进行的,最后Pad的Caps是怎么定下来的。

一个简单地Pad Capabilities例子

[objc] view
plain
 copy

  1. #include <gst/gst.h>
  2. /* Functions below print the Capabilities in a human-friendly format */
  3. static gboolean print_field (GQuark field, const GValue * value, gpointer pfx) {
  4. gchar *str = gst_value_serialize (value);
  5. g_print ("%s  %15s: %s\n", (gchar *) pfx, g_quark_to_string (field), str);
  6. g_free (str);
  7. return TRUE;
  8. }
  9. static void print_caps (const GstCaps * caps, const gchar * pfx) {
  10. guint i;
  11. g_return_if_fail (caps != NULL);
  12. if (gst_caps_is_any (caps)) {
  13. g_print ("%sANY\n", pfx);
  14. return;
  15. }
  16. if (gst_caps_is_empty (caps)) {
  17. g_print ("%sEMPTY\n", pfx);
  18. return;
  19. }
  20. ; i < gst_caps_get_size (caps); i++) {
  21. GstStructure *structure = gst_caps_get_structure (caps, i);
  22. g_print ("%s%s\n", pfx, gst_structure_get_name (structure));
  23. gst_structure_foreach (structure, print_field, (gpointer) pfx);
  24. }
  25. }
  26. /* Prints information about a Pad Template, including its Capabilities */
  27. static void print_pad_templates_information (GstElementFactory * factory) {
  28. const GList *pads;
  29. GstStaticPadTemplate *padtemplate;
  30. g_print ("Pad Templates for %s:\n", gst_element_factory_get_longname (factory));
  31. if (!factory->numpadtemplates) {
  32. g_print ("  none\n");
  33. return;
  34. }
  35. pads = factory->staticpadtemplates;
  36. while (pads) {
  37. padtemplate = (GstStaticPadTemplate *) (pads->data);
  38. pads = g_list_next (pads);
  39. if (padtemplate->direction == GST_PAD_SRC)
  40. g_print ("  SRC template: '%s'\n", padtemplate->name_template);
  41. else if (padtemplate->direction == GST_PAD_SINK)
  42. g_print ("  SINK template: '%s'\n", padtemplate->name_template);
  43. else
  44. g_print ("  UNKNOWN!!! template: '%s'\n", padtemplate->name_template);
  45. if (padtemplate->presence == GST_PAD_ALWAYS)
  46. g_print ("    Availability: Always\n");
  47. else if (padtemplate->presence == GST_PAD_SOMETIMES)
  48. g_print ("    Availability: Sometimes\n");
  49. else if (padtemplate->presence == GST_PAD_REQUEST) {
  50. g_print ("    Availability: On request\n");
  51. } else
  52. g_print ("    Availability: UNKNOWN!!!\n");
  53. if (padtemplate->static_caps.string) {
  54. g_print ("    Capabilities:\n");
  55. print_caps (gst_static_caps_get (&padtemplate->static_caps), "      ");
  56. }
  57. g_print ("\n");
  58. }
  59. }
  60. /* Shows the CURRENT capabilities of the requested pad in the given element */
  61. static void print_pad_capabilities (GstElement *element, gchar *pad_name) {
  62. GstPad *pad = NULL;
  63. GstCaps *caps = NULL;
  64. /* Retrieve pad */
  65. pad = gst_element_get_static_pad (element, pad_name);
  66. if (!pad) {
  67. g_printerr ("Could not retrieve pad '%s'\n", pad_name);
  68. return;
  69. }
  70. /* Retrieve negotiated caps (or acceptable caps if negotiation is not finished yet) */
  71. caps = gst_pad_get_negotiated_caps (pad);
  72. if (!caps)
  73. caps = gst_pad_get_caps_reffed (pad);
  74. /* Print and free */
  75. g_print ("Caps for the %s pad:\n", pad_name);
  76. print_caps (caps, "      ");
  77. gst_caps_unref (caps);
  78. gst_object_unref (pad);
  79. }
  80. int main(int argc, charchar *argv[]) {
  81. GstElement *pipeline, *source, *sink;
  82. GstElementFactory *source_factory, *sink_factory;
  83. GstBus *bus;
  84. GstMessage *msg;
  85. GstStateChangeReturn ret;
  86. gboolean terminate = FALSE;
  87. /* Initialize GStreamer */
  88. gst_init (&argc, &argv);
  89. /* Create the element factories */
  90. source_factory = gst_element_factory_find ("audiotestsrc");
  91. sink_factory = gst_element_factory_find ("autoaudiosink");
  92. if (!source_factory || !sink_factory) {
  93. g_printerr ("Not all element factories could be created.\n");
  94. ;
  95. }
  96. /* Print information about the pad templates of these factories */
  97. print_pad_templates_information (source_factory);
  98. print_pad_templates_information (sink_factory);
  99. /* Ask the factories to instantiate actual elements */
  100. source = gst_element_factory_create (source_factory, "source");
  101. sink = gst_element_factory_create (sink_factory, "sink");
  102. /* Create the empty pipeline */
  103. pipeline = gst_pipeline_new ("test-pipeline");
  104. if (!pipeline || !source || !sink) {
  105. g_printerr ("Not all elements could be created.\n");
  106. ;
  107. }
  108. /* Build the pipeline */
  109. gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
  110. if (gst_element_link (source, sink) != TRUE) {
  111. g_printerr ("Elements could not be linked.\n");
  112. gst_object_unref (pipeline);
  113. ;
  114. }
  115. /* Print initial negotiated caps (in NULL state) */
  116. g_print ("In NULL state:\n");
  117. print_pad_capabilities (sink, "sink");
  118. /* Start playing */
  119. ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
  120. if (ret == GST_STATE_CHANGE_FAILURE) {
  121. g_printerr ("Unable to set the pipeline to the playing state (check the bus for error messages).\n");
  122. }
  123. /* Wait until error, EOS or State Change */
  124. bus = gst_element_get_bus (pipeline);
  125. do {
  126. msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS |
  127. GST_MESSAGE_STATE_CHANGED);
  128. /* Parse message */
  129. if (msg != NULL) {
  130. GError *err;
  131. gchar *debug_info;
  132. switch (GST_MESSAGE_TYPE (msg)) {
  133. case GST_MESSAGE_ERROR:
  134. gst_message_parse_error (msg, &err, &debug_info);
  135. g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);
  136. g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");
  137. g_clear_error (&err);
  138. g_free (debug_info);
  139. terminate = TRUE;
  140. break;
  141. case GST_MESSAGE_EOS:
  142. g_print ("End-Of-Stream reached.\n");
  143. terminate = TRUE;
  144. break;
  145. case GST_MESSAGE_STATE_CHANGED:
  146. /* We are only interested in state-changed messages from the pipeline */
  147. if (GST_MESSAGE_SRC (msg) == GST_OBJECT (pipeline)) {
  148. GstState old_state, new_state, pending_state;
  149. gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);
  150. g_print ("\nPipeline state changed from %s to %s:\n",
  151. gst_element_state_get_name (old_state), gst_element_state_get_name (new_state));
  152. /* Print the current capabilities of the sink element */
  153. print_pad_capabilities (sink, "sink");
  154. }
  155. break;
  156. default:
  157. /* We should not reach here because we only asked for ERRORs, EOS and STATE_CHANGED */
  158. g_printerr ("Unexpected message received.\n");
  159. break;
  160. }
  161. gst_message_unref (msg);
  162. }
  163. } while (!terminate);
  164. /* Free resources */
  165. gst_object_unref (bus);
  166. gst_element_set_state (pipeline, GST_STATE_NULL);
  167. gst_object_unref (pipeline);
  168. gst_object_unref (source_factory);
  169. gst_object_unref (sink_factory);
  170. ;
  171. }

工作流程

这里的print_field,print_caps和print_pad_templates仅仅简单的用方便阅读的方式显示Capabilities结构。如果你想学到GstCaps数据结构的内在组织,那么请度以下Gstreamer文档关于Pad
Caps的部分。

[objc] view
plain
 copy

  1. /* Shows the CURRENT capabilities of the requested pad in the given element */
  2. static void print_pad_capabilities (GstElement *element, gchar *pad_name) {
  3. GstPad *pad = NULL;
  4. GstCaps *caps = NULL;
  5. /* Retrieve pad */
  6. pad = gst_element_get_static_pad (element, pad_name);
  7. if (!pad) {
  8. g_printerr ("Could not retrieve pad '%s'\n", pad_name);
  9. return;
  10. }
  11. /* Retrieve negotiated caps (or acceptable caps if negotiation is not finished yet) */
  12. caps = gst_pad_get_negotiated_caps (pad);
  13. if (!caps)
  14. caps = gst_pad_get_caps_reffed (pad);
  15. /* Print and free */
  16. g_print ("Caps for the %s pad:\n", pad_name);
  17. print_caps (caps, "      ");
  18. gst_caps_unref (caps);
  19. gst_object_unref (pad);
  20. }

gst_element_get_static_pad()方法会从给定的element里面取得Pad的名字。这个Pad是静态的,因为它会一直存在。要进一步了解Pad请阅读GStreamer文档关于Pad的部分。

然后我们调用gst_pad_get_negotiated_caps()方法来获得Pad当前的Capabilities,无论是否已经固定下来,都会依赖协商过程的状态。这时Capabilities可能是不存在的,如果遇到这种情况,我们就调用gst_pad_get_caps_reffed()方法来建立一个当前可以接受的Pad
Capabilities。这个所谓的当前可接受的Caps时Pad Template的在NULL状态下的Caps,但后面这个可能会改变,因为还会查询实际的硬件。

gst_pad_get_caps_reffed()通常来说比gst_pad_get_caps()快一点,而且如果我们不需要改变获得的Caps的话也足够用了。然后我们就打印出这些Capabilities。

[objc] view
plain
 copy

  1. /* Create the element factories */
  2. source_factory = gst_element_factory_find ("audiotestsrc");
  3. sink_factory = gst_element_factory_find ("autoaudiosink");
  4. if (!source_factory || !sink_factory) {
  5. g_printerr ("Not all element factories could be created.\n");
  6. ;
  7. }
  8. /* Print information about the pad templates of these factories */
  9. print_pad_templates_information (source_factory);
  10. print_pad_templates_information (sink_factory);
  11. /* Ask the factories to instantiate actual elements */
  12. source = gst_element_factory_create (source_factory, "source");
  13. sink = gst_element_factory_create (sink_factory, "sink");

在前面的教程中我们直接使用gst_element_factory_make()方法来创建element,而忽略了工厂本身,我们现在补上这一部分。一个GstElementFactory是负责通过一个工厂名来实例化一个element的。

你可以使用gst_element_factory_find()来创建一个“videotestsrc”工厂,然后通过gst_element_factory_create()来实例化多个“videotestsrc” element。gst_element_factory_make()实际上只是这个过程的一个封装。

通过工程,Pad模板实际上已经可以访问了,所以工厂一建立我们立刻打印这些信息。

我们跳过pipeline的创建和启动部分,直接跳到状态切换消息的处理:

[objc] view
plain
 copy

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

这里只是在每次pipeline状态切换的时候简单地打印当前的Pad Caps。你可以看到,在输出信息里面,初始的Caps(Pad模板的Caps)是如何逐步变化直到确定下来的(仅包含一个类型而且数值固定)。

【GStreamer开发】GStreamer基础教程06——媒体格式和pad的Capabilities的更多相关文章

  1. Android程序开发0基础教程(一)

    程序猿学英语就上视觉英语网 Android程序开发0基础教程(一)   平台简单介绍   令人激动的Google手机操作系统平台-Android在2007年11月13日正式公布了,这是一个开放源码的操 ...

  2. 【GStreamer开发】GStreamer基础教程07——多线程和Pad的有效性

    目标 GStreamer会自动处理多线程这部分,但在有些情况下,你需要手动对线程做解耦.本教程会教你怎样才能做到这一点,另外也展示了Pad的有效性.主要内容包括: 如何针对部分的pipeline建立一 ...

  3. GStreamer基础教程06 - 获取媒体信息

    摘要 在常见的媒体文件中,通常包含一些数据(例如:歌手,专辑,编码类型等),用于描述媒体文件.通常称这些数据为元数据(Metadata:data that provides information a ...

  4. iOS开发零基础教程之生成git所需的SSH keys

    在我们github看到了一个不错的第三方库时,可能我们想把他git clone到本地,我们需要复制他的SSH URL,如下图: 复制完地址之后,我们需要打开终端,然后输入命令: git clone + ...

  5. [ASP.NET Core开发实战]基础篇06 配置

    配置,是应用程序很重要的组成部分,常常用于提供信息,像第三方应用登录钥匙.上传格式与大小限制等等. ASP.NET Core提供一系列配置提供程序读取配置文件或配置项信息. ASP.NET Core项 ...

  6. 【GStreamer开发】GStreamer基础教程14——常用的element

    目标 本教程给出了一系列开发中常用的element.它们包括大杂烩般的eleemnt(比如playbin2)以及一些调试时很有用的element. 简单来说,下面用gst-launch这个工具给出一个 ...

  7. 【GStreamer开发】GStreamer基础教程10——GStreamer工具

    目标 GStreamer提供了一系列方便使用的工具.这篇教程里不牵涉任何代码,但还是会讲一些有用的内容: 如何在命令行下建立一个pipeline--完全不使用C 如何找出一个element的Capab ...

  8. 【GStreamer开发】GStreamer基础教程08——pipeline的快捷访问

    目标 GStreamer建立的pipeline不需要完全关闭.有多种方法可以让数据在任何时候送到pipeline中或者从pipeline中取出.本教程会展示: 如何把外部数据送到pipeline中 如 ...

  9. GStreamer基础教程12 - 常用命令工具

    摘要 GStreamer提供了不同的命令行工具用于快速的查看信息以及验证Pipeline的是否能够正确运行,在平时的开发过程中,我们也优先使用GStreamer的命令行工具验证,再将Pipeline集 ...

随机推荐

  1. noi.ac #38 线段树+时间复杂度分析

    \(des\) 存在参数数组 \(a\),\(a\) 升序排列 \[a_1 < a_2 < \cdots < a_m, m <= 10\] 存在长度为 \(n\) 价值数组 \ ...

  2. [matlab工具箱] 曲线拟合Curve Fitting

    ——转载网络 我的matlab版本是 2016a 首先,工具箱如何打开呢? 在 apps 这个菜单项中,可以找到很多很多的应用,点击就可以打开具体的工具窗口 本文介绍的工具有以下这些: curve F ...

  3. fft相关的复习

    任意长度卷积 CZT 就是一波推导 \[ \begin{aligned} b_i &= \sum_{j=0}^{n-1} \omega^{ij}a_j \\ &= \sum_{j=0} ...

  4. Vijos 1057 盖房子

    二次联通门 : Vijos 1057 盖房子 /* Vijos 1057 盖房子 简单的dp 当前点(i, j)所能构成的最大的正方形的边长 为点(i - 1, j - 1)与(i, j - 1), ...

  5. UML图中时序图的基本用法

    快速阅读 序列图主要用来更直观的表现各个对象交互的时间顺序,将体现的重点放在 以时间为参照,各个对象发送.接收消息,处理消息,返回消息的 时间流程顺序,也称为时序图. 里面用到的基本元素如下: 角色- ...

  6. LCT 总结

    刚开始学lct花了一晚上研究模板,调出来就感觉不怎么难打了. 对板子的浅显理解: lct维护树形联通块,通过splay维护实链,可以把需要的路径变换到一颗splay上维护. splay中的关系只依赖实 ...

  7. 开启和关闭oracle数据库中的审计功能

    第1步:查看审计功能是否开启?SQL> show parameter audit;NAME                                 TYPE        VALUE-- ...

  8. 借助中间件优化代码 将请求RequestId在服务端接收到请求在处理业务逻辑之前生成

    将请求RequestId在服务端接收到请求在处理业务逻辑之前生成

  9. Windows安装Redis并添加本地自启动服务并解决客户端dll报错

    参考文章:https://blog.csdn.net/realjh/article/details/82026160 Redis下载: https://github.com/MicrosoftArch ...

  10. java和c# md5加密

    MD5加密的方式有很多,加盐的方式更多,最近项目需要java和c#加密结果一致,形成方法如下: 1.c#加密方法/// <summary> /// MD5 加密字符串 /// </s ...