diff --git a/ext/resindvd/resindvdbin.c b/ext/resindvd/resindvdbin.c
index e5f2828..7ee34c5 100644
--- a/ext/resindvd/resindvdbin.c
+++ b/ext/resindvd/resindvdbin.c
@@ -39,7 +39,7 @@ GST_DEBUG_CATEGORY_EXTERN (resindvd_debug);
 
 #define USE_VIDEOQ 0
 #define USE_HARDCODED_VIDEODEC 1
-#define USE_HARDCODED_AUDIODEC 1
+#define USE_HARDCODED_AUDIODEC 0
 
 #define DVDBIN_LOCK(d) g_mutex_lock((d)->dvd_lock)
 #define DVDBIN_UNLOCK(d) g_mutex_unlock((d)->dvd_lock)
@@ -102,8 +102,6 @@ static void rsn_dvdbin_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 static GstStateChangeReturn rsn_dvdbin_change_state (GstElement * element,
     GstStateChange transition);
-static void dvdbin_pad_blocked_cb (GstPad * pad, gboolean blocked,
-    RsnDvdBin * dvdbin);
 
 static void
 rsn_dvdbin_base_init (gpointer gclass)
@@ -343,11 +341,28 @@ add_failed:
   return FALSE;
 }
 
+typedef struct
+{
+  RsnDvdBin *dvdbin;
+  GstPad *pad;
+} RsnDvdBinPadBlockCtx;
+
+static void dvdbin_pad_blocked_cb (GstPad * pad, gboolean blocked,
+    RsnDvdBinPadBlockCtx * ctx);
+static void
+_pad_block_destroy_notify (RsnDvdBinPadBlockCtx * ctx)
+{
+  gst_object_unref (ctx->dvdbin);
+  gst_object_unref (ctx->pad);
+  g_slice_free (RsnDvdBinPadBlockCtx, ctx);
+}
+
 static gboolean
 create_elements (RsnDvdBin * dvdbin)
 {
   GstPad *src = NULL;
   GstPad *sink = NULL;
+  RsnDvdBinPadBlockCtx *bctx = NULL;
 
   if (!try_create_piece (dvdbin, DVD_ELEM_SOURCE, NULL,
           RESIN_TYPE_DVDSRC, "dvdsrc", "DVD source")) {
@@ -439,11 +454,15 @@ create_elements (RsnDvdBin * dvdbin)
   dvdbin->video_pad = gst_ghost_pad_new ("video", src);
   if (dvdbin->video_pad == NULL)
     goto failed_video_ghost;
+  gst_pad_set_active (dvdbin->video_pad, TRUE);
+  bctx = g_slice_new (RsnDvdBinPadBlockCtx);
+  bctx->dvdbin = gst_object_ref (dvdbin);
+  bctx->pad = gst_object_ref (dvdbin->video_pad);
+  gst_pad_set_blocked_async_full (src, TRUE,
+      (GstPadBlockCallback) dvdbin_pad_blocked_cb, bctx, (GDestroyNotify)
+      _pad_block_destroy_notify);
   gst_object_unref (src);
   src = NULL;
-  gst_pad_set_active (dvdbin->video_pad, TRUE);
-  gst_pad_set_blocked_async (dvdbin->video_pad, TRUE,
-      (GstPadBlockCallback) dvdbin_pad_blocked_cb, dvdbin);
 
 #if USE_HARDCODED_VIDEODEC
   gst_element_add_pad (GST_ELEMENT (dvdbin), dvdbin->video_pad);
@@ -479,8 +498,12 @@ create_elements (RsnDvdBin * dvdbin)
   if (dvdbin->subpicture_pad == NULL)
     goto failed_spu_ghost;
   gst_pad_set_active (dvdbin->subpicture_pad, TRUE);
-  gst_pad_set_blocked_async (dvdbin->subpicture_pad, TRUE,
-      (GstPadBlockCallback) dvdbin_pad_blocked_cb, dvdbin);
+  bctx = g_slice_new (RsnDvdBinPadBlockCtx);
+  bctx->dvdbin = gst_object_ref (dvdbin);
+  bctx->pad = gst_object_ref (dvdbin->subpicture_pad);
+  gst_pad_set_blocked_async_full (src, TRUE,
+      (GstPadBlockCallback) dvdbin_pad_blocked_cb, bctx, (GDestroyNotify)
+      _pad_block_destroy_notify);
   gst_object_unref (src);
   src = NULL;
 
@@ -532,8 +555,12 @@ create_elements (RsnDvdBin * dvdbin)
   if (dvdbin->audio_pad == NULL)
     goto failed_aud_ghost;
   gst_pad_set_active (dvdbin->audio_pad, TRUE);
-  gst_pad_set_blocked_async (dvdbin->audio_pad, TRUE,
-      (GstPadBlockCallback) dvdbin_pad_blocked_cb, dvdbin);
+  bctx = g_slice_new (RsnDvdBinPadBlockCtx);
+  bctx->dvdbin = gst_object_ref (dvdbin);
+  bctx->pad = gst_object_ref (dvdbin->audio_pad);
+  gst_pad_set_blocked_async_full (src, TRUE,
+      (GstPadBlockCallback) dvdbin_pad_blocked_cb, bctx, (GDestroyNotify)
+      _pad_block_destroy_notify);
   gst_object_unref (src);
   src = NULL;
 
@@ -670,6 +697,24 @@ connect_thru_mq (RsnDvdBin * dvdbin, GstPad * pad)
   return mq_src;
 }
 
+static gboolean
+can_sink_caps (GstElement * e, GstCaps * caps)
+{
+  gboolean res = FALSE;
+  GstPad *sink = gst_element_get_static_pad (e, "sink");
+
+  if (sink) {
+    GstCaps *sink_caps = gst_pad_get_caps (sink);
+    if (sink_caps) {
+      res = gst_caps_can_intersect (sink_caps, caps);
+      gst_caps_unref (sink_caps);
+    }
+    gst_object_unref (sink);
+  }
+
+  return res;
+}
+
 static void
 demux_pad_added (GstElement * element, GstPad * pad, RsnDvdBin * dvdbin)
 {
@@ -693,6 +738,9 @@ demux_pad_added (GstElement * element, GstPad * pad, RsnDvdBin * dvdbin)
     return;
   }
 
+  GST_DEBUG_OBJECT (dvdbin,
+      "Pad %" GST_PTR_FORMAT " has caps: %" GST_PTR_FORMAT, pad, caps);
+
   s = gst_caps_get_structure (caps, 0);
   g_return_if_fail (s != NULL);
 
@@ -704,10 +752,15 @@ demux_pad_added (GstElement * element, GstPad * pad, RsnDvdBin * dvdbin)
         gst_element_get_request_pad (dvdbin->pieces[DVD_ELEM_SPU_SELECT],
         "sink%d");
     skip_mq = TRUE;
-  } else if (g_str_equal (gst_structure_get_name (s), "audio/x-private1-ac3")) {
+  } else if (can_sink_caps (dvdbin->pieces[DVD_ELEM_AUDDEC], caps)) {
+    GST_LOG_OBJECT (dvdbin, "Found audio pad w/ caps %" GST_PTR_FORMAT, caps);
     dest_pad =
         gst_element_get_request_pad (dvdbin->pieces[DVD_ELEM_AUD_SELECT],
         "sink%d");
+  } else {
+    /* FIXME: Consider and fire a missing-element message here */
+    GST_DEBUG_OBJECT (dvdbin, "Ignoring unusable pad w/ caps %" GST_PTR_FORMAT,
+        caps);
   }
 
   gst_caps_unref (caps);
