GStreamer 简明教程(五):Pad 相关概念介绍,Pad Capabilities/Templates

系列文章目录



前言

本章基于官方教程 Basic tutorial 6: Media formats and Pad Capabilities 进行一些说明和补充。本来想对 Basic tutorial 5: GUI toolkit integration 进行讨论的,但我的机器上安装 gtk 后运行程序总是崩溃,因此放弃。

在前面的章节中也有泛泛地提到过 Pad,例如 GStreamer 简明教程(二):基本概念介绍,Element 和 PipelineGStreamer 简明教程(三):动态调整 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,其 AvailabilityAlways,表示这是一个 Static Pad。

  • Request Pad:
    例如示例中的 SINK template,其 AvailabilitySometimes,表示这是一个 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,因为其 AvailabilityAlways

二、Pad Templates

在GStreamer中,Pad(插口)是元素之间进行数据流动的接口,而Pad Template(插口模板)则是对这些接口进行预定义的蓝图。Pad Templates在GStreamer的流媒体处理中扮演着至关重要的角色,是描述元素间连接能力和数据流类型的基础。它们为元素间进行高效的连接协商和能力匹配提供了基础。

Pad Templates通过定义一个Pad可能具备的所有特性和能力(Capabilities),即其能够处理的数据格式和媒体类型。GStreamer使用Pad Templates在元素连接之前进行参数匹配,从而快速确定是否具备兼容性。

2.1 Pad Templates的重要性

  1. 描述性
    Pad Templates详细描述了Pad可能具备的所有能力,包括数据类型、格式、宽度、高度、采样率等信息。这些描述性信息对于流媒体处理中的连接协商是至关重要的。

  2. 效率提升
    在构建元素时,通过Pad Templates可以尽早判断元素之间的兼容性。若两个元素的Pad Template在能力上没有公共交集,则无需尝试进一步的连接操作。这大大提高了整个管道构建和数据流处理的效率。

  3. 动态Pad创建
    对于像多路复用器或解复用器这样的元素,可能需要根据实际情况动态创建Pad。Pad Templates为这些动态创建的Pad提供了标准,确保新创建的Pad符合预期且具备预定义的能力。

2.2 Pad Template的组成

每个Pad Template由以下部分组成:

  1. Pad名称(Name Template)
    描述Pad的名称模式,支持通配符。例如,sink_%u表示一个动态创建的汇Pad,其名称后缀为数字。

  2. Pad可用性(Pad Availability)

    • GST_PAD_ALWAYS:Pad总是可用的,即Static Pad。
    • GST_PAD_SOMETIMES:Pad按需创建,即Request Pad。
    • GST_PAD_REQUEST:通过显式请求创建的Pad,即Request Pad。
  3. Pad方向(Pad Direction)

    • GST_PAD_SRC:源Pad,用于输出数据。
    • GST_PAD_SINK:汇Pad,用于输入数据。
  4. 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由多个字段组成,主要包括以下内容:

  1. 媒体类型(Media Type)
    描述数据的基本类型,例如音频(audio)、视频(video)、图片(image)等。每种媒体类型还有相应的次级类型,例如audio/x-raw表示原始音频数据。

  2. 格式(Format)
    指定具体的数据格式,例如音频的位深度、编码格式,视频的像素格式等。

  3. 属性(Properties)
    用于进一步细化媒体数据的描述,包括但不限于以下部分:

    • 音频属性
      • 比特率(bitrate)
      • 采样率(sample rate)
      • 声道数(channels)
    • 视频属性
      • 分辨率(resolution):宽度(width)和高度(height)
      • 帧率(framerate)
      • 色彩格式(color format)
  4. 范围和集合(Ranges and Sets)
    Capabilities中的一些属性可以是范围或集合,以表示该能力的变化范围或多个可能的值。例如:

    • 范围(Range):[ 1, 2147483647 ]表示从1到2147483647之间的所有值均有效。
    • 集合(Set):{ I420, NV12, NV21 }表示可以是I420、NV12或NV21中的任意一种。

3.2 定义和使用

