parse-launch: Support linking all pads with new operator
authorJan Schmidt <jan@centricular.com>
Thu, 25 Jun 2015 17:29:27 +0000 (03:29 +1000)
committerJan Schmidt <jan@centricular.com>
Wed, 2 Nov 2016 01:04:33 +0000 (12:04 +1100)
Introduce a new operator ':' - e.g. element1 ':' element2

For example, 'uridecodebin : encodebin' -
if the encodebin has multiple profiles compatible with the
decodebin, multiple links will be created.

With '!' , after one delayed link is successfully done, the
pad-added callback is disconnected.

https://bugzilla.gnome.org/show_bug.cgi?id=751450

gst/parse/grammar.y
gst/parse/parse.l
gst/parse/types.h
tests/check/pipelines/parse-launch.c
tools/gst-launch.1.in

index 85d37dd..d7b431e 100644 (file)
@@ -233,6 +233,7 @@ typedef struct {
   GstElement *sink;
   GstCaps *caps;
   gulong pad_added_signal_id, no_more_pads_signal_id;
+  gboolean all_pads;
 } DelayedLink;
 
 typedef struct {
@@ -499,11 +500,15 @@ static void gst_parse_no_more_pads (GstElement *src, gpointer data)
 {
   DelayedLink *link = data;
 
-  GST_ELEMENT_WARNING(src, PARSE, DELAYED_LINK,
-    (_("Delayed linking failed.")),
-    ("failed delayed linking " PRETTY_PAD_NAME_FMT " to " PRETTY_PAD_NAME_FMT,
-        PRETTY_PAD_NAME_ARGS (src, link->src_pad),
-        PRETTY_PAD_NAME_ARGS (link->sink, link->sink_pad)));
+  /* Don't warn for all-pads links, as we expect those to
+   * still be active at no-more-pads */
+  if (!link->all_pads) {
+    GST_ELEMENT_WARNING(src, PARSE, DELAYED_LINK,
+      (_("Delayed linking failed.")),
+      ("failed delayed linking " PRETTY_PAD_NAME_FMT " to " PRETTY_PAD_NAME_FMT,
+          PRETTY_PAD_NAME_ARGS (src, link->src_pad),
+          PRETTY_PAD_NAME_ARGS (link->sink, link->sink_pad)));
+  }
   /* we keep the handlers connected, so that in case an element still adds a pad
    * despite no-more-pads, we will consider it for pending delayed links */
 }
@@ -513,7 +518,8 @@ static void gst_parse_found_pad (GstElement *src, GstPad *pad, gpointer data)
   DelayedLink *link = data;
 
   GST_CAT_INFO (GST_CAT_PIPELINE,
-                "trying delayed linking " PRETTY_PAD_NAME_FMT " to " PRETTY_PAD_NAME_FMT,
+                "trying delayed linking %s " PRETTY_PAD_NAME_FMT " to " PRETTY_PAD_NAME_FMT,
+                           link->all_pads ? "all pads" : "one pad",
                 PRETTY_PAD_NAME_ARGS (src, link->src_pad),
                 PRETTY_PAD_NAME_ARGS (link->sink, link->sink_pad));
 
@@ -522,12 +528,14 @@ static void gst_parse_found_pad (GstElement *src, GstPad *pad, gpointer data)
     /* do this here, we don't want to get any problems later on when
      * unlocking states */
     GST_CAT_DEBUG (GST_CAT_PIPELINE,
-                   "delayed linking " PRETTY_PAD_NAME_FMT " to " PRETTY_PAD_NAME_FMT " worked",
+                   "delayed linking %s " PRETTY_PAD_NAME_FMT " to " PRETTY_PAD_NAME_FMT " worked",
+                              link->all_pads ? "all pads" : "one pad",
                           PRETTY_PAD_NAME_ARGS (src, link->src_pad),
                    PRETTY_PAD_NAME_ARGS (link->sink, link->sink_pad));
     g_signal_handler_disconnect (src, link->no_more_pads_signal_id);
     /* releases 'link' */
-    g_signal_handler_disconnect (src, link->pad_added_signal_id);
+    if (!link->all_pads)
+      g_signal_handler_disconnect (src, link->pad_added_signal_id);
   }
 }
 