@@ -744,15 +797,25 @@ failed:
 }
 
 static void
-dvdbin_pad_blocked_cb (GstPad * pad, gboolean blocked, RsnDvdBin * dvdbin)
+dvdbin_pad_blocked_cb (GstPad * opad, gboolean blocked,
+    RsnDvdBinPadBlockCtx * ctx)
 {
+  RsnDvdBin *dvdbin;
+  GstPad *pad;
   gboolean added_last_pad = FALSE;
   gboolean added = FALSE;
-  if (!blocked)
+
+  /* If not blocked ctx is NULL! */
+  if (!blocked) {
+    GST_DEBUG_OBJECT (opad, "Pad unblocked");
     return;
+  }
+
+  dvdbin = ctx->dvdbin;
+  pad = ctx->pad;
 
   if (pad == dvdbin->subpicture_pad) {
-    GST_DEBUG_OBJECT (dvdbin, "Pad block -> subpicture pad");
+    GST_DEBUG_OBJECT (opad, "Pad block -> subpicture pad");
     DVDBIN_PREROLL_LOCK (dvdbin);
     added = dvdbin->subpicture_added;
     dvdbin->subpicture_added = TRUE;
@@ -763,10 +826,10 @@ dvdbin_pad_blocked_cb (GstPad * pad, gboolean blocked, RsnDvdBin * dvdbin)
     }
     DVDBIN_PREROLL_UNLOCK (dvdbin);
 
-    gst_pad_set_blocked_async (pad, FALSE,
-        (GstPadBlockCallback) dvdbin_pad_blocked_cb, dvdbin);
+    gst_pad_set_blocked_async (opad, FALSE,
+        (GstPadBlockCallback) dvdbin_pad_blocked_cb, NULL);
   } else if (pad == dvdbin->audio_pad) {
-    GST_DEBUG_OBJECT (dvdbin, "Pad block -> audio pad");
+    GST_DEBUG_OBJECT (opad, "Pad block -> audio pad");
     DVDBIN_PREROLL_LOCK (dvdbin);
     added = dvdbin->audio_added;
     dvdbin->audio_added = TRUE;
@@ -777,10 +840,10 @@ dvdbin_pad_blocked_cb (GstPad * pad, gboolean blocked, RsnDvdBin * dvdbin)
     }
     DVDBIN_PREROLL_UNLOCK (dvdbin);
 
