gstreamer教程(8)——構建應用之Pad和Pad的能力集

风吹大风车發表於2024-08-29

Pad和能力集:

  正如我們在 Elements 中看到的那樣,pad 是 Element 與外部世界的介面。資料從一個 Element 的 source pad 流向另一個 Element 的 sink pad。元素可以處理的媒體型別都是透過pad的能力集公佈的。我們將在本章後面詳細討論功能(參見 pad 的功能)。

Pad:

  pad 型別有兩個屬性:方向和可用性。正如我們之前提到的,GStreamer 定義了兩個 pad 方向:source pads 和 sink pads。此術語是從 元素內部的檢視定義的:元素在其 sink pad 上接收資料,並在其 source pad 上生成資料。從原理圖上講,sink pads 繪製在 element 的左側,而 source pads 繪製在 element 的右側。在此類圖形中,資料從左向右流動。

  pad 的方向相比 pad 的可用性 要簡單的多。pad 可以一下三種可用性型別:always(總是)、sometimes(有時)和on-request(請求時)。這三種型別的含義正如它所說:always意思是始終存在 pad,sometimes意思是 pad 僅在某些情況下存在(並且可以隨機消失),on-request意思是 pad 只有在明確的請求時才會存在。

動態Pad:

  在建立元素時,某些元素可能沒有pad。例如,這可能發生在 Ogg 解複用器元素中。當該元素在 Ogg 流中檢測到此類流時,該元素將讀取 Ogg 流併為每個包含的基本流 (vorbis:音訊壓縮技術, theora:影片壓縮技術) 動態建立 pad。同樣,當流結束時,它將刪除 pad。這個原則對於 demuxer 元素非常有用。

  執行 gst-inspect-1.0 oggdemux 將顯示該元素只有一個 pad:一個名為 'sink' 的 sink pad。其他 pad 處於 “休眠” 狀態。你可以在 pad 模板中看到這一點,因為有一個 “Availability: Sometimes ”屬性。根據您播放的 Ogg 檔案型別建立 pad。我們將看到,這在當你要建立動態管道時非常重要。你可以將 signal 處理程式附加到 element 上,以便在 element 從其 “sometimes” pad 模板之一建立新 pad 時通知你。以下程式碼是有關如何執行此操作的示例:

  basic-example-11.c

#include <stdio.h>
#include <gst/gst.h>

static void cb_new_pad (GstElement *element, GstPad *pad, gpointer data)
{
    gchar *name;
    name = gst_pad_get_name (pad);
    g_print ("A new pad %s was created\n", name);
    g_free (name);

    /* here, you would setup a new pad link for the newly created pad */
    [..]
}

int main (int argc, char *argv[])
{
    GstElement *pipeline, *source, *demux;
    GMainLoop *loop;

    /* init */
    gst_init (&argc, &argv);

    /* create elements */
    pipeline = gst_pipeline_new ("my_pipeline");
    source = gst_element_factory_make ("filesrc", "source");
    g_object_set (source, "location", argv[1], NULL);
    demux = gst_element_factory_make ("oggdemux", "demuxer");

    /* you would normally check that the elements were created properly */

    /* put together a pipeline */
    gst_bin_add_many (GST_BIN (pipeline), source, demux, NULL);
    gst_element_link_pads (source, "src", demux, "sink");

    /* listen for newly created pads */
    g_signal_connect (demux, "pad-added", G_CALLBACK (cb_new_pad), NULL);

    /* start the pipeline */
    gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
    loop = g_main_loop_new (NULL, FALSE);
    g_main_loop_run (loop);

    [..]
}

  該示例並不是完整程式碼,不能執行,主要用於理解監聽pad-added事件和處理該事件的回撥函式。

  從 “pad-added” 回撥中將元素新增到 pipeline 的情況並不少見。如果新增到了pipeline,請不要忘記使用 gst_element_set_state()gst_element_sync_state_with_parent() 把新新增元素的狀態設定為 pipeline 管道的目標狀態。

