parser: update for childproxy api changes
[platform/upstream/gstreamer.git] / gst / parse / grammar.y
index 7940872..b48072e 100644 (file)
@@ -1,17 +1,19 @@
 %{
+#include "../gst_private.h"
+
 #include <glib-object.h>
 #include <glib.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 
-#include "../gst_private.h"
 #include "../gst-i18n-lib.h"
 
 #include "../gstconfig.h"
 #include "../gstparse.h"
 #include "../gstinfo.h"
 #include "../gsterror.h"
+#include "../gststructure.h"
 #include "../gsturi.h"
 #include "../gstutils.h"
 #include "../gstvalue.h"
  * Don't start the message with a capital, and don't end them with a period,
  * as they will be presented inside a sentence/error.
  */
-  
+
 #define YYERROR_VERBOSE 1
-#define YYLEX_PARAM   scanner
+#define YYLEX_PARAM scanner
+
+#define YYENABLE_NLS 0
+
+#ifndef YYLTYPE_IS_TRIVIAL
+#define YYLTYPE_IS_TRIVIAL 0
+#endif
 
 typedef void* yyscan_t;
 
-int _gst_parse_yylex (void * yylval_param , yyscan_t yyscanner);
-int _gst_parse_yylex_init (yyscan_t scanner);
-int _gst_parse_yylex_destroy (yyscan_t scanner);
-struct yy_buffer_state * _gst_parse_yy_scan_string (char* , yyscan_t);
+int priv_gst_parse_yylex (void * yylval_param , yyscan_t yyscanner);
+int priv_gst_parse_yylex_init (yyscan_t scanner);
+int priv_gst_parse_yylex_destroy (yyscan_t scanner);
+struct yy_buffer_state * priv_gst_parse_yy_scan_string (char* , yyscan_t);
 void _gst_parse_yypush_buffer_state (void * new_buffer ,yyscan_t yyscanner );
 void _gst_parse_yypop_buffer_state (yyscan_t yyscanner );
 
-
 #ifdef __GST_PARSE_TRACE
 static guint __strings;
 static guint __links;
@@ -43,7 +50,7 @@ static guint __chains;
 gchar *
 __gst_parse_strdup (gchar *org)
 {
-  gchar *ret; 
+  gchar *ret;
   __strings++;
   ret = g_strdup (org);
   /* g_print ("ALLOCATED STR   (%3u): %p %s\n", __strings, ret, ret); */
@@ -63,7 +70,7 @@ link_t *__gst_parse_link_new ()
 {
   link_t *ret;
   __links++;
-  ret = g_new0 (link_t, 1);
+  ret = g_slice_new0 (link_t);
   /* g_print ("ALLOCATED LINK  (%3u): %p\n", __links, ret); */
   return ret;
 }
@@ -72,7 +79,7 @@ __gst_parse_link_free (link_t *data)
 {
   if (data) {
     /* g_print ("FREEING LINK    (%3u): %p\n", __links - 1, data); */
-    g_free (data);
+    g_slice_free (link_t, data);
     g_return_if_fail (__links > 0);
     __links--;
   }
@@ -82,7 +89,7 @@ __gst_parse_chain_new ()
 {
   chain_t *ret;
   __chains++;
-  ret = g_new0 (chain_t, 1);
+  ret = g_slice_new0 (chain_t);
   /* g_print ("ALLOCATED CHAIN (%3u): %p\n", __chains, ret); */
   return ret;
 }
@@ -90,7 +97,7 @@ void
 __gst_parse_chain_free (chain_t *data)
 {
   /* g_print ("FREEING CHAIN   (%3u): %p\n", __chains - 1, data); */
-  g_free (data);
+  g_slice_free (chain_t, data);
   g_return_if_fail (__chains > 0);
   __chains--;
 }
@@ -103,11 +110,15 @@ typedef struct {
   GstElement *sink;
   GstCaps *caps;
   gulong signal_id;
-  /* FIXME: need to connect to "disposed" signal to clean up,
-   * but there is no such signal */
 } DelayedLink;
 
-/*** define SET_ERROR and ERROR macros/functions */
+typedef struct {
+  gchar *name;
+  gchar *value_str;
+  gulong signal_id;
+} DelayedSet;
+
+/*** define SET_ERROR macro/function */
 
 #ifdef G_HAVE_ISO_VARARGS
 
@@ -119,9 +130,6 @@ G_STMT_START { \
   } \
 } G_STMT_END
 
-#  define ERROR(type, ...) \
-  SET_ERROR (((graph_t *) graph)->error, (type), __VA_ARGS__ )
-
 #elif defined(G_HAVE_GNUC_VARARGS)
 
 #  define SET_ERROR(error, type, args...) \
@@ -132,9 +140,6 @@ G_STMT_START { \
   } \
 } G_STMT_END
 
-#  define ERROR(type, args...) \
-  SET_ERROR (((graph_t *) graph)->error,(type) , args )
-
 #else
 
 static inline void
@@ -150,7 +155,7 @@ SET_ERROR (GError **error, gint type, const char *format, ...)
       va_start (varargs, format);
       string = g_strdup_vprintf (format, varargs);
       va_end (varargs);
-      
+
       g_set_error (error, GST_PARSE_ERROR, type, string);
 
       g_free (string);
@@ -173,18 +178,14 @@ SET_ERROR (GError **error, gint type, const char *format, ...)
 /* #  define YYFPRINTF(a, ...) GST_CAT_DEBUG (GST_CAT_PIPELINE, __VA_ARGS__) */
 #    define YYFPRINTF(a, ...) \
 G_STMT_START { \
-     gchar *temp = g_strdup_printf (__VA_ARGS__); \
-     GST_CAT_LOG (GST_CAT_PIPELINE, temp); \
-     g_free (temp); \
+     GST_CAT_LOG (GST_CAT_PIPELINE, __VA_ARGS__); \
 } G_STMT_END
 
 #  elif defined(G_HAVE_GNUC_VARARGS)
 
 #    define YYFPRINTF(a, args...) \
 G_STMT_START { \
-     gchar *temp = g_strdup_printf ( args ); \
-     GST_CAT_LOG (GST_CAT_PIPELINE, temp); \
-     g_free (temp); \
+     GST_CAT_LOG (GST_CAT_PIPELINE, args); \
 } G_STMT_END
 
 #  else
@@ -194,7 +195,7 @@ YYPRINTF(const char *format, ...)
 {
   va_list varargs;
   gchar *temp;
-  
+
   va_start (varargs, format);
   temp = g_strdup_vprintf (format, varargs);
   GST_CAT_LOG (GST_CAT_PIPELINE, "%s", temp);
@@ -206,19 +207,34 @@ YYPRINTF(const char *format, ...)
 
 #endif /* GST_DISABLE_GST_DEBUG */
 
-#define GST_BIN_MAKE(res, type, chainval, assign) \
+#define ADD_MISSING_ELEMENT(graph,name) G_STMT_START {                      \
+    if ((graph)->ctx) {                                                     \
+      (graph)->ctx->missing_elements =                                      \
+          g_list_append ((graph)->ctx->missing_elements, g_strdup (name));  \
+    } } G_STMT_END
+
+static void
+no_free (gconstpointer foo)
+{
+  /* do nothing */
+}
+
+#define GST_BIN_MAKE(res, type, chainval, assign, type_string_free_func) \
 G_STMT_START { \
   chain_t *chain = chainval; \
   GSList *walk; \
   GstBin *bin = (GstBin *) gst_element_factory_make (type, NULL); \
   if (!chain) { \
-    SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_EMPTY_BIN, \
+    SET_ERROR (graph->error, GST_PARSE_ERROR_EMPTY_BIN, \
         _("specified empty bin \"%s\", not allowed"), type); \
     g_slist_foreach (assign, (GFunc) gst_parse_strfree, NULL); \
     g_slist_free (assign); \
+    gst_object_unref (bin); \
+    type_string_free_func (type); /* Need to clean up the string */ \
     YYERROR; \
   } else if (!bin) { \
-    SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_NO_SUCH_ELEMENT, \
+    ADD_MISSING_ELEMENT(graph, type); \
+    SET_ERROR (graph->error, GST_PARSE_ERROR_NO_SUCH_ELEMENT, \
         _("no bin \"%s\", skipping"), type); \
     g_slist_foreach (assign, (GFunc) gst_parse_strfree, NULL); \
     g_slist_free (assign); \
@@ -263,60 +279,191 @@ G_STMT_START { \
 } G_STMT_END
 
 static void
+gst_parse_free_delayed_set (DelayedSet *set)
+{
+  g_free(set->name);
+  g_free(set->value_str);
+  g_slice_free(DelayedSet, set);
+}
+
+static void gst_parse_new_child(GstChildProxy *child_proxy, GObject *object,
+                                gpointer data);
+
+static void
+gst_parse_add_delayed_set (GstElement *element, gchar *name, gchar *value_str)
+{
+  DelayedSet *data = g_slice_new0 (DelayedSet);
+
+  GST_CAT_LOG_OBJECT (GST_CAT_PIPELINE, element, "delaying property set %s to %s",
+    name, value_str);
+
+  data->name = g_strdup(name);
+  data->value_str = g_strdup(value_str);
+  data->signal_id = g_signal_connect_data(element, "child-added",
+      G_CALLBACK (gst_parse_new_child), data, (GClosureNotify)
+      gst_parse_free_delayed_set, (GConnectFlags) 0);
+
+  /* FIXME: we would need to listen on all intermediate bins too */
+  if (GST_IS_BIN (element)) {
+    gchar **names, **current;
+    GstElement *parent, *child;
+
+    current = names = g_strsplit (name, "::", -1);
+    parent = gst_bin_get_by_name (GST_BIN_CAST (element), current[0]);
+    current++;
+    while (parent && current[0]) {
+      child = gst_bin_get_by_name (GST_BIN (parent), current[0]);
+      if (!child && current[1]) {
+        char *sub_name = g_strjoinv ("::", &current[0]);
+
+        gst_parse_add_delayed_set(parent, sub_name, value_str);
+        g_free (sub_name);
+      }
+      parent = child;
+      current++;
+    }
+    g_strfreev (names);
+  }
+}
+
+static void gst_parse_new_child(GstChildProxy *child_proxy, GObject *object,
+                                gpointer data)
+{
+  DelayedSet *set = (DelayedSet *) data;
+  GParamSpec *pspec;
+  GValue v = { 0, };
+  GstObject *target = NULL;
+  GType value_type;
+
+  GST_CAT_LOG_OBJECT (GST_CAT_PIPELINE, child_proxy, "new child %s, checking property %s",
+      GST_OBJECT_NAME(object), set->name);
+
+  if (gst_child_proxy_lookup (G_OBJECT (child_proxy), set->name, &target, &pspec)) {
+    gboolean got_value = FALSE;
+
+    value_type = pspec->value_type;
+
+    GST_CAT_LOG_OBJECT (GST_CAT_PIPELINE, child_proxy, "parsing delayed property %s as a %s from %s",
+      pspec->name, g_type_name (value_type), set->value_str);
+    g_value_init (&v, value_type);
+    if (gst_value_deserialize (&v, set->value_str))
+      got_value = TRUE;
+    else if (g_type_is_a (value_type, GST_TYPE_ELEMENT)) {
+       GstElement *bin;
+
+       bin = gst_parse_bin_from_description (set->value_str, TRUE, NULL);
+       if (bin) {
+         g_value_set_object (&v, bin);
+         got_value = TRUE;
+       }
+    }
+    g_signal_handler_disconnect (child_proxy, set->signal_id);
+    if (!got_value)
+      goto error;
+    g_object_set_property (G_OBJECT (target), pspec->name, &v);
+  } else {
+    const gchar *obj_name = GST_OBJECT_NAME(object);
+    gint len = strlen (obj_name);
+
+    /* do a delayed set */
+    if ((strlen (set->name) > (len + 2)) && !strncmp (set->name, obj_name, len) && !strncmp (&set->name[len], "::", 2)) {
+      gst_parse_add_delayed_set (GST_ELEMENT(child_proxy), set->name, set->value_str);
+    }
+  }
+
+out:
+  if (G_IS_VALUE (&v))
+    g_value_unset (&v);
+  if (target)
+    gst_object_unref (target);
+  return;
+
+error:
+  GST_CAT_ERROR (GST_CAT_PIPELINE, "could not set property \"%s\" in element \"%s\"",
+        pspec->name, GST_ELEMENT_NAME (target));
+  goto out;
+}
+
+static void
 gst_parse_element_set (gchar *value, GstElement *element, graph_t *graph)
 {
   GParamSpec *pspec;
   gchar *pos = value;
-  GValue v = { 0, }; 
-  GstObject *target;
+  GValue v = { 0, };
+  GstObject *target = NULL;
   GType value_type;
 
+  /* do nothing if assignment is for missing element */
+  if (element == NULL)
+    goto out;
+
   /* 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'; 
+  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++; 
+    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 (gst_child_proxy_lookup (GST_OBJECT (element), value, &target, &pspec)) { 
-    value_type = G_PARAM_SPEC_VALUE_TYPE (pspec); 
-    GST_LOG ("parsing property %s as a %s", pspec->name,
+  if (gst_child_proxy_lookup (G_OBJECT (element), value, &target, &pspec)) {
+    gboolean got_value = FALSE;
+
+    value_type = pspec->value_type;
+
+    GST_CAT_LOG_OBJECT (GST_CAT_PIPELINE, element, "parsing property %s as a %s", pspec->name,
       g_type_name (value_type));
     g_value_init (&v, value_type);
-    if (!gst_value_deserialize (&v, pos))
+    if (gst_value_deserialize (&v, pos))
+      got_value = TRUE;
+    else if (g_type_is_a (value_type, GST_TYPE_ELEMENT)) {
+       GstElement *bin;
+
+       bin = gst_parse_bin_from_description (pos, TRUE, NULL);
+       if (bin) {
+         g_value_set_object (&v, bin);
+         got_value = TRUE;
+       }
+    }
+    if (!got_value)
       goto error;
     g_object_set_property (G_OBJECT (target), pspec->name, &v);
-    gst_object_unref (target);
-  } else { 
-    SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_NO_SUCH_PROPERTY, \
-        _("no property \"%s\" in element \"%s\""), value, \
-        GST_ELEMENT_NAME (element)); 
+  } else {
+    /* do a delayed set */
+    if (GST_IS_CHILD_PROXY (element)) {
+      gst_parse_add_delayed_set (element, value, pos);
+    }
+    else {
+      SET_ERROR (graph->error, GST_PARSE_ERROR_NO_SUCH_PROPERTY, \
+          _("no property \"%s\" in element \"%s\""), value, \
+          GST_ELEMENT_NAME (element));
+    }
   }
 
 out:
   gst_parse_strfree (value);
   if (G_IS_VALUE (&v))
     g_value_unset (&v);
+  if (target)
+    gst_object_unref (target);
   return;
-  
+
 error:
-  gst_object_unref (target);
-  SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_COULD_NOT_SET_PROPERTY,
-         _("could not set property \"%s\" in element \"%s\" to \"%s\""), 
-        value, GST_ELEMENT_NAME (element), pos); 
+  SET_ERROR (graph->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)
 {
@@ -327,90 +474,24 @@ gst_parse_free_link (link_t *link)
   g_slist_free (link->src_pads);
   g_slist_free (link->sink_pads);
   if (link->caps) gst_caps_unref (link->caps);
-  gst_parse_link_free (link);  
+  gst_parse_link_free (link);
 }
 
 static void
-gst_parse_element_lock (GstElement *element, gboolean lock)
+gst_parse_free_delayed_link (DelayedLink *link)
 {
-  GstPad *pad;
-  GstIterator *pads;
-  gboolean unlocked_peer = FALSE;
-  gboolean done = FALSE;
-  GList *walk;
-  
-  if (gst_element_is_locked_state (element) == lock)
-    return;
-
-  return;
-
-  /* check if we have an unlocked peer */
-  pads = gst_element_iterate_pads (element);
-  while (!done) {
-    gpointer data;
-    switch (gst_iterator_next (pads, &data)) {
-      case GST_ITERATOR_OK:
-      {
-        GstPad *pad = GST_PAD_CAST (data);
-
-        if (GST_PAD_IS_SINK (pad) && GST_PAD_PEER (pad) &&
-            !gst_element_is_locked_state (
-                GST_PAD_PARENT (GST_PAD_PEER (pad)))) {
-          unlocked_peer = TRUE;
-         done = TRUE;
-        }
-       gst_object_unref (GST_OBJECT (pad));
-        break;
-      }
-      case GST_ITERATOR_RESYNC:
-        unlocked_peer = FALSE;
-        gst_iterator_resync (pads);
-        break;
-      case GST_ITERATOR_DONE:
-        done = TRUE;
-        break;
-      default:
-        g_assert_not_reached ();
-        break;
-    }
-  }
-  gst_iterator_free (pads);
-
-  if (!(lock && unlocked_peer)) {
-    GST_CAT_DEBUG (GST_CAT_PIPELINE, "setting locked state on element");
-    gst_element_set_locked_state (element, lock);
-    if (!lock)
-    {
-      /* try to sync state with parent */
-      GST_CAT_DEBUG (GST_CAT_PIPELINE,
-          "trying to sync state of element with parent");
-      /* FIXME: it would be nice if we can figure out why it failed
-         (e.g. caps nego) and give an error about that instead. */
-      if (gst_element_set_state (element, GST_STATE_PLAYING)
-          == GST_STATE_CHANGE_FAILURE)
-        GST_ELEMENT_ERROR (element, CORE, STATE_CHANGE, (NULL), (NULL));
-    }
-  } else {
-    return;
-  }
-  
-  /* check if there are other pads to (un)lock */
-  walk = (GList *) element->pads;
-  for  (; walk; walk = walk->next) {
-    pad = GST_PAD_CAST (walk->data);
-    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_locked_state (next) != lock)
-        gst_parse_element_lock (next, lock);
-    }
-  }
+  g_free (link->src_pad);
+  g_free (link->sink_pad);
+  if (link->caps) gst_caps_unref (link->caps);
+  g_slice_free (DelayedLink, link);
 }
