系列文章目录
- GStreamer 简明教程(一):环境搭建,运行 Basic Tutorial 1 Hello world!
 
- GStreamer 简明教程(二):基本概念介绍,Element 和 Pipeline
 
- GStreamer 简明教程(三):动态调整 Pipeline
- GStreamer 简明教程(四):Seek 以及获取文件时长
文章目录
- 系列文章目录
- 前言
- 一、Pad 基本介绍
- 1.1 Pad
- 1.2 Pad 类型
- 1. Sink Pad(接收 Pad)
- 2. Source Pad(源 Pad)
 
- 1.3 Pad 的模式
 
- 二、Pad Templates
- 2.1 Pad Templates的重要性
- 2.2 Pad Template的组成
- 2.3 查看Pad Templates
- 2.4 Pad Templates在协商过程中的作用
 
- 三、Pad Capabilities
- 3.1 组成部分
- 3.2 定义和使用
- 3.3 Capabilities示例
- 3.4 连接协商(Negotiation)
 
- 四、Basic tutorial 6: Media formats and Pad Capabilities
- 4.1 打印 Pad Templates
- 4.2 打印 Pad Capabilities
- 4.3 不同状态下 Pad Capabilities 的变化
 
- 参考
前言
本章基于官方教程 Basic tutorial 6: Media formats and Pad Capabilities 进行一些说明和补充。本来想对 Basic tutorial 5: GUI toolkit integration 进行讨论的,但我的机器上安装 gtk 后运行程序总是崩溃,因此放弃。
在前面的章节中也有泛泛地提到过 Pad,例如 GStreamer 简明教程(二):基本概念介绍,Element 和 Pipeline和 GStreamer 简明教程(三):动态调整 Pipeline。接下来这一章,我们将对 Pad 这个在 GStreamer 中非常重要的概念进行详细阐述。
一、Pad 基本介绍
1.1 Pad
在 GStreamer 中,Pad 是连接不同元素之间的接口,允许它们相互通信和传递数据的概念。每个 GStreamer 元素都包含一个或多个 Pad,其中的数据流通过 Pad 传递。Pad 可以是输入 Pad,用来接收数据,也可以是输出 Pad,用于发送数据。
Pad 有不同的功能,可以用于传输不同类型的数据,如音频、视频或事件等。Pad 之间的连接是通过链接两个元素的 Pad 来实现的,它们会进行数据流的传递和处理。
在 GStreamer 中,Pad 扮演着非常重要的角色,它们定义了元素之间的连接和协作方式,使得不同元素能够协同工作完成复杂的多媒体处理任务。Pad 的概念使得 GStreamer 具有很强的灵活性和可扩展性,能够支持各种不同的数据流处理需求。
1.2 Pad 类型

 在 GStreamer 中,Pad 的基本类型有两种:Sink Pad 和 Source Pad。这两种类型的 Pad 分别对应数据流的输入和输出端点。详细解释如下:
1. Sink Pad(接收 Pad)
- 作用:用于接收数据。Sink Pad 是元素接收数据的接口。
- 示例:一个解码器元素的 Sink Pad 会接收编码的音频或视频流。
- 常见使用场景: 
  - 解码器接收压缩的媒体流数据。
- 播放器接收解码后的音视频数据。
- 多路解复用器接收多个流的数据。
 
2. Source Pad(源 Pad)
- 作用:用于输出数据。Source Pad 是元素发送数据的接口。
- 示例:一个解码器元素的 Source Pad 会输出解码后的音频或视频流。
- 常见使用场景: 
  - 文件读取器(如 filesrc)从文件中读取数据并通过 Source Pad 输出。
- 编码器将原始音视频数据编码后通过 Source Pad 输出。
- 多路复用器将多个流的数据组合后输出。
 