請求Pad:

  元素當然也可以有請求 pad。這些 pad 不是自動建立的,而只是按需建立。這對於多路複用器、聚合器和 tee 元素是非常有用。聚合器是將多個輸入流的內容合併到一個輸出流中的元素。Tee 元素則相反:它們是具有一個輸入流的元素,並將此流複製到其每個輸出的 pad 上,這些輸出 pad 就是根據請求建立的。每當應用程式需要流的另一個副本時,它只需要從 tee 元素請求新的輸出 pad 即可。

  以下程式碼顯示瞭如何從 “tee” 元素請求新的輸出 pad:

  basic-example-12.c

static void some_function (GstElement * tee)
{
    GstPad *pad;
    gchar *name;

    pad = gst_element_request_pad_simple (tee, "src%d");
    name = gst_pad_get_name (pad);
    g_print ("A new pad %s was created\n", name);
    g_free (name);

    /* here, you would link the pad */

    /* [..] */

    /* and, after doing that, free our reference */
    gst_object_unref (GST_OBJECT (pad));
}

  該方法 gst_element_request_pad_simple() 可用於根據 pad 模板的名稱從element 元素中獲取 pad。也可以請求與另一個 pad 模板相容的 pad。這在你要請求一個相容的 pad 用於將 element 元素連結到多路轉換器 element 元素時會非常有用。該方法 gst_element_get_compatible_pad() 可用於請求相容的 pad,如下例所示。它將從任何輸入源的 Ogg 多路複用器中請求相容的 pad。

static void link_to_multiplexer (GstPad * tolink_pad, GstElement * mux)
{
    GstPad *pad;
    gchar *srcname, *sinkname;

    srcname = gst_pad_get_name (tolink_pad);
    pad = gst_element_get_compatible_pad (mux, tolink_pad, NULL);
    gst_pad_link (tolink_pad, pad);
    sinkname = gst_pad_get_name (pad);
    gst_object_unref (GST_OBJECT (pad));

    g_print ("A new pad %s was created and linked to %s\n", sinkname, srcname);
    g_free (sinkname);
    g_free (srcname);
}

Pad的能力集:

  由於 Pad 在外界如何理解元素方面起著非常重要的作用,因此實現了透過能力集來描述資料可以流經或當下流經的pad的一種機制。在這裡,我們將簡要描述能力集是什麼以及如何使用它們,讓我們足以理解能力集這個概念。要深入瞭解能力集以及 GStreamer 中定義的所有能力集列表,請參閱外掛編寫者指南。

  能力集是附加到 Pad 模板和 Pad的。對於 pad 模板,它將描述可能在從此模板建立的 pad 上流經的媒體型別。對於 pad,對於沒有協商之前,它是可能的 caps 列表(通常是 pad 模板能力集的副本),對於已經協商好的pad,它是當前流經此 pad 的媒體型別。

剖析能力集:

  Pad 的能力集在 GstCaps 物件中描述。在內部, GstCaps 將包含一個或多個 GstStructure ,用於描述一種媒體型別。協商的 pad 將具有僅包含一個結構的功能集。此外,此結構將僅包含固定值。這些約束不適用於未協商的 pad 或 pad 模板。

  例如,下面是 “vorbisdec” 元素功能集,您將透過執行 gst-inspect-1.0 vorbisdec 來獲得。您將看到兩個 Pad:一個 Source Pad 和一個 Sink Pad。這兩個 pad 始終可用,並且都具有附加的功能。sink pad 將接受 vorbis 編碼的音訊資料,媒體型別為 “audio/x-vorbis”。source pad 將用於將原始 (解碼) 音訊樣本傳送到下一個元素,其中包含原始音訊媒體型別 (在本例中為“audio/x-raw”) 。Source Pad 還將包含音訊取樣率和聲道數量的屬性,以及一些您暫時無需擔心的屬性。

/opt/gstreamer# gst-inspect-1.0 vorbisdec
Factory Details:
  Rank                     primary (256)
  Long-name                Vorbis audio decoder
  Klass                    Codec/Decoder/Audio
  Description              decode raw vorbis streams to float audio
  Author                   Benjamin Otte <otte@gnome.org>, Chris Lord <chris@openedhand.com>