@@ -535,7 +543,7 @@ static void gst_parse_found_pad (GstElement *src, GstPad *pad, gpointer data)
 static gboolean
 gst_parse_perform_delayed_link (GstElement *src, const gchar *src_pad,
                                 GstElement *sink, const gchar *sink_pad,
-                                GstCaps *caps)
+                                GstCaps *caps, gboolean all_pads)
 {
   GList *templs = gst_element_class_get_pad_template_list (
       GST_ELEMENT_GET_CLASS (src));
@@ -547,6 +555,8 @@ gst_parse_perform_delayed_link (GstElement *src, const gchar *src_pad,
     {
       DelayedLink *data = g_slice_new (DelayedLink);
 
+      data->all_pads = all_pads;
+
       /* TODO: maybe we should check if src_pad matches this template's names */
 
       GST_CAT_DEBUG (GST_CAT_PIPELINE,
@@ -596,18 +606,30 @@ gst_parse_perform_link (link_t *link, graph_t *graph)
       g_slist_length (srcs), g_slist_length (sinks), link->caps);
 
   if (!srcs || !sinks) {
-    if (gst_element_link_pads_filtered (src,
+    gboolean found_one = gst_element_link_pads_filtered (src,
+        srcs ? (const gchar *) srcs->data : NULL, sink,
+        sinks ? (const gchar *) sinks->data : NULL, link->caps);
+
+    if (found_one) {
+      if (!link->all_pads)
+        goto success; /* Linked one, and not an all-pads link = we're done */
+
+      /* Try and link more available pads */
+      while (gst_element_link_pads_filtered (src,
         srcs ? (const gchar *) srcs->data : NULL, sink,
-        sinks ? (const gchar *) sinks->data : NULL, link->caps)) {
+        sinks ? (const gchar *) sinks->data : NULL, link->caps));
+    }
+
+    /* We either didn't find any static pads, or this is a all-pads link,
+     * in which case watch for future pads and link those. Not a failure
+     * in the all-pads case if there's no sometimes pads to watch */
+    if (gst_parse_perform_delayed_link (src,
+          srcs ? (const gchar *) srcs->data : NULL,
+          sink, sinks ? (const gchar *) sinks->data : NULL, link->caps,
+         link->all_pads) || link->all_pads) {
       goto success;
     } else {
-      if (gst_parse_perform_delayed_link (src,
-          srcs ? (const gchar *) srcs->data : NULL,
-          sink, sinks ? (const gchar *) sinks->data : NULL, link->caps)) {
-       goto success;
-      } else {
-        goto error;
-      }
+      goto error;
     }
   }
   if (g_slist_length (link->src.pads) != g_slist_length (link->sink.pads)) {
@@ -624,7 +646,7 @@ gst_parse_perform_link (link_t *link, graph_t *graph)
     } else {
       if (gst_parse_perform_delayed_link (src, src_pad,
                                           sink, sink_pad,
-                                         link->caps)) {
+                                         link->caps, link->all_pads)) {
        continue;
       } else {
         goto error;
@@ -666,6 +688,7 @@ static int yyerror (void *scanner, graph_t *graph, const char *s);
 %left  <ss> REF PADREF BINREF
 %token <ss> ASSIGNMENT
 %token <ss> LINK
+%token <ss> LINK_ALL
 
 %type <ss> binopener
 %type <gg> graph
@@ -691,7 +714,7 @@ static int yyerror (void *scanner, graph_t *graph, const char *s);
 %left '(' ')'
 %left ','
 %right '.'
-%left '!' '='
+%left '!' '=' ':'
 
 %lex-param { void *scanner }
 %parse-param { void *scanner }
@@ -805,17 +828,19 @@ openchain:
                                                $$ = $4;
                                                $$->last.pads = g_slist_concat ($$->last.pads, $5);
                                              }
-
        ;
 
 link:  LINK                                  { $$ = gst_parse_link_new ();
-                                               $$->src.element = NULL;
-                                               $$->sink.element = NULL;
-                                               $$->src.name = NULL;
-                                               $$->sink.name = NULL;
-                                               $$->src.pads = NULL;
-                                               $$->sink.pads = NULL;
-                                               $$->caps = NULL;
+                                               $$->all_pads = FALSE;
+                                               if ($1) {
+                                                 $$->caps = gst_caps_from_string ($1);
+                                                 if ($$->caps == NULL)
+                                                   SET_ERROR (graph->error, GST_PARSE_ERROR_LINK, _("could not parse caps \"%s\""), $1);
+                                                 gst_parse_strfree ($1);
+                                               }
+                                             }
+       | LINK_ALL                            { $$ = gst_parse_link_new ();
+                                               $$->all_pads = TRUE;
                                                if ($1) {
                                                  $$->caps = gst_caps_from_string ($1);
                                                  if ($$->caps == NULL)
index 53afba8..50acf5c 100644 (file)
@@ -50,7 +50,7 @@ PRINT (const char *format, ...)
 
 %}
 
-_operator [(){}.!,;=]
+_operator [(){}.!:,;=]
 _identifier [[:alnum:]_][[:alnum:]\-_%:]*
 
 _char ("\\".)|([^[:space:]])
@@ -75,7 +75,7 @@ _mimetype {_mimechar}+"/"{_mimechar}+
 _capschar ("\\".)|([^\;!])
 _capsstring {_capschar}+
 _caps {_mimetype}(","[^!]|{_capsstring})*
-_link ("!"[[:space:]]*{_caps}([[:space:]]*(";"[[:space:]]*{_caps})*[[:space:]]*)*"!")|("!")
+_link ([!:][[:space:]]*{_caps}([[:space:]]*(";"[[:space:]]*{_caps})*[[:space:]]*)*[!:])|([!:])
 
 %x value
 %option noyywrap
@@ -128,21 +128,33 @@ _link ("!"[[:space:]]*{_caps}([[:space:]]*(";"[[:space:]]*{_caps})*[[:space:]]*)
 
 {_link} {
     gchar *c = yytext;
+    gchar op;
+    gboolean link_all;
+
     PRINT ("LINK: %s", yytext);
+    /* First char is a link operator */
+    link_all = (*c == ':');
     c++;
     if (*c) {
       while (g_ascii_isspace (*c)) c++;
       c = yylval->ss = gst_parse_strdup (c);
       while (*c) c++;
-      if (*--c != '!')
+      /* Last non-space char is a link operator */
+      op = *--c;
+      if (op != '!' && op != ':')
        g_assert_not_reached ();
+      if (op == ':')
+        link_all = TRUE;
+
+      /* Walk backward past whitespaces - what remains
+       * is a filter caps string, or empty */
       while (g_ascii_isspace (*--c));
       *++c = '\0';
     } else {
       yylval->ss = NULL;
     }
     BEGIN (INITIAL);
-    return LINK;
+    return link_all ? LINK_ALL : LINK;
 }
 {_url} {
   PRINT ("URL: %s", yytext);
index fbeaf20..66d13dd 100644 (file)
@@ -15,6 +15,7 @@ typedef struct {
   reference_t src;
   reference_t sink;
   GstCaps *caps;
+  gboolean all_pads;
 } link_t;
 
 typedef struct {
index 6472070..6e91165 100644 (file)
@@ -108,6 +108,10 @@ static const gchar *test_lines[] = {
 /*  "(name=mabin fakesrc) mabin. ! fakesink", FIXME: linking to named bin does not work yet */
 /*  "(name=mabin name=yoyo fakesrc) yoyo. ! fakesink", FIXME: linking to named bin does not work yet  */
   "deepsrc. ! fakesink fakesrc  ! ( identity ! ( identity ! (  identity name=deepsrc ) ) )",    /* deep name resolution, multilevel ghostpad creation */
+  "fakesrc : fakesink",         /* linking all matching pads */
+  "fakesrc : video/x-all : fakesink",   /* linking all matching pads with filter */
+  "fakesrc ! video/x-all : fakesink",   /* linking all matching pads with filter */
+  "fakesrc : video/x-all ! fakesink",   /* linking all matching pads with filter */
   NULL
 };
 
index 5034f29..9406611 100644 (file)
@@ -165,6 +165,8 @@ partial pipelines instead of a full-fledged top-level pipeline.
 
 \fI[[SRCELEMENT].[PAD1,...]]\fR ! \fI[[SINKELEMENT].[PAD1,...]]\fR
 \fI[[SRCELEMENT].[PAD1,...]]\fR ! CAPS ! \fI[[SINKELEMENT].[PAD1,...]]\fR
+\fI[[SRCELEMENT].[PAD1,...]]\fR : \fI[[SINKELEMENT].[PAD1,...]]\fR
+\fI[[SRCELEMENT].[PAD1,...]]\fR : CAPS : \fI[[SINKELEMENT].[PAD1,...]]\fR
 
 Links the element with name SRCELEMENT to the element with name SINKELEMENT,
 using the caps specified in CAPS as a filter.
@@ -178,6 +180,9 @@ specified and multiple links are done in the given order.
 So the simplest link is a simple exclamation mark, that links the element to
 the left of it to the element right of it.
 .br
+Linking using the : operator attempts to link all possible pads between
+the elements
+.br
 
 .B Caps