typefind: Add _with_extension() variants for typefinding data or a buffer

And make use of that in the typefind element to also be able to make use
of the extension in push mode. It previously only did that in pull mode
and this potentially speeds up typefinding and might also prevent false
positives.

https://bugzilla.gnome.org/show_bug.cgi?id=796865
This commit is contained in:
Sebastian Dröge 2018-07-24 17:28:45 +03:00
parent b079334c1c
commit d196b0b904
5 changed files with 161 additions and 46 deletions

View file

@ -946,8 +946,10 @@ gst_push_src_get_type
<INCLUDE>gst/base/gsttypefindhelper.h</INCLUDE>
gst_type_find_helper
gst_type_find_helper_for_buffer
gst_type_find_helper_for_buffer_with_extension
gst_type_find_helper_for_extension
gst_type_find_helper_for_data
gst_type_find_helper_for_data_with_extension
GstTypeFindHelperGetRangeFunction
gst_type_find_helper_get_range
<SUBSECTION Private>

View file

@ -248,6 +248,57 @@ 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
@ -287,7 +338,6 @@ gst_type_find_helper_get_range (GstObject * obj, GstObject * parent,
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);
@ -312,48 +362,7 @@ 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) {
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);
@ -518,6 +527,48 @@ buf_helper_find_suggest (gpointer data, guint probability, GstCaps * caps)
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;
@ -541,6 +592,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);
@ -589,6 +641,45 @@ gst_type_find_helper_for_data (GstObject * obj, const guint8 * data, gsize size,
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;
@ -600,7 +691,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;

View file

@ -37,10 +37,25 @@ GstCaps * gst_type_find_helper_for_data (GstObject *obj,
const guint8 *data,
gsize size,
GstTypeFindProbability *prob);
GST_BASE_API
GstCaps * gst_type_find_helper_for_data_with_extension (GstObject *obj,
const guint8 *data,
gsize size,
const gchar *extension,
GstTypeFindProbability *prob);
GST_BASE_API
GstCaps * gst_type_find_helper_for_buffer (GstObject *obj,
GstBuffer *buf,
GstTypeFindProbability *prob);
GST_BASE_API
GstCaps * gst_type_find_helper_for_buffer_with_extension (GstObject *obj,
GstBuffer *buf,
const gchar *extension,
GstTypeFindProbability *prob);
GST_BASE_API
GstCaps * gst_type_find_helper_for_extension (GstObject * obj,
const gchar * extension);

View file

@ -930,6 +930,7 @@ gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind,
gsize avail;
const guint8 *data;
gboolean have_min, have_max;
gchar *ext;
GST_OBJECT_LOCK (typefind);
if (typefind->force_caps) {
@ -951,11 +952,13 @@ gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind,
if (!have_min)
goto not_enough_data;
ext = gst_type_find_get_extension (typefind, typefind->sink);
/* map all available data */
data = gst_adapter_map (typefind->adapter, avail);
caps = gst_type_find_helper_for_data (GST_OBJECT (typefind),
data, avail, &probability);
caps = gst_type_find_helper_for_data_with_extension (GST_OBJECT (typefind),
data, avail, ext, &probability);
gst_adapter_unmap (typefind->adapter);
g_free (ext);
if (caps == NULL && have_max)
goto no_type_found;

View file

@ -353,6 +353,8 @@ EXPORTS
gst_queue_array_push_tail_struct
gst_type_find_helper
gst_type_find_helper_for_buffer
gst_type_find_helper_for_buffer_with_extension
gst_type_find_helper_for_data
gst_type_find_helper_for_data_with_extension
gst_type_find_helper_for_extension
gst_type_find_helper_get_range