+
 static void
 gst_parse_found_pad (GstElement *src, GstPad *pad, gpointer data)
 {
-  DelayedLink *link = (DelayedLink *) data;
-  
-  GST_CAT_INFO (GST_CAT_PIPELINE, "trying delayed linking %s:%s to %s:%s", 
+  DelayedLink *link = data;
+
+  GST_CAT_INFO (GST_CAT_PIPELINE, "trying delayed linking %s:%s to %s:%s",
                 GST_STR_NULL (GST_ELEMENT_NAME (src)), GST_STR_NULL (link->src_pad),
                 GST_STR_NULL (GST_ELEMENT_NAME (link->sink)), GST_STR_NULL (link->sink_pad));
 
@@ -418,37 +499,32 @@ gst_parse_found_pad (GstElement *src, GstPad *pad, gpointer data)
       link->sink_pad, link->caps)) {
     /* do this here, we don't want to get any problems later on when
      * unlocking states */
-    GST_CAT_DEBUG (GST_CAT_PIPELINE, "delayed linking %s:%s to %s:%s worked", 
+    GST_CAT_DEBUG (GST_CAT_PIPELINE, "delayed linking %s:%s to %s:%s worked",
                           GST_STR_NULL (GST_ELEMENT_NAME (src)), GST_STR_NULL (link->src_pad),
                           GST_STR_NULL (GST_ELEMENT_NAME (link->sink)), GST_STR_NULL (link->sink_pad));
     g_signal_handler_disconnect (src, link->signal_id);
-    g_free (link->src_pad);
-    g_free (link->sink_pad);
-    if (link->caps) gst_caps_unref (link->caps);
-    if (!gst_element_is_locked_state (src))
-      gst_parse_element_lock (link->sink, FALSE);
-    g_free (link);
   }
 }