-    gst_pad_set_blocked_async (pad, FALSE,
-        (GstPadBlockCallback) dvdbin_pad_blocked_cb, dvdbin);
+    gst_pad_set_blocked_async (opad, FALSE,
+        (GstPadBlockCallback) dvdbin_pad_blocked_cb, NULL);
   } else if (pad == dvdbin->video_pad) {
-    GST_DEBUG_OBJECT (dvdbin, "Pad block -> video pad");
+    GST_DEBUG_OBJECT (opad, "Pad block -> video pad");
 
     DVDBIN_PREROLL_LOCK (dvdbin);
     added = dvdbin->video_added;
@@ -792,8 +855,8 @@ dvdbin_pad_blocked_cb (GstPad * pad, gboolean blocked, RsnDvdBin * dvdbin)
     }
     DVDBIN_PREROLL_UNLOCK (dvdbin);
 
-    gst_pad_set_blocked_async (pad, FALSE,
-        (GstPadBlockCallback) dvdbin_pad_blocked_cb, dvdbin);
+    gst_pad_set_blocked_async (opad, FALSE,
+        (GstPadBlockCallback) dvdbin_pad_blocked_cb, NULL);
   }
 
   if (added_last_pad) {
diff --git a/ext/resindvd/rsnaudiodec.c b/ext/resindvd/rsnaudiodec.c
index 0118ef2..f65c8f5 100644
--- a/ext/resindvd/rsnaudiodec.c
+++ b/ext/resindvd/rsnaudiodec.c
@@ -21,6 +21,8 @@
 #include "config.h"
 #endif
 
+#include <string.h>
+
 #include "rsnaudiodec.h"
 
 GST_DEBUG_CATEGORY_STATIC (rsn_audiodec_debug);
@@ -73,23 +75,15 @@ 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);
 