Plugin Details:
  Name                     vorbis
  Description              Vorbis plugin library
  Filename                 /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstvorbis.so
  Version                  1.14.5
  License                  LGPL
  Source module            gst-plugins-base
  Source release date      2019-05-29
  Binary package           GStreamer Base Plugins (Ubuntu)
  Origin URL               https://launchpad.net/distros/ubuntu/+source/gst-plugins-base1.0

GObject
 +----GInitiallyUnowned
       +----GstObject
             +----GstElement
                   +----GstAudioDecoder
                         +----GstVorbisDec

Pad Templates:
  SRC template: 'src'
    Availability: Always
    Capabilities:
      audio/x-raw
                 format: F32LE
                   rate: [ 1, 2147483647 ]
               channels: [ 1, 256 ]

  SINK template: 'sink'
    Availability: Always
    Capabilities:
      audio/x-vorbis

Element has no clocking capabilities.
Element has no URI handling capabilities.

Pads:
  SINK: 'sink'
    Pad Template: 'sink'
  SRC: 'src'
    Pad Template: 'src'

Element Properties:
  name                : The name of the object
                        flags: 可讀, 可寫
                        String. Default: "vorbisdec0"
  parent              : The parent of the object
                        flags: 可讀, 可寫
                        Object of type "GstObject"
  min-latency         : Aggregate output data to a minimum of latency time (ns)
                        flags: 可讀, 可寫
                        Integer64. Range: 0 - 9223372036854775807 Default: 0
  tolerance           : Perfect ts while timestamp jitter/imperfection within tolerance (ns)
                        flags: 可讀, 可寫
                        Integer64. Range: 0 - 9223372036854775807 Default: 0
  plc                 : Perform packet loss concealment (if supported)
                        flags: 可讀, 可寫
                        Boolean. Default: false

屬性和值:

  屬性用於描述能力集的額外資訊。屬性由鍵 (字串) 和值組成。這裡是可以使用一些不同的可能的值型別:

  • 基礎型別,這幾乎可以是任何在 Glib 中註冊的 GType。這些屬性指示此屬性的特定非動態值。示例包括:
  1. 整數值 (G_TYPE_INT):屬性具有此確切值。
  2. 布林值 (G_TYPE_BOOLEAN):屬性為 TRUEFALSE
  3. 浮點值 (G_TYPE_FLOAT):屬性具有此確切的浮點值。
  4. 字串值 (G_TYPE_STRING):該屬性包含 UTF-8 字串。
  5. 分數值 (GST_TYPE_FRACTION):包含由整數分子和分母表示的分數。
  • 範圍型別是由 GStreamer 註冊的 GType,用於指示可能的值範圍。它們用於指示允許的音訊取樣率值或支援的影片大小。GStreamer 中定義的兩種型別是:
  1. 整數範圍值 (GST_TYPE_INT_RANGE):該屬性表示可能的整數範圍,具有下限和上限。例如,“vorbisdec” 元素的 rate 屬性可以介於 8000 和 50000 之間。
  2. 浮點範圍值 (GST_TYPE_FLOAT_RANGE):該屬性表示可能的浮點值範圍,具有下限和上限。
  3. 分數範圍值 (GST_TYPE_FRACTION_RANGE):該屬性表示可能的分數值範圍,具有下限和上限。
  • 列表值 (GST_TYPE_LIST):該屬性可以從此列表中給出的基本值列表中獲取任何值。
  1. 示例:表示支援 44100 Hz 取樣率和 48000 Hz 取樣率的上限將使用整數值列表,其中一個值為 44100,一個值為 48000。
  • 陣列值 (GST_TYPE_ARRAY):屬性是值的陣列。陣列中的每個值本身也是一個完整值。陣列中的所有值都應該是相同的 elementary 型別。這意味著陣列可以包含整數、整數列表、整數範圍的任意組合,浮點數或字串也是如此,但不能同時包含 float 和 int。
  1. 示例:對於涉及兩個以上聲道的音訊,需要指定聲道佈局(對於單聲道和雙聲道音訊,除非大寫字母中另有說明,否則聲道佈局是隱式的)。因此,聲道佈局將是一個整數列舉值陣列,其中每個列舉值代表一個揚聲器位置。與GST_TYPE_LIST不同,陣列中的值將作為一個整體進行解釋。

