return result;
}
-static GstPad *
-_gst_element_request_pad (GstElement * element, GstPadTemplate * templ,
- const gchar * name, const GstCaps * caps)
+static gboolean
+gst_element_is_valid_request_template_name (const gchar * templ_name,
+ const gchar * name)
{
- GstPad *newpad = NULL;
- GstElementClass *oclass;
+ gchar *endptr;
+ const gchar *templ_name_ptr, *name_ptr;
+ gboolean next_specifier;
+ guint templ_postfix_len = 0, name_postfix_len = 0;
- oclass = GST_ELEMENT_GET_CLASS (element);
+ g_return_val_if_fail (templ_name != NULL, FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
-#ifndef G_DISABLE_CHECKS
- /* Some sanity checking here */
- if (name) {
- GstPad *pad;
+ /* Is this the template name? */
+ if (strcmp (templ_name, name) == 0)
+ return TRUE;
- /* Is this the template name? */
- if (strstr (name, "%") || !strchr (templ->name_template, '%')) {
- g_return_val_if_fail (strcmp (name, templ->name_template) == 0, NULL);
- } else {
- const gchar *str, *data;
- gchar *endptr;
+ /* otherwise check all the specifiers */
+ do {
+ /* Because of sanity checks in gst_pad_template_new(), we know that %s
+ * and %d and %u, occurring at the template_name */
+ templ_name_ptr = strchr (templ_name, '%');
+
+ /* check characters ahead of the specifier */
+ if (!templ_name_ptr || strlen (name) <= templ_name_ptr - templ_name
+ || strncmp (templ_name, name, templ_name_ptr - templ_name) != 0) {
+ return FALSE;
+ }
+
+ /* %s is not allowed for multiple specifiers, just a single specifier can be
+ * accepted in gst_pad_template_new() and can not be mixed with other
+ * specifier '%u' and '%d' */
+ if (*(templ_name_ptr + 1) == 's' && g_strcmp0 (templ_name, name) == 0) {
+ return TRUE;
+ }
+
+ name_ptr = name + (templ_name_ptr - templ_name);
+
+ /* search next specifier, each of specifier should be separated by '_' */
+ templ_name = strchr (templ_name_ptr, '_');
+ name = strchr (name_ptr, '_');
+
+ /* don't match the number of specifiers */
+ if ((templ_name && !name) || (!templ_name && name))
+ return FALSE;
+
+ if (templ_name && name)
+ next_specifier = TRUE;
+ else
+ next_specifier = FALSE;
+
+ /* check characters followed by the specifier */
+ if (*(templ_name_ptr + 2) != '\0' && *(templ_name_ptr + 2) != '_') {
+ if (next_specifier) {
+ templ_postfix_len = templ_name - (templ_name_ptr + 2);
+ name_postfix_len = name - name_ptr;
+ } else {
+ templ_postfix_len = strlen (templ_name_ptr + 2);
+ name_postfix_len = strlen (name_ptr);
+ }
+
+ if (strncmp (templ_name_ptr + 2,
+ name_ptr + name_postfix_len - templ_postfix_len,
+ templ_postfix_len) != 0) {
+ return FALSE;
+ }
+ }
+
+ /* verify the specifier */
+ if (*(name_ptr) == '%') {
+ guint len;
- /* Otherwise check if it's a valid name for the name template */
- str = strchr (templ->name_template, '%');
- g_return_val_if_fail (str != NULL, NULL);
- g_return_val_if_fail (strncmp (templ->name_template, name,
- str - templ->name_template) == 0, NULL);
- g_return_val_if_fail (strlen (name) > str - templ->name_template, NULL);
+ len = (next_specifier) ? name - name_ptr : strlen (name_ptr);
- data = name + (str - templ->name_template);
+ if (strncmp (name_ptr, templ_name_ptr, len) != 0)
+ return FALSE;
+
+ } else {
+ const gchar *specifier;
+ gchar *target = NULL;
- /* Can either be %s or %d or %u, do sanity checking for %d */
- if (*(str + 1) == 'd') {
+ /* extract specifier when it has postfix characters */
+ if (name_postfix_len > templ_postfix_len) {
+ target = g_strndup (name_ptr, name_postfix_len - templ_postfix_len);
+ }
+ specifier = target ? target : name_ptr;
+
+ if (*(templ_name_ptr + 1) == 'd') {
gint64 tmp;
/* it's an int */
- tmp = g_ascii_strtoll (data, &endptr, 10);
- g_return_val_if_fail (tmp >= G_MININT && tmp <= G_MAXINT
- && *endptr == '\0', NULL);
- } else if (*(str + 1) == 'u') {
+ tmp = g_ascii_strtoll (specifier, &endptr, 10);
+ if (tmp < G_MININT || tmp > G_MAXINT || (*endptr != '\0'
+ && *endptr != '_'))
+ return FALSE;
+ } else if (*(templ_name_ptr + 1) == 'u') {
guint64 tmp;
/* it's an int */
- tmp = g_ascii_strtoull (data, &endptr, 10);
- g_return_val_if_fail (tmp <= G_MAXUINT && *endptr == '\0', NULL);
+ tmp = g_ascii_strtoull (specifier, &endptr, 10);
+ if (tmp > G_MAXUINT || (*endptr != '\0' && *endptr != '_'))
+ return FALSE;
}
+
+ g_free (target);
}
+ templ_name++;
+ name++;
+ } while (next_specifier);
+
+ return TRUE;
+}
+
+static GstPad *
+_gst_element_request_pad (GstElement * element, GstPadTemplate * templ,
+ const gchar * name, const GstCaps * caps)
+{
+ GstPad *newpad = NULL;
+ GstElementClass *oclass;
+
+ oclass = GST_ELEMENT_GET_CLASS (element);
+
+#ifndef G_DISABLE_CHECKS
+ /* Some sanity checking here */
+ if (name) {
+ GstPad *pad;
+
+ g_return_val_if_fail (gst_element_is_valid_request_template_name
+ (templ->name_template, name), NULL);
+
pad = gst_element_get_static_pad (element, name);
if (pad) {
gst_object_unref (pad);
const gchar *req_name = NULL;
gboolean templ_found = FALSE;
GList *list;
- const gchar *data;
- gchar *str, *endptr = NULL;
GstElementClass *class;
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
class = GST_ELEMENT_GET_CLASS (element);
- /* if the name contains a %, we assume it's the complete template name. Get
- * the template and try to get a pad */
- if (strstr (name, "%")) {
- templ = gst_element_class_get_request_pad_template (class, name);
- req_name = NULL;
- if (templ)
- templ_found = TRUE;
+ templ = gst_element_class_get_request_pad_template (class, name);
+ if (templ) {
+ req_name = strstr (name, "%") ? NULL : name;
+ templ_found = TRUE;
} else {
/* there is no % in the name, try to find a matching template */
list = class->padtemplates;
if (templ->presence == GST_PAD_REQUEST) {
GST_CAT_DEBUG (GST_CAT_PADS, "comparing %s to %s", name,
templ->name_template);
- /* see if we find an exact match */
- if (strcmp (name, templ->name_template) == 0) {
+ if (gst_element_is_valid_request_template_name (templ->name_template,
+ name)) {
templ_found = TRUE;
req_name = name;
break;
}
- /* Because of sanity checks in gst_pad_template_new(), we know that %s
- and %d and %u, occurring at the end of the name_template, are the only
- possibilities. */
- else if ((str = strchr (templ->name_template, '%'))
- && strncmp (templ->name_template, name,
- str - templ->name_template) == 0
- && strlen (name) > str - templ->name_template) {
- data = name + (str - templ->name_template);
- if (*(str + 1) == 'd') {
- glong tmp;
-
- /* it's an int */
- tmp = strtol (data, &endptr, 10);
- if (tmp != G_MINLONG && tmp != G_MAXLONG && endptr &&
- *endptr == '\0') {
- templ_found = TRUE;
- req_name = name;
- break;
- }
- } else if (*(str + 1) == 'u') {
- gulong tmp;
-
- /* it's an int */
- tmp = strtoul (data, &endptr, 10);
- if (tmp != G_MAXULONG && endptr && *endptr == '\0') {
- templ_found = TRUE;
- req_name = name;
- break;
- }
- } else {
- /* it's a string */
- templ_found = TRUE;
- req_name = name;
- break;
- }
- }
}
list = list->next;
}
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
#include <gst/check/gstcheck.h>
+#include <gst/gstelement.h>
GST_START_TEST (test_add_remove_pad)
{
gst_element_remove_property_notify_watch (pipeline, deep_watch_id1);
gst_element_remove_property_notify_watch (pipeline, deep_watch_id2);
gst_element_set_state (pipeline, GST_STATE_NULL);
+
+ gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
+typedef struct _GstTestElement3
+{
+ GstElement parent;
+
+} GstTestElement3;
+
+typedef struct _GstTestElement3Class
+{
+ GstElementClass parent;
+
+} GstTestElement3Class;
+
+static GstPad *
+gst_test_element3_request_new_pad (GstElement * element, GstPadTemplate * templ,
+ const gchar * name, const GstCaps * caps)
+{
+ GstPad *pad;
+ gchar *str;
+ gchar *pad_name;
+ gint n_conversion = 0;
+ static gint i = 0;
+
+ str = templ->name_template;
+ while ((str = strchr (str, '%'))) {
+ n_conversion++;
+ str++;
+ }
+
+ if (strcmp (templ->name_template, "src_%ublah_blah%ublah") == 0)
+ pad_name = g_strdup_printf ("src_%ublah_blah_%ublah", i, i + 1);
+ else if (n_conversion == 1) {
+ pad_name = g_strdup_printf ("src_%u", i);
+ } else if (n_conversion == 2) {
+ pad_name = g_strdup_printf ("src_%u_%u", i, i + 1);
+ } else if (n_conversion == 3) {
+ pad_name = g_strdup_printf ("src_%u_%u_%u", i, i + 1, i + 2);
+ } else {
+ pad_name = g_strdup (name);
+ }
+
+ pad = gst_pad_new_from_template (templ, pad_name);
+
+ gst_element_add_pad (element, pad);
+
+ i++;
+ g_free (pad_name);
+
+ return pad;
+}
+
+static void
+gst_test_element3_release_pad (GstElement * element, GstPad * pad)
+{
+ gst_element_remove_pad (element, pad);
+}
+
+static void
+gst_test_element3_init (GstTestElement3 * test)
+{
+ GstPadTemplate *pad_template;
+ GstPad *sinkpad;
+
+ pad_template =
+ gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (test), "sink");
+ g_return_if_fail (pad_template != NULL);
+ sinkpad = gst_pad_new_from_template (pad_template, "sink");
+
+ gst_element_add_pad (GST_ELEMENT (test), sinkpad);
+}
+
+static void
+gst_test_element3_class_init (GstTestElement3Class * klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_set_metadata (element_class, "Test element 3",
+ "Element", "For testing request pad template", "Foo Bar <foo@bar.com>");
+
+ element_class->request_new_pad =
+ GST_DEBUG_FUNCPTR (gst_test_element3_request_new_pad);
+ element_class->release_pad =
+ GST_DEBUG_FUNCPTR (gst_test_element3_release_pad);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_pad_template_new ("src_%u", GST_PAD_SRC, GST_PAD_REQUEST,
+ GST_CAPS_ANY));
+
+ gst_element_class_add_pad_template (element_class,
+ gst_pad_template_new ("src_%u_%u", GST_PAD_SRC, GST_PAD_REQUEST,
+ GST_CAPS_ANY));
+
+ gst_element_class_add_pad_template (element_class,
+ gst_pad_template_new ("src_%u_%u_%u", GST_PAD_SRC, GST_PAD_REQUEST,
+ GST_CAPS_ANY));
+
+ gst_element_class_add_pad_template (element_class,
+ gst_pad_template_new ("src_%ublah_blah%ublah", GST_PAD_SRC,
+ GST_PAD_REQUEST, GST_CAPS_ANY));
+
+ gst_element_class_add_pad_template (element_class,
+ gst_pad_template_new ("src_%d", GST_PAD_SRC, GST_PAD_REQUEST,
+ GST_CAPS_ANY));
+
+ gst_element_class_add_pad_template (element_class,
+ gst_pad_template_new ("src_%d_%d", GST_PAD_SRC, GST_PAD_REQUEST,
+ GST_CAPS_ANY));
+
+ gst_element_class_add_pad_template (element_class,
+ gst_pad_template_new ("src_%d_%d_%d", GST_PAD_SRC, GST_PAD_REQUEST,
+ GST_CAPS_ANY));
+
+ gst_element_class_add_pad_template (element_class,
+ gst_pad_template_new ("src_%s", GST_PAD_SRC, GST_PAD_REQUEST,
+ GST_CAPS_ANY));
+
+ gst_element_class_add_pad_template (element_class,
+ gst_pad_template_new ("src_%u_%s", GST_PAD_SRC, GST_PAD_REQUEST,
+ GST_CAPS_ANY));
+
+ gst_element_class_add_pad_template (element_class,
+ gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+ GST_CAPS_ANY));
+}
+
+static GType
+gst_test_element3_get_type (void)
+{
+ static GType gst_test_element3_type = G_TYPE_NONE;
+
+ if (gst_test_element3_type == G_TYPE_NONE) {
+ static const GTypeInfo gst_test_element3_info = {
+ sizeof (GstTestElement3Class),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) gst_test_element3_class_init,
+ NULL,
+ NULL,
+ sizeof (GstTestElement3),
+ 0,
+ (GInstanceInitFunc) gst_test_element3_init,
+ NULL
+ };
+
+ gst_test_element3_type =
+ g_type_register_static (gst_element_get_type (), "GstTestElement3",
+ &gst_test_element3_info, 0);
+ }
+ return gst_test_element3_type;
+}
+
+static gboolean
+gst_test_element3_plugin_init (GstPlugin * plugin)
+{
+ gst_element_register (plugin, "test3", GST_RANK_NONE,
+ gst_test_element3_get_type ());
+ return TRUE;
+}
+
+GST_START_TEST (test_request_pad_templates)
+{
+ GstTestElement3 *test;
+ GstElement *pipeline, *sink;
+ GstPad *pad;
+ GHashTable *padnames;
+ GHashTableIter iter;
+ gpointer key, value;
+ const gchar *pad_name, *templ_name;
+ GSList *padname_blacklists = NULL, *item;
+ GError *err = NULL;
+
+ padnames = g_hash_table_new (g_str_hash, g_str_equal);
+
+ g_hash_table_insert (padnames, (gpointer) "src_0", (gpointer) "src_%u");
+ g_hash_table_insert (padnames, (gpointer) "src_%u", (gpointer) "src_%u");
+ g_hash_table_insert (padnames, (gpointer) "src_%u_%u",
+ (gpointer) "src_%u_%u");
+ g_hash_table_insert (padnames, (gpointer) "src_0_%u", (gpointer) "src_%u_%u");
+ g_hash_table_insert (padnames, (gpointer) "src_%u_0", (gpointer) "src_%u_%u");
+ g_hash_table_insert (padnames, (gpointer) "src_0_1", (gpointer) "src_%u_%u");
+ g_hash_table_insert (padnames, (gpointer) "src_%u_%u_%u",
+ (gpointer) "src_%u_%u_%u");
+ g_hash_table_insert (padnames, (gpointer) "src_0_%u_%u",
+ (gpointer) "src_%u_%u_%u");
+ g_hash_table_insert (padnames, (gpointer) "src_0_1_%u",
+ (gpointer) "src_%u_%u_%u");
+ g_hash_table_insert (padnames, (gpointer) "src_0_1_2",
+ (gpointer) "src_%u_%u_%u");
+ g_hash_table_insert (padnames, (gpointer) "src_%u_0_%u",
+ (gpointer) "src_%u_%u_%u");
+ g_hash_table_insert (padnames, (gpointer) "src_%u_0_1",
+ (gpointer) "src_%u_%u_%u");
+ g_hash_table_insert (padnames, (gpointer) "src_%u_%u_0",
+ (gpointer) "src_%u_%u_%u");
+ g_hash_table_insert (padnames, (gpointer) "src_%ublah_blah%ublah",
+ (gpointer) "src_%ublah_blah%ublah");
+ g_hash_table_insert (padnames, (gpointer) "src_%d", (gpointer) "src_%d");
+ g_hash_table_insert (padnames, (gpointer) "src_%d_%d",
+ (gpointer) "src_%d_%d");
+ g_hash_table_insert (padnames, (gpointer) "src_1_%d", (gpointer) "src_%d_%d");
+ g_hash_table_insert (padnames, (gpointer) "src_%d_%d_%d",
+ (gpointer) "src_%d_%d_%d");
+ g_hash_table_insert (padnames, (gpointer) "src_1_2_%d",
+ (gpointer) "src_%d_%d_%d");
+ g_hash_table_insert (padnames, (gpointer) "src_1_%d_2",
+ (gpointer) "src_%d_%d_%d");
+ g_hash_table_insert (padnames, (gpointer) "src_%d_2_1",
+ (gpointer) "src_%d_%d_%d");
+ g_hash_table_insert (padnames, (gpointer) "src_%d_%d_1",
+ (gpointer) "src_%d_%d_%d");
+ g_hash_table_insert (padnames, (gpointer) "src_%d_1_%d",
+ (gpointer) "src_%d_%d_%d");
+ g_hash_table_insert (padnames, (gpointer) "src_1_%d_%d",
+ (gpointer) "src_%d_%d_%d");
+ g_hash_table_insert (padnames, (gpointer) "src_%s", (gpointer) "src_%s");
+ g_hash_table_insert (padnames, (gpointer) "src_%u_%s",
+ (gpointer) "src_%u_%s");
+
+ padname_blacklists =
+ g_slist_append (padname_blacklists, (gpointer) "src_%u%u");
+ padname_blacklists =
+ g_slist_append (padname_blacklists, (gpointer) "src_%u_%d");
+ padname_blacklists =
+ g_slist_append (padname_blacklists, (gpointer) "src_%u_%u_");
+ padname_blacklists =
+ g_slist_append (padname_blacklists, (gpointer) "src_%u_%s_%s");
+ padname_blacklists =
+ g_slist_append (padname_blacklists, (gpointer) "src_%s_%u");
+ padname_blacklists =
+ g_slist_append (padname_blacklists, (gpointer) "src_%s_%s");
+ padname_blacklists =
+ g_slist_append (padname_blacklists, (gpointer) "src_%s_%s_%s");
+ padname_blacklists =
+ g_slist_append (padname_blacklists, (gpointer) "src_%s_blah");
+
+ test = g_object_new (gst_test_element3_get_type (), NULL);
+
+ /* check available request pad names */
+ g_hash_table_iter_init (&iter, padnames);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ pad_name = (const gchar *) key;
+ templ_name = (const gchar *) value;
+
+ pad = gst_element_get_request_pad (GST_ELEMENT (test), pad_name);
+ fail_unless (pad != NULL);
+ gst_element_release_request_pad (GST_ELEMENT (test), pad);
+ gst_object_unref (pad);
+
+ pad = gst_element_request_pad (GST_ELEMENT (test),
+ gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (test),
+ templ_name), pad_name, NULL);
+ fail_unless (pad != NULL);
+ gst_element_release_request_pad (GST_ELEMENT (test), pad);
+ gst_object_unref (pad);
+ }
+
+ item = padname_blacklists;
+
+ /* check invalid request pad name */
+ while (item) {
+ pad_name = (const gchar *) (item->data);
+ item = g_slist_next (item);
+ pad = gst_element_get_request_pad (GST_ELEMENT (test), pad_name);
+ fail_unless (pad == NULL);
+ }
+
+ /* check it working with some APIs
+ * gst_element_link/link_pads */
+ sink = gst_element_factory_make ("fakesink", "sink");
+
+ fail_unless (gst_element_link (GST_ELEMENT (test), sink));
+ gst_element_unlink (GST_ELEMENT (test), sink);
+
+ fail_unless (gst_element_link_pads (GST_ELEMENT (test), "src_%u_%u", sink,
+ "sink"));
+ gst_element_unlink (GST_ELEMENT (test), sink);
+
+ g_object_unref (test);
+ g_object_unref (sink);
+
+ /* gst_parse_launch */
+ gst_plugin_register_static (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "test3",
+ "request pad template test",
+ gst_test_element3_plugin_init,
+ VERSION, GST_LICENSE, PACKAGE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
+
+ pipeline =
+ gst_parse_launch ("fakesrc ! test3 name=t ! fakesink t. ! fakesink",
+ &err);
+ fail_unless (pipeline && err == NULL);
+
+ if (err) {
+ g_error_free (err);
+ }
+ g_slist_free (padname_blacklists);
+ g_hash_table_unref (padnames);
gst_object_unref (pipeline);
}
tcase_add_test (tc_chain, test_link_no_pads);
tcase_add_test (tc_chain, test_pad_templates);
tcase_add_test (tc_chain, test_property_notify_message);
+ tcase_add_test (tc_chain, test_request_pad_templates);
return s;
}