gst-launch: Improve GstContext handling
authorSebastian Dröge <slomo@circular-chaos.org>
Sun, 9 Jun 2013 15:20:22 +0000 (17:20 +0200)
committerSebastian Dröge <slomo@circular-chaos.org>
Sun, 9 Jun 2013 15:20:22 +0000 (17:20 +0200)
https://bugzilla.gnome.org/show_bug.cgi?id=700967

tools/gst-launch.c

index 7d88dbd..d43a30e 100644 (file)
@@ -63,6 +63,9 @@ static gboolean messages = FALSE;
 static gboolean is_live = FALSE;
 static gboolean waiting_eos = FALSE;
 
+G_LOCK_DEFINE_STATIC (context);
+static GstContext *context = NULL;
+
 /* convenience macro so we don't have to litter the code with if(!quiet) */
 #define PRINT if(!quiet)g_print
 
@@ -805,34 +808,26 @@ event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress,
         break;
       }
       case GST_MESSAGE_HAVE_CONTEXT:{
-        GstContext *context1, *context2;
+        GstContext *context_new;
         gchar *context_str;
 
-        gst_message_parse_have_context (message, &context1);
+        gst_message_parse_have_context (message, &context_new);
 
         context_str =
-            gst_structure_to_string (gst_context_get_structure (context1));
+            gst_structure_to_string (gst_context_get_structure (context_new));
         PRINT (_("Got context from element '%s': %s\n"),
             GST_ELEMENT_NAME (GST_MESSAGE_SRC (message)), context_str);
         g_free (context_str);
-
-        context2 = gst_element_get_context (pipeline);
-        if (context2) {
-          const GstStructure *s1;
-          GstStructure *s2;
-
-          /* Merge structures */
-          context2 = gst_context_make_writable (context2);
-          s1 = gst_context_get_structure (context1);
-          s2 = gst_context_writable_structure (context2);
-          gst_structure_foreach (s1, merge_structures, s2);
-          gst_element_set_context (pipeline, context2);
-          gst_context_unref (context2);
-        } else {
-          /* Copy over the context */
-          gst_element_set_context (pipeline, context1);
-        }
-        gst_context_unref (context1);
+        gst_context_unref (context_new);
+
+        /* The contexts were merged in the sync handler already, here
+         * now just print them and propagate the merged context to the
+         * complete pipeline */
+        G_LOCK (context);
+        context_new = gst_context_ref (context_new);
+        G_UNLOCK (context);
+        gst_element_set_context (pipeline, context_new);
+        gst_context_unref (context_new);
         break;
       }
       default:
@@ -892,6 +887,50 @@ bus_sync_handler (GstBus * bus, GstMessage * message, gpointer data)
 
         g_free (state_transition_name);
       }
+    case GST_MESSAGE_NEED_CONTEXT:{
+      G_LOCK (context);
+      /* We could filter something here, but instead we can also just pass the complete
+       * context knowledge we have to the element. If we have what it needs, it will be
+       * happy, otherwise we can't do anything else anyway */
+      if (context)
+        gst_element_set_context (GST_ELEMENT_CAST (GST_MESSAGE_SRC (message)),
+            context);
+      G_UNLOCK (context);
+
+      break;
+    }
+    case GST_MESSAGE_HAVE_CONTEXT:{
+      GstContext *context_new;
+
+      gst_message_parse_have_context (message, &context_new);
+
+      /* Merge the contexts here as soon as possible and not
+       * in the async bus handler, in case something asks for
+       * a specific context before the async bus handler is run.
+       *
+       * Don't set the context on the complete pipeline here as it
+       * might deadlock, but do that from the async bus handler
+       * instead.
+       */
+      G_LOCK (context);
+      if (context) {
+        const GstStructure *s1;
+        GstStructure *s2;
+
+        /* Merge structures */
+        context = gst_context_make_writable (context);
+        s1 = gst_context_get_structure (context_new);
+        s2 = gst_context_writable_structure (context);
+        gst_structure_foreach (s1, merge_structures, s2);
+        gst_context_unref (context);
+      } else {
+        /* Copy over the context */
+        gst_context_replace (&context, context_new);
+      }
+      gst_context_unref (context_new);
+      G_UNLOCK (context);
+      break;
+    }
     default:
       break;
   }
@@ -1170,6 +1209,7 @@ main (int argc, char *argv[])
 
   PRINT (_("Freeing pipeline ...\n"));
   gst_object_unref (pipeline);
+  gst_context_replace (&context, NULL);
 
   gst_deinit ();