能力集能幹什麼:

  能力集 (簡稱:caps) 描述在兩個 Pad 之間流式傳輸的資料型別,或者一個Pad (模板) 支援的資料型別。這使得它們對於各種目的非常有用:

  • Autoplugging 自適應插拔器:根據其能力集自動連結元素之間的 pad。所有 Autoplugging 自適應插拔器都使用此方法。
  • 能力集檢測:當兩個 pad 連結時,GStreamer 可以驗證兩個 pad 是否使用的是相同的媒體型別。連結兩個 pad 並校驗它們是否相容的過程稱為 “能力集協商”。
  • 後設資料:透過從pad讀取能力集,應用程式可以提供有關流經pad的媒體型別的資訊,即有關當前正在播放的流的資訊。
  • 篩選:應用程式可以使用能力集將可在兩個pad之間流式傳輸的流媒體型別限制為其支援的流媒體型別的特定子集。例如,應用程式可以使用 “filtered caps” 來限定兩個 pad 之間流經的流的屬性為特定的 (固定或非固定) 影片大小。您將在本手冊後面的 Manually adding or removing data from / to a pipeline 中看到一個過濾的示例。你可以透過向pipeline管道插入一個 capsfilter 元素,並設定其 “caps” 屬性來執行 caps 過濾。Caps 過濾器通常放置在 audioconvert、audioresample、videoconvert 或 videoscale 等轉換器元素之後,以強制這些轉換器在流中的某位置將資料轉換為特定的輸出格式。

使用後設資料能力集:

  一個 pad 可以附加一組 (即一個或多個) 能力集。能力集 (GstCaps) 表示為一個或多個 GstStructure的陣列,每個 GstStructure 都是一個欄位陣列,其中每個欄位由欄位名稱字串(例如“width”)和型別化值(例如 G_TYPE_INTGST_TYPE_INT_RANGE)組成。

  -請注意,pad的可能功能(即通常是 gst-inspect 中顯示的焊盤模板的 caps ),焊盤允許的電容(可以與 pad 的模板電容或它們的子集相同,具體取決於對等焊盤的可能電容)和最後協商之間存在明顯差異caps (這些描述流或緩衝區的確切格式,並且只包含一個結構,並且沒有像 ranges 或 lists 這樣的可變位,即它們是固定的 caps)。

  您可以透過查詢一個結構體的單個屬性來獲取一組功能中的屬性值。您可以使用 gst_caps_get_structure () 從 Cap 中獲取結構,使用 gst_caps_get_size ()GstCaps 中獲取結構數。

  當大寫字母僅包含一個結構時稱為簡單大寫字母,當它們僅包含一個結構且沒有可變欄位型別(如範圍或可能值列表)時稱為固定大寫字母。另外兩種特殊型別的 Cap 是 ANY CapEmpty Cap

  以下是如何從一組固定影片大寫字母中提取寬度和高度的示例:

static void read_video_props (GstCaps *caps)
{
    gint width, height;
    const GstStructure *str;

    g_return_if_fail (gst_caps_is_fixed (caps));

    str = gst_caps_get_structure (caps, 0);
    if (!gst_structure_get_int (str, "width", &width) || !gst_structure_get_int (str, "height", &height)) {
        g_print ("No width/height available\n");
        return;
    }

    g_print ("The video size of this set of capabilities is %dx%d\n", width, height);
}

建立篩選功能:

  雖然功能主要在外掛內部用於描述打擊墊的媒體型別,但應用程式程式設計師通常還必須對功能有基本的瞭解,以便與外掛連線,尤其是在使用過濾電容時。當您使用過濾的 Cap 或 Fixation 時,您將允許在兩個打擊墊之間流式傳輸的媒體型別限制為其支援的媒體型別的子集。您可以在管道中使用 capsfilter 元素來執行此操作。為此,您還需要建立自己的 GstCap。最簡單的方法是使用便捷函式 gst_caps_new_simple ()