Capabilities通常在Pad Template中定义,用来描述一个Pad可能的全部能力。GStreamer使用这些定义在元素连接前进行初步匹配。如果两个Pad的模板在能力上没有公共交集,那么进一步连接会被跳过,从而提高处理效率。

3.3 Capabilities示例

以下是一些Pad Capabilities的示例:

  1. 音频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个声道。
  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上具有公共交集,则可以建立连接并进一步协商实际的数据传输格式。

协商过程通常包括以下步骤:

  1. 初步匹配(Initial Match)
    元素根据Pad Template的Capabilities进行初步匹配。如果找不到公共交集,则连接失败。

  2. 详细协商(Detailed Negotiation)
    一旦初步匹配成功,元素进一步协商具体的格式、帧率、分辨率等详细参数,直到达成一致或协商失败。

  3. 最终确定(Final Fixation)
    确定最终的传输格式和参数后,Pad的Capabilities被固定,后续数据流按照协商结果进行传输。

四、Basic tutorial 6: Media formats and Pad Capabilities

接下来对 Basic tutorial 6: Media formats and Pad Capabilities 代码部分进行说明,代码太长就不贴了。这部分代码想说明几个内容:

  1. 如何获取元素的 Pad Templates 信息
  2. 如何获取元素的 Pad Capabilities 信息
  3. 不同状态下元素的 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 模板信息。以下是代码的详细解释:

  1. 函数接受一个 GstElementFactory 指针作为参数。

  2. 首先打印元素工厂的长名称。

  3. 检查元素是否有 pad 模板,如果没有,打印 “none” 并返回。

  4. 获取元素工厂的静态 pad 模板列表。

  5. 遍历 pad 模板列表,对每个模板执行以下操作:

    • 根据 pad 的方向(SRC、SINK 或未知)打印相应的信息。
    • 打印 pad 的可用性(Always、Sometimes、On request 或未知)。
    • 如果 pad 模板有静态能力(caps),则打印能力信息。
  6. 打印能力信息时,使用 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)信息。让我逐一解释:

  1. print_pad_capabilities 函数:

    • 接受一个 GstElement 和 pad 名称作为参数。
    • 获取指定的 pad。
    • 尝试获取当前协商好的 caps,如果没有,则查询可接受的 caps。
    • 调用 print_caps 函数打印 caps 信息。
    • 最后释放资源。
  2. print_field 函数:

    • 这是一个回调函数,用于打印单个字段的信息。
    • 将字段值序列化为字符串并打印。
    • 返回 TRUE 以继续遍历。
  3. 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)变化。让我们逐一解释:

  1. NULL 状态:

    • Caps 显示为 ANY,这意味着在 NULL 状态下,元素还没有进行任何初始化或配置。它可以接受任何类型的音频输入。
  2. READY 状态:

    • 在这个状态下,autoaudiosink 已经初始化,但还没有分配资源或开始处理数据。
    • 显示了三种不同的 caps 配置:
      a. 第一个是一个具体的配置,可能是基于系统默认音频设置。
      b. 第二个和第三个是更广泛的配置,显示了元素可以支持的各种音频格式、采样率和通道数。
    • 这表明 autoaudiosink 在 READY 状态下已经查询了系统音频capabilities,但还没有固定到特定的配置。
  3. PAUSED 状态:

    • Caps 变得更加具体,固定为一种特定的格式(F32LE,48000Hz,2通道)。
    • 这表明在 PAUSED 状态下,autoaudiosink 已经与上游元素协商并选择了一个特定的音频格式。
  4. PLAYING 状态:

    • Caps 保持与 PAUSED 状态相同。
    • 这表明 PLAYING 状态没有引起进一步的 caps 变化,元素已经准备好以协商好的格式处理音频数据。

总结:

  • NULL 到 READY:元素初始化并收集可能的音频配置。
  • READY 到 PAUSED:元素与管道中的其他元素协商,选择特定的音频格式。
  • PAUSED 到 PLAYING:保持协商好的格式,开始处理音频数据。

这个过程展示了 GStreamer 元素如何逐步从一个通用状态转变为特定配置,以适应整个管道的需求。它也说明了为什么在构建 GStreamer 管道时,将元素推进到 PAUSED 状态对于正确配置很重要。

参考

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值