playbin2: handle custom audiosinks differently
authorWim Taymans <wim.taymans@collabora.co.uk>
Fri, 17 Apr 2009 08:57:16 +0000 (10:57 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 12 May 2009 08:37:45 +0000 (10:37 +0200)
Keep track of the autoplugged custom sinks and configure them in the playsink
element when we have collected all streams.
Also make sure that we only select one custom sink.
When unreffing the internal sink, we don't need to change the state to NULL.

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

index 71a8520..1be6c2e 100644 (file)
@@ -286,6 +286,9 @@ struct _GstSourceGroup
   GPtrArray *text_channels;     /* links to selector pads */
   GPtrArray *subp_channels;     /* links to selector pads */
 
+  GstElement *audio_sink;       /* autoplugged audio and video sinks */
+  GstElement *video_sink;
+
   /* uridecodebins for uri and subtitle uri */
   GstElement *uridecodebin;
   GstElement *suburidecodebin;
@@ -989,6 +992,12 @@ free_group (GstPlayBin * playbin, GstSourceGroup * group)
   g_ptr_array_free (group->text_channels, TRUE);
   g_ptr_array_free (group->subp_channels, TRUE);
   g_mutex_free (group->lock);
+  if (group->audio_sink)
+    gst_object_unref (group->audio_sink);
+  group->audio_sink = NULL;
+  if (group->video_sink)
+    gst_object_unref (group->video_sink);
+  group->video_sink = NULL;
 }
 
 static void
@@ -2001,6 +2010,16 @@ no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
   GST_SOURCE_GROUP_UNLOCK (group);
 
   if (configure) {
+    /* if we have custom sinks, configure them now */
+    GST_SOURCE_GROUP_LOCK (group);
+    GST_LOG_OBJECT (playbin, "setting custom audio sink %p", group->audio_sink);
+    gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
+        group->audio_sink);
+    GST_LOG_OBJECT (playbin, "setting custom video sink %p", group->video_sink);
+    gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
+        group->video_sink);
+    GST_SOURCE_GROUP_UNLOCK (group);
+
     GST_LOG_OBJECT (playbin, "reconfigure sink");
     /* we configure the modes if we were the last decodebin to complete. */
     gst_play_sink_reconfigure (playbin->playsink);
@@ -2110,6 +2129,8 @@ autoplug_select_cb (GstElement * decodebin, GstPad * pad,
   GstPlayBin *playbin;
   GstElement *element;
   const gchar *klass;
+  GstPlaySinkType type;
+  GstElement **sinkp;
 
   playbin = group->playbin;
 
@@ -2128,15 +2149,42 @@ autoplug_select_cb (GstElement * decodebin, GstPad * pad,
 
   klass = gst_element_factory_get_klass (factory);
 
+  /* figure out the klass */
+  if (strstr (klass, "Audio")) {
+    GST_DEBUG_OBJECT (playbin, "we found an audio sink");
+    type = GST_PLAY_SINK_TYPE_AUDIO;
+    sinkp = &group->audio_sink;
+  } else if (strstr (klass, "Video")) {
+    GST_DEBUG_OBJECT (playbin, "we found a video sink");
+    type = GST_PLAY_SINK_TYPE_VIDEO;
+    sinkp = &group->video_sink;
+  } else {
+    /* unknown klass, skip this element */
+    GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
+    return GST_AUTOPLUG_SELECT_SKIP;
+  }
+
   /* if we are asked to do visualisations and it's an audio sink, skip the
    * element. We can only do visualisations with raw sinks */
   if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
-    if (strstr (klass, "Audio")) {
+    if (type == GST_PLAY_SINK_TYPE_AUDIO) {
       GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
       return GST_AUTOPLUG_SELECT_SKIP;
     }
   }
 
+  /* now see if we already have a sink element */
+  GST_SOURCE_GROUP_LOCK (group);
+  if (*sinkp) {
+    GST_DEBUG_OBJECT (playbin, "we already have a pending sink, expose pad");
+    /* for now, just assume that we can link the pad to this same sink. FIXME,
+     * check that we can link this new pad to this sink as well. */
+    GST_SOURCE_GROUP_UNLOCK (group);
+    return GST_AUTOPLUG_SELECT_EXPOSE;
+  }
+  GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
+  GST_SOURCE_GROUP_UNLOCK (group);
+
   if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
     GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
         gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
@@ -2154,20 +2202,24 @@ autoplug_select_cb (GstElement * decodebin, GstPad * pad,
     return GST_AUTOPLUG_SELECT_SKIP;
   }
 
-  /* get klass to figure out if it's audio or video */
-  if (strstr (klass, "Audio")) {
-    GST_DEBUG_OBJECT (playbin, "configure audio sink");
-    gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
-        element);
-    g_object_notify (G_OBJECT (playbin), "audio-sink");
-  } else if (strstr (klass, "Video")) {
-    GST_DEBUG_OBJECT (playbin, "configure video sink");
-    gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
-        element);
-    g_object_notify (G_OBJECT (playbin), "video-sink");
+  /* remember the sink in the group now, the element is floating, we take
+   * ownership now */
+  GST_SOURCE_GROUP_LOCK (group);
+  if (*sinkp == NULL) {
+    /* store the sink in the group, we will configure it later when we
+     * reconfigure the sink */
+    GST_DEBUG_OBJECT (playbin, "remember sink");
+    gst_object_ref (element);
+    gst_object_sink (element);
+    *sinkp = element;
   } else {
-    GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
+    /* some other thread configured a sink while we were testing the sink, set
+     * the sink back to NULL and assume we can use the other sink */
+    GST_DEBUG_OBJECT (playbin, "another sink was found, expose pad");
+    gst_element_set_state (element, GST_STATE_NULL);
+    gst_object_unref (element);
   }
+  GST_SOURCE_GROUP_UNLOCK (group);
 
   /* tell decodebin to expose the pad because we are going to use this
    * sink */
@@ -2406,6 +2458,13 @@ deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
       select->selector = NULL;
     }
   }
+  /* delete any custom sinks we might have */
+  if (group->audio_sink)
+    gst_object_unref (group->audio_sink);
+  group->audio_sink = NULL;
+  if (group->video_sink)
+    gst_object_unref (group->video_sink);
+  group->video_sink = NULL;
   /* we still have the decodebins added to the playbin2 but we can't remove them
    * yet or change their state because this function might be called from the
    * streaming threads, instead block the state so that state changes on the
index 1072fea..461cd07 100644 (file)
@@ -364,10 +364,8 @@ gst_play_sink_set_sink (GstPlaySink * playsink, GstPlaySinkType type,
   }
   GST_PLAY_SINK_UNLOCK (playsink);
 
-  if (old) {
-    gst_element_set_state (old, GST_STATE_NULL);
+  if (old)
     gst_object_unref (old);
-  }
 }
 
 GstElement *