diff options
Diffstat (limited to 'ext/resindvd')
-rw-r--r-- | ext/resindvd/resindvdbin.c | 4 | ||||
-rw-r--r-- | ext/resindvd/rsnaudiodec.c | 308 | ||||
-rw-r--r-- | ext/resindvd/rsnaudiodec.h | 15 |
3 files changed, 315 insertions, 12 deletions
diff --git a/ext/resindvd/resindvdbin.c b/ext/resindvd/resindvdbin.c index f9821111..f22e1818 100644 --- a/ext/resindvd/resindvdbin.c +++ b/ext/resindvd/resindvdbin.c @@ -439,8 +439,8 @@ create_elements (RsnDvdBin * dvdbin) RSN_TYPE_AUDIOMUNGE, "audiomunge", "Audio output filter")) return FALSE; - if (!try_create_piece (dvdbin, DVD_ELEM_AUDDEC, "a52dec", 0, "auddec", - "audio decoder")) + if (!try_create_piece (dvdbin, DVD_ELEM_AUDDEC, NULL, + RSN_TYPE_AUDIODEC, "auddec", "audio decoder")) return FALSE; src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUDDEC], "src"); diff --git a/ext/resindvd/rsnaudiodec.c b/ext/resindvd/rsnaudiodec.c index df7fc0c8..3ba4442e 100644 --- a/ext/resindvd/rsnaudiodec.c +++ b/ext/resindvd/rsnaudiodec.c @@ -31,7 +31,8 @@ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/mpeg,mpegversion=(int)1;" "audio/x-private1-lpcm;" - "audio/x-private1-ac3;" "audio/x-private1-dts;" "audio/ac3") + "audio/x-private1-ac3;" "audio/ac3;" "audio/x-ac3;" + "audio/x-private1-dts;") ); static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", @@ -72,10 +73,22 @@ 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 * sinkpad, GstCaps * caps); -static GstCaps *rsn_audiodec_get_sink_caps (GstPad * sinkpad); +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); static void rsn_audiodec_class_init (RsnAudioDecClass * klass) @@ -86,11 +99,16 @@ rsn_audiodec_class_init (RsnAudioDecClass * klass) "Resin DVD audio stream decoder", "Jan Schmidt <thaytan@noraisin.net>" }; + GObjectClass *object_class = G_OBJECT_CLASS (klass); GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GST_DEBUG_CATEGORY_INIT (rsn_audiodec_debug, "rsn_audiodec", + GST_DEBUG_CATEGORY_INIT (rsn_audiodec_debug, "rsnaudiodec", 0, "Resin DVD audio stream decoder"); + object_class->dispose = rsn_audiodec_dispose; + + element_class->change_state = GST_DEBUG_FUNCPTR (rsn_audiodec_change_state); + gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_template)); gst_element_class_add_pad_template (element_class, @@ -114,30 +132,306 @@ rsn_audiodec_init (RsnAudioDec * self) gst_element_add_pad (GST_ELEMENT (self), self->sinkpad); self->srcpad = gst_pad_new_from_static_template (&src_template, "src"); - gst_element_add_pad (GST_ELEMENT (self), self->srcpad); } +static void +rsn_audiodec_dispose (GObject * object) +{ + RsnAudioDec *self = (RsnAudioDec *) object; + cleanup_child (self); + + G_OBJECT_CLASS (rsn_audiodec_parent_class)->dispose (object); +} + static gboolean -rsn_audiodec_set_sink_caps (GstPad * sinkpad, GstCaps * caps) +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) { - return NULL; + /* FIXME: Calculate set of allowed caps for all discovered decoders */ + RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (sinkpad); + GstCaps *res; + if (self == NULL || self->child_sink == NULL) + goto error; + + res = gst_pad_get_caps (self->child_sink); + 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 = (RsnAudioDec *) 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) +{ + RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (pad); + GstCaps *ret; + + if (self != NULL && self->child_sink != NULL) { + ret = gst_pad_get_caps (self->child_sink); + } else + ret = gst_caps_new_any (); + + if (self) + gst_object_unref (self); + + return ret; +} + +static GstCaps * +rsn_audiodec_get_proxy_src_caps (GstPad * pad) +{ + RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (pad); + GstCaps *ret; + + if (self != NULL && self->child_src != NULL) { + ret = gst_pad_get_caps (self->child_src); + } else + ret = gst_caps_new_any (); + + if (self) + gst_object_unref (self); + + return ret; +} + +static GstFlowReturn +rsn_audiodec_proxy_src_chain (GstPad * pad, GstBuffer * buf) +{ + RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (pad); + GstFlowReturn ret; + + g_print ("srcpad %p\n", self->srcpad); + if (self != NULL && self->srcpad != NULL) { + GST_DEBUG_OBJECT (self, "Data from decoder, pushing to pad %" + GST_PTR_FORMAT, self->srcpad); + ret = gst_pad_push (self->srcpad, buf); + } else + ret = GST_FLOW_ERROR; + + if (self) + gst_object_unref (self); + + return ret; +} + +static gboolean +rsn_audiodec_proxy_src_event (GstPad * pad, GstEvent * event) +{ + RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (pad); + gboolean ret; + + if (self != NULL && self->srcpad != NULL) { + ret = gst_pad_push_event (self->srcpad, event); + } else + ret = GST_FLOW_ERROR; + + if (self) + 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_pad_set_getcaps_function (self->child_sink_proxy, + GST_DEBUG_FUNCPTR (rsn_audiodec_get_proxy_sink_caps)); + gst_object_set_parent ((GstObject *) self->child_sink_proxy, + (GstObject *) self); + } + + 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); + 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) +{ + if (self->current_decoder) { + 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) + 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)) + return FALSE; + + 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); + + g_print ("Returning TRUE\n"); + + return TRUE; +} + +static void +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 GstStateChangeReturn +rsn_audiodec_change_state (GstElement * element, GstStateChange transition) +{ + GstStateChangeReturn ret; + RsnAudioDec *self = RSN_AUDIODEC (element); + + g_print ("State change in element %p trans %d\n", element, transition); + 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 ("a52dec", NULL); + if (new_child == NULL || !rsn_audiodec_set_child (self, new_child)) + ret = GST_STATE_CHANGE_FAILURE; + 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; + } + + ret = + GST_ELEMENT_CLASS (rsn_audiodec_parent_class)->change_state (element, + transition); + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + 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); + break; + default: + break; + } + + return ret; + +} diff --git a/ext/resindvd/rsnaudiodec.h b/ext/resindvd/rsnaudiodec.h index 1c08f9f6..269a7b86 100644 --- a/ext/resindvd/rsnaudiodec.h +++ b/ext/resindvd/rsnaudiodec.h @@ -25,8 +25,8 @@ G_BEGIN_DECLS #define RSN_TYPE_AUDIODEC (rsn_audiodec_get_type()) -#define RSN_AUDIODEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),RSN_TYPE_AUDIODEC,RsnAudioMunge)) -#define RSN_AUDIODEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),RSN_TYPE_AUDIODEC,RsnAudioMungeClass)) +#define RSN_AUDIODEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),RSN_TYPE_AUDIODEC,RsnAudioDec)) +#define RSN_AUDIODEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),RSN_TYPE_AUDIODEC,RsnAudioDecClass)) #define RSN_IS_AUDIODEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),RSN_TYPE_AUDIODEC)) #define RSN_IS_AUDIODEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),RSN_TYPE_AUDIODEC)) @@ -38,10 +38,19 @@ typedef struct _RsnAudioDecClass RsnAudioDecClass; struct _RsnAudioDec { GstBin element; + /* Our sink and source pads */ GstPad *sinkpad; GstPad *srcpad; - GstElement *cur_dec; + /* Proxy pads that are linked to the child sink pad + * and source pad respectively */ + GstPad *child_sink_proxy; + GstPad *child_src_proxy; + + GstElement *current_decoder; + /* Current child's sink and source pads */ + GstPad *child_sink; + GstPad *child_src; }; struct _RsnAudioDecClass { |