gst/playback/gstplaybin2.c: Enable vis setting.
authorWim Taymans <wim.taymans@gmail.com>
Fri, 29 Feb 2008 12:26:48 +0000 (12:26 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Fri, 29 Feb 2008 12:26:48 +0000 (12:26 +0000)
Original commit message from CVS:
* gst/playback/gstplaybin2.c: (gst_play_bin_set_property):
Enable vis setting.
* gst/playback/gstplaysink.c: (gst_play_sink_init),
(gst_play_sink_dispose), (gst_play_sink_vis_unblocked),
(gst_play_sink_vis_blocked), (gst_play_sink_set_vis_plugin),
(gen_vis_chain):
Implement vis switching while playing.

ChangeLog
gst/playback/gstplaybin2.c
gst/playback/gstplaysink.c

index c35be94..661af93 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2008-02-29  Wim Taymans  <wim.taymans@collabora.co.uk>
+
+       * gst/playback/gstplaybin2.c: (gst_play_bin_set_property):
+       Enable vis setting.
+
+       * gst/playback/gstplaysink.c: (gst_play_sink_init),
+       (gst_play_sink_dispose), (gst_play_sink_vis_unblocked),
+       (gst_play_sink_vis_blocked), (gst_play_sink_set_vis_plugin),
+       (gen_vis_chain):
+       Implement vis switching while playing.
+
 2008-02-28  David Schleef  <ds@schleef.org>
 
        * gst-libs/gst/riff/riff-media.c: Add Dirac mapping
index b208d31..2b964af 100644 (file)
@@ -1157,6 +1157,8 @@ gst_play_bin_set_property (GObject * object, guint prop_id,
     case PROP_AUDIO_SINK:
       break;
     case PROP_VIS_PLUGIN:
+      gst_play_sink_set_vis_plugin (playbin->playsink,
+          g_value_get_object (value));
       break;
     case PROP_VOLUME:
       gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
index 4032acd..ead991c 100644 (file)
@@ -72,8 +72,12 @@ typedef struct
   GstElement *queue;
   GstElement *conv;
   GstElement *resample;
+  GstPad *blockpad;             /* srcpad of resample, used for switching the vis */
+  GstPad *vissinkpad;           /* visualisation sinkpad, */
   GstElement *vis;
-  GstPad *srcpad;
+  GstPad *vissrcpad;            /* visualisation srcpad, */
+  GstPad *srcpad;               /* outgoing srcpad, used to connect to the next
+                                 * chain */
 } GstPlayVisChain;
 
 #define GST_PLAY_SINK_GET_LOCK(playsink) (((GstPlaySink *)playsink)->lock)
@@ -115,9 +119,6 @@ struct _GstPlaySink
 
   /* internal elements */
   GstElement *textoverlay_element;
-
-  GstElement *pending_visualisation;
-  GstElement *fakesink;
 };
 
 struct _GstPlaySinkClass
@@ -256,7 +257,6 @@ gst_play_sink_init (GstPlaySink * playsink)
   playsink->video_sink = NULL;
   playsink->audio_sink = NULL;
   playsink->visualisation = NULL;
-  playsink->pending_visualisation = NULL;
   playsink->textoverlay_element = NULL;
   playsink->volume = 1.0;
   playsink->font_desc = NULL;
@@ -287,11 +287,6 @@ gst_play_sink_dispose (GObject * object)
     gst_object_unref (playsink->visualisation);
     playsink->visualisation = NULL;
   }