- 文件读取器(如 
1.3 Pad 的模式
- 固定 Pad(Static Pad):在元素创建时就已经存在,并且它们的生命周期与元素同步。这些 Pad 静态地附着在元素上。
- 请求 Pad(Request Pad):这些 Pad 是动态创建的,只有在外部请求时才会生成。这种模式特别适用于需要动态添加或删除流的场景,如多路复用器或解复用器元素。
使用 gst-inspect 工具查看元素信息,通过 Pad Templates 中的信息判断 Pad 的模式,例如,以下是一个假设的元素输出的一部分:
Pad Templates:
  SRC template: 'src'
    Availability: Always
    Capabilities:
      video/x-raw
    
  SINK template: 'sink_%u'
    Availability: Sometimes
    Capabilities:
      video/x-raw
-  Static Pad: 
 例如上面示例中的SRC template,其Availability为Always,表示这是一个 Static Pad。
-  Request Pad: 
 例如示例中的SINK template,其Availability为Sometimes,表示这是一个 Request Pad(在特定需求时才会生成)。
这是一个具体例子,假设查看 audiotestsrc 元素的信息:
gst-inspect-1.0 audiotestsrc
部分输出可能类似如下:
Pad Templates:
  SRC template: 'src'
    Availability: Always
    Capabilities:
      audio/x-raw
         format: S16LE
           rate: [ 1, 2147483647 ]
       channels: [ 1, 2147483647 ]
       ...
在这个例子中,src 是一个static pad,因为其 Availability 为 Always。
二、Pad Templates
在GStreamer中,Pad(插口)是元素之间进行数据流动的接口,而Pad Template(插口模板)则是对这些接口进行预定义的蓝图。Pad Templates在GStreamer的流媒体处理中扮演着至关重要的角色,是描述元素间连接能力和数据流类型的基础。它们为元素间进行高效的连接协商和能力匹配提供了基础。
Pad Templates通过定义一个Pad可能具备的所有特性和能力(Capabilities),即其能够处理的数据格式和媒体类型。GStreamer使用Pad Templates在元素连接之前进行参数匹配,从而快速确定是否具备兼容性。
2.1 Pad Templates的重要性
-  描述性: 
 Pad Templates详细描述了Pad可能具备的所有能力,包括数据类型、格式、宽度、高度、采样率等信息。这些描述性信息对于流媒体处理中的连接协商是至关重要的。
-  效率提升: 
 在构建元素时,通过Pad Templates可以尽早判断元素之间的兼容性。若两个元素的Pad Template在能力上没有公共交集,则无需尝试进一步的连接操作。这大大提高了整个管道构建和数据流处理的效率。
-  动态Pad创建: 
 对于像多路复用器或解复用器这样的元素,可能需要根据实际情况动态创建Pad。Pad Templates为这些动态创建的Pad提供了标准,确保新创建的Pad符合预期且具备预定义的能力。
2.2 Pad Template的组成
每个Pad Template由以下部分组成:
-  Pad名称(Name Template): 
 描述Pad的名称模式,支持通配符。例如,sink_%u表示一个动态创建的汇Pad,其名称后缀为数字。
-  Pad可用性(Pad Availability): - GST_PAD_ALWAYS:Pad总是可用的,即Static Pad。
- GST_PAD_SOMETIMES:Pad按需创建,即Request Pad。
- GST_PAD_REQUEST:通过显式请求创建的Pad,即Request Pad。
 
-  Pad方向(Pad Direction): - GST_PAD_SRC:源Pad,用于输出数据。
- GST_PAD_SINK:汇Pad,用于输入数据。
 
-  Capabilities(能力): 
 描述Pad能够处理的数据格式和属性。这可能包括诸如媒体类型(音频、视频)、格式(如audio/x-raw)、编码类型(如H.264)、分辨率、帧率、比特率等详细信息。
2.3 查看Pad Templates
通过GStreamer提供的工具gst-inspect-1.0命令,可以查看某个元素的Pad Templates。例如:
gst-inspect-1.0 videotestsrc
示例输出:
Pad Templates:
  SRC template: 'src'
    Availability: Always
    Capabilities:
      video/x-raw
         format: RGB
         width: [ 1, 2147483647 ]
         height: [ 1, 2147483647 ]
2.4 Pad Templates在协商过程中的作用
Pad Templates是连接协商过程的第一步。元素在建立连接之前,会通过它们的Pad Templates进行初步匹配。如果两个Pad的模板在定义的能力上存在交集,则进行下一步的协商。实际建立连接后,两个Pad的实际能力可能根据协商结果进一步细化,直到最终确定。
三、Pad Capabilities
在GStreamer中,Pads(插口)是元素间数据流动的接口,而Pad Capabilities(插口能力)是这些接口所能处理的数据类型和属性的详细描述。Pad Capabilities起到定义和描述数据格式的关键作用,为元素间的连接协商奠定基础。
Pad Capabilities是一个结构化的数据描述,它定义了一个Pad能够接受和输出的数据格式、媒体类型及其可能的属性范围。这些能力定义在创建Pad Templates(插口模板)时就已明确,用于元素之间的互操作性和连接匹配。
3.1 组成部分
Pad Capabilities由多个字段组成,主要包括以下内容:
-  媒体类型(Media Type): 
 描述数据的基本类型,例如音频(audio)、视频(video)、图片(image)等。每种媒体类型还有相应的次级类型,例如audio/x-raw表示原始音频数据。
-  格式(Format): 
 指定具体的数据格式,例如音频的位深度、编码格式,视频的像素格式等。
-  属性(Properties): 
 用于进一步细化媒体数据的描述,包括但不限于以下部分:- 音频属性: 
    - 比特率(bitrate)
- 采样率(sample rate)
- 声道数(channels)
 
- 视频属性: 
    - 分辨率(resolution):宽度(width)和高度(height)
- 帧率(framerate)
- 色彩格式(color format)
 
 
- 音频属性: 
    
-  范围和集合(Ranges and Sets): 
 Capabilities中的一些属性可以是范围或集合,以表示该能力的变化范围或多个可能的值。例如:- 范围(Range):[ 1, 2147483647 ]表示从1到2147483647之间的所有值均有效。
- 集合(Set):{ I420, NV12, NV21 }表示可以是I420、NV12或NV21中的任意一种。
 
- 范围(Range):
3.2 定义和使用
Capabilities通常在Pad Template中定义,用来描述一个Pad可能的全部能力。GStreamer使用这些定义在元素连接前进行初步匹配。如果两个Pad的模板在能力上没有公共交集,那么进一步连接会被跳过,从而提高处理效率。
3.3 Capabilities示例
以下是一些Pad Capabilities的示例:
-  音频Capabilties: audio/x-raw format: S16LE rate: [ 1, 2147483647 ] channels: [ 1, 2 ]- 媒体类型:audio/x-raw,表示原始音频数据。
- 格式:S16LE,16位有符号小端格式。
- 采样率:rate: [ 1, 2147483647 ],从1到2147483647的范围。
- 声道数:channels: [ 1, 2 ],表示1到2个声道。
 
- 媒体类型:
-  视频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,表示原始视频数据。
- 分辨率:width: [ 1, 2147483647 ]和height: [ 1, 2147483647 ],表示支持从1到2147483647范围的宽度和高度。
- 帧率:framerate: [ 0/1, 2147483647/1 ],表示支持从0/1到2147483647/1之间的帧率。
- 格式:format: { I420, NV12, NV21, ... },表示可以是I420、NV12、NV21等多种图像格式。
 
- 媒体类型:
3.4 连接协商(Negotiation)
在管道构建过程中,Pad Capabilities是连接协商的关键元素。元素通过各自的Pad Template中预定义的Capabilities进行匹配。如果两个元素的Pad在其Capabilities上具有公共交集,则可以建立连接并进一步协商实际的数据传输格式。
协商过程通常包括以下步骤:
-  初步匹配(Initial Match): 
 元素根据Pad Template的Capabilities进行初步匹配。如果找不到公共交集,则连接失败。
-  详细协商(Detailed Negotiation): 
 一旦初步匹配成功,元素进一步协商具体的格式、帧率、分辨率等详细参数,直到达成一致或协商失败。
-  最终确定(Final Fixation): 
 确定最终的传输格式和参数后,Pad的Capabilities被固定,后续数据流按照协商结果进行传输。
四、Basic tutorial 6: Media formats and Pad Capabilities
接下来对 Basic tutorial 6: Media formats and Pad Capabilities 代码部分进行说明,代码太长就不贴了。这部分代码想说明几个内容:
- 如何获取元素的 Pad Templates 信息
- 如何获取元素的 Pad Capabilities 信息
- 不同状态下元素的 Pad Capabilities 的切换
4.1 打印 Pad Templates
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");
  }
}
这段代码是一个 GStreamer 相关的函数,用于打印一个 GstElementFactory(元素工厂)的 pad 模板信息。以下是代码的详细解释:
-  函数接受一个 GstElementFactory 指针作为参数。 
-  首先打印元素工厂的长名称。 
-  检查元素是否有 pad 模板,如果没有,打印 “none” 并返回。 
-  获取元素工厂的静态 pad 模板列表。 
-  遍历 pad 模板列表,对每个模板执行以下操作: - 根据 pad 的方向(SRC、SINK 或未知)打印相应的信息。
- 打印 pad 的可用性(Always、Sometimes、On request 或未知)。
- 如果 pad 模板有静态能力(caps),则打印能力信息。
 