+static GList *decoder_factories = NULL;
+static GstCaps *decoder_caps = NULL;
+
 static void
 rsn_audiodec_class_init (RsnAudioDecClass * klass)
 {
@@ -117,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,
+  GstPadTemplate *templ;
+
+  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));
-  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);
+  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
@@ -145,276 +161,182 @@ rsn_audiodec_dispose (GObject * 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)
-{
-  /* 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)
+rsn_audiodec_set_child (RsnAudioDec * self, GstElement * new_child)
 {
-  RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (pad);
-  GstFlowReturn res;
-  if (self == NULL)
-    goto error;
+  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;
+  }
 
-  GST_INFO_OBJECT (self, "Pushing buffer %" GST_PTR_FORMAT " into decoder",
-      buf);
-  res = gst_pad_chain (self->child_sink, buf);
+  if (new_child == NULL)
+    return TRUE;
 
-  gst_object_unref (self);
-  return res;
-error:
-  if (self)
-    gst_object_unref (self);
-  return GST_FLOW_ERROR;
-}
+  if (!gst_bin_add ((GstBin *) self, new_child))
+    return FALSE;
 
-static gboolean
-rsn_audiodec_sink_event (GstPad * pad, GstEvent * event)
-{
-  GstPad *sinkpad = GST_PAD (gst_pad_get_parent (pad));
-  RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (sinkpad);
-  gboolean res;
+  child_pad = gst_element_get_static_pad (new_child, "sink");
+  if (child_pad == NULL) {
+    return FALSE;
+  }
+  gst_ghost_pad_set_target (self->sinkpad, child_pad);
+  gst_object_unref (child_pad);
 
-  gst_object_unref (sinkpad);
+  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);
 
-  if (self == NULL)
-    goto error;
+  GST_DEBUG_OBJECT (self, "Add child %" GST_PTR_FORMAT, new_child);
+  self->current_decoder = new_child;
 
-  GST_INFO_OBJECT (self, "Sending event %" GST_PTR_FORMAT " into decoder",
-      event);
-  res = gst_pad_send_event (self->child_sink, event);
+  gst_element_sync_state_with_parent (new_child);
 
-  gst_object_unref (self);
-  return res;
-error:
-  if (self)
-    gst_object_unref (self);
-  return FALSE;
+  return TRUE;
 }
 
-static GstCaps *
-rsn_audiodec_get_proxy_sink_caps (GstPad * pad)
+static void
+cleanup_child (RsnAudioDec * self)
 {
-  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;
+  GST_DEBUG_OBJECT (self, "Removing child element");
+  (void) rsn_audiodec_set_child (self, NULL);
 }
 
-static GstCaps *
-rsn_audiodec_get_proxy_src_caps (GstPad * pad)
+static gboolean
+rsnaudiodec_factory_filter (GstPluginFeature * feature, GstCaps * desired_caps)
 {
-  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;
-}
+  GstElementFactory *factory;
+  guint rank;
+  const gchar *klass;
+  const GList *templates;
+  GList *walk;
+  gboolean can_sink = FALSE;
+
+  /* we only care about element factories */
+  if (!GST_IS_ELEMENT_FACTORY (feature))
+    return FALSE;
 
-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;
+  factory = GST_ELEMENT_FACTORY (feature);
 
-  gst_object_unref (srcpad);
+  klass = gst_element_factory_get_klass (factory);
+  /* only decoders can play */
+  if (strstr (klass, "Decoder") == NULL)
+    return FALSE;
 
-  if (self == NULL)
-    return GST_FLOW_ERROR;
+  /* only select elements with autoplugging rank */
+  rank = gst_plugin_feature_get_rank (feature);
+  if (rank < GST_RANK_MARGINAL)
+    return FALSE;
 
-  GST_DEBUG_OBJECT (self, "Data from decoder, pushing to pad %"
-      GST_PTR_FORMAT, self->srcpad);
-  ret = gst_pad_push (self->srcpad, buf);
+  /* See if the element has a sink pad that can possibly sink this caps */
+
+  /* get the templates from the element factory */
+  templates = gst_element_factory_get_static_pad_templates (factory);
+  for (walk = (GList *) templates; walk && !can_sink; walk = g_list_next (walk)) {
+    GstStaticPadTemplate *templ = walk->data;
+
+    /* we only care about the sink templates */
+    if (templ->direction == GST_PAD_SINK) {
+      GstCaps *intersect;
+      GstCaps *tmpl_caps;
+
+      /* try to intersect the caps with the caps of the template */
+      tmpl_caps = gst_static_caps_get (&templ->static_caps);
+
+      intersect = gst_caps_intersect (desired_caps, tmpl_caps);
+      gst_caps_unref (tmpl_caps);
+
+      /* check if the intersection is empty */
+      if (!gst_caps_is_empty (intersect)) {
+        GstCaps *new_dec_caps;
+        /* non empty intersection, we can use this element */
+        can_sink = TRUE;
+        new_dec_caps = gst_caps_union (decoder_caps, intersect);
+        gst_caps_unref (decoder_caps);
+        decoder_caps = new_dec_caps;
+      }
+      gst_caps_unref (intersect);
+    }
+  }
 
-  gst_object_unref (self);
+  if (can_sink) {
+    GST_DEBUG ("Found decoder element %s (%s)",
+        gst_element_factory_get_longname (factory),
+        gst_plugin_feature_get_name (feature));
+  }
 
-  return ret;
+  return can_sink;
 }
 
