Index: Makefile.am
===================================================================
RCS file: /cvs/gstreamer/gst-plugins/gst/apetag/Makefile.am,v
retrieving revision 1.1
diff -u -r1.1 Makefile.am
--- Makefile.am	25 Nov 2004 20:14:32 -0000	1.1
+++ Makefile.am	18 Jul 2005 08:25:15 -0000
@@ -2,7 +2,8 @@
 
 libgstapetag_la_SOURCES = \
 	apedemux.c \
-	apetag.c
+	apetag.c \
+	gstapedemuxbin.c
 libgstapetag_la_CFLAGS = $(GST_CFLAGS)
 libgstapetag_la_LIBADD =
 libgstapetag_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
Index: apedemux.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins/gst/apetag/apedemux.c,v
retrieving revision 1.6.2.2
diff -u -r1.6.2.2 apedemux.c
--- apedemux.c	22 Apr 2005 14:23:20 -0000	1.6.2.2
+++ apedemux.c	18 Jul 2005 08:25:16 -0000
@@ -38,7 +38,7 @@
 
 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
-    GST_PAD_SOMETIMES,          /* spider/decodebin hack */
+    GST_PAD_ALWAYS,
     GST_STATIC_CAPS_ANY);
 
 static void gst_ape_demux_base_init (GstApeDemuxClass * klass);
@@ -124,7 +124,6 @@
       "sink");
   gst_element_add_pad (GST_ELEMENT (ape), ape->sinkpad);
 
-#if 0
   ape->srcpad =
       gst_pad_new_from_template (gst_static_pad_template_get (&src_templ),
       "src");
@@ -134,10 +133,13 @@
   gst_pad_set_query_type_function (ape->srcpad,
       gst_ape_demux_get_src_query_types);
   gst_pad_set_query_function (ape->srcpad, gst_ape_demux_handle_src_query);
+#if 0
   gst_pad_use_explicit_caps (ape->srcpad);
-  gst_element_add_pad (GST_ELEMENT (ape), ape->srcpad);
 #endif
+  gst_element_add_pad (GST_ELEMENT (ape), ape->srcpad);
+#if 0
   ape->srcpad = NULL;
+#endif
 
   gst_element_set_loop_function (GST_ELEMENT (ape), gst_ape_demux_loop);
 
@@ -288,6 +290,7 @@
   return res;
 }
 
+#if 0
 /*
  * Find media type. Simple for now.
  */
@@ -416,6 +419,7 @@
 
   return TRUE;
 }
+#endif
 
 /*
  * Parse tags from a buffer.
@@ -596,10 +600,12 @@
     if (size != 0)
       gst_bytestream_flush_fast (bs, size);
 
+#if 0
     if (!gst_ape_demux_typefind (ape, bs, FALSE)) {
       res = FALSE;
       goto the_city;
     }
+#endif
 
     gst_bytestream_get_status (bs, &size, NULL);
     if (size) {
@@ -670,11 +676,13 @@
     }
   }
 
+#if 0
   /* typefind */
   if (!gst_ape_demux_typefind (ape, bs, TRUE)) {
     res = FALSE;
     goto the_city;
   }
+#endif
 
   /* push any leftover data */
   gst_bytestream_get_status (bs, &size, NULL);
@@ -806,10 +814,12 @@
 
   switch (GST_STATE_TRANSITION (element)) {
     case GST_STATE_PAUSED_TO_READY:
+#if 0
       if (ape->srcpad) {
         gst_element_remove_pad (element, ape->srcpad);
         ape->srcpad = NULL;
       }
+#endif
       ape->state = GST_APE_DEMUX_TAGREAD;
       ape->start_off = ape->end_off = 0;
       break;
Index: apetag.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins/gst/apetag/apetag.c,v
retrieving revision 1.1
diff -u -r1.1 apetag.c
--- apetag.c	25 Nov 2004 20:14:32 -0000	1.1
+++ apetag.c	18 Jul 2005 08:25:16 -0000
@@ -23,6 +23,7 @@
 #endif
 
 #include "apedemux.h"
+extern GType	gst_apedemux_bin_get_type	(void);
 
 static gboolean
 plugin_init (GstPlugin * plugin)
@@ -31,7 +32,9 @@
     return FALSE;
 
   return (gst_element_register (plugin, "apedemux",
-          GST_RANK_PRIMARY, GST_TYPE_APE_DEMUX));
+              GST_RANK_NONE, GST_TYPE_APE_DEMUX) &&
+          gst_element_register (plugin, "apedemuxbin",
+              GST_RANK_PRIMARY, gst_apedemux_bin_get_type ()));
 }
 
 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