+
 /* both padnames and the caps may be NULL */
 static gboolean
-gst_parse_perform_delayed_link (GstElement *src, const gchar *src_pad, 
+gst_parse_perform_delayed_link (GstElement *src, const gchar *src_pad,
                                 GstElement *sink, const gchar *sink_pad,
                                 GstCaps *caps)
 {
   GList *templs = gst_element_class_get_pad_template_list (
       GST_ELEMENT_GET_CLASS (src));
-        
+
   for (; templs; templs = templs->next) {
     GstPadTemplate *templ = (GstPadTemplate *) templs->data;
     if ((GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SRC) &&
         (GST_PAD_TEMPLATE_PRESENCE(templ) == GST_PAD_SOMETIMES))
     {
-      DelayedLink *data = g_new (DelayedLink, 1); 
-      
+      DelayedLink *data = g_slice_new (DelayedLink);
+
       /* TODO: maybe we should check if src_pad matches this template's names */
 
-      GST_CAT_DEBUG (GST_CAT_PIPELINE, "trying delayed link %s:%s to %s:%s", 
+      GST_CAT_DEBUG (GST_CAT_PIPELINE, "trying delayed link %s:%s to %s:%s",
                      GST_STR_NULL (GST_ELEMENT_NAME (src)), GST_STR_NULL (src_pad),
                      GST_STR_NULL (GST_ELEMENT_NAME (sink)), GST_STR_NULL (sink_pad));
 
@@ -460,13 +536,15 @@ gst_parse_perform_delayed_link (GstElement *src, const gchar *src_pad,
       } else {
        data->caps = NULL;
       }
-      data->signal_id = g_signal_connect (G_OBJECT (src), "pad-added", 
-          G_CALLBACK (gst_parse_found_pad), data);
+      data->signal_id = g_signal_connect_data (src, "pad-added",
+          G_CALLBACK (gst_parse_found_pad), data,
+          (GClosureNotify) gst_parse_free_delayed_link, (GConnectFlags) 0);
       return TRUE;
     }
   }
   return FALSE;
 }
+
 /*
  * performs a link and frees the struct. src and sink elements must be given
  * return values   0 - link performed
@@ -482,9 +560,9 @@ gst_parse_perform_link (link_t *link, graph_t *graph)
   GSList *sinks = link->sink_pads;
   g_assert (GST_IS_ELEMENT (src));
   g_assert (GST_IS_ELEMENT (sink));
-  
+
   GST_CAT_INFO (GST_CAT_PIPELINE,
-      "linking %s:%s to %s:%s (%u/%u) with caps \"%" GST_PTR_FORMAT "\"", 
+      "linking %s:%s to %s:%s (%u/%u) with caps \"%" GST_PTR_FORMAT "\"",
       GST_ELEMENT_NAME (src), link->src_name ? link->src_name : "(any)",
       GST_ELEMENT_NAME (sink), link->sink_name ? link->sink_name : "(any)",
       g_slist_length (srcs), g_slist_length (sinks), link->caps);
@@ -493,20 +571,18 @@ gst_parse_perform_link (link_t *link, graph_t *graph)
     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_locked_state (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)) {
+  if (g_slist_length (link->src_pads) != g_slist_length (link->sink_pads)) {
     goto error;
   }
   while (srcs && sinks) {
@@ -516,26 +592,24 @@ gst_parse_perform_link (link_t *link, graph_t *graph)
     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_locked_state (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:
-  SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_LINK,
+  SET_ERROR (graph->error, GST_PARSE_ERROR_LINK,
       _("could not link %s to %s"), GST_ELEMENT_NAME (src),
       GST_ELEMENT_NAME (sink));
   gst_parse_free_link (link);
@@ -543,7 +617,7 @@ error:
 }
 
 
-static int yyerror (graph_t *graph, const char *s);
+static int yyerror (void *scanner, graph_t *graph, const char *s);
 %}
 
 %union {
@@ -566,7 +640,7 @@ static int yyerror (graph_t *graph, const char *s);
 %type <l> reference
 %type <l> linkpart link
 %type <p> linklist
-%type <e> element 
+%type <e> element
 %type <p> padlist pads assignments
 
 %left '(' ')'
@@ -574,17 +648,24 @@ static int yyerror (graph_t *graph, const char *s);
 %right '.'
 %left '!' '='
 
-%parse-param { void *scanner, graph_t *graph }
+%parse-param { void *scanner }
+%parse-param { graph_t *graph }
 %pure-parser
 
 %start graph
 %%
 
-element:       IDENTIFIER                    { $$ = gst_element_factory_make ($1, NULL); 
+element:       IDENTIFIER                    { $$ = gst_element_factory_make ($1, NULL);
                                                if ($$ == NULL) {
-                                                 SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_NO_SUCH_ELEMENT, _("no element \"%s\""), $1);
-                                                 gst_parse_strfree ($1);
-                                                 YYERROR;
+                                                 ADD_MISSING_ELEMENT (graph, $1);
+                                                 SET_ERROR (graph->error, GST_PARSE_ERROR_NO_SUCH_ELEMENT, _("no element \"%s\""), $1);
+                                                 /* if FATAL_ERRORS flag is set, we don't have to worry about backwards
+                                                  * compatibility and can continue parsing and check for other missing
+                                                  * elements */
+                                                 if ((graph->flags & GST_PARSE_FLAG_FATAL_ERRORS) == 0) {
+                                                   gst_parse_strfree ($1);
+                                                   YYERROR;
+                                                 }
                                                }
                                                gst_parse_strfree ($1);
                                               }