-static gboolean
-rsn_audiodec_proxy_src_event (GstPad * pad, GstEvent * event)
+static gint
+sort_by_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
 {
-  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;
+  gint diff;
+  const gchar *rname1, *rname2;
 
-  ret = gst_pad_push_event (self->srcpad, event);
+  diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
+  if (diff != 0)
+    return diff;
 
-  gst_object_unref (self);
-  return ret;
-}
+  rname1 = gst_plugin_feature_get_name (f1);
+  rname2 = gst_plugin_feature_get_name (f2);
 
-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));
-  }
+  diff = strcmp (rname2, rname1);
 
-  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));
-  }
+  return diff;
 }
 
-static gboolean
-rsn_audiodec_set_child (RsnAudioDec * self, GstElement * new_child)
+static gpointer
+_get_decoder_factories (gpointer arg)
 {
-  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;
-  }
+  GList *factories;
+  GstCaps *desired_caps =
+      gst_caps_from_string ("audio/mpeg,mpegversion = (int) 1;"
+      "audio/x-private1-lpcm; " "audio/x-private1-ac3; audio/ac3; "
+      "audio/x-private1-dts");
 
-  if (new_child == NULL)
-    return TRUE;
+  /* Set decoder caps to empty. Will be filled by the factory_filter */
+  decoder_caps = gst_caps_new_empty ();
 
-  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;
-  }
+  factories = gst_default_registry_feature_filter (
+      (GstPluginFeatureFilter) rsnaudiodec_factory_filter, FALSE, desired_caps);
 
-  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);
+  decoder_factories = g_list_sort (factories, (GCompareFunc) sort_by_ranks);
 
-  return TRUE;
-}
+  GST_DEBUG ("Available decoder caps %" GST_PTR_FORMAT, decoder_caps);
 
-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;
-  }
+  return NULL;
 }
 
 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 ("a52dec", NULL);
+      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);
       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;
   }
 
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    return ret;
   ret =
       GST_ELEMENT_CLASS (rsn_audiodec_parent_class)->change_state (element,
       transition);
@@ -423,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 269a7b8..bd74fc6 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 {
diff --git a/ext/resindvd/rsnbasesrc.c b/ext/resindvd/rsnbasesrc.c
index abbdf5e..503b6c0 100644
--- a/ext/resindvd/rsnbasesrc.c
+++ b/ext/resindvd/rsnbasesrc.c
@@ -131,6 +131,7 @@ rsn_base_src_get_type (void)
   }
   return base_src_type;
 }
+
 static GstCaps *rsn_base_src_getcaps (GstPad * pad);
 static gboolean rsn_base_src_setcaps (GstPad * pad, GstCaps * caps);
 static void rsn_base_src_fixate (GstPad * pad, GstCaps * caps);
diff --git a/ext/resindvd/rsnstreamselector.c b/ext/resindvd/rsnstreamselector.c
index 2c7e58e..7b38976 100644
--- a/ext/resindvd/rsnstreamselector.c
+++ b/ext/resindvd/rsnstreamselector.c
@@ -114,7 +114,6 @@ static GstPadClass *selector_pad_parent_class = NULL;
 static void gst_selector_pad_reset (RsnSelectorPad * pad);
 static gboolean gst_selector_pad_event (GstPad * pad, GstEvent * event);
 static GstCaps *gst_selector_pad_getcaps (GstPad * pad);
-static GList *gst_selector_pad_get_linked_pads (GstPad * pad);
 static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstBuffer * buf);
 static GstFlowReturn gst_selector_pad_bufferalloc (GstPad * pad,
     guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
@@ -233,23 +232,6 @@ gst_selector_pad_reset (RsnSelectorPad * pad)
   gst_segment_init (&pad->segment, GST_FORMAT_UNDEFINED);
 }
 