--- /dev/null	2004-02-23 22:02:56.000000000 +0100
+++ gstapedemuxbin.c	2005-07-18 10:03:37.000000000 +0200
@@ -0,0 +1,250 @@
+/* GStreamer
+ * (c) 2005 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * gstapedemuxbin.c: hack around autoplugging.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_G
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#define GST_TYPE_APEDEMUX_BIN \
+  (gst_apedemux_bin_get_type())
+#define GST_APEDEMUX_BIN(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_APEDEMUX_BIN, \
+			      GstApeDemuxBin))
+#define GST_APEDEMUX_BIN_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_APEDEMUX_BIN, \
+			   GstApeDemuxBinClass))
+#define GST_IS_APEDEMUX_BIN(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_APEDEMUX_BIN))
+#define GST_IS_APEDEMUX_BIN_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_APEDEMUX_BIN))
+
+typedef struct _GstApeDemuxBin
+{
+  GstBin parent;
+
+  /* ghost pads */
+  GstPad *srcpad;
+
+  /* kids */
+  GstElement *demux, *typefind;
+
+  /* intercepted tag events */
+  GList *tag_events;
+} GstApeDemuxBin;
+
+typedef struct _GstApeDemuxBinClass
+{
+  GstBinClass parent;
+} GstApeDemuxBinClass;
+
+static GstStaticPadTemplate apedemux_bin_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("ANY")
+    );
+
+static GstStaticPadTemplate apedemux_bin_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-apetag")
+    );
+
+static void gst_apedemux_bin_class_init (GstApeDemuxBinClass * klass);
+static void gst_apedemux_bin_base_init (GstApeDemuxBinClass * klass);
+static void gst_apedemux_bin_init (GstApeDemuxBin * manager);
+
+static void found_type (GstElement * element, guint probability,
+    const GstCaps * caps, gpointer data);
+static GstElementStateReturn gst_apedemux_bin_change_state (GstElement *
+    element);
+
+static GstBinClass *parent_class;
+
+GType
+gst_apedemux_bin_get_type (void)
+{
+  static GType gst_apedemux_bin_type = 0;
+
+  if (!gst_apedemux_bin_type) {
+    static const GTypeInfo gst_apedemux_bin_info = {
+      sizeof (GstApeDemuxBinClass),
+      (GBaseInitFunc) gst_apedemux_bin_base_init,
+      NULL,
+      (GClassInitFunc) gst_apedemux_bin_class_init,
+      NULL,
+      NULL,
+      sizeof (GstApeDemuxBin),
+      0,
+      (GInstanceInitFunc) gst_apedemux_bin_init,
+      NULL
+    };
+
+    gst_apedemux_bin_type =
+        g_type_register_static (GST_TYPE_BIN,
+        "GstApeDemuxBin", &gst_apedemux_bin_info, 0);
+  }
+
+  return gst_apedemux_bin_type;
+}
+
+static void
+gst_apedemux_bin_base_init (GstApeDemuxBinClass * klass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  static GstElementDetails gst_apedemux_bin_details =
+      GST_ELEMENT_DETAILS ("APE-demux bin",
+      "Codec/Demuxer/Audio",
+      "Manages typefinding for an APE demuxer",
+      "Ronald Bultje <rbultje@ronald.bitfreak.net>");
+
+  gst_element_class_set_details (element_class, &gst_apedemux_bin_details);
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&apedemux_bin_src_template));
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&apedemux_bin_sink_template));
+}
+
+static void
+gst_apedemux_bin_class_init (GstApeDemuxBinClass * klass)
+{
+  parent_class = g_type_class_ref (GST_TYPE_BIN);
+
+  GST_ELEMENT_CLASS (klass)->change_state = gst_apedemux_bin_change_state;
+}
+
+static gboolean
+probe_cb (GstProbe * probe, GstData ** p_data, gpointer userdata)
+{
+  GstApeDemuxBin *ape = GST_APEDEMUX_BIN (userdata);
+
+  /* we are only interested in tag events that 
+   *  are sent before our ghost src pad exists */
+  if (ape->srcpad == NULL && p_data && *p_data && GST_IS_EVENT (*p_data)) {
+    GstEvent *event = GST_EVENT (*p_data);
+
+    if (GST_EVENT_TYPE (event) == GST_EVENT_TAG) {
+      gst_data_ref (*p_data);
+      ape->tag_events = g_list_append (ape->tag_events, event);
+    }
+  }
+
+  return TRUE;                  /* do not remove data */
+}
+
+
+static void
+gst_apedemux_bin_init (GstApeDemuxBin * ape)
+{
+  GstProbe *probe;
+  GstPad *probe_pad;
+
+  ape->demux = gst_element_factory_make ("apedemux", NULL);
+  ape->typefind = gst_element_factory_make ("typefind", NULL);
+
+  g_signal_connect (ape->typefind, "have-type", G_CALLBACK (found_type), ape);
+
+  gst_pad_use_explicit_caps (gst_element_get_pad (ape->typefind, "src"));
+
+  /* we have to intercept tag events that are sent before
+   * typefind is done with its typefinding and then re-send
+   * them after we have created our ghost src pad, otherwise
+   * those events will be discarded by typefind (but even if
+   * they were not, no downstream element would be able to
+   * catch them because we haven't created our src pad yet) */
+  probe_pad = gst_element_get_pad (ape->demux, "src");
+  probe = gst_probe_new (FALSE, probe_cb, ape);
+  gst_pad_add_probe (probe_pad, probe);
+
+  gst_element_add_ghost_pad (GST_ELEMENT (ape),
+      gst_element_get_pad (ape->demux, "sink"), "sink");
+
+  gst_bin_add_many (GST_BIN (ape), ape->demux, ape->typefind, NULL);
+  gst_element_link (ape->demux, ape->typefind);
+}
+
+static void
+gst_apedemux_bin_remove_pad (GstApeDemuxBin * ape)
+{
+  if (ape->srcpad) {
+    gst_element_remove_pad (GST_ELEMENT (ape), ape->srcpad);
+    ape->srcpad = NULL;
+  }
+}
+
+static void
+found_type (GstElement * element, guint probability,
+    const GstCaps * caps, gpointer data)
+{
+  GstApeDemuxBin *ape = GST_APEDEMUX_BIN (data);
+
+  /* get rid of old */
+  gst_apedemux_bin_remove_pad (ape);
+
+  GST_LOG ("Found type");
+
+  /* add new */
+  if (!gst_pad_set_explicit_caps (gst_element_get_pad (ape->typefind,
+              "src"), caps)) {
+    GST_ELEMENT_ERROR (ape, CORE, NEGOTIATION, (NULL), (NULL));
+    return;
+  }
+
+  ape->srcpad = gst_ghost_pad_new ("src",
+      gst_element_get_pad (ape->typefind, "src"));
+  gst_element_add_pad (GST_ELEMENT (ape), ape->srcpad);
+
+  while (ape->tag_events) {
+    GstEvent *ev = GST_EVENT (ape->tag_events->data);
+
+    GST_LOG ("Forwarding tag event intercepted earlier");
+    /* we are in processing context, so this should be fine
+     * even if it's not our own pad and we are not in a chain
+     * function, at least with our current schedulers */
+    gst_pad_push (GST_PAD (GST_GPAD_REALPAD (ape->srcpad)), GST_DATA (ev));
+    ape->tag_events = g_list_remove (ape->tag_events, ev);
+  }
+}
+
+static GstElementStateReturn
+gst_apedemux_bin_change_state (GstElement * element)
+{
+  GstApeDemuxBin *ape = GST_APEDEMUX_BIN (element);
+
+  switch (GST_STATE_TRANSITION (element)) {
+    case GST_STATE_PAUSED_TO_READY:
+      gst_apedemux_bin_remove_pad (ape);
+      g_list_foreach (ape->tag_events, (GFunc) gst_data_unref, NULL);
+      g_list_free (ape->tag_events);
+      ape->tag_events = NULL;
+      break;
+    default:
+      break;
+  }
+
+  if (GST_ELEMENT_CLASS (parent_class)->change_state)
+    return GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+  return GST_STATE_SUCCESS;
+}
