parse-launch: Support linking all pads with new operator

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
This commit is contained in:
Jan Schmidt 2015-06-26 03:29:27 +10:00
parent bf3a7c54f7
commit 5a5ae1be1f
5 changed files with 79 additions and 32 deletions

View 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)) {
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));
}
/* 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)

View 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);

View file

@ -15,6 +15,7 @@ typedef struct {
reference_t src;
reference_t sink;
GstCaps *caps;
gboolean all_pads;
} link_t;
typedef struct {

View 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
};

View 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