-/* strictly get the linked pad from the sinkpad. If the pad is active we return
- * the srcpad else we return NULL */
-static GList *
-gst_selector_pad_get_linked_pads (GstPad * pad)
-{
-  GstPad *otherpad;
-
-  otherpad = rsn_stream_selector_get_linked_pad (pad, TRUE);
-  if (!otherpad)
-    return NULL;
-
-  /* need to drop the ref, internal linked pads is not MT safe */
-  gst_object_unref (otherpad);
-
-  return g_list_append (NULL, otherpad);
-}
-
 static gboolean
 gst_selector_pad_event (GstPad * pad, GstEvent * event)
 {
@@ -467,7 +449,7 @@ static GstPad *rsn_stream_selector_request_new_pad (GstElement * element,
     GstPadTemplate * templ, const gchar * unused);
 static void rsn_stream_selector_release_pad (GstElement * element,
     GstPad * pad);
-static GList *rsn_stream_selector_get_linked_pads (GstPad * pad);
+static GstIterator *rsn_stream_selector_iterate_linked_pads (GstPad * pad);
 static GstCaps *rsn_stream_selector_getcaps (GstPad * pad);
 
 static GstElementClass *parent_class = NULL;
@@ -544,8 +526,8 @@ static void
 rsn_stream_selector_init (RsnStreamSelector * sel)
 {
   sel->srcpad = gst_pad_new ("src", GST_PAD_SRC);
-  gst_pad_set_internal_link_function (sel->srcpad,
-      GST_DEBUG_FUNCPTR (rsn_stream_selector_get_linked_pads));
+  gst_pad_set_iterate_internal_links_function (sel->srcpad,
+      GST_DEBUG_FUNCPTR (rsn_stream_selector_iterate_linked_pads));
   gst_pad_set_getcaps_function (sel->srcpad,
       GST_DEBUG_FUNCPTR (rsn_stream_selector_getcaps));
   gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad);
@@ -733,17 +715,19 @@ rsn_stream_selector_set_active (RsnStreamSelector * sel, GstPad * pad)
   GST_OBJECT_UNLOCK (GST_OBJECT_CAST (sel));
 }
 
-static GList *
-rsn_stream_selector_get_linked_pads (GstPad * pad)
+static GstIterator *
+rsn_stream_selector_iterate_linked_pads (GstPad * pad)
 {
-  GstPad *otherpad;
+  RsnStreamSelector *sel = RSN_STREAM_SELECTOR (gst_pad_get_parent (pad));
+  GstPad *otherpad = rsn_stream_selector_get_linked_pad (pad, TRUE);
+  GstIterator *it = gst_iterator_new_single (GST_TYPE_PAD, otherpad,
+      (GstCopyFunction) gst_object_ref, (GFreeFunc) gst_object_unref);
+
+  if (otherpad)
+    gst_object_unref (otherpad);
+  gst_object_unref (sel);
 
-  otherpad = rsn_stream_selector_get_linked_pad (pad, TRUE);
-  if (!otherpad)
-    return NULL;
-  /* need to drop the ref, internal linked pads is not MT safe */
-  gst_object_unref (otherpad);
-  return g_list_append (NULL, otherpad);
+  return it;
 }
 
 static GstPad *
@@ -771,8 +755,8 @@ rsn_stream_selector_request_new_pad (GstElement * element,
       GST_DEBUG_FUNCPTR (gst_selector_pad_getcaps));
   gst_pad_set_chain_function (sinkpad,
       GST_DEBUG_FUNCPTR (gst_selector_pad_chain));
-  gst_pad_set_internal_link_function (sinkpad,
-      GST_DEBUG_FUNCPTR (gst_selector_pad_get_linked_pads));
+  gst_pad_set_iterate_internal_links_function (sinkpad,
+      GST_DEBUG_FUNCPTR (rsn_stream_selector_iterate_linked_pads));
   gst_pad_set_bufferalloc_function (sinkpad,
       GST_DEBUG_FUNCPTR (gst_selector_pad_bufferalloc));
 
