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);}
- Gstreamer插件教程3.1—高级概念(Advanced Concepts):需求pads和间或pads(Request and Sometimes pads)
- Gstreamer插件教程2.2—编写一个插件(Writing a Plugin):详解pads(Specifying the pads)
- PADS
- PADS
- Gstreamer插件教程3.2—高级概念(Advanced Concepts):不同的调度模式(Different scheduling modes)
- PADS 拼版教程
- 差分线走法——PADS
- PADS2007_教程之PADS LAYOUT
- PADS Logic图文教程(三):PADS元件类型
- pads问题
- PADS备忘录
- PADS 基础
- PADS 快捷键
- pads规则
- PADS 心得
- pads破解
- 关于PADS的一些概念和实用技巧(一)
- 关于PADS的一些概念和实用技巧(二)
- MySQL数据库之MyISAM与InnoDB的区别
- template.js —一款基于JS的模板引擎
- JAVA开发环境的配置步骤
- linux64位下无法编译c文件的解决方法
- Tomcat闪退
- Gstreamer插件教程3.1—高级概念(Advanced Concepts):需求pads和间或pads(Request and Sometimes pads)
- NHibernate之旅(22):探索NHibernate一级缓存
- git init 与 git init --bare 的区别
- 关于编程、重构等 42条建议 中
- Material Design
- 金字塔原理学习笔记第1篇-表达的逻辑(一)
- Android 开发进阶指南
- 小波部分特征说明和小波特征比较---未写完
- Mysql InnoDB行锁实现方式