gst/playback/: Add some debug info to decodebin, update README

Original commit message from CVS:
* gst/playback/README:
* gst/playback/gstdecodebin.c: (gst_decode_bin_factory_filter),
(gst_decode_bin_init), (find_compatibles), (close_pad_link),
(try_to_link_1), (no_more_pads), (close_link), (type_found):
Add some debug info to decodebin, update README
This commit is contained in:
Wim Taymans 2004-10-01 15:57:53 +00:00
parent 586f6f31da
commit f92e880040
3 changed files with 180 additions and 36 deletions

View file

@ -1,3 +1,11 @@
2004-10-01 Wim Taymans <wim@fluendo.com>
* gst/playback/README:
* gst/playback/gstdecodebin.c: (gst_decode_bin_factory_filter),
(gst_decode_bin_init), (find_compatibles), (close_pad_link),
(try_to_link_1), (no_more_pads), (close_link), (type_found):
Add some debug info to decodebin, update README
2004-10-01 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* ext/dvdnav/dvdnavsrc.c: (dvdnav_handle_navigation_event):

View file

@ -7,9 +7,7 @@ decoderbin:
TODO
- reuse of decoderbin, cleanup in READY state
- debugging
- threading after demuxing?
- better factory selection, based on Demuxer/Decoder types and ranks.
- error handling
baseplaybin:

View file

