plugins/elements/gsttypefindelement.*: Use gst_type_find_helper_for_buffer() for chain-based typefinding.

Original commit message from CVS:
* plugins/elements/gsttypefindelement.h:
* plugins/elements/gsttypefindelement.c:
(gst_type_find_element_src_event), (start_typefinding),
(stop_typefinding), (gst_type_find_element_handle_event),
(gst_type_find_element_chain),
(gst_type_find_element_chain_do_typefinding):
Use gst_type_find_helper_for_buffer() for chain-based
typefinding.
This commit is contained in:
Tim-Philipp Müller 2006-03-03 14:18:01 +00:00
parent 4a4a73adf1
commit 6619c85779
3 changed files with 64 additions and 281 deletions

View file

@ -1,3 +1,14 @@
2006-03-03 Tim-Philipp Müller <tim at centricular dot net>
* plugins/elements/gsttypefindelement.h:
* plugins/elements/gsttypefindelement.c:
(gst_type_find_element_src_event), (start_typefinding),
(stop_typefinding), (gst_type_find_element_handle_event),
(gst_type_find_element_chain),
(gst_type_find_element_chain_do_typefinding):
Use gst_type_find_helper_for_buffer() for chain-based
typefinding.
2006-03-03 Tim-Philipp Müller <tim at centricular dot net>
* plugins/elements/gsttypefindelement.c:

View file

