From bf1b64fab05ef19a32b8176ce89a1a74dd1b10ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 26 Sep 2009 17:21:35 +0200 Subject: [PATCH] rsnaudiodec: Use ghost pads and always forward application/x-gst-dvd events immediately Fixes bug #582779. --- ext/resindvd/rsnaudiodec.c | 303 +++++++------------------------------ ext/resindvd/rsnaudiodec.h | 12 +- 2 files changed, 57 insertions(+), 258 deletions(-) diff --git a/ext/resindvd/rsnaudiodec.c b/ext/resindvd/rsnaudiodec.c index 60bd249c62..f65c8f548c 100644 --- a/ext/resindvd/rsnaudiodec.c +++ b/ext/resindvd/rsnaudiodec.c @@ -75,20 +75,9 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", G_DEFINE_TYPE (RsnAudioDec, rsn_audiodec, GST_TYPE_BIN); -static gboolean rsn_audiodec_set_sink_caps (GstPad * pad, GstCaps * caps); -static GstCaps *rsn_audiodec_get_sink_caps (GstPad * pad); -static GstFlowReturn rsn_audiodec_chain (GstPad * pad, GstBuffer * buf); -static gboolean rsn_audiodec_sink_event (GstPad * pad, GstEvent * event); static GstStateChangeReturn rsn_audiodec_change_state (GstElement * element, GstStateChange transition); -static GstCaps *rsn_audiodec_get_proxy_sink_caps (GstPad * pad); -static GstCaps *rsn_audiodec_get_proxy_src_caps (GstPad * pad); - -static GstFlowReturn rsn_audiodec_proxy_src_chain (GstPad * pad, - GstBuffer * buf); -static gboolean rsn_audiodec_proxy_src_event (GstPad * pad, GstEvent * event); - static void rsn_audiodec_dispose (GObject * gobj); static void cleanup_child (RsnAudioDec * self); @@ -122,22 +111,44 @@ rsn_audiodec_class_init (RsnAudioDecClass * klass) gst_element_class_set_details (element_class, &element_details); } +static gboolean +rsn_audiodec_sink_event (GstPad * pad, GstEvent * event) +{ + RsnAudioDec *self = RSN_AUDIODEC (gst_pad_get_parent (pad)); + gboolean ret = TRUE; + const GstStructure *s = gst_event_get_structure (event); + const gchar *name = (s ? gst_structure_get_name (s) : NULL); + + if (name && g_str_equal (name, "application/x-gst-dvd")) + ret = gst_pad_push_event (GST_PAD_CAST (self->srcpad), event); + else + ret = self->sink_event_func (pad, event); + + gst_object_unref (self); + + return ret; +} + static void rsn_audiodec_init (RsnAudioDec * self) { - self->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink"); - gst_pad_set_setcaps_function (self->sinkpad, - GST_DEBUG_FUNCPTR (rsn_audiodec_set_sink_caps)); - gst_pad_set_getcaps_function (self->sinkpad, - GST_DEBUG_FUNCPTR (rsn_audiodec_get_sink_caps)); - gst_pad_set_chain_function (self->sinkpad, - GST_DEBUG_FUNCPTR (rsn_audiodec_chain)); - gst_pad_set_event_function (self->sinkpad, - GST_DEBUG_FUNCPTR (rsn_audiodec_sink_event)); - gst_element_add_pad (GST_ELEMENT (self), self->sinkpad); + GstPadTemplate *templ; - self->srcpad = gst_pad_new_from_static_template (&src_template, "src"); - gst_element_add_pad (GST_ELEMENT (self), self->srcpad); + templ = gst_static_pad_template_get (&sink_template); + self->sinkpad = + GST_GHOST_PAD_CAST (gst_ghost_pad_new_no_target_from_template ("sink", + templ)); + gst_object_unref (templ); + self->sink_event_func = GST_PAD_EVENTFUNC (self->sinkpad); + gst_pad_set_event_function (GST_PAD_CAST (self->sinkpad), + GST_DEBUG_FUNCPTR (rsn_audiodec_sink_event)); + templ = gst_static_pad_template_get (&src_template); + self->srcpad = + GST_GHOST_PAD_CAST (gst_ghost_pad_new_no_target_from_template ("src", + templ)); + gst_object_unref (templ); + gst_element_add_pad (GST_ELEMENT (self), GST_PAD_CAST (self->sinkpad)); + gst_element_add_pad (GST_ELEMENT (self), GST_PAD_CAST (self->srcpad)); } static void @@ -149,228 +160,41 @@ rsn_audiodec_dispose (GObject * object) G_OBJECT_CLASS (rsn_audiodec_parent_class)->dispose (object); } -static gboolean -rsn_audiodec_set_sink_caps (GstPad * pad, GstCaps * caps) -{ - RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (pad); - gboolean res; - if (self == NULL) - goto error; - - res = gst_pad_set_caps (self->child_sink, caps); - - gst_object_unref (self); - return res; -error: - if (self) - gst_object_unref (self); - return FALSE; -} - -static GstCaps * -rsn_audiodec_get_sink_caps (GstPad * sinkpad) -{ - RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (sinkpad); - GstCaps *res; - if (self == NULL || self->child_sink == NULL) - goto error; - - /* FIXME: Can't get the caps of the child as this - * will deadlock! */ - res = gst_caps_copy (decoder_caps); - GST_INFO_OBJECT (self, "Returning caps %" GST_PTR_FORMAT, res); - - gst_object_unref (self); - return res; -error: - if (self) - gst_object_unref (self); - return gst_caps_copy (gst_pad_get_pad_template_caps (sinkpad)); -} - -static GstFlowReturn -rsn_audiodec_chain (GstPad * pad, GstBuffer * buf) -{ - RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (pad); - GstFlowReturn res; - if (self == NULL) - goto error; - - GST_INFO_OBJECT (self, "Pushing buffer %" GST_PTR_FORMAT " into decoder", - buf); - res = gst_pad_chain (self->child_sink, buf); - - gst_object_unref (self); - return res; -error: - if (self) - gst_object_unref (self); - return GST_FLOW_ERROR; -} - -static gboolean -rsn_audiodec_sink_event (GstPad * pad, GstEvent * event) -{ - RsnAudioDec *self = RSN_AUDIODEC (gst_pad_get_parent (pad)); - gboolean res; - - if (self == NULL) - goto error; - - GST_INFO_OBJECT (self, "Sending event %" GST_PTR_FORMAT " into decoder", - event); - res = gst_pad_send_event (self->child_sink, event); - - gst_object_unref (self); - return res; -error: - if (self) - gst_object_unref (self); - return FALSE; -} - -static GstCaps * -rsn_audiodec_get_proxy_sink_caps (GstPad * pad) -{ - GstPad *sinkpad = GST_PAD (gst_pad_get_parent (pad)); - GstCaps *ret; - - if (sinkpad != NULL) { - ret = gst_pad_get_caps (sinkpad); - } else - ret = gst_caps_new_any (); - - gst_object_unref (sinkpad); - - return ret; -} - -static GstCaps * -rsn_audiodec_get_proxy_src_caps (GstPad * pad) -{ - GstPad *srcpad = GST_PAD (gst_pad_get_parent (pad)); - GstCaps *ret; - - if (srcpad != NULL) { - ret = gst_pad_get_caps (srcpad); - } else - ret = gst_caps_new_any (); - - gst_object_unref (srcpad); - - return ret; -} - -static GstFlowReturn -rsn_audiodec_proxy_src_chain (GstPad * pad, GstBuffer * buf) -{ - GstPad *srcpad = GST_PAD (gst_pad_get_parent (pad)); - RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (srcpad); - GstFlowReturn ret; - - gst_object_unref (srcpad); - - if (self == NULL) - return GST_FLOW_ERROR; - - GST_DEBUG_OBJECT (self, "Data from decoder, pushing to pad %" - GST_PTR_FORMAT, self->srcpad); - ret = gst_pad_push (self->srcpad, buf); - - gst_object_unref (self); - - return ret; -} - -static gboolean -rsn_audiodec_proxy_src_event (GstPad * pad, GstEvent * event) -{ - GstPad *srcpad = GST_PAD (gst_pad_get_parent (pad)); - RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (srcpad); - gboolean ret; - - gst_object_unref (srcpad); - - if (self == NULL) - return FALSE; - - ret = gst_pad_push_event (self->srcpad, event); - - gst_object_unref (self); - return ret; -} - -static void -create_proxy_pads (RsnAudioDec * self) -{ - if (self->child_sink_proxy == NULL) { - /* A src pad the child can query/send events to */ - self->child_sink_proxy = gst_pad_new ("sink_proxy", GST_PAD_SRC); - gst_object_set_parent ((GstObject *) self->child_sink_proxy, - (GstObject *) self->sinkpad); - gst_pad_set_getcaps_function (self->child_sink_proxy, - GST_DEBUG_FUNCPTR (rsn_audiodec_get_proxy_sink_caps)); - } - - if (self->child_src_proxy == NULL) { - /* A sink pad the child can push to */ - self->child_src_proxy = gst_pad_new ("src_proxy", GST_PAD_SINK); - gst_object_set_parent ((GstObject *) self->child_src_proxy, - (GstObject *) self->srcpad); - gst_pad_set_getcaps_function (self->child_src_proxy, - GST_DEBUG_FUNCPTR (rsn_audiodec_get_proxy_src_caps)); - gst_pad_set_chain_function (self->child_src_proxy, - GST_DEBUG_FUNCPTR (rsn_audiodec_proxy_src_chain)); - gst_pad_set_event_function (self->child_src_proxy, - GST_DEBUG_FUNCPTR (rsn_audiodec_proxy_src_event)); - } -} - static gboolean rsn_audiodec_set_child (RsnAudioDec * self, GstElement * new_child) { + GstPad *child_pad; if (self->current_decoder) { + gst_ghost_pad_set_target (self->srcpad, NULL); + gst_ghost_pad_set_target (self->sinkpad, NULL); gst_bin_remove ((GstBin *) self, self->current_decoder); self->current_decoder = NULL; } - if (self->child_sink) { - (void) gst_pad_unlink (self->child_sink_proxy, self->child_sink); - gst_object_unref (self->child_sink); - self->child_sink = NULL; - } - if (self->child_src) { - (void) gst_pad_unlink (self->child_src, self->child_src_proxy); - gst_object_unref (self->child_src); - self->child_src = NULL; - } if (new_child == NULL) return TRUE; - self->child_sink = gst_element_get_static_pad (new_child, "sink"); - if (self->child_sink == NULL) { + if (!gst_bin_add ((GstBin *) self, new_child)) + return FALSE; + + child_pad = gst_element_get_static_pad (new_child, "sink"); + if (child_pad == NULL) { return FALSE; } - self->child_src = gst_element_get_static_pad (new_child, "src"); - if (self->child_src == NULL) { - return FALSE; - } - if (!gst_bin_add ((GstBin *) self, new_child)) { + gst_ghost_pad_set_target (self->sinkpad, child_pad); + gst_object_unref (child_pad); + + child_pad = gst_element_get_static_pad (new_child, "src"); + if (child_pad == NULL) { return FALSE; } + gst_ghost_pad_set_target (self->srcpad, child_pad); + gst_object_unref (child_pad); GST_DEBUG_OBJECT (self, "Add child %" GST_PTR_FORMAT, new_child); self->current_decoder = new_child; - if (gst_pad_link (self->child_sink_proxy, - self->child_sink) != GST_PAD_LINK_OK) - return FALSE; - GST_DEBUG_OBJECT (self, "linked proxy sink pad %" GST_PTR_FORMAT - " to child sink %" GST_PTR_FORMAT, self->child_sink_proxy, - self->child_sink); - if (gst_pad_link (self->child_src, self->child_src_proxy) != GST_PAD_LINK_OK) - return FALSE; - GST_DEBUG_OBJECT (self, "linked child src pad %" GST_PTR_FORMAT - " to proxy pad %" GST_PTR_FORMAT, self->child_src, self->child_src_proxy); + + gst_element_sync_state_with_parent (new_child); return TRUE; } @@ -380,15 +204,6 @@ cleanup_child (RsnAudioDec * self) { GST_DEBUG_OBJECT (self, "Removing child element"); (void) rsn_audiodec_set_child (self, NULL); - GST_DEBUG_OBJECT (self, "Destroying proxy pads"); - if (self->child_sink_proxy != NULL) { - gst_object_unparent ((GstObject *) self->child_sink_proxy); - self->child_sink_proxy = NULL; - } - if (self->child_src_proxy != NULL) { - gst_object_unparent ((GstObject *) self->child_src_proxy); - self->child_src_proxy = NULL; - } } static gboolean @@ -500,15 +315,13 @@ _get_decoder_factories (gpointer arg) static GstStateChangeReturn rsn_audiodec_change_state (GstElement * element, GstStateChange transition) { - GstStateChangeReturn ret; + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; RsnAudioDec *self = RSN_AUDIODEC (element); static GOnce gonce = G_ONCE_INIT; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY:{ GstElement *new_child; - create_proxy_pads (self); - GST_DEBUG_OBJECT (self, "Created proxy pads"); new_child = gst_element_factory_make ("autoconvert", NULL); g_once (&gonce, _get_decoder_factories, NULL); g_object_set (G_OBJECT (new_child), "factories", decoder_factories, NULL); @@ -517,16 +330,13 @@ rsn_audiodec_change_state (GstElement * element, GstStateChange transition) break; } case GST_STATE_CHANGE_READY_TO_PAUSED: - GST_DEBUG_OBJECT (self, "Activating proxy pads"); - if (self->child_sink_proxy) - gst_pad_set_active (self->child_sink_proxy, TRUE); - if (self->child_src_proxy) - gst_pad_set_active (self->child_src_proxy, TRUE); break; default: break; } + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; ret = GST_ELEMENT_CLASS (rsn_audiodec_parent_class)->change_state (element, transition); @@ -535,11 +345,6 @@ rsn_audiodec_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: - GST_DEBUG_OBJECT (self, "Deactivating proxy pads"); - if (self->child_sink_proxy) - gst_pad_set_active (self->child_sink_proxy, FALSE); - if (self->child_src_proxy) - gst_pad_set_active (self->child_src_proxy, FALSE); break; case GST_STATE_CHANGE_READY_TO_NULL: cleanup_child (self); diff --git a/ext/resindvd/rsnaudiodec.h b/ext/resindvd/rsnaudiodec.h index 269a7b8690..bd74fc6540 100644 --- a/ext/resindvd/rsnaudiodec.h +++ b/ext/resindvd/rsnaudiodec.h @@ -39,18 +39,12 @@ struct _RsnAudioDec { GstBin element; /* Our sink and source pads */ - GstPad *sinkpad; - GstPad *srcpad; + GstGhostPad *sinkpad; + GstGhostPad *srcpad; - /* Proxy pads that are linked to the child sink pad - * and source pad respectively */ - GstPad *child_sink_proxy; - GstPad *child_src_proxy; + GstPadEventFunction sink_event_func; GstElement *current_decoder; - /* Current child's sink and source pads */ - GstPad *child_sink; - GstPad *child_src; }; struct _RsnAudioDecClass {