@ -1,5 +1,5 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) <2004> Wim Taymans <wim@fluendo.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -51,26 +51,28 @@ typedef struct _GstDecodeBinClass GstDecodeBinClass;
struct _GstDecodeBin
{
GstBin bin;
GstBin bin; /* we extend GstBin */
GstElement *typefind;
GstElement *typefind; /* this holds the typefind object */
gboolean threaded;
GList *dynamics;
gboolean threaded; /* indicating threaded execution is desired */
GList *dynamics; /* list of dynamic connections */
GList *factories;
GList *factories; /* factories we can use for selecting elements */
gint numpads;
GList *elements;
GList *elements; /* elements we added in autoplugging */
guint have_type_id;
guint have_type_id; /* signal id for the typefind element */
};
struct _GstDecodeBinClass
{
GstBinClass parent_class;
/* signal we fire when a new pad has been decoded into raw audio/video */
void (*new_decoded_pad) (GstElement * element, GstPad * pad, gboolean last);
/* signal fired when we found a pad that we cannot decode */
void (*unknown_type) (GstElement * element, GstCaps * caps);
};
@ -89,12 +91,14 @@ enum
LAST_SIGNAL
};
/* this structure is created for all dynamic pads that could get created
* at runtime */
typedef struct
{
gint np_sig_id;
gint nmp_sig_id;
GstElement *element;
GstDecodeBin *decode_bin;
gint np_sig_id; /* signal id of new_pad */
gint nmp_sig_id; /* signal id of no_more_pads */
GstElement *element; /* the element sending the signal */
GstDecodeBin *decode_bin; /* pointer to ourself */
}
GstDynamic;
@ -196,12 +200,19 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
GST_DEBUG_FUNCPTR (gst_decode_bin_change_state);
}
/* check if the bin is dynamic.
*
* If there are no outstanding dynamic connections, the bin is
* considered to be non-dynamic.
*/
static gboolean
gst_decode_bin_is_dynamic (GstDecodeBin * decode_bin)
{
return decode_bin->dynamics != NULL;
}
/* the filter function for selecting the elements we can use in
* autoplugging */
static gboolean
gst_decode_bin_factory_filter (GstPluginFeature * feature,
GstDecodeBin * decode_bin)
@ -209,14 +220,17 @@ gst_decode_bin_factory_filter (GstPluginFeature * feature,
guint rank;
const gchar *klass;
/* we only care about element factories */
if (!GST_IS_ELEMENT_FACTORY (feature))
return FALSE;
klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
/* only demuxers and decoders can play */
if (strstr (klass, "Demux") == NULL && strstr (klass, "Decoder") == NULL) {
return FALSE;
}
/* only select elements with autoplugging rank */
rank = gst_plugin_feature_get_rank (feature);
if (rank < GST_RANK_MARGINAL)
return FALSE;
@ -224,6 +238,7 @@ gst_decode_bin_factory_filter (GstPluginFeature * feature,
return TRUE;
}
/* function used to sort element features */
static gint
compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
{
@ -241,24 +256,33 @@ gst_decode_bin_init (GstDecodeBin * decode_bin)
{
GList *factories;
/* first filter out the interesting element factories */
factories = gst_registry_pool_feature_filter (
(GstPluginFeatureFilter) gst_decode_bin_factory_filter,
FALSE, decode_bin);
/* sort them according to their ranks */
decode_bin->factories = g_list_sort (factories, (GCompareFunc) compare_ranks);
/* do some debugging */
g_list_foreach (decode_bin->factories, (GFunc) print_feature, NULL);
/* we create the typefind element only once */
decode_bin->typefind = gst_element_factory_make ("typefind", "typefind");
if (!decode_bin->typefind) {
g_warning ("can't find typefind element");
}
gst_bin_add (GST_BIN (decode_bin), decode_bin->typefind);
gst_element_add_ghost_pad (GST_ELEMENT (decode_bin),
gst_element_get_pad (decode_bin->typefind, "sink"), "sink");
g_warning ("can't find typefind element, decodebin will not work");
} else {
/* add the typefind element */
gst_bin_add (GST_BIN (decode_bin), decode_bin->typefind);
/* ghost the sink pad to ourself */
gst_element_add_ghost_pad (GST_ELEMENT (decode_bin),
gst_element_get_pad (decode_bin->typefind, "sink"), "sink");
decode_bin->have_type_id =
g_signal_connect (G_OBJECT (decode_bin->typefind), "have_type",
G_CALLBACK (type_found), decode_bin);
/* connect a signal to find out when the typefind element found
* a type */
decode_bin->have_type_id =
g_signal_connect (G_OBJECT (decode_bin->typefind), "have_type",
G_CALLBACK (type_found), decode_bin);
}
decode_bin->dynamics = NULL;
}
@ -291,28 +315,37 @@ gst_decode_bin_dispose (GObject * object)
}
}
/* this function runs through the element factories and returns a list
* of all elements that are able to sink the given caps
*/
static GList *
find_compatibles (GstDecodeBin * decode_bin, const GstCaps * caps)
{
GList *factories;
GList *to_try = NULL;
/* loop over all the factories */
for (factories = decode_bin->factories; factories;
factories = g_list_next (factories)) {
GstElementFactory *factory = GST_ELEMENT_FACTORY (factories->data);
const GList *templates;
GList *walk;
/* get the templates from the element factory */
templates = gst_element_factory_get_pad_templates (factory);
for (walk = (GList *) templates; walk; walk = g_list_next (walk)) {
GstPadTemplate *templ = GST_PAD_TEMPLATE (walk->data);
/* we only care about the sink templates */
if (templ->direction == GST_PAD_SINK) {
GstCaps *intersect;
/* try to intersect the caps with the caps of the template */
intersect =
gst_caps_intersect (caps, gst_pad_template_get_caps (templ));
/* check if the intersection is empty */
if (!gst_caps_is_empty (intersect)) {
/* non empty intersection, we can use this element */
to_try = g_list_append (to_try, factory);
}
gst_caps_free (intersect);
@ -322,6 +355,15 @@ find_compatibles (GstDecodeBin * decode_bin, const GstCaps * caps)
return to_try;
}
/* given a pad and a caps from an element, find the list of elements
* that could connect to the pad
*
* If the pad has a raw format, this function will create a ghostpad
* for the pad onto the decodebin.
*
* If no compatible elements could be found, this function will signal
* the unknown_type signal.
*/
static void
close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
GstDecodeBin * decode_bin)
@ -330,29 +372,34 @@ close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
GstStructure *structure;
const gchar *mimetype;
/* the caps is empty, this means the pad has no type, we can only
* decide to fire the unknown_type signal. */
if (gst_caps_is_empty (caps)) {
g_signal_emit (G_OBJECT (decode_bin),
gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, caps);
return;
}
/* FIXME, iterate over more structures? */
structure = gst_caps_get_structure (caps, 0);
mimetype = gst_structure_get_name (structure);
/* first see if this is raw */
/* first see if this is raw. If the type is raw, we can
* create a ghostpad for this pad. */
if (g_str_has_prefix (mimetype, "video/x-raw") ||
g_str_has_prefix (mimetype, "audio/x-raw")) {
gchar *padname;
GstPad *ghost;
gboolean dynamic;
/* make a unique name for this new pad */
padname = g_strdup_printf ("src%d", decode_bin->numpads);
decode_bin->numpads++;
gst_element_add_ghost_pad (GST_ELEMENT (decode_bin), pad, padname);
ghost = gst_element_get_pad (GST_ELEMENT (decode_bin), padname);
/* make it a ghostpad */
ghost = gst_element_add_ghost_pad (GST_ELEMENT (decode_bin), pad, padname);
/* see if any more pending dynamic connections exist */
dynamic = gst_decode_bin_is_dynamic (decode_bin);
/* our own signal with an extra flag that this is the only pad */
@ -363,85 +410,128 @@ close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
return;
}
/* then continue plugging */
/* then continue plugging, first find all compatible elements */
to_try = find_compatibles (decode_bin, caps);
if (to_try == NULL) {
/* no compatible elements, fire the unknown_type signal, we cannot go
* on */
g_signal_emit (G_OBJECT (decode_bin),
gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, caps);
return;
}
/* now try to link the elements in the to_try list to the pad */
try_to_link_1 (decode_bin, pad, to_try);
}
/* given a list of element factories, try to link one of the factories
* to the given pad */
static GstElement *
try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
{
GList *walk;
/* loop over the factories */
for (walk = factories; walk; walk = g_list_next (walk)) {
GstElementFactory *factory = GST_ELEMENT_FACTORY (walk->data);
GstElement *element;
gboolean ret;
GST_DEBUG ("trying to link %s",
GST_DEBUG_OBJECT (decode_bin, "trying to link %s",
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
/* make an element from the factory first */
element = gst_element_factory_create (factory, NULL);
if (element == NULL)
if (element == NULL) {
/* hmm, strange */
GST_WARNING_OBJECT (decode_bin, "could not create an element from %s",
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
continue;
}
GST_DEBUG ("adding %s", gst_element_get_name (element));
/* now add the element to the bin first */
GST_DEBUG_OBJECT (decode_bin, "adding %s", gst_element_get_name (element));
gst_bin_add (GST_BIN (decode_bin), element);
/* keep out own list of elements */
decode_bin->elements = g_list_prepend (decode_bin->elements, element);
/* try to link the given pad to a sinkpad */
/* FIXME, find the sinkpad by looping over the pads instead of
* looking it up by name */
ret = gst_pad_link (pad, gst_element_get_pad (element, "sink"));
if (ret) {
const gchar *klass;
GstElementFactory *factory;
/* The link worked, now figure out what it was that we connected */
factory = gst_element_get_factory (element);
klass = gst_element_factory_get_klass (factory);
/* check if we can use threads */
if (decode_bin->threaded) {
if (strstr (klass, "Demux") != NULL) {
/* FIXME, do something with threads here */
}
}
/* now that we added the element we can try to continue autoplugging
* on it until we have a raw type */
close_link (element, decode_bin);
/* change the state of the element to that of the parent */
gst_element_sync_state_with_parent (element);
return element;
} else {
/* this element did not work, remove it again and continue trying
* other elements */
gst_bin_remove (GST_BIN (decode_bin), element);
}
}
return NULL;
}
/* This function will be called when a dynamic pad is created on an element.
* We try to continue autoplugging on this new pad. */
static void
new_pad (GstElement * element, GstPad * pad, GstDynamic * dynamic)
{
close_pad_link (element, pad, gst_pad_get_caps (pad), dynamic->decode_bin);
}
/* this signal is fired when an element signals the no_more_pads signal.
* This means that the element will not generate more dynamic pads and
* we can remove the element from the list of dynamic elements. When we
* have no more dynamic elements in the pipeline, we can fire a no_more_pads
* signal ourselves. */
static void
no_more_pads (GstElement * element, GstDynamic * dynamic)
{
GstDecodeBin *decode_bin = dynamic->decode_bin;
GST_DEBUG ("decodebin: no more pads");
GST_DEBUG_OBJECT (decode_bin, "no more pads on element %s",
gst_element_get_name (element));
/* disconnect signals */
g_signal_handler_disconnect (G_OBJECT (dynamic->element), dynamic->np_sig_id);
g_signal_handler_disconnect (G_OBJECT (dynamic->element),
dynamic->nmp_sig_id);
/* remove the element from the list of dynamic elements */
decode_bin->dynamics = g_list_remove (decode_bin->dynamics, dynamic);
g_free (dynamic);
if (decode_bin->dynamics == NULL)
/* if we have no more dynamic elements, we have no change of creating
* more pads, so we fire the no_more_pads signal */
if (decode_bin->dynamics == NULL) {
GST_DEBUG_OBJECT (decode_bin,
"no more dynamic elements, signaling no_more_pads");
gst_element_no_more_pads (GST_ELEMENT (decode_bin));
} else {
GST_DEBUG_OBJECT (decode_bin, "we have more dynamic elements");
}
}
/* this function inspects the given element and tries to connect something
* on the srcpads. If there are dynamic pads, it sets up a signal handler to
* continue autoplugging when they become available */
static void
close_link (GstElement * element, GstDecodeBin * decode_bin)
{
@ -449,43 +539,74 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
gboolean dynamic = FALSE;
GList *to_connect = NULL;
GST_DEBUG_OBJECT (decode_bin, "closing links with element %s",
gst_element_get_name (element));
/* loop over all the padtemplates */
for (pads = gst_element_get_pad_template_list (element); pads;
pads = g_list_next (pads)) {
GstPadTemplate *templ = GST_PAD_TEMPLATE (pads->data);
const gchar *templ_name;
/* we are only interested in source pads */
if (GST_PAD_TEMPLATE_DIRECTION (templ) != GST_PAD_SRC)
continue;
templ_name = GST_PAD_TEMPLATE_NAME_TEMPLATE (templ);
GST_DEBUG_OBJECT (decode_bin, "got a source pad template %s", templ_name);
/* figure out what kind of pad this is */
switch (GST_PAD_TEMPLATE_PRESENCE (templ)) {
case GST_PAD_ALWAYS:
{
GstPad *pad = gst_element_get_pad (element,
GST_PAD_TEMPLATE_NAME_TEMPLATE (templ));
/* get the pad that we need to autoplug */
GstPad *pad = gst_element_get_pad (element, templ_name);
if (pad) {
GST_DEBUG_OBJECT (decode_bin, "got the pad for always template %s",
templ_name);
/* here is the pad, we need to autoplug it */
to_connect = g_list_prepend (to_connect, pad);
} else {
/* strange, pad is marked as always but it's not
* there. Fix the element */
GST_WARNING_OBJECT (decode_bin,
"could not get the pad for always template %s", templ_name);
}
break;
}
case GST_PAD_SOMETIMES:
{
GstPad *pad = gst_element_get_pad (element,
GST_PAD_TEMPLATE_NAME_TEMPLATE (templ));
/* try to get the pad to see if it is already created or
* not */
GstPad *pad = gst_element_get_pad (element, templ_name);
if (pad) {
GST_DEBUG_OBJECT (decode_bin, "got the pad for sometimes template %s",
templ_name);
/* the pad is created, we need to autoplug it */
to_connect = g_list_prepend (to_connect, pad);
} else {
GST_DEBUG_OBJECT (decode_bin,
"did not get the sometimes pad of template %s", templ_name);
/* we have an element that will create dynamic pads */
dynamic = TRUE;
}
break;
}
case GST_PAD_REQUEST:
/* ignore request pads */
GST_DEBUG_OBJECT (decode_bin, "ignoring request padtemplate %s",
templ_name);
break;
}
}
if (dynamic) {
GstDynamic *dyn;
GST_DEBUG_OBJECT (decode_bin, "got a dynamic element here");
/* ok, this element has dynamic pads, set up the signal handlers to be
* notified of them */
dyn = g_new0 (GstDynamic, 1);
dyn->np_sig_id = g_signal_connect (G_OBJECT (element), "new-pad",
G_CALLBACK (new_pad), dyn);
@ -494,29 +615,46 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
dyn->element = element;
dyn->decode_bin = decode_bin;
/* and add this element to the dynamic elements */
decode_bin->dynamics = g_list_prepend (decode_bin->dynamics, dyn);
}
/* now loop over all the pads we need to connect */
for (pads = to_connect; pads; pads = g_list_next (pads)) {
GstPad *pad = GST_PAD (pads->data);
GST_DEBUG_OBJECT (decode_bin, "closing pad link for %s",
gst_pad_get_name (pad));
/* continue autoplugging on the pads */
close_pad_link (element, pad, gst_pad_get_caps (pad), decode_bin);
}
g_list_free (to_connect);
}
/* this is the signal handler for the typefind element have_type signal.
* It tries to continue autoplugging on the typefind src pad */
static void
type_found (GstElement * typefind, guint probability, GstCaps * caps,
GstDecodeBin * decode_bin)
{
gboolean dynamic;
GST_DEBUG_OBJECT (decode_bin, "typefind found caps %" GST_PTR_FORMAT, caps);
/* autoplug the new pad with the caps that the signal gave us */
close_pad_link (typefind, gst_element_get_pad (typefind, "src"), caps,
decode_bin);
dynamic = gst_decode_bin_is_dynamic (decode_bin);
if (dynamic == FALSE) {
GST_DEBUG_OBJECT (decode_bin, "we have no dynamic elements anymore");
/* if we have no dynamic elements, we know that no new pads
* will be created and we can signal out no_more_pads signal */
gst_element_no_more_pads (GST_ELEMENT (decode_bin));
} else {
/* more dynamic elements exist that could create new pads */
GST_DEBUG_OBJECT (decode_bin, "we more dynamic elements");
}
}