-  if (playsink->pending_visualisation != NULL) {
-    gst_element_set_state (playsink->pending_visualisation, GST_STATE_NULL);
-    gst_object_unref (playsink->pending_visualisation);
-    playsink->pending_visualisation = NULL;
-  }
   if (playsink->textoverlay_element != NULL) {
     gst_object_unref (playsink->textoverlay_element);
     playsink->textoverlay_element = NULL;
@@ -314,125 +309,6 @@ gst_play_sink_finalize (GObject * object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
-static void
-gst_play_sink_vis_unblocked (GstPad * tee_pad, gboolean blocked,
-    gpointer user_data)
-{
-  GstPlaySink *playsink = GST_PLAY_SINK (user_data);
-
-  if (playsink->pending_visualisation)
-    gst_pad_set_blocked_async (tee_pad, FALSE, gst_play_sink_vis_unblocked,
-        playsink);
-}
-
-static void
-gst_play_sink_vis_blocked (GstPad * tee_pad, gboolean blocked,
-    gpointer user_data)
-{
-  GstPlaySink *playsink = GST_PLAY_SINK (user_data);
-  GstBin *vis_bin = NULL;
-  GstPad *vis_sink_pad = NULL, *vis_src_pad = NULL, *vqueue_pad = NULL;
-  GstState bin_state;
-  GstElement *pending_visualisation;
-
-  GST_OBJECT_LOCK (playsink);
-  pending_visualisation = playsink->pending_visualisation;
-  playsink->pending_visualisation = NULL;
-  GST_OBJECT_UNLOCK (playsink);
-
-  /* We want to disable visualisation */
-  if (!GST_IS_ELEMENT (pending_visualisation)) {
-    /* Set visualisation element to READY */
-    gst_element_set_state (playsink->visualisation, GST_STATE_READY);
-    goto beach;
-  }
-
-  vis_bin =
-      GST_BIN_CAST (gst_object_get_parent (GST_OBJECT_CAST (playsink->
-              visualisation)));
-
-  if (!GST_IS_BIN (vis_bin) || !GST_IS_PAD (tee_pad)) {
-    goto beach;
-  }
-
-  vis_src_pad = gst_element_get_pad (playsink->visualisation, "src");
-  vis_sink_pad = gst_pad_get_peer (tee_pad);
-
-  /* Can be fakesink */
-  if (GST_IS_PAD (vis_src_pad)) {
-    vqueue_pad = gst_pad_get_peer (vis_src_pad);
-  }
-
-  if (!GST_IS_PAD (vis_sink_pad)) {
-    goto beach;
-  }
-
-  /* Check the bin's state */
-  GST_OBJECT_LOCK (vis_bin);
-  bin_state = GST_STATE (vis_bin);
-  GST_OBJECT_UNLOCK (vis_bin);
-
-  /* Unlink */
-  gst_pad_unlink (tee_pad, vis_sink_pad);
-  gst_object_unref (vis_sink_pad);
-  vis_sink_pad = NULL;
-
-  if (GST_IS_PAD (vqueue_pad)) {
-    gst_pad_unlink (vis_src_pad, vqueue_pad);
-    gst_object_unref (vis_src_pad);
-    vis_src_pad = NULL;
-  }
-
-  /* Remove from vis_bin */
-  gst_bin_remove (vis_bin, playsink->visualisation);
-  /* Set state to NULL */
-  gst_element_set_state (playsink->visualisation, GST_STATE_NULL);
-  /* And loose our ref */
-  gst_object_unref (playsink->visualisation);
-
-  if (pending_visualisation) {
-    /* Ref this new visualisation element before adding to the bin */
-    gst_object_ref (pending_visualisation);
-    /* Add the new one */
-    gst_bin_add (vis_bin, pending_visualisation);
-    /* Synchronizing state */
-    gst_element_set_state (pending_visualisation, bin_state);
-
-    vis_sink_pad = gst_element_get_pad (pending_visualisation, "sink");
-    vis_src_pad = gst_element_get_pad (pending_visualisation, "src");
-
-    if (!GST_IS_PAD (vis_sink_pad) || !GST_IS_PAD (vis_src_pad)) {
-      goto beach;
-    }
-
-    /* Link */
-    gst_pad_link (tee_pad, vis_sink_pad);
-    gst_pad_link (vis_src_pad, vqueue_pad);
-  }
-
-  /* We are done */
-  gst_object_unref (playsink->visualisation);
-  playsink->visualisation = pending_visualisation;
-
-beach:
-  if (vis_sink_pad) {
-    gst_object_unref (vis_sink_pad);
-  }
-  if (vis_src_pad) {
-    gst_object_unref (vis_src_pad);
-  }
-  if (vqueue_pad) {
-    gst_object_unref (vqueue_pad);
-  }
-  if (vis_bin) {
-    gst_object_unref (vis_bin);
-  }
-
-  /* Unblock the pad */
-  gst_pad_set_blocked_async (tee_pad, FALSE, gst_play_sink_vis_unblocked,
-      playsink);
-}
-
 void
 gst_play_sink_set_video_sink (GstPlaySink * playsink, GstElement * sink)
 {
@@ -463,66 +339,89 @@ gst_play_sink_set_audio_sink (GstPlaySink * playsink, GstElement * sink)
   GST_OBJECT_UNLOCK (playsink);
 }
 
+static void
+gst_play_sink_vis_unblocked (GstPad * tee_pad, gboolean blocked,
+    gpointer user_data)
+{
+  GstPlaySink *playsink;
+
+  playsink = GST_PLAY_SINK (user_data);
+  /* nothing to do here, we need a dummy callback here to make the async call
+   * non-blocking. */
+  GST_DEBUG_OBJECT (playsink, "vis pad unblocked");
+}
+
+static void
+gst_play_sink_vis_blocked (GstPad * tee_pad, gboolean blocked,
+    gpointer user_data)
+{
+  GstPlaySink *playsink;
+  GstPlayVisChain *chain;
+
+  playsink = GST_PLAY_SINK (user_data);
+
+  GST_PLAY_SINK_LOCK (playsink);
+  GST_DEBUG_OBJECT (playsink, "vis pad blocked");
+  /* now try to change the plugin in the running vis chain */
+  if (!(chain = (GstPlayVisChain *) playsink->vischain))
+    goto done;
+
+  /* unlink the old plugin and unghost the pad */
+  gst_pad_unlink (chain->blockpad, chain->vissinkpad);
+  gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (chain->srcpad), NULL);
+
+  /* set the old plugin to NULL and remove */
+  gst_element_set_state (chain->vis, GST_STATE_NULL);
+  gst_bin_remove (GST_BIN_CAST (chain->chain.bin), chain->vis);
+
+  /* add new plugin and set state to playing */
+  chain->vis = gst_object_ref (playsink->visualisation);
+  gst_bin_add (GST_BIN_CAST (chain->chain.bin), chain->vis);
+  gst_element_set_state (chain->vis, GST_STATE_PLAYING);
+
+  /* get pads */
+  chain->vissinkpad = gst_element_get_pad (chain->vis, "sink");
+  chain->vissrcpad = gst_element_get_pad (chain->vis, "src");
+
+  /* link pads */
+  gst_pad_link (chain->blockpad, chain->vissinkpad);
+  gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (chain->srcpad),
+      chain->vissrcpad);
+
+done:
+  /* Unblock the pad */
+  gst_pad_set_blocked_async (tee_pad, FALSE, gst_play_sink_vis_unblocked,
+      playsink);
+  GST_PLAY_SINK_UNLOCK (playsink);
+}
+
 void
