summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Penquerc'h <vincent.penquerch@collabora.co.uk>2010-12-21 10:26:40 +0000
committerSebastian Dröge <sebastian.droege@collabora.co.uk>2010-12-21 17:42:58 +0100
commitf221466099b9193fb737cafc6bde1195aaeec06a (patch)
tree6c42ad38a8cb105867a8afcb034d6d81a75c0fa2
parent4b3e1403a1ac83cc5cc2a19c009bfd1149f0f496 (diff)
playbin2: delay stream-changed messages
https://bugzilla.gnome.org/show_bug.cgi?id=637586
-rw-r--r--gst/playback/gstplaybin2.c76
1 files changed, 73 insertions, 3 deletions
diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c
index 75f19ab98..154ffd296 100644
--- a/gst/playback/gstplaybin2.c
+++ b/gst/playback/gstplaybin2.c
@@ -264,6 +264,8 @@ struct _GstSourceSelect
GstPad *sinkpad; /* the sinkpad of the sink when the selector
* is linked
*/
+ GstEvent *sinkpad_delayed_event;
+ gulong sinkpad_data_probe;
};
#define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
@@ -1056,6 +1058,8 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
static void
init_group (GstPlayBin * playbin, GstSourceGroup * group)
{
+ int n;
+
/* store the array for the different channels */
group->video_channels = g_ptr_array_new ();
group->audio_channels = g_ptr_array_new ();
@@ -1089,11 +1093,27 @@ init_group (GstPlayBin * playbin, GstSourceGroup * group)
group->selector[4].media_list[0] = "video/";
group->selector[4].type = GST_PLAY_SINK_TYPE_VIDEO;
group->selector[4].channels = group->video_channels;
+
+ for (n = 0; n < GST_PLAY_SINK_TYPE_LAST; n++) {
+ GstSourceSelect *select = &group->selector[n];
+ select->sinkpad_delayed_event = NULL;
+ select->sinkpad_data_probe = 0;
+ }
}
static void
free_group (GstPlayBin * playbin, GstSourceGroup * group)
{
+ int n;
+
+ for (n = 0; n < GST_PLAY_SINK_TYPE_LAST; n++) {
+ GstSourceSelect *select = &group->selector[n];
+ if (select->sinkpad && select->sinkpad_data_probe)
+ gst_pad_remove_data_probe (select->sinkpad, select->sinkpad_data_probe);
+ if (select->sinkpad_delayed_event)
+ gst_event_unref (select->sinkpad_delayed_event);
+ }
+
g_free (group->uri);
g_free (group->suburi);
g_ptr_array_free (group->video_channels, TRUE);
@@ -2301,6 +2321,39 @@ selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
}
+/* this callback sends a delayed event once the pad becomes unblocked */
+static gboolean
+stream_changed_data_probe (GstPad * pad, GstMiniObject * object, gpointer data)
+{
+ GstSourceSelect *select = (GstSourceSelect *) data;
+ GstEvent *e;
+
+ /* we need do this just once, so cleanup first */
+ gst_pad_remove_data_probe (pad, select->sinkpad_data_probe);
+ select->sinkpad_data_probe = 0;
+ e = select->sinkpad_delayed_event;
+ select->sinkpad_delayed_event = NULL;
+
+ /* really, this should not happen */
+ if (!e) {
+ GST_WARNING ("Data probed called, but no delayed event");
+ return TRUE;
+ }
+
+ if (GST_IS_EVENT (object)
+ && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_NEWSEGMENT) {
+ /* push the event first, then send the delayed one */
+ gst_event_ref (GST_EVENT_CAST (object));
+ gst_pad_send_event (pad, GST_EVENT_CAST (object));
+ gst_pad_send_event (pad, e);
+ return FALSE;
+ } else {
+ /* send delayed event, then allow the caller to go on */
+ gst_pad_send_event (pad, e);
+ return TRUE;
+ }
+}
+
/* helper function to lookup stuff in lists */
static gboolean
array_has_value (const gchar * values[], const gchar * value)
@@ -2742,8 +2795,25 @@ no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
group->stream_changed_pending =
g_list_prepend (group->stream_changed_pending,
GUINT_TO_POINTER (seqnum));
+
+ /* remove any data probe we might have, and replace */
+ if (select->sinkpad_delayed_event)
+ gst_event_unref (select->sinkpad_delayed_event);
+ select->sinkpad_delayed_event = event;
+ if (select->sinkpad_data_probe)
+ gst_pad_remove_data_probe (select->sinkpad,
+ select->sinkpad_data_probe);
+
+ /* we go to the trouble of setting a probe on the pad to send
+ the playbin2-stream-changed event as sending it here might
+ find that the pad is blocked, so we'd block here, and the
+ pad might not be linked yet. Additionally, sending it here
+ apparently would be on the wrong thread */
+ select->sinkpad_data_probe =
+ gst_pad_add_data_probe (select->sinkpad,
+ (GCallback) stream_changed_data_probe, (gpointer) select);
+
g_mutex_unlock (group->stream_changed_pending_lock);
- gst_pad_send_event (select->sinkpad, event);
gst_message_unref (msg);
}
@@ -2870,8 +2940,8 @@ autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
GstPad *text_sinkpad = NULL;
text_sink =
- (group->playbin->text_sink) ? gst_object_ref (group->playbin->
- text_sink) : NULL;
+ (group->playbin->text_sink) ? gst_object_ref (group->
+ playbin->text_sink) : NULL;
if (text_sink)
text_sinkpad = gst_element_get_static_pad (text_sink, "sink");