-  打印能力信息时,使用 print_caps函数(未在代码中给出)来格式化输出。
输入如下,整体和 gst-inspect 输出类似
Pad Templates for Audio test source:
  SRC template: 'src'
    Availability: Always
    Capabilities:
      audio/x-raw
                 format: { (string)S16LE, (string)S16BE, (string)U16LE, (string)U16BE, (string)S24_32LE, (string)S24_32BE, (string)U24_32LE, (string)U24_32BE, (string)S32LE, (string)S32BE, (string)U32LE, (string)U32BE, (string)S24LE, (string)S24BE, (string)U24LE, (string)U24BE, (string)S20LE, (string)S20BE, (string)U20LE, (string)U20BE, (string)S18LE, (string)S18BE, (string)U18LE, (string)U18BE, (string)F32LE, (string)F32BE, (string)F64LE, (string)F64BE, (string)S8, (string)U8 }
                 layout: { (string)interleaved, (string)non-interleaved }
                   rate: [ 1, 2147483647 ]
               channels: [ 1, 2147483647 ]
Pad Templates for Auto audio sink:
  SINK template: 'sink'
    Availability: Always
    Capabilities:
      ANY
4.2 打印 Pad Capabilities
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);
}
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);
  }
}
上面三个函数用于打印 GStreamer 元素 pad 的能力(capabilities)信息。让我逐一解释:
-  print_pad_capabilities函数:- 接受一个 GstElement 和 pad 名称作为参数。
- 获取指定的 pad。
- 尝试获取当前协商好的 caps,如果没有,则查询可接受的 caps。
- 调用 print_caps函数打印 caps 信息。
- 最后释放资源。
 