@ -143,6 +143,8 @@ gst_type_find_element_change_state (GstElement * element,
static gboolean gst_type_find_element_activate (GstPad * pad);
static gboolean
gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active);
static GstFlowReturn
gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind);
static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
@ -389,42 +391,16 @@ gst_type_find_element_src_event (GstPad * pad, GstEvent * event)
}
return gst_pad_event_default (pad, event);
}
typedef struct
{
GstTypeFindFactory *factory;
guint probability;
GstCaps *caps;
guint requested_size;
GstTypeFindElement *self;
}
TypeFindEntry;
static inline TypeFindEntry *
new_entry (void)
{
return g_new0 (TypeFindEntry, 1);
}
static void
free_entry (TypeFindEntry * entry)
{
if (entry->caps)
gst_caps_unref (entry->caps);
gst_object_unref (entry->factory);
g_free (entry);
}
static void
start_typefinding (GstTypeFindElement * typefind)
{
g_assert (typefind->possibilities == NULL);
GST_DEBUG_OBJECT (typefind, "starting typefinding");
gst_pad_set_caps (typefind->src, NULL);
if (typefind->caps) {
gst_caps_replace (&typefind->caps, NULL);
}
typefind->mode = MODE_TYPEFIND;
typefind->stream_length_available = TRUE;
typefind->stream_length = 0;
}
static void
@ -439,15 +415,6 @@ stop_typefinding (GstTypeFindElement * typefind)
GST_DEBUG_OBJECT (typefind, "stopping typefinding%s",
push_cached_buffers ? " and pushing cached buffers" : "");
if (typefind->possibilities != NULL) {
/* this should only happen on PAUSED => READY or EOS */
GST_LOG_OBJECT (typefind, "freeing remaining %u typefind functions",
g_list_length (typefind->possibilities));
g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
g_list_free (typefind->possibilities);
typefind->possibilities = NULL;
}
//typefind->mode = MODE_TRANSITION;
if (typefind->store) {
if (!push_cached_buffers) {
@ -483,64 +450,6 @@ stop_typefinding (GstTypeFindElement * typefind)
}
}
static guint64
find_element_get_length (gpointer data)
{
TypeFindEntry *entry = (TypeFindEntry *) data;
GstTypeFindElement *typefind = entry->self;
GstFormat format = GST_FORMAT_BYTES;
if (!typefind->stream_length_available) {
GST_LOG_OBJECT (entry->self,
"'%s' called get_length () but we know it's not available",
GST_PLUGIN_FEATURE_NAME (entry->factory));
return 0;
}
if (entry->self->stream_length == 0) {
if (!gst_pad_query_duration (GST_PAD_PEER (entry->self->sink), &format,
(gint64 *) & entry->self->stream_length))
goto no_length;
if (format != GST_FORMAT_BYTES) {
typefind->stream_length_available = FALSE;
entry->self->stream_length = 0;
} else {
GST_DEBUG_OBJECT (entry->self,
"'%s' called get_length () and it's %" G_GUINT64_FORMAT " bytes",
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->self->stream_length);
}
}
return entry->self->stream_length;
no_length:
{
typefind->stream_length_available = FALSE;
GST_DEBUG_OBJECT (entry->self,
"'%s' called get_length () but it's not available",
GST_PLUGIN_FEATURE_NAME (entry->factory));
return 0;
}
}
static TypeFindEntry *
gst_type_find_element_get_best_possibility (GstTypeFindElement * typefind)
{
TypeFindEntry *best = NULL;
GList *walk;
for (walk = typefind->possibilities; walk != NULL; walk = walk->next) {
TypeFindEntry *entry;
entry = (TypeFindEntry *) walk->data;
if ((!best || entry->probability > best->probability) &&
entry->probability >= typefind->min_probability) {
best = entry;
}
}
return best;
}
static gboolean
gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
{
@ -598,85 +507,12 @@ gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
}
return res;
}
static guint8 *
find_peek (gpointer data, gint64 offset, guint size)
{
TypeFindEntry *entry = (TypeFindEntry *) data;
GST_LOG_OBJECT (entry->self, "'%s' called peek (%" G_GINT64_FORMAT ", %u)",
GST_PLUGIN_FEATURE_NAME (entry->factory), offset, size);
if (offset < 0) {
GST_LOG_OBJECT (entry->self, "peek at end not supported in push mode");
return NULL;
}
if (offset > 0) {
if ((offset + size) <= entry->self->store->size) {
entry->requested_size = 0;
return GST_BUFFER_DATA (entry->self->store) + offset;
}
/* no can do */
return NULL;
}
/* offset == 0 ... */
if (size <= entry->self->store->size) {
entry->requested_size = 0;
return GST_BUFFER_DATA (entry->self->store);
} else {
entry->requested_size = size;
GST_LOG_OBJECT (entry->self,
"setting requested peek (%" G_GINT64_FORMAT ", %u) on '%s'", offset,
size, GST_PLUGIN_FEATURE_NAME (entry->factory));
return NULL;
}
}
static void
find_suggest (gpointer data, guint probability, const GstCaps * caps)
{
TypeFindEntry *entry = (TypeFindEntry *) data;
GST_LOG_OBJECT (entry->self, "'%s' called suggest (%u, %" GST_PTR_FORMAT ")",
GST_PLUGIN_FEATURE_NAME (entry->factory), probability, caps);
if (((gint) probability) > entry->probability) {
entry->probability = probability;
gst_caps_replace (&entry->caps, (GstCaps *) caps);
}
}
#if 0
static gint
compare_type_find_entry (gconstpointer a, gconstpointer b)
{
TypeFindEntry *one = (TypeFindEntry *) a;
TypeFindEntry *two = (TypeFindEntry *) b;
if (one->probability == two->probability) {
/* FIXME: can be improved by analyzing requests */
return 0;
} else {
return two->probability - one->probability;
}
}
#endif
static gint
compare_type_find_factory (gconstpointer fac1, gconstpointer fac2)
{
return GST_PLUGIN_FEATURE (fac1)->rank - GST_PLUGIN_FEATURE (fac2)->rank;
}
static GstFlowReturn
gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
{
GstTypeFindElement *typefind;
TypeFindEntry *entry;
GList *walk;
GstFlowReturn res = GST_FLOW_OK;
GstTypeFind find = { find_peek, find_suggest, NULL, find_element_get_length };
typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
@ -688,121 +524,12 @@ gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
gst_buffer_set_caps (buffer, typefind->caps);
return gst_pad_push (typefind->src, buffer);
case MODE_TYPEFIND:{
gboolean done = TRUE;
if (typefind->store)
typefind->store = gst_buffer_join (typefind->store, buffer);
else
typefind->store = buffer;
if (GST_BUFFER_SIZE (typefind->store) < TYPE_FIND_MIN_SIZE) {
GST_DEBUG_OBJECT (typefind, "not enough data for typefinding yet");
return GST_FLOW_OK;
}
if (typefind->possibilities == NULL) {
/* not yet started, get all typefinding functions into our "queue" */
GList *all_factories = gst_type_find_factory_get_list ();
GST_INFO_OBJECT (typefind, "starting with %u typefinding functions",
g_list_length (all_factories));
all_factories = g_list_sort (all_factories, compare_type_find_factory);
walk = all_factories;
while (walk) {
entry = new_entry ();
entry->factory = gst_object_ref (GST_TYPE_FIND_FACTORY (walk->data));
entry->self = typefind;
entry->probability = 0;
typefind->possibilities =
g_list_prepend (typefind->possibilities, entry);
walk = g_list_next (walk);
}
gst_plugin_feature_list_free (all_factories);
}
/* call every typefind function once */
walk = typefind->possibilities;
GST_INFO_OBJECT (typefind, "iterating %u typefinding functions",
g_list_length (walk));
while (walk) {
find.data = entry = (TypeFindEntry *) walk->data;
if (entry->probability != 0) {
/* Probability already known, just continue along the list */
walk = g_list_next (walk);
continue;
}
entry->requested_size = 0;
gst_type_find_factory_call_function (entry->factory, &find);
if (entry->probability == 0 && entry->requested_size == 0) {
GList *next;
GST_DEBUG_OBJECT (typefind,
"'%s' was removed - no chance of being the right plugin",
GST_PLUGIN_FEATURE_NAME (entry->factory));
next = g_list_next (walk);
free_entry (entry);
typefind->possibilities =
g_list_delete_link (typefind->possibilities, walk);
walk = next;
} else if (entry->probability >= typefind->max_probability) {
/* wooha, got caps */
GstCaps *found_caps = entry->caps;
guint probability = entry->probability;
GST_INFO_OBJECT (typefind,
"'%s' returned %u/%u probability, using it NOW",
GST_PLUGIN_FEATURE_NAME (entry->factory), probability,
typefind->max_probability);
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
probability, found_caps);
g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
g_list_free (typefind->possibilities);
typefind->possibilities = NULL;
break;
} else {
walk = g_list_next (walk);
if (entry->requested_size != 0)
done = FALSE;
}
}
/* we may now already have caps or we might be left without functions to try */
if (typefind->caps) {
stop_typefinding (typefind);
} else if (typefind->possibilities == NULL) {
if (GST_BUFFER_SIZE (typefind->store) > TYPE_FIND_MAX_SIZE) {
GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
stop_typefinding (typefind);
return GST_FLOW_ERROR;
} else {
GST_DEBUG_OBJECT (typefind, "no type found with %u bytes - waiting "
"for more data", GST_BUFFER_SIZE (typefind->store));
return GST_FLOW_OK;
}
} else if (done) {
TypeFindEntry *best;
if ((best = gst_type_find_element_get_best_possibility (typefind))) {
GST_INFO_OBJECT (typefind,
"'%s' is the best typefind left, using it now (probability %u)",
GST_PLUGIN_FEATURE_NAME (best->factory), best->probability);
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
0, best->probability, best->caps);
g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
g_list_free (typefind->possibilities);
typefind->possibilities = NULL;
stop_typefinding (typefind);
} else {
GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
stop_typefinding (typefind);
return GST_FLOW_ERROR;
}
}
res = gst_type_find_element_chain_do_typefinding (typefind);
if (typefind->mode == MODE_ERROR)
res = GST_FLOW_ERROR;
@ -817,6 +544,56 @@ gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
return res;
}
static GstFlowReturn
gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind)
{
GstTypeFindProbability probability;
GstCaps *caps;
if (GST_BUFFER_SIZE (typefind->store) < TYPE_FIND_MIN_SIZE) {
GST_DEBUG_OBJECT (typefind, "not enough data for typefinding yet "
"(%u bytes)", GST_BUFFER_SIZE (typefind->store));
return GST_FLOW_OK;
}
caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind),
typefind->store, &probability);
if (caps == NULL && GST_BUFFER_SIZE (typefind->store) > TYPE_FIND_MAX_SIZE) {
GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
stop_typefinding (typefind);
return GST_FLOW_ERROR;
} else if (caps == NULL) {
GST_DEBUG_OBJECT (typefind, "no caps found with %u bytes of data, "
"waiting for more data", GST_BUFFER_SIZE (typefind->store));
return GST_FLOW_OK;
}
/* found a type */
if (probability < typefind->min_probability) {
GST_DEBUG_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", but "
"probability is %u which is lower than the required minimum of %u",
caps, probability, typefind->min_probability);
if (GST_BUFFER_SIZE (typefind->store) >= TYPE_FIND_MAX_SIZE) {
GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
stop_typefinding (typefind);
return GST_FLOW_ERROR;
}
GST_DEBUG_OBJECT (typefind, "waiting for more data to try again");
return GST_FLOW_OK;
}
/* probability is good enough too, so let's make it known ... */
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
probability, caps);
/* .. and send out the accumulated data */
stop_typefinding (typefind);
return GST_FLOW_OK;
}
static gboolean
gst_type_find_element_checkgetrange (GstPad * srcpad)
{

View file

@ -25,7 +25,6 @@
#include <gst/gstinfo.h>
#include <gst/gstelement.h>
/* #include <gst/gstbufferstore.h> */
#include "gstbufferstore.h"
G_BEGIN_DECLS
@ -59,10 +58,6 @@ struct _GstTypeFindElement {
guint mode;
GstBuffer * store;
guint64 stream_length;
gboolean stream_length_available;
GList * possibilities;
};
struct _GstTypeFindElementClass {