Merge branch 'tizen' into tizen_gst_1.19.2
[platform/upstream/gstreamer.git] / ext / kate / gstkatedec.c
index 6b1ee73..93854ed 100644 (file)
  *
  * 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.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 /**
  * SECTION:element-katedec
+ * @title: katedec
  * @see_also: oggdemux
  *
- * <refsect2>
- * <para>
- * This element decodes Kate streams
- * <ulink url="http://libkate.googlecode.com/">Kate</ulink> is a free codec
+ * This element decodes Kate streams.
+ *
+ * [Kate](http://libkate.googlecode.com/) is a free codec
  * for text based data, such as subtitles. Any number of kate streams can be
  * embedded in an Ogg stream.
- * </para>
- * <para>
+ *
  * libkate (see above url) is needed to build this plugin.
- * </para>
- * <title>Example pipeline</title>
- * <para>
- * This explicitely decodes a Kate stream:
- * <programlisting>
- * gst-launch filesrc location=test.ogg ! oggdemux ! katedec ! fakesink silent=TRUE
- * </programlisting>
- * </para>
- * <para>
+ *
+ * ## Example pipeline
+ *
+ * This explicitly decodes a Kate stream:
+ * |[
+ * gst-launch-1.0 filesrc location=test.ogg ! oggdemux ! katedec ! fakesink silent=TRUE
+ * ]|
+ *
  * This will automatically detect and use any Kate streams multiplexed
  * in an Ogg stream:
- * <programlisting>
- * gst-launch playbin uri=file:///tmp/test.ogg
- * </programlisting>
- * </para>
- * </refsect2>
+ * |[
+ * gst-launch-1.0 playbin uri=file:///tmp/test.ogg
+ * ]|
+ *
  */
 
 #ifdef HAVE_CONFIG_H
@@ -82,7 +79,7 @@
 
 #include <gst/gst.h>
 
-#include "gstkate.h"
+#include "gstkateelements.h"
 #include "gstkatespu.h"
 #include "gstkatedec.h"
 
@@ -114,24 +111,37 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("text/plain; text/x-pango-markup; " GST_KATE_SPU_MIME_TYPE)
+    GST_STATIC_CAPS ("text/x-raw, format = { pango-markup, utf8 }; "
+        GST_KATE_SPU_MIME_TYPE)
     );
 
+GST_DEBUG_CATEGORY (gst_katedec_debug);
+
 #define gst_kate_dec_parent_class parent_class
 G_DEFINE_TYPE (GstKateDec, gst_kate_dec, GST_TYPE_ELEMENT);
+#define _do_init \
+  kate_element_init (plugin); \
+  GST_DEBUG_CATEGORY_INIT (gst_katedec_debug, "katedec", 0, "Kate decoder");
+GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (katedec, "katedec", GST_RANK_PRIMARY,
+    GST_TYPE_KATE_DEC, _do_init);
 
 static void gst_kate_dec_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
 static void gst_kate_dec_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
-static GstFlowReturn gst_kate_dec_chain (GstPad * pad, GstBuffer * buf);
+static GstFlowReturn gst_kate_dec_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buf);
 static GstStateChangeReturn gst_kate_dec_change_state (GstElement * element,
     GstStateChange transition);
-static gboolean gst_kate_dec_sink_query (GstPad * pad, GstQuery * query);
-static gboolean gst_kate_dec_sink_event (GstPad * pad, GstEvent * event);
-static gboolean gst_kate_dec_sink_handle_event (GstPad * pad, GstEvent * event);
-static GstCaps *gst_kate_dec_src_get_caps (GstPad * pad, GstCaps * filter);
+static gboolean gst_kate_dec_sink_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+static gboolean gst_kate_dec_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static gboolean gst_kate_dec_sink_handle_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static gboolean gst_kate_dec_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
 
 /* initialize the plugin's class */
 static void
@@ -156,12 +166,10 @@ gst_kate_dec_class_init (GstKateDecClass * klass)
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_kate_dec_change_state);
 
-  gst_element_class_add_pad_template (gstelement_class,
-      gst_static_pad_template_get (&src_factory));
-  gst_element_class_add_pad_template (gstelement_class,
-      gst_static_pad_template_get (&sink_factory));
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
 