-  print_field函数:- 这是一个回调函数,用于打印单个字段的信息。
- 将字段值序列化为字符串并打印。
- 返回 TRUE 以继续遍历。
 
-  print_caps函数:- 打印 GstCaps 的详细信息。
- 如果 caps 是 ANY 或 EMPTY,直接打印对应信息。
- 否则,遍历 caps 中的每个结构(structure)。
- 对每个结构,打印其名称,然后使用 print_field函数打印每个字段的详细信息。
 
这些函数共同工作来提供 GStreamer 元素 pad 的详细能力信息:
- print_pad_capabilities获取特定 pad 的 caps。
- print_caps负责整体 caps 的打印逻辑。
- print_field处理单个字段的打印。
4.3 不同状态下 Pad Capabilities 的变化
示例代码中,分别在不同转态下打印了 autoaudiosink 元素的 pad caps 变换,如下:
In NULL state:
Caps for the sink pad:
      ANY
Pipeline state changed from NULL to READY:
Caps for the sink pad:
      audio/x-raw
                 format: F32LE
                 layout: interleaved
                   rate: 48000
               channels: 2
           channel-mask: 0x0000000000000003
      audio/x-raw
                 format: { (string)F64LE, (string)F64BE, (string)F32LE, (string)F32BE, (string)S32LE, (string)S32BE, (string)U32LE, (string)U32BE, (string)S24_32LE, (string)S24_32BE, (string)U24_32LE, (string)U24_32BE, (string)S24LE, (string)S24BE, (string)U24LE, (string)U24BE, (string)S20LE, (string)S20BE, (string)U20LE, (string)U20BE, (string)S18LE, (string)S18BE, (string)U18LE, (string)U18BE, (string)S16LE, (string)S16BE, (string)U16LE, (string)U16BE, (string)S8, (string)U8 }
                 layout: interleaved
                   rate: [ 1, 2147483647 ]
               channels: 2
           channel-mask: 0x0000000000000003
      audio/x-raw
                 format: { (string)F64LE, (string)F64BE, (string)F32LE, (string)F32BE, (string)S32LE, (string)S32BE, (string)U32LE, (string)U32BE, (string)S24_32LE, (string)S24_32BE, (string)U24_32LE, (string)U24_32BE, (string)S24LE, (string)S24BE, (string)U24LE, (string)U24BE, (string)S20LE, (string)S20BE, (string)U20LE, (string)U20BE, (string)S18LE, (string)S18BE, (string)U18LE, (string)U18BE, (string)S16LE, (string)S16BE, (string)U16LE, (string)U16BE, (string)S8, (string)U8 }
                 layout: interleaved
                   rate: [ 1, 2147483647 ]
               channels: 1