-gst_play_sink_set_vis_plugin (GstPlaySink * playsink,
-    GstElement * pending_visualisation)
+gst_play_sink_set_vis_plugin (GstPlaySink * playsink, GstElement * vis)
 {
-  /* Take ownership */
-  if (pending_visualisation) {
-    gst_object_ref (pending_visualisation);
-    gst_object_sink (pending_visualisation);
-  }
+  GstPlayVisChain *chain;
 
-  /* Do we already have a visualisation change pending? If yes, change the
-   * pending vis with the new one. */
-  GST_OBJECT_LOCK (playsink);
-  if (playsink->pending_visualisation) {
-    gst_object_unref (playsink->pending_visualisation);
-    playsink->pending_visualisation = pending_visualisation;
-    GST_OBJECT_UNLOCK (playsink);
-  } else {
-    GST_OBJECT_UNLOCK (playsink);
-    /* Was there a visualisation already set ? */
-    if (playsink->visualisation != NULL) {
-      GstBin *vis_bin = NULL;
-
-      vis_bin =
-          GST_BIN_CAST (gst_object_get_parent (GST_OBJECT_CAST (playsink->
-                  visualisation)));
-
-      /* Check if the visualisation is already in a bin */
-      if (GST_IS_BIN (vis_bin)) {
-        GstPad *vis_sink_pad = NULL, *tee_pad = NULL;
-
-        /* Now get tee pad and block it async */
-        vis_sink_pad = gst_element_get_pad (playsink->visualisation, "sink");
-        if (!GST_IS_PAD (vis_sink_pad)) {
-          goto beach;
-        }
-        tee_pad = gst_pad_get_peer (vis_sink_pad);
-        if (!GST_IS_PAD (tee_pad)) {
-          goto beach;
-        }
-
-        playsink->pending_visualisation = pending_visualisation;
-        /* Block with callback */
-        gst_pad_set_blocked_async (tee_pad, TRUE, gst_play_sink_vis_blocked,
-            playsink);
-      beach:
-        if (vis_sink_pad) {
-          gst_object_unref (vis_sink_pad);
-        }
-        if (tee_pad) {
-          gst_object_unref (tee_pad);
-        }
-        gst_object_unref (vis_bin);
-      } else {
-        playsink->visualisation = pending_visualisation;
-      }
-    } else {
-      playsink->visualisation = pending_visualisation;
-    }
-  }
+  GST_PLAY_SINK_LOCK (playsink);
+  /* first store the new vis */
+  if (playsink->visualisation)
+    gst_object_unref (playsink->visualisation);
+  playsink->visualisation = gst_object_ref (vis);
+
+  /* now try to change the plugin in the running vis chain, if we have no chain,
+   * we don't bother, any future vis chain will be created with the new vis
+   * plugin. */
+  if (!(chain = (GstPlayVisChain *) playsink->vischain))
+    goto done;
+
+  /* block the pad, the next time the callback is called we can change the
+   * visualisation. It's possible that this never happens or that the pad was
+   * already blocked. */
+  GST_DEBUG_OBJECT (playsink, "blocking vis pad");
+  gst_pad_set_blocked_async (chain->blockpad, TRUE, gst_play_sink_vis_blocked,
+      playsink);
+done:
+  GST_PLAY_SINK_UNLOCK (playsink);
+
+  return;
 }
 
 void