-  gst_element_class_set_details_simple (gstelement_class,
+  gst_element_class_set_static_metadata (gstelement_class,
       "Kate stream text decoder", "Codec/Decoder/Subtitle",
       "Decodes Kate text streams",
       "Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>");
@@ -175,6 +183,7 @@ gst_kate_dec_class_init (GstKateDecClass * klass)
 static void
 gst_kate_dec_init (GstKateDec * dec)
 {
+  GstCaps *tmp = NULL;
   GST_DEBUG_OBJECT (dec, "gst_kate_dec_init");
 
   dec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
@@ -186,17 +195,19 @@ gst_kate_dec_init (GstKateDec * dec)
       GST_DEBUG_FUNCPTR (gst_kate_dec_sink_event));
   gst_pad_use_fixed_caps (dec->sinkpad);
   gst_pad_set_caps (dec->sinkpad,
-      gst_static_pad_template_get_caps (&sink_factory));
+      tmp = gst_static_pad_template_get_caps (&sink_factory));
   gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
 
   dec->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
-  gst_pad_set_getcaps_function (dec->srcpad,
-      GST_DEBUG_FUNCPTR (gst_kate_dec_src_get_caps));
+  gst_pad_set_query_function (dec->srcpad,
+      GST_DEBUG_FUNCPTR (gst_kate_dec_src_query));
   gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
 
   gst_kate_util_decode_base_init (&dec->decoder, TRUE);
 
+  gst_caps_unref(tmp);
   dec->src_caps = NULL;
+  dec->output_format = GST_KATE_FORMAT_UNDEFINED;
   dec->remove_markup = FALSE;
 }
 
@@ -230,6 +241,114 @@ gst_kate_dec_get_property (GObject * object, guint prop_id,
   }
 }
 
+static GstFlowReturn
+gst_kate_dec_handle_kate_event (GstKateDec * kd, const kate_event * ev)
+{
+  GstFlowReturn rflow = GST_FLOW_OK;
+  GstKateFormat format = GST_KATE_FORMAT_UNDEFINED;
+  gchar *escaped;
+  GstBuffer *buffer;
+  size_t len;
+  gboolean plain = TRUE;
+
+  if (kd->remove_markup && ev->text_markup_type != kate_markup_none) {
+    size_t len0 = ev->len + 1;
+    escaped = g_strdup (ev->text);
+    if (escaped) {
+      kate_text_remove_markup (ev->text_encoding, escaped, &len0);
+    }
+    plain = TRUE;
+  } else if (ev->text_markup_type == kate_markup_none) {
+    /* no pango markup yet, escape text */
+    /* TODO: actually do the pango thing */
+    escaped = g_strdup (ev->text);
+    plain = TRUE;
+  } else {
+    escaped = g_strdup (ev->text);
+    plain = FALSE;
+  }
+
+  if (G_LIKELY (escaped)) {
+    len = strlen (escaped);
+    if (len > 0) {
+      GST_DEBUG_OBJECT (kd, "kate event: %s, escaped %s", ev->text, escaped);
+      buffer = gst_buffer_new_and_alloc (len + 1);
+      if (G_LIKELY (buffer)) {
+        GstCaps *caps;
+        if (plain)
+          format = GST_KATE_FORMAT_TEXT_UTF8;
+        else
+          format = GST_KATE_FORMAT_TEXT_PANGO_MARKUP;
+        if (format != kd->output_format) {
+          caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
+              (format == GST_KATE_FORMAT_TEXT_UTF8) ? "utf8" : "pango-markup",
+              NULL);
+          gst_pad_push_event (kd->srcpad, gst_event_new_caps (caps));
+          gst_caps_unref (caps);
+          kd->output_format = format;
+        }
+        /* allocate and copy the NULs, but don't include them in passed size */
+        gst_buffer_fill (buffer, 0, escaped, len + 1);
+        gst_buffer_resize (buffer, 0, len);
+        GST_BUFFER_TIMESTAMP (buffer) = ev->start_time * GST_SECOND;
+        GST_BUFFER_DURATION (buffer) =
+            (ev->end_time - ev->start_time) * GST_SECOND;
+        rflow = gst_pad_push (kd->srcpad, buffer);
+        if (rflow == GST_FLOW_NOT_LINKED) {
+          GST_DEBUG_OBJECT (kd, "source pad not linked, ignored");
+        } else if (rflow != GST_FLOW_OK) {
+          GST_WARNING_OBJECT (kd, "failed to push buffer: %s",
+              gst_flow_get_name (rflow));
+        }
+      } else {
+        GST_ELEMENT_ERROR (kd, STREAM, DECODE, (NULL),
+            ("Failed to create buffer"));
+        rflow = GST_FLOW_ERROR;
+      }
+    } else {
+      GST_WARNING_OBJECT (kd, "Empty string, nothing to do");
+      rflow = GST_FLOW_OK;
+    }
+    g_free (escaped);
+  } else {
+    GST_ELEMENT_ERROR (kd, STREAM, DECODE, (NULL),
+        ("Failed to allocate string"));
+    rflow = GST_FLOW_ERROR;
+  }
+
+  /* if there's a background paletted bitmap, construct a DVD SPU for it */
+  if (ev->bitmap && ev->palette) {
+    GstBuffer *buffer = gst_kate_spu_encode_spu (kd, ev);
+    if (buffer) {
+      GstCaps *caps;
+
+      GST_BUFFER_TIMESTAMP (buffer) = ev->start_time * GST_SECOND;
+      GST_BUFFER_DURATION (buffer) =
+          (ev->end_time - ev->start_time) * GST_SECOND;
+
+      if (kd->output_format != GST_KATE_FORMAT_SPU) {
+        caps = gst_caps_new_empty_simple (GST_KATE_SPU_MIME_TYPE);
+        gst_pad_push_event (kd->srcpad, gst_event_new_caps (caps));
+        gst_caps_unref (caps);
+        kd->output_format = GST_KATE_FORMAT_SPU;
+      }
+
+      rflow = gst_pad_push (kd->srcpad, buffer);
+      if (rflow == GST_FLOW_NOT_LINKED) {
+        GST_DEBUG_OBJECT (kd, "source pad not linked, ignored");
+      } else if (rflow != GST_FLOW_OK) {
+        GST_WARNING_OBJECT (kd, "failed to push buffer: %s",
+            gst_flow_get_name (rflow));
+      }
+    } else {
+      GST_ELEMENT_ERROR (kd, STREAM, DECODE, (NULL),
+          ("failed to create SPU from paletted bitmap"));
+      rflow = GST_FLOW_ERROR;
+    }
+  }
+  return rflow;
+}
+
 /* GstElement vmethod implementations */
 
 /* chain function
@@ -237,9 +356,9 @@ gst_kate_dec_get_property (GObject * object, guint prop_id,
  */
 
 static GstFlowReturn
