aggregator: Assert if the sink/src pad type that is to be used is not a GstAggregator...
[platform/upstream/gstreamer.git] / libs / gst / base / gsttypefindhelper.c
index 41f66bf..56003d5 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:gsttypefindhelper
- * @short_description: Utility functions for typefinding 
+ * @title: GstTypeFindHelper
+ * @short_description: Utility functions for typefinding
  *
  * Utility functions for elements doing typefinding:
  * gst_type_find_helper() does typefinding in pull mode, while
@@ -62,6 +63,7 @@ typedef struct
   GstTypeFindFactory *factory;  /* for logging */
   GstObject *obj;               /* for logging */
   GstObject *parent;
+  GstFlowReturn flow_ret;
 } GstTypeFindHelper;
 
 /*
@@ -74,15 +76,14 @@ typedef struct
  * for performance reasons, but mostly because pointers returned by us need
  * to stay valid until typefinding has finished)
  *
- * Returns: address of the data or %NULL if buffer does not cover the
- * requested range.
+ * Returns: (nullable): address of the data or %NULL if buffer does not cover
+ * the requested range.
  */
 static const guint8 *
 helper_find_peek (gpointer data, gint64 offset, guint size)
 {
   GstTypeFindHelper *helper;
   GstBuffer *buffer;
-  GstFlowReturn ret;
   GSList *insert_pos = NULL;
   gsize buf_size;
   guint64 buf_offset;
@@ -113,11 +114,12 @@ helper_find_peek (gpointer data, gint64 offset, guint size)
     for (walk = helper->buffers; walk; walk = walk->next) {
       GstMappedBuffer *bmp = (GstMappedBuffer *) walk->data;
       GstBuffer *buf = GST_BUFFER_CAST (bmp->buffer);
-      guint64 buf_offset = GST_BUFFER_OFFSET (buf);
-      guint buf_size = gst_buffer_get_size (buf);
+
+      buf_offset = GST_BUFFER_OFFSET (buf);
+      buf_size = bmp->map.size;
 
       /* buffers are kept sorted by end offset (highest first) in the list, so
-       * at this point we save the current position and stop searching if 
+       * at this point we save the current position and stop searching if
        * we're after the searched end offset */
       if (buf_offset <= offset) {
         if ((offset + size) < (buf_offset + buf_size)) {
@@ -138,11 +140,11 @@ helper_find_peek (gpointer data, gint64 offset, guint size)
    * of the file is also not a problem here, we'll just get a truncated buffer
    * in that case (and we'll have to double-check the size we actually get
    * anyway, see below) */
-  ret =
+  helper->flow_ret =
       helper->func (helper->obj, helper->parent, offset, MAX (size, 4096),
       &buffer);
 
-  if (ret != GST_FLOW_OK)
+  if (helper->flow_ret != GST_FLOW_OK)
     goto error;
 
 #if 0
@@ -161,20 +163,31 @@ helper_find_peek (gpointer data, gint64 offset, guint size)
 #endif
 
   /* getrange might silently return shortened buffers at the end of a file,
-   * we must, however, always return either the full requested data or NULL */
+   * we must, however, always return either the full requested data or %NULL */
   buf_offset = GST_BUFFER_OFFSET (buffer);
   buf_size = gst_buffer_get_size (buffer);
 
-  if ((buf_offset != -1 && buf_offset != offset) || buf_size < size) {
-    GST_DEBUG ("dropping short buffer: %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT
-        " instead of %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT,
-        buf_offset, buf_offset + buf_size - 1, offset, offset + size - 1);
+  if (buf_size < size) {
+    GST_DEBUG ("dropping short buffer of size %" G_GSIZE_FORMAT ","
+        "requested size was %u", buf_size, size);
+    gst_buffer_unref (buffer);
+    return NULL;
+  }
+
+  if (buf_offset != -1 && buf_offset != offset) {
+    GST_DEBUG ("dropping buffer with unexpected offset %" G_GUINT64_FORMAT ", "
+        "expected offset was %" G_GUINT64_FORMAT, buf_offset, offset);
     gst_buffer_unref (buffer);
     return NULL;
   }
 
   bmap = g_slice_new0 (GstMappedBuffer);
+
+  if (!gst_buffer_map (buffer, &bmap->map, GST_MAP_READ))
+    goto map_failed;
+
   bmap->buffer = buffer;
+
   if (insert_pos) {
     helper->buffers = g_slist_insert_before (helper->buffers, insert_pos, bmap);
   } else {
@@ -185,13 +198,19 @@ helper_find_peek (gpointer data, gint64 offset, guint size)
     helper->buffers = g_slist_prepend (helper->buffers, bmap);
   }
 
-  gst_buffer_map (buffer, &bmap->map, GST_MAP_READ);
-
   return bmap->map.data;
 
 error:
   {
-    GST_INFO ("typefind function returned: %s", gst_flow_get_name (ret));
+    GST_INFO ("typefind function returned: %s",
+        gst_flow_get_name (helper->flow_ret));
+    return NULL;
+  }
+map_failed:
+  {
+    GST_ERROR ("map failed");
+    gst_buffer_unref (buffer);
+    g_slice_free (GstMappedBuffer, bmap);
     return NULL;
   }
 }
@@ -205,8 +224,7 @@ error:
  * If given @probability is higher, replace previously store caps.
  */
 static void
-helper_find_suggest (gpointer data, GstTypeFindProbability probability,
-    GstCaps * caps)
+helper_find_suggest (gpointer data, guint probability, GstCaps * caps)
 {
   GstTypeFindHelper *helper = (GstTypeFindHelper *) data;
 
@@ -231,16 +249,67 @@ helper_find_get_length (gpointer data)
   return helper->size;
 }
 
+static GList *
+prioritize_extension (GstObject * obj, GList * type_list,
+    const gchar * extension)
+{
+  gint pos = 0;
+  GList *next, *l;
+
+  if (!extension)
+    return type_list;
+
+  /* move the typefinders for the extension first in the list. The idea is that
+   * when one of them returns MAX we don't need to search further as there is a
+   * very high chance we got the right type. */
+
+  GST_LOG_OBJECT (obj, "sorting typefind for extension %s to head", extension);
+
+  for (l = type_list; l; l = next) {
+    const gchar *const *ext;
+    GstTypeFindFactory *factory;
+
+    next = l->next;
+
+    factory = GST_TYPE_FIND_FACTORY (l->data);
+
+    ext = gst_type_find_factory_get_extensions (factory);
+    if (ext == NULL)
+      continue;
+
+    GST_LOG_OBJECT (obj, "testing factory %s for extension %s",
+        GST_OBJECT_NAME (factory), extension);
+
+    while (*ext != NULL) {
+      if (strcmp (*ext, extension) == 0) {
+        /* found extension, move in front */
+        GST_LOG_OBJECT (obj, "moving typefind for extension %s to head",
+            extension);
+        /* remove entry from list */
+        type_list = g_list_delete_link (type_list, l);
+        /* insert at the position */
+        type_list = g_list_insert (type_list, factory, pos);
+        /* next element will be inserted after this one */
+        pos++;
+        break;
+      }
+      ++ext;
+    }
+  }
+
+  return type_list;
+}
+
 /**
  * gst_type_find_helper_get_range:
  * @obj: A #GstObject that will be passed as first argument to @func
- * @parent: the parent of @obj or NULL
+ * @parent: (allow-none): the parent of @obj or %NULL
  * @func: (scope call): A generic #GstTypeFindHelperGetRangeFunction that will
  *        be used to access data at random offsets when doing the typefinding
  * @size: The length in bytes
- * @extension: extension of the media
+ * @extension: (allow-none): extension of the media, or %NULL
  * @prob: (out) (allow-none): location to store the probability of the found
- *     caps, or #NULL
+ *     caps, or %NULL
  *
  * Utility function to do pull-based typefinding. Unlike gst_type_find_helper()
  * however, this function will use the specified function @func to obtain the
@@ -251,31 +320,74 @@ helper_find_get_length (gpointer data)
  * callback can then call the upstream peer pad with offsets adjusted for the
  * tag size, for example).
  *
- * When @extension is not NULL, this function will first try the typefind
+ * When @extension is not %NULL, this function will first try the typefind
  * functions for the given extension, which might speed up the typefinding
  * in many cases.
  *
  * Free-function: gst_caps_unref
  *
- * Returns: (transfer full): the #GstCaps corresponding to the data stream.
- *     Returns #NULL if no #GstCaps matches the data stream.
- *
- * Since: 0.10.26
+ * Returns: (transfer full) (nullable): the #GstCaps corresponding to the data
+ *     stream.  Returns %NULL if no #GstCaps matches the data stream.
  */
 GstCaps *
 gst_type_find_helper_get_range (GstObject * obj, GstObject * parent,
     GstTypeFindHelperGetRangeFunction func, guint64 size,
     const gchar * extension, GstTypeFindProbability * prob)
 {
+  GstCaps *caps = NULL;
+
+  gst_type_find_helper_get_range_full (obj, parent, func, size, extension,
+      &caps, prob);
+
+  return caps;
+}
+
+/**
+ * gst_type_find_helper_get_range_full:
+ * @obj: A #GstObject that will be passed as first argument to @func
+ * @parent: (allow-none): the parent of @obj or %NULL
+ * @func: (scope call): A generic #GstTypeFindHelperGetRangeFunction that will
+ *        be used to access data at random offsets when doing the typefinding
+ * @size: The length in bytes
+ * @extension: (allow-none): extension of the media, or %NULL
+ * @caps: (out) (transfer full): returned caps
+ * @prob: (out) (allow-none): location to store the probability of the found
+ *     caps, or %NULL
+ *
+ * Utility function to do pull-based typefinding. Unlike gst_type_find_helper()
+ * however, this function will use the specified function @func to obtain the
+ * data needed by the typefind functions, rather than operating on a given
+ * source pad. This is useful mostly for elements like tag demuxers which
+ * strip off data at the beginning and/or end of a file and want to typefind
+ * the stripped data stream before adding their own source pad (the specified
+ * callback can then call the upstream peer pad with offsets adjusted for the
+ * tag size, for example).
+ *
+ * When @extension is not %NULL, this function will first try the typefind
+ * functions for the given extension, which might speed up the typefinding
+ * in many cases.
+ *
+ * Returns: the last %GstFlowReturn from pulling a buffer or %GST_FLOW_OK if
+ *          typefinding was successful.
+ *
+ * Since: 1.14.3
+ */
+GstFlowReturn
+gst_type_find_helper_get_range_full (GstObject * obj, GstObject * parent,
+    GstTypeFindHelperGetRangeFunction func, guint64 size,
+    const gchar * extension, GstCaps ** caps, GstTypeFindProbability * prob)
+{
   GstTypeFindHelper helper;
   GstTypeFind find;
   GSList *walk;
   GList *l, *type_list;
   GstCaps *result = NULL;
-  gint pos = 0;
 
-  g_return_val_if_fail (GST_IS_OBJECT (obj), NULL);
-  g_return_val_if_fail (func != NULL, NULL);
+  g_return_val_if_fail (GST_IS_OBJECT (obj), GST_FLOW_ERROR);
+  g_return_val_if_fail (func != NULL, GST_FLOW_ERROR);
+  g_return_val_if_fail (caps != NULL, GST_FLOW_ERROR);
+
+  *caps = NULL;
 
   helper.buffers = NULL;
   helper.size = size;
@@ -285,6 +397,7 @@ gst_type_find_helper_get_range (GstObject * obj, GstObject * parent,
   helper.caps = NULL;
   helper.obj = obj;
   helper.parent = parent;
+  helper.flow_ret = GST_FLOW_OK;
 
   find.data = &helper;
   find.peek = helper_find_peek;
@@ -297,54 +410,24 @@ gst_type_find_helper_get_range (GstObject * obj, GstObject * parent,
   }
 
   type_list = gst_type_find_factory_get_list ();
-
-  /* move the typefinders for the extension first in the list. The idea is that
-   * when one of them returns MAX we don't need to search further as there is a
-   * very high chance we got the right type. */
-  if (extension) {
-    GList *next;
-
-    GST_LOG_OBJECT (obj, "sorting typefind for extension %s to head",
-        extension);
-
-    for (l = type_list; l; l = next) {
-      GstTypeFindFactory *factory;
-      gint i;
-      gchar **ext;
-
-      next = l->next;
-
-      factory = GST_TYPE_FIND_FACTORY (l->data);
-
-      ext = gst_type_find_factory_get_extensions (factory);
-      if (ext == NULL)
-        continue;
-
-      GST_LOG_OBJECT (obj, "testing factory %s for extension %s",
-          GST_OBJECT_NAME (factory), extension);
-
-      for (i = 0; ext[i]; i++) {
-        if (strcmp (ext[i], extension) == 0) {
-          /* found extension, move in front */
-          GST_LOG_OBJECT (obj, "moving typefind for extension %s to head",
-              extension);
-          /* remove entry from list */
-          type_list = g_list_delete_link (type_list, l);
-          /* insert at the position */
-          type_list = g_list_insert (type_list, factory, pos);
-          /* next element will be inserted after this one */
-          pos++;
-          break;
-        }
-      }
-    }
-  }
+  type_list = prioritize_extension (obj, type_list, extension);
 
   for (l = type_list; l; l = l->next) {
     helper.factory = GST_TYPE_FIND_FACTORY (l->data);
     gst_type_find_factory_call_function (helper.factory, &find);
-    if (helper.best_probability >= GST_TYPE_FIND_MAXIMUM)
+    if (helper.best_probability >= GST_TYPE_FIND_MAXIMUM) {
+      /* Any other flow return can be ignored here, we found
+       * something before any error with highest probability */
+      helper.flow_ret = GST_FLOW_OK;
+      break;
+    } else if (helper.flow_ret != GST_FLOW_OK
+        && helper.flow_ret != GST_FLOW_EOS) {
+      /* We had less than maximum probability and an error, don't return
+       * any caps as they might be with a lower probability than what
+       * we would've gotten when continuing if there was no error */
+      gst_caps_replace (&helper.caps, NULL);
       break;
+    }
   }
   gst_plugin_feature_list_free (type_list);
 
@@ -363,10 +446,18 @@ gst_type_find_helper_get_range (GstObject * obj, GstObject * parent,
   if (prob)
     *prob = helper.best_probability;
 
+  *caps = result;
+  if (helper.flow_ret == GST_FLOW_EOS) {
+    /* Some typefinder might've tried to read too much, if we
+     * didn't get any meaningful caps because of that this is
+     * just a normal error */
+    helper.flow_ret = GST_FLOW_ERROR;
+  }
+
   GST_LOG_OBJECT (obj, "Returning %" GST_PTR_FORMAT " (probability = %u)",
       result, (guint) helper.best_probability);
 
-  return result;
+  return helper.flow_ret;
 }
 
 /**
@@ -378,8 +469,8 @@ gst_type_find_helper_get_range (GstObject * obj, GstObject * parent,
  *
  * Free-function: gst_caps_unref
  *
- * Returns: (transfer full): the #GstCaps corresponding to the data stream.
- *     Returns #NULL if no #GstCaps matches the data stream.
+ * Returns: (transfer full) (nullable): the #GstCaps corresponding to the data
+ *     stream.  Returns %NULL if no #GstCaps matches the data stream.
  */
 
 GstCaps *
@@ -416,8 +507,8 @@ typedef struct
  *
  * Get data pointer within a buffer.
  *
- * Returns: address inside the buffer or %NULL if buffer does not cover the
- * requested range.
+ * Returns: (nullable): address inside the buffer or %NULL if buffer does not
+ * cover the requested range.
  */
 static const guint8 *
 buf_helper_find_peek (gpointer data, gint64 off, guint size)
@@ -437,7 +528,15 @@ buf_helper_find_peek (gpointer data, gint64 off, guint size)
     return NULL;
   }
 
-  if ((off + size) <= helper->size)
+  /* If we request beyond the available size, we're sure we can't return
+   * anything regardless of the requested offset */
+  if (size > helper->size)
+    return NULL;
+
+  /* Only return data if there's enough room left for the given offset.
+   * This is the same as "if (off + size <= helper->size)" except that
+   * it doesn't exceed type limits */
+  if (off <= helper->size - size)
     return helper->data + off;
 
   return NULL;
@@ -452,8 +551,7 @@ buf_helper_find_peek (gpointer data, gint64 off, guint size)
  * If given @probability is higher, replace previously store caps.
  */
 static void
-buf_helper_find_suggest (gpointer data, GstTypeFindProbability probability,
-    GstCaps * caps)
+buf_helper_find_suggest (gpointer data, guint probability, GstCaps * caps)
 {
   GstTypeFindBufHelper *helper = (GstTypeFindBufHelper *) data;
 
@@ -470,33 +568,75 @@ buf_helper_find_suggest (gpointer data, GstTypeFindProbability probability,
 
 /**
  * gst_type_find_helper_for_data:
- * @obj: object doing the typefinding, or NULL (used for logging)
- * @data: (in) (transfer none): a pointer with data to typefind
- * @size: (in) (transfer none): the size of @data
+ * @obj: (allow-none): object doing the typefinding, or %NULL (used for logging)
+ * @data: (transfer none) (array length=size): * a pointer with data to typefind
+ * @size: the size of @data
  * @prob: (out) (allow-none): location to store the probability of the found
- *     caps, or #NULL
+ *     caps, or %NULL
  *
  * Tries to find what type of data is contained in the given @data, the
  * assumption being that the data represents the beginning of the stream or
  * file.
  *
  * All available typefinders will be called on the data in order of rank. If
- * a typefinding function returns a probability of #GST_TYPE_FIND_MAXIMUM,
+ * a typefinding function returns a probability of %GST_TYPE_FIND_MAXIMUM,
  * typefinding is stopped immediately and the found caps will be returned
  * right away. Otherwise, all available typefind functions will the tried,
- * and the caps with the highest probability will be returned, or #NULL if
+ * and the caps with the highest probability will be returned, or %NULL if
  * the content of @data could not be identified.
  *
  * Free-function: gst_caps_unref
  *
- * Returns: (transfer full): the #GstCaps corresponding to the data, or #NULL
- *     if no type could be found. The caller should free the caps returned
- *     with gst_caps_unref().
+ * Returns: (transfer full) (nullable): the #GstCaps corresponding to the data,
+ *     or %NULL if no type could be found. The caller should free the caps
+ *     returned with gst_caps_unref().
  */
 GstCaps *
 gst_type_find_helper_for_data (GstObject * obj, const guint8 * data, gsize size,
     GstTypeFindProbability * prob)
 {
+  return gst_type_find_helper_for_data_with_extension (obj, data, size, NULL,
+      prob);
+}
+
+/**
+ * gst_type_find_helper_for_data_with_extension:
+ * @obj: (allow-none): object doing the typefinding, or %NULL (used for logging)
+ * @data: (transfer none) (array length=size): * a pointer with data to typefind
+ * @size: the size of @data
+ * @extension: (allow-none): extension of the media, or %NULL
+ * @prob: (out) (allow-none): location to store the probability of the found
+ *     caps, or %NULL
+ *
+ * Tries to find what type of data is contained in the given @data, the
+ * assumption being that the data represents the beginning of the stream or
+ * file.
+ *
+ * All available typefinders will be called on the data in order of rank. If
+ * a typefinding function returns a probability of %GST_TYPE_FIND_MAXIMUM,
+ * typefinding is stopped immediately and the found caps will be returned
+ * right away. Otherwise, all available typefind functions will the tried,
+ * and the caps with the highest probability will be returned, or %NULL if
+ * the content of @data could not be identified.
+ *
+ * When @extension is not %NULL, this function will first try the typefind
+ * functions for the given extension, which might speed up the typefinding
+ * in many cases.
+ *
+ * Free-function: gst_caps_unref
+ *
+ * Returns: (transfer full) (nullable): the #GstCaps corresponding to the data,
+ *     or %NULL if no type could be found. The caller should free the caps
+ *     returned with gst_caps_unref().
+ *
+ * Since: 1.16
+ *
+ */
+GstCaps *
+gst_type_find_helper_for_data_with_extension (GstObject * obj,
+    const guint8 * data, gsize size, const gchar * extension,
+    GstTypeFindProbability * prob)
+{
   GstTypeFindBufHelper helper;
   GstTypeFind find;
   GList *l, *type_list;
@@ -519,6 +659,7 @@ gst_type_find_helper_for_data (GstObject * obj, const guint8 * data, gsize size,
   find.get_length = NULL;
 
   type_list = gst_type_find_factory_get_list ();
+  type_list = prioritize_extension (obj, type_list, extension);
 
   for (l = type_list; l; l = l->next) {
     helper.factory = GST_TYPE_FIND_FACTORY (l->data);
@@ -542,32 +683,71 @@ gst_type_find_helper_for_data (GstObject * obj, const guint8 * data, gsize size,
 
 /**
  * gst_type_find_helper_for_buffer:
- * @obj: object doing the typefinding, or NULL (used for logging)
+ * @obj: (allow-none): object doing the typefinding, or %NULL (used for logging)
  * @buf: (in) (transfer none): a #GstBuffer with data to typefind
  * @prob: (out) (allow-none): location to store the probability of the found
- *     caps, or #NULL
+ *     caps, or %NULL
  *
  * Tries to find what type of data is contained in the given #GstBuffer, the
  * assumption being that the buffer represents the beginning of the stream or
  * file.
  *
  * All available typefinders will be called on the data in order of rank. If
- * a typefinding function returns a probability of #GST_TYPE_FIND_MAXIMUM,
+ * a typefinding function returns a probability of %GST_TYPE_FIND_MAXIMUM,
  * typefinding is stopped immediately and the found caps will be returned
  * right away. Otherwise, all available typefind functions will the tried,
- * and the caps with the highest probability will be returned, or #NULL if
+ * and the caps with the highest probability will be returned, or %NULL if
  * the content of the buffer could not be identified.
  *
  * Free-function: gst_caps_unref
  *
- * Returns: (transfer full): the #GstCaps corresponding to the data, or #NULL
- *     if no type could be found. The caller should free the caps returned
- *     with gst_caps_unref().
+ * Returns: (transfer full) (nullable): the #GstCaps corresponding to the data,
+ *     or %NULL if no type could be found. The caller should free the caps
+ *     returned with gst_caps_unref().
  */
 GstCaps *
 gst_type_find_helper_for_buffer (GstObject * obj, GstBuffer * buf,
     GstTypeFindProbability * prob)
 {
+  return gst_type_find_helper_for_buffer_with_extension (obj, buf, NULL, prob);
+}
+
+/**
+ * gst_type_find_helper_for_buffer_with_extension:
+ * @obj: (allow-none): object doing the typefinding, or %NULL (used for logging)
+ * @buf: (in) (transfer none): a #GstBuffer with data to typefind
+ * @extension: (allow-none): extension of the media, or %NULL
+ * @prob: (out) (allow-none): location to store the probability of the found
+ *     caps, or %NULL
+ *
+ * Tries to find what type of data is contained in the given #GstBuffer, the
+ * assumption being that the buffer represents the beginning of the stream or
+ * file.
+ *
+ * All available typefinders will be called on the data in order of rank. If
+ * a typefinding function returns a probability of %GST_TYPE_FIND_MAXIMUM,
+ * typefinding is stopped immediately and the found caps will be returned
+ * right away. Otherwise, all available typefind functions will the tried,
+ * and the caps with the highest probability will be returned, or %NULL if
+ * the content of the buffer could not be identified.
+ *
+ * When @extension is not %NULL, this function will first try the typefind
+ * functions for the given extension, which might speed up the typefinding
+ * in many cases.
+ *
+ * Free-function: gst_caps_unref
+ *
+ * Returns: (transfer full) (nullable): the #GstCaps corresponding to the data,
+ *     or %NULL if no type could be found. The caller should free the caps
+ *     returned with gst_caps_unref().
+ *
+ * Since: 1.16
+ *
+ */
+GstCaps *
+gst_type_find_helper_for_buffer_with_extension (GstObject * obj,
+    GstBuffer * buf, const gchar * extension, GstTypeFindProbability * prob)
+{
   GstCaps *result;
   GstMapInfo info;
 
@@ -578,7 +758,9 @@ gst_type_find_helper_for_buffer (GstObject * obj, GstBuffer * buf,
 
   if (!gst_buffer_map (buf, &info, GST_MAP_READ))
     return NULL;
-  result = gst_type_find_helper_for_data (obj, info.data, info.size, prob);
+  result =
+      gst_type_find_helper_for_data_with_extension (obj, info.data, info.size,
+      extension, prob);
   gst_buffer_unmap (buf, &info);
 
   return result;
@@ -586,7 +768,7 @@ gst_type_find_helper_for_buffer (GstObject * obj, GstBuffer * buf,
 
 /**
  * gst_type_find_helper_for_extension:
- * @obj: (allow-none): object doing the typefinding, or NULL (used for logging)
+ * @obj: (allow-none): object doing the typefinding, or %NULL (used for logging)
  * @extension: an extension
  *
  * Tries to find the best #GstCaps associated with @extension.
@@ -597,11 +779,9 @@ gst_type_find_helper_for_buffer (GstObject * obj, GstBuffer * buf,
  *
  * Free-function: gst_caps_unref
  *
- * Returns: (transfer full): the #GstCaps corresponding to @extension, or
- *     #NULL if no type could be found. The caller should free the caps
- *     returned with gst_caps_unref().
- * 
- * Since: 0.10.23
+ * Returns: (transfer full) (nullable): the #GstCaps corresponding to
+ *     @extension, or %NULL if no type could be found. The caller should free
+ *     the caps returned with gst_caps_unref().
  */
 GstCaps *
 gst_type_find_helper_for_extension (GstObject * obj, const gchar * extension)
@@ -617,13 +797,12 @@ gst_type_find_helper_for_extension (GstObject * obj, const gchar * extension)
 
   for (l = type_list; l; l = g_list_next (l)) {
     GstTypeFindFactory *factory;
-    gchar **ext;
-    gint i;
+    const gchar *const *ext;
 
     factory = GST_TYPE_FIND_FACTORY (l->data);
 
     /* we only want to check those factories without a function */
-    if (factory->function != NULL)
+    if (gst_type_find_factory_has_function (factory))
       continue;
 
     /* get the extension that this typefind factory can handle */
@@ -633,14 +812,15 @@ gst_type_find_helper_for_extension (GstObject * obj, const gchar * extension)
 
     /* there are extension, see if one of them matches the requested
      * extension */
-    for (i = 0; ext[i]; i++) {
-      if (strcmp (ext[i], extension) == 0) {
+    while (*ext != NULL) {
+      if (strcmp (*ext, extension) == 0) {
         /* we found a matching extension, take the caps */
         if ((result = gst_type_find_factory_get_caps (factory))) {
           gst_caps_ref (result);
           goto done;
         }
       }
+      ++ext;
     }
   }
 done: