/**
* 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
/* ********************** typefinding in pull mode ************************ */
static void
-helper_find_suggest (gpointer data, GstTypeFindProbability probability,
- GstCaps * caps);
+helper_find_suggest (gpointer data, guint probability, GstCaps * caps);
typedef struct
{
GstTypeFindFactory *factory; /* for logging */
GstObject *obj; /* for logging */
GstObject *parent;
+ GstFlowReturn flow_ret;
} GstTypeFindHelper;
/*
* 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;
GstBuffer *buf = GST_BUFFER_CAST (bmp->buffer);
buf_offset = GST_BUFFER_OFFSET (buf);
- buf_size = gst_buffer_get_size (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)) {
* 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
#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;
}
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:
* 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;
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: (allow-none): 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
* 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.
+ * 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;
helper.caps = NULL;
helper.obj = obj;
helper.parent = parent;
+ helper.flow_ret = GST_FLOW_OK;
find.data = &helper;
find.peek = helper_find_peek;
}
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) {
- 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;
- }
- }
- }
+ 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);
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;
}
/**
*
* 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 *
*
* 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)
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;
* 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;
/**
* gst_type_find_helper_for_data:
- * @obj: (allow-none): 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;
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);
/**
* gst_type_find_helper_for_buffer:
- * @obj: (allow-none): 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;
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;
/**
* 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.
*
* 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().
+ * 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)