@@ -1120,14 +1019,14 @@ link_failed:
 }
 
 /*
- *  +----------------------------------------------------+
- *  | visbin                                             |
- *  |      +----------+   +------------+   +-------+     |
- *  |      | visqueue |   | audioconv  |   |  vis  |     |
- *  |   +-sink       src-sink + samp  src-sink    src-+  |
- *  |   |  +----------+   +------------+   +-------+  |  |
- * sink-+                                             +-src
- *  +----------------------------------------------------+
+ *  +-------------------------------------------------------------------+
+ *  | visbin                                                            |
+ *  |      +----------+   +------------+   +----------+   +-------+     |
+ *  |      | visqueue |   | audioconv  |   | audiores |   |  vis  |     |
+ *  |   +-sink       src-sink + samp  src-sink       src-sink    src-+  |
+ *  |   |  +----------+   +------------+   +----------+   +-------+  |  |
+ * sink-+                                                            +-src
+ *  +-------------------------------------------------------------------+
  *           
  */
 static GstPlayChain *
@@ -1161,8 +1060,12 @@ gen_vis_chain (GstPlaySink * playsink)
     goto no_audioresample;
   gst_bin_add (bin, chain->resample);
 
+  /* this pad will be used for blocking the dataflow and switching the vis
+   * plugin */
+  chain->blockpad = gst_element_get_pad (chain->resample, "src");
+
   if (playsink->visualisation) {
-    chain->vis = playsink->visualisation;
+    chain->vis = gst_object_ref (playsink->visualisation);
   } else {
     chain->vis = gst_element_factory_make ("goom", "vis");
     if (!chain->vis)
@@ -1176,14 +1079,15 @@ gen_vis_chain (GstPlaySink * playsink)
   if (!res)
     goto link_failed;
 
+  chain->vissinkpad = gst_element_get_pad (chain->vis, "sink");
+  chain->vissrcpad = gst_element_get_pad (chain->vis, "src");
+
   pad = gst_element_get_pad (chain->queue, "sink");
   chain->chain.sinkpad = gst_ghost_pad_new ("sink", pad);
   gst_object_unref (pad);
   gst_element_add_pad (chain->chain.bin, chain->chain.sinkpad);
 
-  pad = gst_element_get_pad (chain->vis, "src");
-  chain->srcpad = gst_ghost_pad_new ("src", pad);
-  gst_object_unref (pad);
+  chain->srcpad = gst_ghost_pad_new ("src", chain->vissrcpad);
   gst_element_add_pad (chain->chain.bin, chain->srcpad);
 
   return (GstPlayChain *) chain;