-gst_kate_dec_chain (GstPad * pad, GstBuffer * buf)
+gst_kate_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
 {
-  GstKateDec *kd = GST_KATE_DEC (gst_pad_get_parent (pad));
+  GstKateDec *kd = GST_KATE_DEC (parent);
   const kate_event *ev = NULL;
   GstFlowReturn rflow = GST_FLOW_OK;
 
@@ -254,96 +373,15 @@ gst_kate_dec_chain (GstPad * pad, GstBuffer * buf)
       GST_ELEMENT_CAST (kd), pad, buf, kd->srcpad, kd->srcpad, &kd->src_caps,
       &ev);
   if (G_UNLIKELY (rflow != GST_FLOW_OK)) {
-    gst_object_unref (kd);
     gst_buffer_unref (buf);
     return rflow;
   }
 
   if (ev) {
-    gchar *escaped;
-    GstBuffer *buffer;
-    size_t len;
-    gboolean plain = TRUE;
-
-    if (kd->remove_markup && ev->text_markup_type != kate_markup_none) {
-      size_t len0 = ev->len + 1;
-      escaped = g_strdup (ev->text);
-      if (escaped) {
-        kate_text_remove_markup (ev->text_encoding, escaped, &len0);
-      }
-      plain = TRUE;
-    } else if (ev->text_markup_type == kate_markup_none) {
-      /* no pango markup yet, escape text */
-      /* TODO: actually do the pango thing */
-      escaped = g_strdup (ev->text);
-      plain = TRUE;
-    } else {
-      escaped = g_strdup (ev->text);
-      plain = FALSE;
-    }
-
-    if (G_LIKELY (escaped)) {
-      len = strlen (escaped);
-      if (len > 0) {
-        GST_DEBUG_OBJECT (kd, "kate event: %s, escaped %s", ev->text, escaped);
-        buffer = gst_buffer_new_and_alloc (len + 1);
-        if (G_LIKELY (buffer)) {
-          const char *mime = plain ? "text/plain" : "text/x-pango-markup";
-          GstCaps *caps = gst_caps_new_empty_simple (mime);
-          gst_caps_unref (caps);
-          /* allocate and copy the NULs, but don't include them in passed size */
-          gst_buffer_fill (buffer, 0, escaped, len + 1);
-          gst_buffer_resize (buffer, 0, len);
-          GST_BUFFER_TIMESTAMP (buffer) = ev->start_time * GST_SECOND;
-          GST_BUFFER_DURATION (buffer) =
-              (ev->end_time - ev->start_time) * GST_SECOND;
-          rflow = gst_pad_push (kd->srcpad, buffer);
-          if (rflow == GST_FLOW_NOT_LINKED) {
-            GST_DEBUG_OBJECT (kd, "source pad not linked, ignored");
-          } else if (rflow != GST_FLOW_OK) {
-            GST_WARNING_OBJECT (kd, "failed to push buffer: %s",
-                gst_flow_get_name (rflow));
-          }
-        } else {
-          GST_ELEMENT_ERROR (kd, STREAM, DECODE, (NULL),
-              ("Failed to create buffer"));
-          rflow = GST_FLOW_ERROR;
-        }
-      } else {
-        GST_WARNING_OBJECT (kd, "Empty string, nothing to do");
-        rflow = GST_FLOW_OK;
-      }
-      g_free (escaped);
-    } else {
-      GST_ELEMENT_ERROR (kd, STREAM, DECODE, (NULL),
-          ("Failed to allocate string"));
-      rflow = GST_FLOW_ERROR;
-    }
-
-    // if there's a background paletted bitmap, construct a DVD SPU for it
-    if (ev->bitmap && ev->palette) {
-      GstBuffer *buffer = gst_kate_spu_encode_spu (kd, ev);
-      if (buffer) {
-        GST_BUFFER_TIMESTAMP (buffer) = ev->start_time * GST_SECOND;
-        GST_BUFFER_DURATION (buffer) =
-            (ev->end_time - ev->start_time) * GST_SECOND;
-        rflow = gst_pad_push (kd->srcpad, buffer);
-        if (rflow == GST_FLOW_NOT_LINKED) {
-          GST_DEBUG_OBJECT (kd, "source pad not linked, ignored");
-        } else if (rflow != GST_FLOW_OK) {
-          GST_WARNING_OBJECT (kd, "failed to push buffer: %s",
-              gst_flow_get_name (rflow));
-        }
-      } else {
-        GST_ELEMENT_ERROR (kd, STREAM, DECODE, (NULL),
-            ("failed to create SPU from paletted bitmap"));
-        rflow = GST_FLOW_ERROR;
-      }
-    }
+    rflow = gst_kate_dec_handle_kate_event (kd, ev);
   }
 
 not_in_seg:
-  gst_object_unref (kd);
   gst_buffer_unref (buf);
   return rflow;
 }
@@ -365,89 +403,161 @@ gst_kate_dec_change_state (GstElement * element, GstStateChange transition)
 }
 
 gboolean
-gst_kate_dec_sink_query (GstPad * pad, GstQuery * query)
+gst_kate_dec_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
 {
-  GstKateDec *kd = GST_KATE_DEC (gst_pad_get_parent (pad));
+  GstKateDec *kd = GST_KATE_DEC (parent);
   gboolean res =
       gst_kate_decoder_base_sink_query (&kd->decoder, GST_ELEMENT_CAST (kd),
-      pad, query);
-  gst_object_unref (kd);
+      pad, parent, query);
   return res;
 }
 
 static gboolean
-gst_kate_dec_sink_event (GstPad * pad, GstEvent * event)
+gst_kate_dec_set_caps (GstKateDec * kd, GstCaps * caps)
 {
-  GstKateDec *kd = (GstKateDec *) (gst_object_get_parent (GST_OBJECT (pad)));
+  GstStructure *structure = gst_caps_get_structure (caps, 0);
+  GstFlowReturn rflow = GST_FLOW_OK;
+
+  if (gst_structure_has_field (structure, "streamheader")) {
+    const GValue *value;
+    GstBuffer *buf;
+    const kate_event *ev;
+
+    value = gst_structure_get_value (structure, "streamheader");
+
+    if (GST_VALUE_HOLDS_BUFFER (value)) {
+      buf = gst_value_get_buffer (value);
+
+      gst_kate_util_decoder_base_chain_kate_packet (&kd->decoder,
+          GST_ELEMENT_CAST (kd), kd->sinkpad, buf, kd->srcpad, kd->srcpad,
+          &kd->src_caps, &ev);
+
+      if (ev) {
+        rflow = gst_kate_dec_handle_kate_event (kd, ev);
+      }
+    } else if (GST_VALUE_HOLDS_ARRAY (value)) {
+      gint i, size = gst_value_array_get_size (value);
+
+      for (i = 0; i < size; i++) {
+        const GValue *v = gst_value_array_get_value (value, i);
+
+        buf = gst_value_get_buffer (v);
+        gst_kate_util_decoder_base_chain_kate_packet (&kd->decoder,
+            GST_ELEMENT_CAST (kd), kd->sinkpad, buf, kd->srcpad, kd->srcpad,
+            &kd->src_caps, &ev);
+
+        if (ev) {
+          rflow = gst_kate_dec_handle_kate_event (kd, ev);
+          if (rflow != GST_FLOW_OK && rflow != GST_FLOW_NOT_LINKED)
+            break;
+        }
+      }
+    } else {
+      GST_WARNING_OBJECT (kd, "Unhandled streamheader type: %s",
+          G_VALUE_TYPE_NAME (value));
+    }
+  }
+
+  return rflow == GST_FLOW_OK || rflow == GST_FLOW_NOT_LINKED;
+}
+
+static gboolean
+gst_kate_dec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstKateDec *kd = GST_KATE_DEC (parent);
   gboolean res = TRUE;
 