Pipeline state changed from READY to PAUSED:
Caps for the sink pad:
      audio/x-raw
                 format: F32LE
                 layout: interleaved
                   rate: 48000
               channels: 2
           channel-mask: 0x0000000000000003
Pipeline state changed from PAUSED to PLAYING:
Caps for the sink pad:
      audio/x-raw
                 format: F32LE
                 layout: interleaved
                   rate: 48000
               channels: 2
           channel-mask: 0x0000000000000003
这个输出展示了 autoaudiosink 元素在不同状态下 sink pad 的能力(capabilities)变化。让我们逐一解释:
-  NULL 状态: - Caps 显示为 ANY,这意味着在 NULL 状态下,元素还没有进行任何初始化或配置。它可以接受任何类型的音频输入。
 
-  READY 状态: - 在这个状态下,autoaudiosink 已经初始化,但还没有分配资源或开始处理数据。
- 显示了三种不同的 caps 配置:
 a. 第一个是一个具体的配置,可能是基于系统默认音频设置。
 b. 第二个和第三个是更广泛的配置,显示了元素可以支持的各种音频格式、采样率和通道数。
- 这表明 autoaudiosink 在 READY 状态下已经查询了系统音频capabilities,但还没有固定到特定的配置。
 
-  PAUSED 状态: - Caps 变得更加具体,固定为一种特定的格式(F32LE,48000Hz,2通道)。
- 这表明在 PAUSED 状态下,autoaudiosink 已经与上游元素协商并选择了一个特定的音频格式。
 
-  PLAYING 状态: - Caps 保持与 PAUSED 状态相同。
- 这表明 PLAYING 状态没有引起进一步的 caps 变化,元素已经准备好以协商好的格式处理音频数据。
 
总结:
- NULL 到 READY:元素初始化并收集可能的音频配置。
- READY 到 PAUSED:元素与管道中的其他元素协商,选择特定的音频格式。
- PAUSED 到 PLAYING:保持协商好的格式,开始处理音频数据。
这个过程展示了 GStreamer 元素如何逐步从一个通用状态转变为特定配置,以适应整个管道的需求。它也说明了为什么在构建 GStreamer 管道时,将元素推进到 PAUSED 状态对于正确配置很重要。
参考
- Basic tutorial 6: Media formats and Pad Capabilities



















