Gstreamer插件教程3.1—高级概念(Advanced Concepts):需求pads和间或pads(Request and Sometimes pads)

来源:互联网 发布:淘宝导航栏是多少尺寸 编辑:程序博客网 时间:2024/09/21 09:20

英文原文:https://gstreamer.freedesktop.org/documentation/plugin-development/advanced/request.html

到目前为止,你应该能够创建可以接收和发送数据的filter element。这是Gstreamer所支持的简单模型。但Gstreamer还可以做更多的事!在这接下来的章节,我们将讨论多个高级主题,如时间安排、特殊的pad类型、时钟、事件、接口和标签等更多。这些主题使得应用中使用Gstreamer更简单。

直到目前为止,我们只处理了那些一直存在的pads,然而,还有许多pads是只有在某些时候或只有应用程序要求时才被创建的。第一个被称为sometimes pad,第二个被称为request pad。pad的可用性(即always, sometimes或request)是可以在pad的template中看出来的。这章将讨论这两种pad在何时有用,如何创建它们及它们什么时候被销毁。

Sometimes pads

一个 “sometimes" pad是一个在某些特定情况下,而不是任何时候被创建的pad。这主要依赖于流的内容:分流器一般会解析流的头信息,决定什么样的基础(视频、音频及标题等)流会被嵌入到系统流中,并且将会为这些基础流分别创建一个sometimes pad。正如它能够自己选择,对于每一个element实例,它也可以创建不止一个实例。唯一的限制是,每一个创建的pad都必须有其独一无二的名称。sometimes pad在流数据被销毁时,它也会被销毁(如PAUSED状态转变到READY状态时)。你不应该在流末尾销毁pad,因为可能有人重新激活pipeline,并返回至流末尾之前的某点。当到达流末尾时,流至少在流数据被销毁之前保持有效。任何情况下,element都是这个pad的拥有者。

下面的示例代码将解析一个文本文件,其中文件中的第一行是一个数字(n),后面的所有行都将以数字(0到n-1)开头,此数字表示source pad的数量,通过source pad就能够发送数据。

30: foo1: bar0: boo2: bye
用于解析此文件及创建动态的"sometimes" pads的代码是类似下面这样的:

typedef struct _GstMyFilter {[..]  gboolean firstrun;  GList *srcpadlist;} GstMyFilter;static GstStaticPadTemplate src_factory =GST_STATIC_PAD_TEMPLATE (  "src_%u",  GST_PAD_SRC,  GST_PAD_SOMETIMES,  GST_STATIC_CAPS ("ANY"));static voidgst_my_filter_class_init (GstMyFilterClass *klass){  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);[..]  gst_element_class_add_pad_template (element_class,    gst_static_pad_template_get (&src_factory));[..]}static voidgst_my_filter_init (GstMyFilter *filter){[..]  filter->firstrun = TRUE;  filter->srcpadlist = NULL;}/* * Get one line of data - without newline. */static GstBuffer *gst_my_filter_getline (GstMyFilter *filter){  guint8 *data;  gint n, num;  /* max. line length is 512 characters - for safety */  for (n = 0; n < 512; n++) {    num = gst_bytestream_peek_bytes (filter->bs, &data, n + 1);    if (num != n + 1)      return NULL;    /* newline? */    if (data[n] == '\n') {      GstBuffer *buf = gst_buffer_new_allocate (NULL, n + 1, NULL);      gst_bytestream_peek_bytes (filter->bs, &data, n);      gst_buffer_fill (buf, 0, data, n);      gst_buffer_memset (buf, n, '\0', 1);      gst_bytestream_flush_fast (filter->bs, n + 1);      return buf;    }  }}static voidgst_my_filter_loopfunc (GstElement *element){  GstMyFilter *filter = GST_MY_FILTER (element);  GstBuffer *buf;  GstPad *pad;  GstMapInfo map;  gint num, n;  /* parse header */  if (filter->firstrun) {    gchar *padname;    guint8 id;    if (!(buf = gst_my_filter_getline (filter))) {      gst_element_error (element, STREAM, READ, (NULL),             ("Stream contains no header"));      return;    }    gst_buffer_extract (buf, 0, &id, 1);    num = atoi (id);    gst_buffer_unref (buf);    /* for each of the streams, create a pad */    for (n = 0; n < num; n++) {      padname = g_strdup_printf ("src_%u", n);      pad = gst_pad_new_from_static_template (src_factory, padname);      g_free (padname);      /* here, you would set _event () and _query () functions */      /* need to activate the pad before adding */      gst_pad_set_active (pad, TRUE);      gst_element_add_pad (element, pad);      filter->srcpadlist = g_list_append (filter->srcpadlist, pad);    }  }  /* and now, simply parse each line and push over */  if (!(buf = gst_my_filter_getline (filter))) {    GstEvent *event = gst_event_new (GST_EVENT_EOS);    GList *padlist;    for (padlist = srcpadlist;         padlist != NULL; padlist = g_list_next (padlist)) {      pad = GST_PAD (padlist->data);      gst_pad_push_event (pad, gst_event_ref (event));    }    gst_event_unref (event);    /* pause the task here */    return;  }  /* parse stream number and go beyond the ':' in the data */  gst_buffer_map (buf, &map, GST_MAP_READ);  num = atoi (map.data[0]);  if (num >= 0 && num < g_list_length (filter->srcpadlist)) {    pad = GST_PAD (g_list_nth_data (filter->srcpadlist, num);    /* magic buffer parsing foo */    for (n = 0; map.data[n] != ':' &&                map.data[n] != '\0'; n++) ;    if (map.data[n] != '\0') {      GstBuffer *sub;      /* create region copy that starts right past the space. The reason       * that we don't just forward the data pointer is because the       * pointer is no longer the start of an allocated block of memory,       * but just a pointer to a position somewhere in the middle of it.       * That cannot be freed upon disposal, so we'd either crash or have       * a memleak. Creating a region copy is a simple way to solve that. */      sub = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,          n + 1, map.size - n - 1);      gst_pad_push (pad, sub);    }  }  gst_buffer_unmap (buf, &map);  gst_buffer_unref (buf);}
注意我们到处都使用了许多检查以确保文件中的内容是有效的。这有两个目的:第一,文件可能是错误的,若是如此,会导致程序崩溃。第二且最重要的原因,在一些极端的情况下,此文件可能被恶意地使用,以导致插件中存在未知行为,而这可能导致安全问题。我们应总是假设此文件可能导致一些坏的事情的发生。

request pads

"Request" pads和sometimes pads类似,除了request pad是应element之外的(而不是在element内)需求时被创建的。此概念经常被用在整流器上,此时,整流器会应需求生成一个sink pad。整流器会将每一个基础流(视频、音频及标题等)放至要输出的系统流中。request pads也可以被用在拥有多个输入或输出pad的element上,例如tee(多输出)和input-selector(多输入)element。

为了实现request pads,你需要提供一个包含GST_PAD_REQUEST的pad template并在GstElement中实现request_new_pad虚函数。最后为了清理,你还需要实现release_pad虚函数。

static GstPad * gst_my_filter_request_new_pad   (GstElement     *element,                         GstPadTemplate *templ,                                                 const gchar    *name,                                                 const GstCaps  *caps);static void gst_my_filter_release_pad (GstElement *element,                                       GstPad *pad);static GstStaticPadTemplate sink_factory =GST_STATIC_PAD_TEMPLATE (  "sink_%u",  GST_PAD_SINK,  GST_PAD_REQUEST,  GST_STATIC_CAPS ("ANY"));static voidgst_my_filter_class_init (GstMyFilterClass *klass){  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);[..]  gst_element_class_add_pad_template (klass,    gst_static_pad_template_get (&sink_factory));[..]  element_class->request_new_pad = gst_my_filter_request_new_pad;  element_class->release_pad = gst_my_filter_release_pad;}static GstPad *gst_my_filter_request_new_pad (GstElement     *element,                   GstPadTemplate *templ,                   const gchar    *name,                   const GstCaps  *caps){  GstPad *pad;  GstMyFilterInputContext *context;  context = g_new0 (GstMyFilterInputContext, 1);  pad = gst_pad_new_from_template (templ, name);  gst_pad_set_element_private (pad, context);  /* normally, you would set _chain () and _event () functions here */  gst_element_add_pad (element, pad);  return pad;}static voidgst_my_filter_release_pad (GstElement *element,                           GstPad *pad){  GstMyFilterInputContext *context;  context = gst_pad_get_element_private (pad);  g_free (context);  gst_element_remove_pad (element, pad);}

0 0
原创粉丝点击