-  GST_LOG_OBJECT (pad, "Event on sink pad: %s", GST_EVENT_TYPE_NAME (event));
+  GST_LOG_OBJECT (pad, "Event on sink pad: %" GST_PTR_FORMAT, event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:{
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      gst_kate_dec_set_caps (kd, caps);
+      break;
+    }
+    default:
+      break;
+  }
 
   /* Delay events till we've set caps */
   if (gst_kate_util_decoder_base_queue_event (&kd->decoder, event,
-          &gst_kate_dec_sink_handle_event, pad)) {
-    gst_object_unref (kd);
+          &gst_kate_dec_sink_handle_event, parent, pad)) {
     return TRUE;
   }
 
-  res = gst_kate_dec_sink_handle_event (pad, event);
-
-  gst_object_unref (kd);
+  res = gst_kate_dec_sink_handle_event (pad, parent, event);
 
   return res;
 }
 
 static gboolean
-gst_kate_dec_sink_handle_event (GstPad * pad, GstEvent * event)
+gst_kate_dec_sink_handle_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
 {
-  GstKateDec *kd = (GstKateDec *) (gst_object_get_parent (GST_OBJECT (pad)));
-  gboolean res = TRUE;
+  GstKateDec *kd = GST_KATE_DEC (parent);
 
   GST_LOG_OBJECT (pad, "Handling event on sink pad: %s",
       GST_EVENT_TYPE_NAME (event));
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_SEGMENT:
-      gst_kate_util_decoder_base_segment_event (&kd->decoder, event);
-      res = gst_pad_event_default (pad, event);
       break;
 
     case GST_EVENT_FLUSH_START:
       gst_kate_util_decoder_base_set_flushing (&kd->decoder, TRUE);
-      res = gst_pad_event_default (pad, event);
       break;
 
     case GST_EVENT_FLUSH_STOP:
       gst_kate_util_decoder_base_set_flushing (&kd->decoder, FALSE);
-      res = gst_pad_event_default (pad, event);
       break;
 
+    case GST_EVENT_TAG:{
+      GstTagList *tags;
+      gst_event_parse_tag (event, &tags);
+      gst_kate_util_decoder_base_add_tags (&kd->decoder, tags, FALSE);
+      gst_event_unref (event);
+      event = gst_kate_util_decoder_base_get_tag_event (&kd->decoder);
+      break;
+    }
     default:
-      res = gst_pad_event_default (pad, event);
       break;
   }
 
-  gst_object_unref (kd);
-
-  return res;
+  return gst_pad_event_default (pad, parent, event);
 }
 
-static GstCaps *
-gst_kate_dec_src_get_caps (GstPad * pad, GstCaps * filter)
+static gboolean
+gst_kate_dec_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
 {
-  GstKateDec *kd = (GstKateDec *) (gst_object_get_parent (GST_OBJECT (pad)));
-  GstCaps *caps;
+  GstKateDec *kd = GST_KATE_DEC (parent);
+  gboolean res = TRUE;
 
-  if (kd->src_caps) {
-    GST_DEBUG_OBJECT (kd, "We have src caps %" GST_PTR_FORMAT, kd->src_caps);
-    caps = kd->src_caps;
-  } else {
-    GST_DEBUG_OBJECT (kd, "We have no src caps, using template caps");
-    caps = gst_static_pad_template_get_caps (&src_factory);
-  }
+  GST_LOG_OBJECT (pad, "Handling query on src pad: %s",
+      GST_QUERY_TYPE_NAME (query));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:{
+      GstCaps *caps;
 
-  caps = gst_caps_copy (caps);
+      if (kd->src_caps) {
+        GST_DEBUG_OBJECT (kd, "We have src caps %" GST_PTR_FORMAT,
+            kd->src_caps);
+        caps = gst_caps_copy (kd->src_caps);
+      } else {
+        GST_DEBUG_OBJECT (kd, "We have no src caps, using template caps");
+        caps = gst_static_pad_template_get_caps (&src_factory);
+      }
 
-  gst_object_unref (kd);
-  return caps;
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+
+  return res;
 }