@@ -594,28 +675,28 @@ element:  IDENTIFIER                    { $$ = gst_element_factory_make ($1, NULL);
        ;
 assignments:   /* NOP */                     { $$ = NULL; }
        |       assignments ASSIGNMENT        { $$ = g_slist_prepend ($1, $2); }
-       ;               
-bin:           '(' assignments chain ')' { GST_BIN_MAKE ($$, "bin", $3, $2); }
-        |       BINREF assignments chain ')'  { GST_BIN_MAKE ($$, $1, $3, $2); 
+       ;
+bin:           '(' assignments chain ')' { GST_BIN_MAKE ($$, "bin", $3, $2, no_free); }
+        |       BINREF assignments chain ')'  { GST_BIN_MAKE ($$, $1, $3, $2, gst_parse_strfree);
                                                gst_parse_strfree ($1);
                                              }
-        |       BINREF assignments ')'       { GST_BIN_MAKE ($$, $1, NULL, $2); 
+        |       BINREF assignments ')'       { GST_BIN_MAKE ($$, $1, NULL, $2, gst_parse_strfree);
                                                gst_parse_strfree ($1);
                                              }
-        |       BINREF assignments error ')'  { GST_BIN_MAKE ($$, $1, NULL, $2); 
+        |       BINREF assignments error ')'  { GST_BIN_MAKE ($$, $1, NULL, $2, gst_parse_strfree);
                                                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); }
        ;
@@ -624,12 +705,12 @@ linkpart: reference                     { $$ = $1; }
        |       pads                          { MAKE_REF ($$, NULL, $1); }
        |       /* NOP */                     { MAKE_REF ($$, NULL, NULL); }
        ;
-       
+
 link:          linkpart LINK linkpart        { $$ = $1;
                                                if ($2) {
                                                  $$->caps = gst_caps_from_string ($2);
                                                  if ($$->caps == NULL)
-                                                   SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_LINK, _("could not parse caps \"%s\""), $2);
+                                                   SET_ERROR (graph->error, GST_PARSE_ERROR_LINK, _("could not parse caps \"%s\""), $2);
                                                  gst_parse_strfree ($2);
                                                }
                                                $$->sink_name = $3->src_name;
@@ -637,11 +718,11 @@ link:             linkpart LINK linkpart        { $$ = $1;
                                                gst_parse_link_free ($3);
                                              }
        ;
-       
+
 linklist:      link                          { $$ = g_slist_prepend (NULL, $1); }
        |       link linklist                 { $$ = g_slist_prepend ($2, $1); }
        |       linklist error                { $$ = $1; }
-       ;       
+       ;
 
 chain:         element                       { $$ = gst_parse_chain_new ();
                                                $$->first = $$->last = $1;
@@ -651,16 +732,16 @@ chain:    element                       { $$ = gst_parse_chain_new ();
        |       bin                           { $$ = $1; }
        |       chain chain                   { if ($1->back && $2->front) {
                                                  if (!$1->back->sink_name) {
-                                                   SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_LINK, _("link without source element"));
+                                                   SET_ERROR (graph->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);
+                                                   graph->links = g_slist_prepend (graph->links, $1->back);
                                                  }
                                                  if (!$2->front->src_name) {
-                                                   SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_LINK, _("link without sink element"));
+                                                   SET_ERROR (graph->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);
+                                                   graph->links = g_slist_prepend (graph->links, $2->front);
                                                  }
                                                  $1->back = NULL;
                                                } else if ($1->back) {
@@ -673,9 +754,9 @@ chain:      element                       { $$ = gst_parse_chain_new ();
                                                  }
                                                  $1->back = $2->front;
                                                }
-                                               
+
                                                if ($1->back) {
-                                                 ((graph_t *) graph)->links = g_slist_prepend (((graph_t *) graph)->links, $1->back);
+                                                 graph->links = g_slist_prepend (graph->links, $1->back);
                                                }
                                                $1->last = $2->last;
                                                $1->back = $2->back;
@@ -691,19 +772,19 @@ chain:    element                       { $$ = gst_parse_chain_new ();
                                                } else {
                                                  if (!((link_t *) $2->data)->src_name) {
                                                    ((link_t *) $2->data)->src = $1->last;
-                                                 }                                               
+                                                 }
                                                }
                                                for (walk = $2; walk; walk = walk->next) {
                                                  link_t *link = (link_t *) walk->data;
                                                  if (!link->sink_name && walk->next) {
-                                                   SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_LINK, _("link without sink element"));
+                                                   SET_ERROR (graph->error, GST_PARSE_ERROR_LINK, _("link without sink element"));
                                                    gst_parse_free_link (link);
                                                  } else if (!link->src_name && !link->src) {
-                                                   SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_LINK, _("link without source element"));
+                                                   SET_ERROR (graph->error, GST_PARSE_ERROR_LINK, _("link without source element"));
                                                    gst_parse_free_link (link);
                                                  } else {
                                                    if (walk->next) {
-                                                     ((graph_t *) graph)->links = g_slist_prepend (((graph_t *) graph)->links, link);
+                                                     graph->links = g_slist_prepend (graph->links, link);
                                                    } else {
                                                      $1->back = link;
                                                    }
@@ -715,10 +796,10 @@ chain:    element                       { $$ = gst_parse_chain_new ();
        |       chain error                   { $$ = $1; }
        |       link chain                    { if ($2->front) {
                                                  if (!$2->front->src_name) {
-                                                   SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_LINK, _("link without source element"));
+                                                   SET_ERROR (graph->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);
+                                                   graph->links = g_slist_prepend (graph->links, $2->front);
                                                  }
                                                }
                                                if (!$1->sink_name) {
@@ -729,20 +810,20 @@ chain:    element                       { $$ = gst_parse_chain_new ();
                                              }
        |       PARSE_URL chain               { $$ = $2;
                                                if ($$->front) {
-                                                 GstElement *element = 
+                                                 GstElement *element =
                                                          gst_element_make_from_uri (GST_URI_SRC, $1, NULL);
                                                  if (!element) {
-                                                   SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_NO_SUCH_ELEMENT, 
+                                                   SET_ERROR (graph->error, GST_PARSE_ERROR_NO_SUCH_ELEMENT,
                                                            _("no source element for URI \"%s\""), $1);
                                                  } else {
                                                    $$->front->src = element;
-                                                   ((graph_t *) graph)->links = g_slist_prepend (
-                                                           ((graph_t *) graph)->links, $$->front);
+                                                   graph->links = g_slist_prepend (
+                                                           graph->links, $$->front);
                                                    $$->front = NULL;
                                                    $$->elements = g_slist_prepend ($$->elements, element);
                                                  }
                                                } else {
-                                                 SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_LINK, 
+                                                 SET_ERROR (graph->error, GST_PARSE_ERROR_LINK,
                                                          _("no element to link URI \"%s\" to"), $1);
                                                }
                                                g_free ($1);
@@ -750,14 +831,14 @@ chain:    element                       { $$ = gst_parse_chain_new ();
        |       link PARSE_URL                { GstElement *element =
                                                          gst_element_make_from_uri (GST_URI_SINK, $2, NULL);
                                                if (!element) {
-                                                 SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_NO_SUCH_ELEMENT, 
+                                                 SET_ERROR (graph->error, GST_PARSE_ERROR_NO_SUCH_ELEMENT,
                                                          _("no sink element for URI \"%s\""), $2);
                                                  gst_parse_link_free ($1);
                                                  g_free ($2);
                                                  YYERROR;
                                                } else if ($1->sink_name || $1->sink_pads) {
                                                   gst_object_unref (element);
-                                                 SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_LINK, 
+                                                 SET_ERROR (graph->error, GST_PARSE_ERROR_LINK,
                                                          _("could not link sink element for URI \"%s\""), $2);
                                                  gst_parse_link_free ($1);
                                                  g_free ($2);
@@ -772,13 +853,13 @@ chain:    element                       { $$ = gst_parse_chain_new ();
                                                g_free ($2);
                                              }
        ;
-graph:         /* NOP */                     { SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_EMPTY, _("empty pipeline not allowed"));
-                                               $$ = (graph_t *) graph;
+graph:         /* NOP */                     { SET_ERROR (graph->error, GST_PARSE_ERROR_EMPTY, _("empty pipeline not allowed"));
+                                               $$ = graph;
                                              }
-       |       chain                         { $$ = (graph_t *) graph;
+       |       chain                         { $$ = graph;
                                                if ($1->front) {
                                                  if (!$1->front->src_name) {
-                                                   SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_LINK, _("link without source element"));
+                                                   SET_ERROR (graph->error, GST_PARSE_ERROR_LINK, _("link without source element"));
                                                    gst_parse_free_link ($1->front);
                                                  } else {
                                                    $$->links = g_slist_prepend ($$->links, $1->front);
@@ -787,7 +868,7 @@ graph:              /* NOP */                     { SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERRO
                                                }
                                                if ($1->back) {
                                                  if (!$1->back->sink_name) {
-                                                   SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_LINK, _("link without sink element"));
+                                                   SET_ERROR (graph->error, GST_PARSE_ERROR_LINK, _("link without sink element"));
                                                    gst_parse_free_link ($1->back);
                                                  } else {
                                                    $$->links = g_slist_prepend ($$->links, $1->back);
@@ -802,7 +883,7 @@ graph:              /* NOP */                     { SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERRO
 
 
 static int
-yyerror (graph_t *graph, const char *s)
+yyerror (void *scanner, graph_t *graph, const char *s)
 {
   /* FIXME: This should go into the GError somehow, but how? */
   GST_WARNING ("Error during parsing: %s", s);
@@ -811,7 +892,8 @@ yyerror (graph_t *graph, const char *s)
 
 
 GstElement *
-_gst_parse_launch (const gchar *str, GError **error)
+priv_gst_parse_launch (const gchar *str, GError **error, GstParseContext *ctx,
+    GstParseFlags flags)
 {
   graph_t g;
   gchar *dstr;
@@ -821,19 +903,22 @@ _gst_parse_launch (const gchar *str, GError **error)
   yyscan_t scanner;
 
   g_return_val_if_fail (str != NULL, NULL);
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
   g.chain = NULL;
   g.links = NULL;
   g.error = error;
-  
+  g.ctx = ctx;
+  g.flags = flags;
+
 #ifdef __GST_PARSE_TRACE
   GST_CAT_DEBUG (GST_CAT_PIPELINE, "TRACE: tracing enabled");
   __strings = __chains = __links = 0;
 #endif /* __GST_PARSE_TRACE */
 
   dstr = g_strdup (str);
-  _gst_parse_yylex_init( &scanner );
-  _gst_parse_yy_scan_string (dstr, scanner);
+  priv_gst_parse_yylex_init (&scanner);
+  priv_gst_parse_yy_scan_string (dstr, scanner);
 
 #ifndef YYDEBUG
   yydebug = 1;
@@ -842,40 +927,43 @@ _gst_parse_launch (const gchar *str, GError **error)
   if (yyparse (scanner, &g) != 0) {
     SET_ERROR (error, GST_PARSE_ERROR_SYNTAX,
         "Unrecoverable syntax error while parsing pipeline %s", str);
-    
+
+    priv_gst_parse_yylex_destroy (scanner);
+    g_free (dstr);
+
     goto error1;
   }
-  _gst_parse_yylex_destroy( scanner );
+  priv_gst_parse_yylex_destroy (scanner);
   g_free (dstr);
 
   GST_CAT_DEBUG (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);
+  } else if (!g.chain->elements->next) {
+    /* only one toplevel element */
+    ret = (GstElement *) g.chain->elements->data;
+    g_slist_free (g.chain->elements);
     if (GST_IS_BIN (ret))
       bin = GST_BIN (ret);
     gst_parse_chain_free (g.chain);
-  } else {  
+  } else {
     /* put all elements in our bin */
     bin = GST_BIN (gst_element_factory_make ("pipeline", NULL));
     g_assert (bin);
-    
+
     for (walk = g.chain->elements; walk; walk = walk->next) {
       if (walk->data != NULL)
         gst_bin_add (bin, GST_ELEMENT (walk->data));
     }
-    
+
     g_slist_free (g.chain->elements);
     ret = GST_ELEMENT (bin);
     gst_parse_chain_free (g.chain);
   }
-  
+
   /* remove links */
   for (walk = g.links; walk; walk = walk->next) {
     link_t *l = (link_t *) walk->data;
@@ -890,8 +978,12 @@ _gst_parse_launch (const gchar *str, GError **error)
         }
       }
       if (!l->src) {
-        SET_ERROR (error, GST_PARSE_ERROR_NO_SUCH_ELEMENT,
-            "No element named \"%s\" - omitting link", l->src_name);
+        if (l->src_name) {
+          SET_ERROR (error, GST_PARSE_ERROR_NO_SUCH_ELEMENT,
+              "No element named \"%s\" - omitting link", l->src_name);
+        } else {
+          /* probably a missing element which we've handled already */
+        }
         gst_parse_free_link (l);
         continue;
       }
@@ -907,8 +999,12 @@ _gst_parse_launch (const gchar *str, GError **error)
         }
       }
       if (!l->sink) {
-        SET_ERROR (error, GST_PARSE_ERROR_NO_SUCH_ELEMENT,
-            "No element named \"%s\" - omitting link", l->sink_name);
+        if (l->sink_name) {
+          SET_ERROR (error, GST_PARSE_ERROR_NO_SUCH_ELEMENT,
+              "No element named \"%s\" - omitting link", l->sink_name);
+        } else {
+          /* probably a missing element which we've handled already */
+        }
         gst_parse_free_link (l);
         continue;
       }
@@ -929,10 +1025,8 @@ out:
 #endif /* __GST_PARSE_TRACE */
 
   return ret;
-  
+
 error1:
-  g_free (dstr);
-  
   if (g.chain) {
     g_slist_foreach (g.chain->elements, (GFunc)gst_object_unref, NULL);
     g_slist_free (g.chain->elements);
@@ -941,10 +1035,10 @@ error1:
 
   g_slist_foreach (g.links, (GFunc)gst_parse_free_link, NULL);
   g_slist_free (g.links);
-  
+
   if (error)
     g_assert (*error);
   ret = NULL;
-  
+
   goto out;
 }