#include "gstparse.h"
#include "gstinfo.h"
#include "gstlog.h"
-#include "parse/types.h"
-
-typedef struct _gst_parse_delayed_pad gst_parse_delayed_pad;
-struct _gst_parse_delayed_pad
-{
- gchar *name;
- GstPad *peer;
-};
-
-typedef struct
-{
- gchar *srcpadname;
- GstPad *target_pad;
- GstElement *target_element;
- GstElement *pipeline;
-}
-dynamic_link_t;
+extern GstElement *_gst_parse_launch (const gchar *, GError **);
GQuark
gst_parse_error_quark (void)
return quark;
}
-G_GNUC_UNUSED static void
-dynamic_link (GstElement * element, GstPad * newpad, gpointer data)
-{
- dynamic_link_t *dc = (dynamic_link_t *) data;
- gboolean warn = TRUE;
-
- /* do we know the exact srcpadname? */
- if (dc->srcpadname) {
- GstPadTemplate *templ = gst_pad_get_pad_template (newpad);
-
- /* see if this is the one */
- if (strcmp (gst_pad_get_name (newpad), dc->srcpadname) &&
- strcmp (gst_object_get_name (GST_OBJECT (templ)), dc->srcpadname)) {
- return;
- }
- }
-
- /* try to find a target pad if we don't know it yet */
- if (!dc->target_pad) {
- if (!GST_PAD_IS_LINKED (newpad)) {
- dc->target_pad = gst_element_get_compatible_pad (dc->target_element, newpad);
- warn = FALSE;
- }
- else {
- return;
- }
- }
- if (!GST_PAD_IS_LINKED (dc->target_pad) && !GST_PAD_IS_LINKED (newpad)) {
- gst_element_set_state (dc->pipeline, GST_STATE_PAUSED);
- if (!gst_pad_link (newpad, dc->target_pad) && warn) {
- g_warning ("could not link %s:%s to %s:%s", GST_DEBUG_PAD_NAME (newpad),
- GST_DEBUG_PAD_NAME (dc->target_pad));
- }
- gst_element_set_state (dc->pipeline, GST_STATE_PLAYING);
- }
-}
-
-static gboolean
-make_elements (graph_t *g, GError **error)
-{
- GList *l = NULL;
- gchar *bin_type;
- element_t *e;
-
- if (!(g->bins || g->elements)) {
- g_set_error (error,
- GST_PARSE_ERROR,
- GST_PARSE_ERROR_SYNTAX,
- "Empty bin");
- return FALSE;
- }
-
- if (g->current_bin_type)
- bin_type = g->current_bin_type;
- else
- bin_type = "pipeline";
-
- if (!(g->bin = gst_element_factory_make (bin_type, NULL))) {
- g_set_error (error,
- GST_PARSE_ERROR,
- GST_PARSE_ERROR_NO_SUCH_ELEMENT,
- "No such bin type %s", bin_type);
- return FALSE;
- }
-
- l = g->elements;
- while (l) {
- e = (element_t*)l->data;
- if (!(e->element = gst_element_factory_make (e->type, NULL))) {
- g_set_error (error,
- GST_PARSE_ERROR,
- GST_PARSE_ERROR_NO_SUCH_ELEMENT,
- "No such element %s", e->type);
- return FALSE;
- }
- gst_bin_add (GST_BIN (g->bin), e->element);
- l = g_list_next (l);
- }
-
- l = g->bins;
- while (l) {
- if (!make_elements ((graph_t*)l->data, error))
- return FALSE;
- gst_bin_add (GST_BIN (g->bin), ((graph_t*)l->data)->bin);
- l = g_list_next (l);
- }
-
- return TRUE;
-}
-
-static gboolean
-set_properties (graph_t *g, GError **error)
-{
- GList *l, *l2;
- element_t *e;
- property_t *p;
- GParamSpec *pspec;
-
- l = g->elements;
- while (l) {
- e = (element_t*)l->data;
- l2 = e->property_values;
- while (l2) {
- p = (property_t*)l2->data;
- if ((pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (e->element), p->name))) {
- g_object_set_property (G_OBJECT (e->element), p->name, p->value);
- } else {
- g_set_error (error,
- GST_PARSE_ERROR,
- GST_PARSE_ERROR_NO_SUCH_PROPERTY,
- "No such property '%s' in element '%s'",
- p->name, GST_OBJECT_NAME (GST_OBJECT (e->element)));
- return FALSE;
- }
- l2 = g_list_next (l2);
- }
- l = g_list_next (l);
- }
-
- l = g->bins;
- while (l) {
- if (!set_properties ((graph_t*)l->data, error))
- return FALSE;
- l = g_list_next (l);
- }
-
- return TRUE;
-}
-
-static GstElement*
-find_element_by_index_recurse (graph_t *g, gint i)
+static gchar *_gst_parse_escape (const gchar *str)
{
- GList *l;
- element_t *e;
- GstElement *element;
-
- l = g->elements;
- while (l) {
- e = (element_t*)l->data;
- if (e->index == i) {
- return e->element;
- }
- l = g_list_next (l);
- }
-
- l = g->bins;
- while (l) {
- if ((element = find_element_by_index_recurse ((graph_t*)l->data, i)))
- return element;
- l = g_list_next (l);
- }
+ GString *gstr = NULL;
- return NULL;
-}
-
-static GstElement*
-find_element_by_index (graph_t *g, gint i)
-{
- while (g->parent)
- g = g->parent;
-
- return find_element_by_index_recurse (g, i);
-}
-
-static gboolean
-make_links (graph_t *g, GError **error)
-{
- GList *l, *a, *b;
- link_t *c;
- dynamic_link_t *dc;
- GstElement *src, *sink;
- GstPad *p1, *p2;
- GstPadTemplate *pt1, *pt2;
- GstCaps *caps;
+ g_return_val_if_fail (str != NULL, NULL);
- l = g->links;
- while (l) {
- c = (link_t*)l->data;
- if (c->src_name) {
- if (!(src = gst_bin_get_by_name (GST_BIN (g->bin), c->src_name))) {
- g_set_error (error,
- GST_PARSE_ERROR,
- GST_PARSE_ERROR_NO_SUCH_ELEMENT,
- "No such element '%s'",
- c->src_name);
- return FALSE;
- }
- } else {
- src = find_element_by_index (g, c->src_index);
- g_assert (src);
- }
- if (c->sink_name) {
- if (!(sink = gst_bin_get_by_name (GST_BIN (g->bin), c->sink_name))) {
- g_set_error (error,
- GST_PARSE_ERROR,
- GST_PARSE_ERROR_NO_SUCH_ELEMENT,
- "No such element '%s'",
- c->sink_name);
- return FALSE;
- }
- } else {
- sink = find_element_by_index (g, c->sink_index);
- g_assert (sink);
- }
-
- a = c->src_pads;
- b = c->sink_pads;
- caps = c->caps;
- gst_caps_ref (caps);
- gst_caps_sink (caps);
-
- gst_caps_debug (caps, "foo");
- /* g_print ("a: %p, b: %p\n", a, b); */
- if (a && b) {
- /* balanced multipad link */
- while (a && b) {
- p1 = gst_element_get_pad (src, (gchar*)a->data);
- p2 = gst_element_get_pad (sink, (gchar*)b->data);
-
- if (!p2)
- goto could_not_get_pad_b;
-
- if (!p1 && p2 && (pt1 = gst_element_get_pad_template (src, (gchar*)a->data)) &&
- pt1->presence == GST_PAD_SOMETIMES) {
- dc = g_new0 (dynamic_link_t, 1);
- dc->srcpadname = (gchar*)a->data;
- dc->target_pad = p2;
- dc->target_element = sink;
- dc->pipeline = g->bin;
-
- GST_DEBUG (GST_CAT_PIPELINE, "setting up dynamic link %s:%s and %s:%s",
- GST_OBJECT_NAME (GST_OBJECT (src)),
- (gchar*)a->data, GST_DEBUG_PAD_NAME (p2));
-
- g_signal_connect (G_OBJECT (src), "new_pad", G_CALLBACK (dynamic_link), dc);
- } else if (!p1) {
- goto could_not_get_pad_a;
- } else if (!gst_pad_link_filtered (p1, p2, caps)) {
- goto could_not_link_pads;
- }
- a = g_list_next (a);
- b = g_list_next (b);
- }
- } else if (a) {
- if ((pt1 = gst_element_get_pad_template (src, (gchar*)a->data))) {
- if ((p1 = gst_element_get_pad (src, (gchar*)a->data)) || pt1->presence == GST_PAD_SOMETIMES) {
- if (!p1) {
- /* sigh, a hack until i fix the gstelement api... */
- if ((pt2 = gst_element_get_compatible_pad_template (sink, pt1))) {
- if ((p2 = gst_element_get_pad (sink, pt2->name_template))) {
- dc = g_new0 (dynamic_link_t, 1);
- dc->srcpadname = (gchar*)a->data;
- dc->target_pad = p2;
- dc->target_element = NULL;
- dc->pipeline = g->bin;
-
- GST_DEBUG (GST_CAT_PIPELINE, "setting up dynamic link %s:%s and %s:%s",
- GST_OBJECT_NAME (GST_OBJECT (src)),
- (gchar*)a->data, GST_DEBUG_PAD_NAME (p2));
-
- g_signal_connect (G_OBJECT (src), "new_pad", G_CALLBACK (dynamic_link), dc);
- goto next;
- } else {
- /* both pt1 and pt2 are sometimes templates. sheesh. */
- goto both_templates_have_sometimes_presence;
- }
- } else {
- /* if the target pad has no padtemplate we will figure out a target
- * pad later on */
- dc = g_new0 (dynamic_link_t, 1);
- dc->srcpadname = (gchar*)a->data;
- dc->target_pad = NULL;
- dc->target_element = sink;
- dc->pipeline = g->bin;
-
- GST_DEBUG (GST_CAT_PIPELINE, "setting up dynamic link %s:%s, and some pad in %s",
- GST_OBJECT_NAME (GST_OBJECT (src)),
- (gchar*)a->data, GST_OBJECT_NAME (sink));
-
- g_signal_connect (G_OBJECT (src), "new_pad", G_CALLBACK (dynamic_link), dc);
- goto next;
- }
- } else {
- goto could_not_get_compatible_to_a;
- }
- } else {
- goto could_not_get_pad_a;
- }
- } else {
- goto could_not_get_pad_a;
- }
-
- if (!gst_pad_link_filtered (p1, p2, caps)) {
- goto could_not_link_pads;
- }
- } else if (b) {
- /* we don't support dynamic links on this side yet, if ever */
- if (!(p2 = gst_element_get_pad (sink, (gchar*)b->data))) {
- goto could_not_get_pad_b;
- }
- if (!(p1 = gst_element_get_compatible_pad (src, p2))) {
- goto could_not_get_compatible_to_b;
- }
- if (!gst_pad_link_filtered (p1, p2, caps)) {
- goto could_not_link_pads;
- }
- } else {
- if (!gst_element_link_filtered (src, sink, caps)) {
- goto could_not_link_elements;
- }
- }
-next:
- gst_caps_unref (caps);
- l = g_list_next (l);
- }
+ gstr = g_string_sized_new (strlen (str));
- l = g->bins;
- while (l) {
- if (!make_links ((graph_t*)l->data, error))
- return FALSE;
- l = g_list_next (l);
+ while (*str) {
+ if (*str == ' ')
+ g_string_append_c (gstr, '\\');
+ g_string_append_c (gstr, *str);
+ str++;
}
- return TRUE;
-
-could_not_get_pad_a:
- g_set_error (error,
- GST_PARSE_ERROR,
- GST_PARSE_ERROR_LINK,
- "Could not get a pad %s from element %s",
- (gchar*)a->data, GST_OBJECT_NAME (src));
- return FALSE;
-could_not_get_pad_b:
- g_set_error (error,
- GST_PARSE_ERROR,
- GST_PARSE_ERROR_LINK,
- "Could not get a pad %s from element %s",
- (gchar*)b->data, GST_OBJECT_NAME (sink));
- return FALSE;
-could_not_get_compatible_to_a:
- g_set_error (error,
- GST_PARSE_ERROR,
- GST_PARSE_ERROR_LINK,
- "Could not find a compatible pad in element %s to for %s:%s",
- GST_OBJECT_NAME (sink), GST_OBJECT_NAME (src), (gchar*)a->data);
- return FALSE;
-could_not_get_compatible_to_b:
- g_set_error (error,
- GST_PARSE_ERROR,
- GST_PARSE_ERROR_LINK,
- "Could not find a compatible pad in element %s to for %s:%s",
- GST_OBJECT_NAME (src), GST_OBJECT_NAME (sink), (gchar*)b->data);
- return FALSE;
-both_templates_have_sometimes_presence:
- g_set_error (error,
- GST_PARSE_ERROR,
- GST_PARSE_ERROR_LINK,
- "Both %s:%s and %s:%s have GST_PAD_SOMETIMES presence, operation not supported",
- GST_OBJECT_NAME (src), pt1->name_template, GST_OBJECT_NAME (sink), pt2->name_template);
- return FALSE;
-could_not_link_pads:
- g_set_error (error,
- GST_PARSE_ERROR,
- GST_PARSE_ERROR_LINK,
- "Could not link %s:%s to %s:%s",
- GST_DEBUG_PAD_NAME (p1),
- GST_DEBUG_PAD_NAME (p2));
- return FALSE;
-could_not_link_elements:
- g_set_error (error,
- GST_PARSE_ERROR,
- GST_PARSE_ERROR_LINK,
- "Could not link element %s to %s",
- GST_OBJECT_NAME (src),
- GST_OBJECT_NAME (sink));
- return FALSE;
-}
-
-static GstBin*
-pipeline_from_graph (graph_t *g, GError **error)
-{
- if (!make_elements (g, error))
- return NULL;
-
- if (!set_properties (g, error))
- return NULL;
-
- if (!make_links (g, error))
- return NULL;
-
- return (GstBin*)g->bin;
+ return gstr->str;
}
-
/**
* gst_parse_launchv:
* @argv: null-terminated array of arguments
- * @error: pointer to GError
+ * @error: pointer to a #GError
*
- * Create a new pipeline based on command line syntax.
+ * Create a new element based on command line syntax.
+ * #error will contain an error message if pipeline creation fails and can
+ * contain an error message, when a recoverable error happened.
*
- * Returns: a new pipeline on success, NULL on failure and error
- * will contain the error message.
+ * Returns: a new element on success and NULL on failure.
*/
-GstBin *
+GstElement *
gst_parse_launchv (const gchar **argv, GError **error)
{
- GstBin *pipeline;
+ GstElement *element;
GString *str;
const gchar **argvp, *arg;
gchar *tmp;
argvp++;
}
- pipeline = gst_parse_launch (str->str, error);
+ element = gst_parse_launch (str->str, error);
g_string_free (str, TRUE);
- return pipeline;
-}
-
-gchar *_gst_parse_escape (const gchar *str)
-{
- GString *gstr = NULL;
-
- g_return_val_if_fail (str != NULL, NULL);
-
- gstr = g_string_sized_new (strlen (str));
-
- while (*str) {
- if (*str == ' ')
- g_string_append_c (gstr, '\\');
- g_string_append_c (gstr, *str);
- str++;
- }
-
- return gstr->str;
-}
-
-void _gst_parse_unescape (gchar *str)
-{
- gchar *walk;
-
- g_return_if_fail (str != NULL);
-
- walk = str;
-
- while (*walk) {
- if (*walk == '\\')
- walk++;
- *str = *walk;
- str++;
- walk++;
- }
- *str = '\0';
+ return element;
}
/**
* Returns: a new bin on success, NULL on failure. By default the bin is
* a GstPipeline, but it depends on the pipeline_description.
*/
-GstBin *
+GstElement *
gst_parse_launch (const gchar * pipeline_description, GError **error)
{
- graph_t *graph;
+ GstElement *element;
static GStaticMutex flex_lock = G_STATIC_MUTEX_INIT;
g_return_val_if_fail (pipeline_description != NULL, NULL);
/* the need for the mutex will go away with flex 2.5.6 */
g_static_mutex_lock (&flex_lock);
- graph = _gst_parse_launch (pipeline_description, error);
+ element = _gst_parse_launch (pipeline_description, error);
g_static_mutex_unlock (&flex_lock);
- if (!graph)
- return NULL;
-
- return pipeline_from_graph (graph, error);
+ return element;
}
%{
+#include <glib-object.h>
#include <glib.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "../gstparse.h"
+#include "../gstinfo.h"
#include "types.h"
-#define YYDEBUG 1
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#define YYERROR_VERBOSE 1
-#define YYPARSE_PARAM pgraph
+#define YYPARSE_PARAM graph
+
+#ifdef __GST_PARSE_TRACE
+static uint __strings;
+static uint __links;
+static uint __chains;
+gchar *
+__gst_parse_strdup (gchar *org)
+{
+ __strings++;
+ /* g_print ("ALLOCATED: %p %s\n", org, org); */
+ return g_strdup (org);
+}
+void
+__gst_parse_strfree (gchar *str)
+{
+ if (str) {
+ /* g_print ("FREEING : %p %s\n", str, str); */
+ g_free (str);
+ g_return_if_fail (__strings > 0);
+ __strings--;
+ }
+}
+link_t *__gst_parse_link_new ()
+{
+ __links++;
+ return g_new0 (link_t, 1);
+}
+void
+__gst_parse_link_free (link_t *data)
+{
+ if (data) {
+ g_free (data);
+ g_return_if_fail (__links > 0);
+ __links--;
+ }
+}
+chain_t *
+__gst_parse_chain_new ()
+{
+ __chains++;
+ return g_new0 (chain_t, 1);
+}
+void
+__gst_parse_chain_free (chain_t *data)
+{
+ if (data) {
+ g_free (data);
+ g_return_if_fail (__chains > 0);
+ __chains--;
+ }
+}
+
+#endif /* __GST_PARSE_TRACE */
+
+typedef struct {
+ gchar *src_pad;
+ gchar *sink_pad;
+ GstElement *sink;
+ GstCaps *caps;
+ gulong signal_id;
+ /* FIXME: need to connect to "disposed" signal to clean up, but there is no such signal */
+} DelayedLink;
+
+#ifdef G_HAVE_ISO_VARARGS
+#define SET_ERROR(error, type, ...) G_STMT_START{ \
+ if (error) { \
+ if (*(error)) { \
+ g_warning (__VA_ARGS__); \
+ } else { \
+ g_set_error ((error), GST_PARSE_ERROR, (type), __VA_ARGS__); \
+ }\
+ } \
+}G_STMT_END
+#define ERROR(type, ...) SET_ERROR (((graph_t *) graph)->error, (type), __VA_ARGS__ )
+#ifdef GST_DEBUG_ENABLED
+# define YYDEBUG 1
+# define YYFPRINTF(a, ...) GST_DEBUG (GST_CAT_PIPELINE, __VA_ARGS__)
+#endif
+
+#elif defined(G_HAVE_GNUC_VARARGS)
+
+#define SET_ERROR(error, type, args...) G_STMT_START{ \
+ if (error) { \
+ if (*(error)) { \
+ g_warning ( ## args ); \
+ } else { \
+ g_set_error ((error), GST_PARSE_ERROR, (type), ## args ); \
+ }\
+ } \
+}G_STMT_END
+#define ERROR(type, args...) SET_ERROR (((graph_t *) graph)->error, (type), ## args )
+#ifdef GST_DEBUG_ENABLED
+# define YYDEBUG 1
+# define YYFPRINTF(a, args...) GST_DEBUG (GST_CAT_PIPELINE, ## args )
+#endif
+
+#else
+
+#define SET_ERROR(error, type, ...) G_STMT_START{ \
+ if (error) { \
+ if (*(error)) { \
+ g_warning ("error while parsing"); \
+ } else { \
+ g_set_error ((error), GST_PARSE_ERROR, (type), "error while parsing"); \
+ }\
+ } \
+}G_STMT_END
+#define ERROR(type, ...) SET_ERROR (((graph_t *) graph)->error, (type), "error while parsing")
+#ifdef GST_DEBUG_ENABLED
+# define YYDEBUG 1
+#endif
+
+#endif // G_HAVE_ISO_VARARGS
+
+#define GST_BIN_MAKE(res, type, chain, assign) G_STMT_START{ \
+ GSList *walk; \
+ GstBin *bin = (GstBin *) gst_element_factory_make (type, NULL); \
+ if (!bin) { \
+ ERROR (GST_PARSE_ERROR_NO_SUCH_ELEMENT, "No bin \"%s\"", type); \
+ } else { \
+ walk = chain->elements; \
+ while (walk) { \
+ gst_bin_add (bin, GST_ELEMENT (walk->data)); \
+ walk = walk->next; \
+ } \
+ g_slist_free (chain->elements); \
+ chain->elements = g_slist_prepend (NULL, bin); \
+ res = chain; \
+ /* set the properties now */ \
+ walk = assign; \
+ while (walk) { \
+ gst_parse_element_set ((gchar *) walk->data, GST_ELEMENT (bin), graph); \
+ walk = g_slist_next (walk); \
+ } \
+ g_slist_free (assign); \
+ } \
+}G_STMT_END
+
+#define MAKE_LINK(link, _src, _src_name, _src_pads, _sink, _sink_name, _sink_pads) G_STMT_START{ \
+ link = gst_parse_link_new (); \
+ link->src = _src; \
+ link->sink = _sink; \
+ link->src_name = _src_name; \
+ link->sink_name = _sink_name; \
+ link->src_pads = _src_pads; \
+ link->sink_pads = _sink_pads; \
+ link->caps = NULL; \
+}G_STMT_END
+
+#define MAKE_REF(link, _src, _pads) G_STMT_START{ \
+ gchar *padname = _src; \
+ GSList *pads = _pads; \
+ if (padname) { \
+ while (*padname != '.') padname++; \
+ *padname = '\0'; \
+ padname++; \
+ if (*padname != '\0') \
+ pads = g_slist_prepend (pads, gst_parse_strdup (padname)); \
+ } \
+ MAKE_LINK (link, NULL, _src, pads, NULL, NULL, NULL); \
+}G_STMT_END
+
+static inline void gst_parse_unescape (gchar *str)
+{
+ gchar *walk;
+
+ g_return_if_fail (str != NULL);
+
+ walk = str;
+
+ while (*walk) {
+ if (*walk == '\\')
+ walk++;
+ *str = *walk;
+ str++;
+ walk++;
+ }
+ *str = '\0';
+}
+static void
+gst_parse_element_set (gchar *value, GstElement *element, graph_t *graph)
+{
+ GParamSpec *pspec;
+ gchar *pos = value;
+ /* parse the string, so the property name is null-terminated an pos points
+ to the beginning of the value */
+ while (!g_ascii_isspace (*pos) && (*pos != '=')) pos++;
+ if (*pos == '=') {
+ *pos = '\0';
+ } else {
+ *pos = '\0';
+ pos++;
+ while (g_ascii_isspace (*pos)) pos++;
+ }
+ pos++;
+ while (g_ascii_isspace (*pos)) pos++;
+ if (*pos == '"') {
+ pos++;
+ pos[strlen (pos) - 1] = '\0';
+ }
+ gst_parse_unescape (pos);
+ if ((pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (element), value))) {
+ GValue v = { 0, };
+ GValue v2 = { 0, };
+ g_value_init (&v, G_PARAM_SPEC_VALUE_TYPE(pspec));
+ switch (G_TYPE_FUNDAMENTAL (G_PARAM_SPEC_VALUE_TYPE (pspec))) {
+ case G_TYPE_STRING:
+ g_value_set_string (&v, pos);
+ break;
+ case G_TYPE_BOOLEAN:
+ if (g_ascii_strcasecmp (pos, "true") && g_ascii_strcasecmp (pos, "yes") && g_ascii_strcasecmp (pos, "1")) {
+ g_value_set_boolean (&v, FALSE);
+ } else {
+ g_value_set_boolean (&v, TRUE);
+ }
+ break;
+ case G_TYPE_ENUM: {
+ GEnumValue *en;
+ gchar **endptr;
+ GEnumClass *klass = (GEnumClass *) g_type_class_peek (G_PARAM_SPEC_VALUE_TYPE (pspec));
+ if (klass == NULL) goto error;
+ if (!(en = g_enum_get_value_by_name (klass, pos)))
+ en = g_enum_get_value_by_nick (klass, pos);
+ if (en) {
+ g_value_set_enum (&v, en->value);
+ } else {
+ gint i = strtol (value, endptr, 0);
+ if (**endptr == '\0') {
+ g_value_set_enum (&v, i);
+ } else {
+ goto error;
+ }
+ }
+ break;
+ }
+ case G_TYPE_INT:
+ case G_TYPE_LONG:
+ case G_TYPE_INT64:
+ g_value_init (&v2, G_TYPE_LONG);
+ g_value_set_long (&v2, strtol (pos, NULL, 0));
+ if (!g_value_transform (&v2, &v)) goto error;
+ break;
+ case G_TYPE_UINT:
+ case G_TYPE_ULONG:
+ case G_TYPE_UINT64:
+ g_value_init (&v2, G_TYPE_ULONG);
+ g_value_set_long (&v2, strtoul (pos, NULL, 0));
+ if (!g_value_transform (&v2, &v)) goto error;
+ break;
+ case G_TYPE_FLOAT:
+ case G_TYPE_DOUBLE:
+ g_value_init (&v2, G_TYPE_DOUBLE);
+ g_value_set_double (&v2, atof (pos));
+ if (!g_value_transform (&v2, &v)) goto error;
+ break;
+ default:
+ /* add more */
+ g_warning ("property \"%s\" in element %s cannot be set", value, GST_ELEMENT_NAME (element));
+ goto error;
+ }
+ g_object_set_property (G_OBJECT (element), value, &v);
+ } else {
+ ERROR (GST_PARSE_ERROR_NO_SUCH_PROPERTY, "No property \"%s\" in element \"%s\"", value, GST_ELEMENT_NAME (element));
+ }
+
+out:
+ gst_parse_strfree (value);
+ return;
+
+error:
+ ERROR (GST_PARSE_ERROR_COULD_NOT_SET_PROPERTY, "Could not set property \"%s\" in element \"%s\" to \"%s\"", value, GST_ELEMENT_NAME (element), pos);
+ goto out;
+}
+static inline void
+gst_parse_free_link (link_t *link)
+{
+ gst_parse_strfree (link->src_name);
+ gst_parse_strfree (link->sink_name);
+ g_slist_foreach (link->src_pads, (GFunc) gst_parse_strfree, NULL);
+ g_slist_foreach (link->sink_pads, (GFunc) gst_parse_strfree, NULL);
+ g_slist_free (link->src_pads);
+ g_slist_free (link->sink_pads);
+ gst_caps_unref (link->caps);
+ gst_parse_link_free (link);
+}
+static void
+gst_parse_element_lock (GstElement *element, gboolean lock)
+{
+ GstPad *pad;
+ GList *walk = (GList *) gst_element_get_pad_list (element);
+ gboolean unlocked_peer = FALSE;
+
+ if (gst_element_is_state_locked (element) == lock)
+ return;
+ /* check if we have an unlocked peer */
+ while (walk) {
+ pad = (GstPad *) GST_PAD_REALIZE (walk->data);
+ walk = walk->next;
+ if (GST_PAD_IS_SINK (pad) && GST_PAD_PEER (pad) &&
+ !gst_element_is_state_locked (GST_PAD_PARENT (GST_PAD_PEER (pad)))) {
+ unlocked_peer = TRUE;
+ break;
+ }
+ }
+
+ if (lock && !unlocked_peer) {
+ gst_element_lock_state (element);
+ } else if (!lock) {
+ gst_element_unlock_state (element);
+ } else {
+ return;
+ }
+
+ /* check if there are other pads to (un)lock */
+ walk = (GList *) gst_element_get_pad_list (element);
+ while (walk) {
+ pad = (GstPad *) GST_PAD_REALIZE (walk->data);
+ walk = walk->next;
+ if (GST_PAD_IS_SRC (pad) && GST_PAD_PEER (pad)) {
+ GstElement *next = GST_ELEMENT (GST_OBJECT_PARENT (GST_PAD_PEER (pad)));
+ if (gst_element_is_state_locked (next) != lock)
+ gst_parse_element_lock (next, lock);
+ }
+ }
+}
+static void
+gst_parse_found_pad (GstElement *src, GstPad *pad, gpointer data)
+{
+ DelayedLink *link = (DelayedLink *) data;
+ gboolean restart = FALSE;
+
+ GST_INFO (GST_CAT_PIPELINE, "trying delayed linking %s:%s to %s:%s",
+ GST_ELEMENT_NAME (src), link->src_pad,
+ GST_ELEMENT_NAME (link->sink), link->sink_pad);
+ if (gst_element_get_state (src) == GST_STATE_PLAYING) {
+ restart = TRUE;
+ gst_element_set_state (src, GST_STATE_PAUSED);
+ }
+
+ if (gst_element_link_pads_filtered (src, link->src_pad, link->sink, link->sink_pad, link->caps)) {
+ /* do this here, we don't want to get any problems later on when unlocking states */
+ GST_DEBUG (GST_CAT_PIPELINE, "delayed linking %s:%s to %s:%s worked",
+ GST_ELEMENT_NAME (src), link->src_pad,
+ GST_ELEMENT_NAME (link->sink), link->sink_pad);
+ if (restart) {
+ gst_element_set_state (src, GST_STATE_PLAYING);
+ }
+ g_signal_handler_disconnect (src, link->signal_id);
+ g_free (link->src_pad);
+ g_free (link->sink_pad);
+ gst_caps_unref (link->caps);
+ if (!gst_element_is_state_locked (src))
+ gst_parse_element_lock (link->sink, FALSE);
+ g_free (link);
+ } else {
+ if (restart) {
+ gst_element_set_state (src, GST_STATE_PLAYING);
+ }
+ }
+}
+/* both padnames and the caps may be NULL */
+static gboolean
+gst_parse_perform_delayed_link (GstElement *src, const gchar *src_pad,
+ GstElement *sink, const gchar *sink_pad, GstCaps *caps)
+{
+ GList *templs = gst_element_get_pad_template_list (src);
+
+ while (templs) {
+ GstPadTemplate *templ = (GstPadTemplate *) templs->data;
+ if ((GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SRC) && (GST_PAD_TEMPLATE_PRESENCE(templ) == GST_PAD_SOMETIMES))
+ {
+ /* TODO: maybe we should check if src_pad matches this template's names */
+
+ GST_DEBUG (GST_CAT_PIPELINE, "trying delayed link %s:%s to %s:%s",
+ GST_ELEMENT_NAME (src), src_pad, GST_ELEMENT_NAME (sink), sink_pad);
+
+ DelayedLink *data = g_new (DelayedLink, 1);
+ data->src_pad = g_strdup (src_pad);
+ data->sink = sink;
+ data->sink_pad = g_strdup (sink_pad);
+ data->caps = gst_caps_ref (caps);
+ data->signal_id = g_signal_connect (G_OBJECT (src), "new_pad",
+ G_CALLBACK (gst_parse_found_pad), data);
+ return TRUE;
+ }
+ templs = g_list_next (templs);
+ }
+ return FALSE;
+}
+/**
+ * performs a link and frees the struct. src and sink elements must be given
+ * return values: 0 - link performed
+ * 1 - link delayed
+ * <0 - error
+ */
+static gint
+gst_parse_perform_link (link_t *link, graph_t *graph)
+{
+ GstElement *src = link->src;
+ GstElement *sink = link->sink;
+ GSList *srcs = link->src_pads;
+ GSList *sinks = link->sink_pads;
+ g_assert (GST_IS_ELEMENT (src));
+ g_assert (GST_IS_ELEMENT (sink));
+
+ GST_INFO (GST_CAT_PIPELINE, "linking %s(%s):%u to %s(%s):%u",
+ GST_ELEMENT_NAME (src), link->src_name ? link->src_name : "---", g_slist_length (srcs),
+ GST_ELEMENT_NAME (sink), link->sink_name ? link->sink_name : "---", g_slist_length (sinks));
+
+ if (!srcs || !sinks) {
+ if (gst_element_link_pads_filtered (src, srcs ? (const gchar *) srcs->data : NULL,
+ sink, sinks ? (const gchar *) sinks->data : NULL,
+ link->caps)) {
+ gst_parse_element_lock (sink, gst_element_is_state_locked (src));
+ 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)) {
+ gst_parse_element_lock (sink, TRUE);
+ goto success;
+ } else {
+ goto error;
+ }
+ }
+ }
+ if (g_slist_length (link->src_pads) != g_slist_length (link->src_pads)) {
+ goto error;
+ }
+ while (srcs && sinks) {
+ const gchar *src_pad = (const gchar *) srcs->data;
+ const gchar *sink_pad = (const gchar *) sinks->data;
+ srcs = g_slist_next (srcs);
+ sinks = g_slist_next (sinks);
+ if (gst_element_link_pads_filtered (src, src_pad, sink, sink_pad, link->caps)) {
+ gst_parse_element_lock (sink, gst_element_is_state_locked (src));
+ continue;
+ } else {
+ if (gst_parse_perform_delayed_link (src, src_pad,
+ sink, sink_pad,
+ link->caps)) {
+ gst_parse_element_lock (sink, TRUE);
+ continue;
+ } else {
+ goto error;
+ }
+ }
+ }
+
+success:
+ gst_parse_free_link (link);
+ return 0;
+
+error:
+ ERROR (GST_PARSE_ERROR_LINK, "could not link %s to %s", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink));
+ gst_parse_free_link (link);
+ return -1;
+}
+
static int yylex (void *lvalp);
static int yyerror (const char *s);
%union {
gchar *s;
- GValue *v;
+ chain_t *c;
+ link_t *l;
+ GstElement *e;
+ GSList *p;
graph_t *g;
- link_t *c;
- property_t *p;
- element_t *e;
}
%token <s> IDENTIFIER
-%token <c> LINK BLINK FLINK
-%token <v> VALUE
+%left <s> REF PADREF BINREF
+%token <s> ASSIGNMENT
-%type <s> id
-%type <g> graph bin
+%type <g> graph
+%type <c> chain bin
+%type <l> reference
+%type <l> linkpart link
+%type <p> linklist
%type <e> element
-%type <p> property_value value
-%type <c> link rlink
+%type <p> padlist pads assignments
+
%left '{' '}' '(' ')'
-%left '!' '='
%left ','
-%left '.'
+%right '.'
+%left '!' '='
%pure_parser
%start graph
%%
-id: IDENTIFIER
- ;
-
-value: VALUE { $$ = g_new0 (property_t, 1); $$->value = $1; }
- ;
-
-property_value: id '=' value { $$ = $3; $$->name = $1; }
- ;
-
-element: id { static int i = 0; $$ = g_new0 (element_t, 1);
- $$->type = $1; $$->index = ++i; }
- ;
-
-graph: /* empty */ { $$ = g_new0 (graph_t, 1); *((graph_t**) pgraph) = $$; }
- | graph element { GList *l;
- $$ = $1; l = $$->links_pending;
- $$->elements = g_list_append ($$->elements, $2);
- $$->current = $2;
- if (!$$->first)
- $$->first = $$->current;
- while (l) {
- ((link_t*) l->data)->sink_index = $$->current->index;
- l = g_list_next (l);
- }
- if ($$->links_pending) {
- g_list_free ($$->links_pending);
- $$->links_pending = NULL;
- }
- }
- | graph bin { GList *l; $$ = $1; l = $$->links_pending;
- *((graph_t**) pgraph) = $$;
- $$->bins = g_list_append ($$->bins, $2);
- $2->parent = $$;
- $$->current = $2->first;
- if (!$$->first)
- $$->first = $$->current;
- while (l) {
- ((link_t*) l->data)->sink_index = $$->current->index;
- l = g_list_next (l);
- }
- if ($$->links_pending) {
- g_list_free ($$->links_pending);
- $$->links_pending = NULL;
- }
- $$->current = $2->current;
- }
- | graph link { $$ = $1;
- $$->links = g_list_append ($$->links, $2);
- if ($$->current)
- $2->src_index = $$->current->index;
- if (!$2->sink_name)
- $$->links_pending = g_list_append ($$->links_pending, $2);
- }
- | graph property_value { $$ = $1;
- if (!$$->current) {
- fprintf (stderr, "error: property value assignments must be preceded by an element definition\n");
- YYABORT;
- }
- $$->current->property_values = g_list_append ($$->current->property_values,
- $2);
- }
- ;
-
-bin: '{' graph '}' { $$ = $2; $$->current_bin_type = "thread"; }
- | id '.' '(' graph ')' { $$ = $4; $$->current_bin_type = $1; }
- ;
-
-link: LINK
- | rlink
- ;
-
-rlink: '!' { $$ = g_new0 (link_t, 1); }
- | BLINK { $$ = $1; }
- | FLINK { $$ = $1; }
- | id ',' rlink ',' id
- { $$ = $3;
- $$->src_pads = g_list_prepend ($$->src_pads, $1);
- $$->sink_pads = g_list_append ($$->sink_pads, $5);
- }
- ;
+element: IDENTIFIER { $$ = gst_element_factory_make ($1, NULL);
+ if (!$$) ERROR (GST_PARSE_ERROR_NO_SUCH_ELEMENT, "No element \"%s\"", $1);
+ gst_parse_strfree ($1);
+ }
+ | element ASSIGNMENT { gst_parse_element_set ($2, $1, graph);
+ $$ = $1;
+ }
+ ;
+
+assignments: /* NOP */ { $$ = NULL; }
+ | assignments ASSIGNMENT { $$ = g_slist_prepend ($1, $2); }
+
+bin: '{' assignments chain '}' { GST_BIN_MAKE ($$, "thread", $3, $2); }
+ | '(' assignments chain ')' { GST_BIN_MAKE ($$, "bin", $3, $2); }
+ | BINREF assignments chain ')' { GST_BIN_MAKE ($$, $1, $3, $2);
+ gst_parse_strfree ($1);
+ }
+ ;
+
+pads: PADREF { $$ = g_slist_prepend (NULL, $1); }
+ | PADREF padlist { $$ = $2;
+ $$ = g_slist_prepend ($$, $1);
+ }
+
+padlist: ',' IDENTIFIER { $$ = g_slist_prepend (NULL, $2); }
+ | ',' IDENTIFIER padlist { $$ = g_slist_prepend ($3, $2); }
+ ;
+
+reference: REF { MAKE_REF ($$, $1, NULL); }
+ | REF padlist { MAKE_REF ($$, $1, $2); }
+ ;
+
+linkpart: reference { $$ = $1; }
+ | pads { MAKE_REF ($$, NULL, $1); }
+ | /* NOP */ { MAKE_REF ($$, NULL, NULL); }
+ ;
+
+link: linkpart '!' linkpart { $$ = $1;
+ $$->sink_name = $3->src_name;
+ $$->sink_pads = $3->src_pads;
+ gst_parse_link_free ($3);
+ }
+ ;
+
+linklist: link { $$ = g_slist_prepend (NULL, $1); }
+ | link linklist { $$ = g_slist_prepend ($2, $1); }
+ ;
+
+chain: element { $$ = gst_parse_chain_new ();
+ $$->first = $$->last = $1;
+ $$->front = $$->back = NULL;
+ $$->elements = g_slist_prepend (NULL, $1);
+ }
+ | bin { $$ = $1; }
+ | chain chain { if ($1->back && $2->front) {
+ if (!$1->back->sink_name) {
+ ERROR (GST_PARSE_ERROR_LINK, "link without source element");
+ gst_parse_free_link ($1->back);
+ } else {
+ ((graph_t *) graph)->links = g_slist_prepend (((graph_t *) graph)->links, $1->back);
+ }
+ if (!$2->front->src_name) {
+ ERROR (GST_PARSE_ERROR_LINK, "link without sink element");
+ gst_parse_free_link ($2->front);
+ } else {
+ ((graph_t *) graph)->links = g_slist_prepend (((graph_t *) graph)->links, $2->front);
+ }
+ $1->back = NULL;
+ } else if ($1->back) {
+ if (!$1->back->sink_name) {
+ $1->back->sink = $2->first;
+ } else {
+ ((graph_t *) graph)->links = g_slist_prepend (((graph_t *) graph)->links, $1->back);
+ $1->back = NULL;
+ }
+ } else if ($2->front) {
+ if (!$2->front->src_name) {
+ $2->front->src = $1->last;
+ $1->back = $2->front;
+ } else {
+ ((graph_t *) graph)->links = g_slist_prepend (((graph_t *) graph)->links, $2->front);
+ }
+ }
+
+ if ($1->back)
+ gst_parse_perform_link ($1->back, (graph_t *) graph);
+ $1->last = $2->last;
+ $1->back = $2->back;
+ $1->elements = g_slist_concat ($1->elements, $2->elements);
+ gst_parse_chain_free ($2);
+ $$ = $1;
+ }
+ | link chain { if ($2->front) {
+ if (!$2->front->src_name) {
+ ERROR (GST_PARSE_ERROR_LINK, "link without source element");
+ gst_parse_free_link ($2->front);
+ } else {
+ ((graph_t *) graph)->links = g_slist_prepend (((graph_t *) graph)->links, $2->front);
+ }
+ }
+ if (!$1->sink_name) {
+ $1->sink = $2->first;
+ }
+ $2->front = $1;
+ $$ = $2;
+ }
+
+ | chain linklist { GSList *walk;
+ if ($1->back) {
+ g_slist_prepend ($2, $1->back);
+ $1->back = NULL;
+ } else {
+ if (!((link_t *) $2->data)->src_name) {
+ ((link_t *) $2->data)->src = $1->last;
+ }
+ }
+ walk = $2;
+ while (walk) {
+ link_t *link = (link_t *) walk->data;
+ walk = walk->next;
+ if (!link->sink_name) {
+ ERROR (GST_PARSE_ERROR_LINK, "link without sink element");
+ gst_parse_free_link (link);
+ } else if (!link->src_name && !link->src) {
+ ERROR (GST_PARSE_ERROR_LINK, "link without source element");
+ gst_parse_free_link (link);
+ } else {
+ if (walk) {
+ ((graph_t *) graph)->links = g_slist_prepend (((graph_t *) graph)->links, link);
+ } else {
+ $1->back = link;
+ }
+ }
+ }
+ g_slist_free ($2);
+ $$ = $1;
+ }
+ ;
+
+graph: chain { $$ = (graph_t *) graph;
+ if ($1->front) {
+ if (!$1->front->src_name) {
+ ERROR (GST_PARSE_ERROR_LINK, "link without source element");
+ gst_parse_free_link ($1->front);
+ } else {
+ $$->links = g_slist_prepend ($$->links, $1->front);
+ }
+ $1->front = NULL;
+ }
+ if ($1->back) {
+ if (!$1->back->sink_name) {
+ ERROR (GST_PARSE_ERROR_LINK, "link without sink element");
+ gst_parse_free_link ($1->back);
+ } else {
+ $$->links = g_slist_prepend ($$->links, $1->back);
+ }
+ $1->back = NULL;
+ }
+ $$->chain = $1;
+ }
+ ;
%%
static int
yyerror (const char *s)
{
- fprintf (stderr, "error: %s\n", s);
+ /* FIXME: This should go into the GError somehow, but how? */
+ g_warning ("error: %s\n", s);
return -1;
}
int _gst_parse_yy_scan_string (char*);
-
-graph_t * _gst_parse_launch (const gchar *str, GError **error)
+GstElement *
+_gst_parse_launch (const gchar *str, GError **error)
{
- graph_t *g = NULL;
- gchar *dstr;
-
- g_return_val_if_fail (str != NULL, NULL);
+ graph_t g;
+ gchar *dstr;
+ GSList *walk;
+ GstBin *bin = NULL;
+ GstElement *ret;
+
+ g_return_val_if_fail (str != NULL, NULL);
- dstr = g_strdup (str);
- _gst_parse_yy_scan_string (dstr);
+ g.chain = NULL;
+ g.links = NULL;
+ g.error = error;
+
+#ifdef __GST_PARSE_TRACE
+ GST_DEBUG (GST_CAT_PIPELINE, "TRACE: tracing enabled");
+ __strings = __chains = __links = 0;
+#endif /* __GST_PARSE_TRACE */
+
+ dstr = g_strdup (str);
+ _gst_parse_yy_scan_string (dstr);
#ifdef DEBUG
- _gst_parse_yydebug = 1;
+ yydebug = 1;
#endif
- if (yyparse (&g) != 0) {
- g_set_error (error,
- GST_PARSE_ERROR,
- GST_PARSE_ERROR_SYNTAX,
- "Invalid syntax");
- g_free (dstr);
- return NULL;
- }
+ if (yyparse (&g) != 0) {
+ SET_ERROR (error, GST_PARSE_ERROR_SYNTAX, "Unrecoverable syntax error while parsing pipeline");
- g_assert (g != NULL);
+ goto error1;
+ }
+ g_free (dstr);
+
+ GST_INFO (GST_CAT_PIPELINE, "got %u elements and %u links", g.chain ? g_slist_length (g.chain->elements) : 0, g_slist_length (g.links));
+
+ if (!g.chain) {
+ ret = NULL;
+ } else if (!(((chain_t *) g.chain)->elements->next)) {
+ /* only one toplevel element */
+ ret = (GstElement *) ((chain_t *) g.chain)->elements->data;
+ g_slist_free (((chain_t *) g.chain)->elements);
+ if (GST_IS_BIN (ret))
+ bin = GST_BIN (ret);
+ } else {
+ /* put all elements in our bin */
+ bin = GST_BIN (gst_element_factory_make ("pipeline", NULL));
+ g_assert (bin);
+ walk = g.chain->elements;
+ while (walk) {
+ gst_bin_add (bin, GST_ELEMENT (walk->data));
+ walk = g_slist_next (walk);
+ }
+ g_slist_free (g.chain->elements);
+ ret = GST_ELEMENT (bin);
+ }
+ gst_parse_chain_free (g.chain);
+
+ /* remove links */
+ walk = g.links;
+ while (walk) {
+ link_t *l = (link_t *) walk->data;
+ GstElement *sink;
+ walk = g_slist_next (walk);
+ if (!l->src) {
+ if (l->src_name) {
+ if (bin) {
+ l->src = gst_bin_get_by_name_recurse_up (bin, l->src_name);
+ } else {
+ l->src = strcmp (GST_ELEMENT_NAME (ret), l->src_name) == 0 ? ret : NULL;
+ }
+ }
+ if (!l->src) {
+ SET_ERROR (error, GST_PARSE_ERROR_NO_SUCH_ELEMENT, "No element named \"%s\" - omitting link", l->src_name);
+ gst_parse_free_link (l);
+ continue;
+ }
+ }
+ if (!l->sink) {
+ if (l->sink_name) {
+ if (bin) {
+ l->sink = gst_bin_get_by_name_recurse_up (bin, l->sink_name);
+ } else {
+ l->sink = strcmp (GST_ELEMENT_NAME (ret), l->sink_name) == 0 ? ret : NULL;
+ }
+ }
+ if (!l->sink) {
+ SET_ERROR (error, GST_PARSE_ERROR_NO_SUCH_ELEMENT, "No element named \"%s\" - omitting link", l->sink_name);
+ gst_parse_free_link (l);
+ continue;
+ }
+ }
+ sink = l->sink;
+ gst_parse_perform_link (l, &g);
+ }
+ g_slist_free (g.links);
- g_free (dstr);
+out:
+#ifdef __GST_PARSE_TRACE
+ GST_DEBUG (GST_CAT_PIPELINE, "TRACE: %u strings, %u chains and %u links left", __strings, __chains, __links);
+ if (__strings || __chains || __links) {
+ g_warning ("TRACE: %u strings, %u chains and %u links left", __strings, __chains, __links);
+ }
+#endif /* __GST_PARSE_TRACE */
- /* if the toplevel only contains one bin, make that bin top-level */
- if (g->elements == NULL && g->bins && g->bins->next == NULL) {
- g = (graph_t*)g->bins->data;
- g_free (g->parent);
- g->parent = NULL;
+ return ret;
+
+error1:
+ g_free (dstr);
+
+ if (g.chain) {
+ walk = g.chain->elements;
+ while (walk) {
+ gst_object_unref (GST_OBJECT (walk->data));
+ walk = walk->next;
}
-
- return g;
+ g_slist_free (g.chain->elements);
+ }
+ gst_parse_chain_free (g.chain);
+
+ walk = g.links;
+ while (walk) {
+ gst_parse_free_link ((link_t *) walk->data);
+ walk = walk->next;
+ }
+ g_slist_free (g.links);
+
+ g_assert (*error);
+ ret = NULL;
+
+ goto out;
}
#include <ctype.h>
#include <string.h>
#include "types.h"
-#include <grammar.tab.h>
+#include "../gstinfo.h"
+#include "grammar.tab.h"
-#ifdef G_HAVE_ISO_VARARGS
-
-#ifdef DEBUG
-# define PRINT(...) printf(__VAR_ARGS__)
-#else
-#define PRINT(...)
+#ifdef HAVE_CONFIG_H
+#include <config.h>
#endif
+#ifdef G_HAVE_ISO_VARARGS
+# ifdef GST_DEBUG_ENABLED
+# define PRINT(...) GST_DEBUG (GST_CAT_PIPELINE, "flex: "__VA_ARGS__)
+# endif
#elif defined(G_HAVE_GNUC_VARARGS)
-
-#ifdef DEBUG
-# define PRINT(a...) printf(##a)
+# ifdef GST_DEBUG_ENABLED
+# define PRINT(...) GST_DEBUG (GST_CAT_PIPELINE, "flex: "##args)
+# endif
#else
-#define PRINT(a...)
-#endif
-
-#endif
-
-#define CHAR(x) PRINT ("char: %c\n", *yytext); return *yytext;
+# ifdef GST_DEBUG_ENABLED
+# define PRINT(a...) GST_DEBUG (GST_CAT_PIPELINE, "flex: "##a)
+# endif
+#endif // G_HAVE_ISO_VARARGS
#define YY_DECL int _gst_parse_yylex (YYSTYPE *lvalp)
#define YY_NO_UNPUT
%}
-_integer [-+]?[[:digit:]]+
-_double [-+]?[[:digit:]]+"."*[[:digit:]]*
-_number {_integer}|{_double}
-_boolean "true"|"false"|"TRUE"|"FALSE"
-_identifier [[:alpha:]][[:alnum:]\-_%:]*
-_char ([^[:space:]])|("\\".)
+_operators [(){}.:!,=]
+_identifier [[:alpha:]][[:alnum:]\-_%]*
+
+_char ("\\".)|([^[:space:]])
_string {_char}+|("\""([^\"]|"\\\"")*"\"")
+
_comma [[:space:]]*","[[:space:]]*
_assign [[:space:]]*"="[[:space:]]*
-_caps_type_string "fourcc"|"string"
-_caps_type_double "float"
-_caps_string {_string}{_assign}{_caps_type_string}[[:space:]]+{_string}
-_caps_int {_string}{_assign}"int"[[:space:]]+{_integer}
-_caps_double {_string}{_assign}{_caps_type_double}[[:space:]]+{_double}
-_caps_boolean {_string}{_assign}"boolean"[[:space:]]+{_boolean}
-_caps_pair {_caps_string}|{_caps_int}|{_caps_double}|{_caps_boolean}
-_caps {_string}({_comma}{_caps_pair})*
-_llink ({_identifier}\.)?{_identifier}!
-_rlink !({_identifier}\.)?{_identifier}
-_blink ({_identifier}\.)?{_identifier}!({_identifier}\.)?{_identifier}
-_flink ({_identifier}\.)?{_identifier}!{_caps}!({_identifier}\.)?{_identifier}
+
+/* we must do this here, because nearly everything matches a {_string} */
+_assignment {_identifier}{_assign}{_string}
+
+/* get pad/element references and stuff with dots right */
+_padref "."{_identifier}
+_ref {_identifier}"."{_identifier}?
+_binref {_identifier}[[:space:]]*"."[[:space:]]*"("
%x value
%option noyywrap
%%
-<value>{
- {_integer} {
- PRINT ("An integer: %s (%d)\n", yytext,
- atoi (yytext));
- lvalp->v = g_new0 (GValue, 1);
- g_value_init (lvalp->v, G_TYPE_INT);
- g_value_set_int (lvalp->v, atoi (yytext));
- BEGIN (INITIAL);
- return VALUE;
- }
-
- {_double} {
- PRINT ("A double: %s (%g)\n", yytext, atof (yytext));
- lvalp->v = g_new0 (GValue, 1);
- g_value_init (lvalp->v, G_TYPE_DOUBLE);
- g_value_set_double (lvalp->v, atof (yytext));
- BEGIN (INITIAL);
- return VALUE;
- }
-
- {_boolean} {
- PRINT ("A boolean: %s (%d)\n", yytext, tolower (*yytext) == 't' ? 1 : 0);
- lvalp->v = g_new0 (GValue, 1);
- g_value_init (lvalp->v, G_TYPE_BOOLEAN);
- g_value_set_boolean (lvalp->v, tolower (*yytext) == 't' ? TRUE : FALSE);
- BEGIN (INITIAL);
- return VALUE;
- }
-
- {_string} {
- if (*yytext == '"') {
- yytext++;
- *(yytext + strlen (yytext) - 1) = '\0';
- }
- _gst_parse_unescape (yytext);
- PRINT ("A string: \"%s\"\n", yytext);
- lvalp->v = g_new0 (GValue, 1);
- g_value_init (lvalp->v, G_TYPE_STRING);
- g_value_set_string (lvalp->v, yytext);
- BEGIN (INITIAL);
- return VALUE;
- }
-
- [[:space:]]+ { /* PRINT ("space: [%s]\n", yytext); */ }
+{_assignment} {
+ /* "=" */
+ PRINT ("ASSIGNMENT: %s\n", yytext);
+ lvalp->s = gst_parse_strdup (yytext);
+ BEGIN (INITIAL);
+ return ASSIGNMENT;
}
-{_llink} {
- gchar *d1, *q;
- lvalp->c = g_new0 (link_t, 1);
- PRINT ("An link: %s\n", yytext);
- q = strchr (yytext, '!');
- d1 = strchr (yytext, '.');
- if (d1) {
- lvalp->c->src_name = g_strndup (yytext, d1 - yytext);
- lvalp->c->src_pads = g_list_append (lvalp->c->src_pads, g_strndup (d1 + 1, q - d1 - 1));
- } else {
- lvalp->c->src_pads = g_list_append (lvalp->c->src_pads, g_strndup (yytext, q - yytext));
- }
-
- return LINK;
+{_padref} {
+ yytext++;
+ PRINT ("PADREF: %s\n", yytext);
+ lvalp->s = gst_parse_strdup (yytext);
+ BEGIN (INITIAL);
+ return PADREF;
}
-{_rlink} {
- gchar *d2;
- lvalp->c = g_new0 (link_t, 1);
- PRINT ("An rlink: %s\n", yytext);
- d2 = strchr (yytext, '.');
- if (d2) {
- lvalp->c->sink_name = g_strndup (yytext + 1, d2 - yytext - 1);
- lvalp->c->sink_pads = g_list_append (lvalp->c->sink_pads, g_strdup (d2 + 1));
- } else {
- lvalp->c->sink_pads = g_list_append (lvalp->c->sink_pads, g_strdup (yytext + 1));
- }
-
- return LINK;
+{_ref} {
+ PRINT ("REF: %s\n", yytext);
+ lvalp->s = gst_parse_strdup (yytext);
+ BEGIN (INITIAL);
+ return REF;
}
-{_blink} {
- gchar *d1, *d2, *q;
- lvalp->c = g_new0 (link_t, 1);
- PRINT ("A blink: %s\n", yytext);
- q = strchr (yytext, '!');
- d1 = strchr (yytext, '.');
- d2 = strchr (q, '.');
- if (d1 && d1 < q) {
- lvalp->c->src_name = g_strndup (yytext, d1 - yytext);
- lvalp->c->src_pads = g_list_append (lvalp->c->src_pads, g_strndup (d1 + 1, q - d1 - 1));
- } else {
- lvalp->c->src_pads = g_list_append (lvalp->c->src_pads, g_strndup (yytext, q - yytext));
- }
-
- if (d2) {
- lvalp->c->sink_name = g_strndup (q + 1, d2 - q - 1);
- lvalp->c->sink_pads = g_list_append (lvalp->c->sink_pads, g_strdup (d2 + 1));
- } else {
- lvalp->c->sink_pads = g_list_append (lvalp->c->sink_pads, g_strdup (q + 1));
- }
-
- return BLINK;
-}
-
-{_flink} {
- gchar *d1, *d2, *q1, *q2, *a1, *m1;
- gchar *mime;
- GstProps *props;
-
- lvalp->c = g_new0 (link_t, 1);
- PRINT ("An flink: %s\n", yytext);
- q1 = strchr (yytext, '!');
- d1 = strchr (yytext, '.');
- q2 = strchr (q1+1, '!');
- d2 = strchr (q2, '.');
- if (d1 && d1 < q1) {
- lvalp->c->src_name = g_strndup (yytext, d1 - yytext);
- lvalp->c->src_pads = g_list_append (lvalp->c->src_pads, g_strndup (d1 + 1, q1 - d1 - 1));
- } else {
- lvalp->c->src_pads = g_list_append (lvalp->c->src_pads, g_strndup (yytext, q1 - yytext));
- }
-
- if (d2) {
- lvalp->c->sink_name = g_strndup (q2 + 1, d2 - q2 - 1);
- lvalp->c->sink_pads = g_list_append (lvalp->c->sink_pads, g_strdup (d2 + 1));
- } else {
- lvalp->c->sink_pads = g_list_append (lvalp->c->sink_pads, g_strdup (q2 + 1));
- }
- /* parse mime type */
- m1 = strchr (q1 + 1, ',');
- mime = g_strndup (q1 + 1, m1 - q1 - 1);
-
- props = gst_props_empty_new ();
-
- a1 = strchr (m1 + 1, ',');
- if (a1 == NULL)
- a1 = q2;
-
- while (a1 && a1 <= q2) {
- gchar *key, *t, *v;
- gchar *k1, *k2;
- GstPropsEntry *entry = NULL;
-
- k1 = strchr (m1, '=');
- key = g_strstrip (g_strndup (m1 + 1, k1 - m1 -1));
-
- k1++;
-
- while (g_ascii_isspace (*k1)) k1++;
-
- k2 = strchr (k1, ' ');
- t = g_strstrip (g_strndup (k1, k2 - k1));
-
- while (g_ascii_isspace (*k2)) k2++;
-
- v = g_strstrip (g_strndup (k2, a1 - k2));
-
- if (!strcmp (t, "string")) {
- entry = gst_props_entry_new (key, GST_PROPS_STRING (v));
- }
- else if (!strcmp (t, "fourcc")) {
- entry = gst_props_entry_new (key, GST_PROPS_FOURCC (GST_STR_FOURCC(v)));
- }
- else if (!strcmp (t, "float")) {
- gfloat f;
- sscanf (v, "%f", &f);
- entry = gst_props_entry_new (key, GST_PROPS_FLOAT (f));
- }
- else if (!strcmp (t, "int")) {
- gint i;
- sscanf (v, "%d", &i);
- entry = gst_props_entry_new (key, GST_PROPS_INT (i));
- }
- else if (!strcmp (t, "boolean")) {
- gboolean b;
- b = (!strcmp (v, "true") || ! strcmp (v, "TRUE"));
- entry = gst_props_entry_new (key, GST_PROPS_BOOLEAN (b));
- }
- gst_props_add_entry (props, entry);
-
- m1 = a1;
- if (a1 < q2) {
- a1 = strchr (m1 + 1, ',');
- if (a1 == NULL)
- a1 = q2;
- }
- else
- break;
- }
- lvalp->c->caps = gst_caps_new ("parse_caps", mime, props);
-
- return FLINK;
+{_binref} {
+ gchar *pos = yytext;
+ while (!g_ascii_isspace (*pos) && (*pos != '.')) pos++;
+ *pos = '\0';
+ PRINT ("BINREF: %s\n", yytext);
+ lvalp->s = gst_parse_strdup (yytext);
+ BEGIN (INITIAL);
+ return BINREF;
}
{_identifier} {
- PRINT ("An identifier: %s\n", yytext);
- lvalp->s = g_strdup (yytext);
+ PRINT ("IDENTIFIER: %s\n", yytext);
+ lvalp->s = gst_parse_strdup (yytext);
+ BEGIN (INITIAL);
return IDENTIFIER;
}
-"=" { BEGIN (value); CHAR ('='); }
-"@" { CHAR ('@'); }
-"." { CHAR ('.'); }
-"," { CHAR (','); }
-"{" { CHAR ('{'); }
-"}" { CHAR ('}'); }
-"[" { CHAR ('['); }
-"]" { CHAR (']'); }
-"(" { CHAR ('('); }
-")" { CHAR (')'); }
-"!" { CHAR ('!'); }
-"+" { CHAR ('+'); }
+{_operators} { PRINT ("OPERATOR: [%s]\n", yytext); return *yytext; }
-[[:space:]]+ { PRINT ("space: [%s]\n", yytext); }
+[[:space:]]+ { PRINT ("SPACE: [%s]\n", yytext); }
. {
- printf ("unknown: %s\n", yytext);
+ printf ("???: %s\n", yytext);
return *yytext;
}