static gboolean link_elements_with_filter (GstElement *element1, GstElement *element2)
{
    gboolean link_ok;
    GstCaps *caps;

    caps = gst_caps_new_simple ("video/x-raw",
            "format", G_TYPE_STRING, "I420",
            "width", G_TYPE_INT, 384,
            "height", G_TYPE_INT, 288,
            "framerate", GST_TYPE_FRACTION, 25, 1,
            NULL);

    link_ok = gst_element_link_filtered (element1, element2, caps);
    gst_caps_unref (caps);

    if (!link_ok) {
        g_warning ("Failed to link element1 and element2!");
    }

    return link_ok;
}

  這將強制這兩個元素之間的資料流達到特定的影片格式、寬度、高度和幀速率(或者在所涉及的元素的上下文中無法實現,則連結將失敗)。請記住,當你使用 gst_element_link_filtered () 時,它會自動為你建立一個 capsfilter 元素,並將其插入到你想要連線的兩個元素之間的 bin 或管道中(如果你想斷開這些元素,這一點很重要,因為這樣你將不得不斷開兩個元素與 capsfilter 的連線)。

  在某些情況下,您將需要建立一組更復雜的功能來過濾兩個 pad 之間的連結。那麼,這個函式太簡單了,你需要使用 () gst_caps_new_full方法:

static gboolean link_elements_with_filter (GstElement *element1, GstElement *element2)
{
    gboolean link_ok;
    GstCaps *caps;

    caps = gst_caps_new_full (
        gst_structure_new ("video/x-raw",
                "width", G_TYPE_INT, 384,
                "height", G_TYPE_INT, 288,
                "framerate", GST_TYPE_FRACTION, 25, 1,
                NULL),
        gst_structure_new ("video/x-bayer",
                "width", G_TYPE_INT, 384,
                "height", G_TYPE_INT, 288,
                "framerate", GST_TYPE_FRACTION, 25, 1,
                NULL),
        NULL);

    link_ok = gst_element_link_filtered (element1, element2, caps);
    gst_caps_unref (caps);

    if (!link_ok) {
        g_warning ("Failed to link element1 and element2!");
    }

    return link_ok;
}

  有關 GstStructureGstCaps 的完整 API,請參閱 API 參考。

Ghost Pad:

  從沒有重影焊盤的 GstBin 元素的視覺化中可以看到,bin 如何沒有自己的焊盤。這就是 “幽靈墊 ”發揮作用的地方。

gstreamer教程(8)——構建應用之Pad和Pad的能力集

  鬼墊是來自 bin 中某個元素的 pad,也可以直接從 bin 訪問。將其與 UNIX 檔案系統中的符號連結進行比較。在 bin 上使用 ghost pad,bin 也有一個 pad,並且可以透明地用作程式碼其他部分的元素。

gstreamer教程(8)——構建應用之Pad和Pad的能力集

  帶有 ghost pad 的 GstBin 元素的視覺化是 ghost pad 的表示形式。元素 1 的 sink pad 現在也是 bin 的 pad。因為 ghost pad 的外觀和工作方式與任何其他 pads 一樣,所以它們可以新增到任何型別的元素中,而不僅僅是 GstBin,就像普通 pad 一樣。

  使用函式 gst_ghost_pad_new () 建立 ghostpad :

#include <gst/gst.h>

int main (int argc, char *argv[])
{
    GstElement *bin, *sink;
    GstPad *pad;

    /* init */
    gst_init (&argc, &argv);

    /* create element, add to bin */
    sink = gst_element_factory_make ("fakesink", "sink");
    bin = gst_bin_new ("mybin");
    gst_bin_add (GST_BIN (bin), sink);

    /* add ghostpad */
    pad = gst_element_get_static_pad (sink, "sink");
    gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad));
    gst_object_unref (GST_OBJECT (pad));

    [..]
}

  在上面的例子中,bin 現在也有一個 pad:給定元素的名為 “sink” 的 pad。從這裡開始,bin 可以用作 sink 元素的替代品。例如,您可以將另一個元素連結到 bin。

相關文章