From 4f55ae4ded29f7a7d951bdb201ac0476671a0040 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 3 Dec 2000 17:51:29 +0000 Subject: [PATCH] Added multiple types to the pads. Original commit message from CVS: Added multiple types to the pads. Added first preview of the capabilities system. Autoplugging is seriously broken with these (and other) changes. --- gst/Makefile.am | 4 +- gst/gst.h | 1 + gst/gstcaps.c | 328 +++++++++++++++++++++++++++++++++++++++++++ gst/gstcaps.h | 68 +++++++++ gst/gstcapsprivate.h | 49 +++++++ gst/gstpad.c | 28 ++-- gst/gstpad.h | 9 +- gst/gstpipeline.c | 44 ++++-- 8 files changed, 501 insertions(+), 30 deletions(-) create mode 100644 gst/gstcaps.c create mode 100644 gst/gstcaps.h create mode 100644 gst/gstcapsprivate.h diff --git a/gst/Makefile.am b/gst/Makefile.am index 26942f85eb..f3076dc8a7 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -37,6 +37,7 @@ libgst_la_SOURCES = \ gstsink.c \ gstconnection.c \ gsttype.c \ + gstcaps.c \ gstplugin.c \ gstutils.c \ gsttrace.c \ @@ -65,6 +66,7 @@ libgstinclude_HEADERS = \ gstsink.h \ gstconnection.h \ gsttype.h \ + gstcaps.h \ gstplugin.h \ gstutils.h \ gsttrace.h \ @@ -78,7 +80,7 @@ noinst_HEADERS = \ gsti386.h \ gstppc.h -CFLAGS += -O2 -Wall +CFLAGS += -g -O6 -Wall libgst_la_LIBADD = $(GLIB_LIBS) $(GTK_LIBS) $(XML_LIBS) libgst_la_LDFLAGS = -version-info $(STREAMER_CURRENT):$(STREAMER_REVISION):$(STREAMER_AGE) diff --git a/gst/gst.h b/gst/gst.h index 88e3665048..905823473a 100644 --- a/gst/gst.h +++ b/gst/gst.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include diff --git a/gst/gstcaps.c b/gst/gstcaps.c new file mode 100644 index 0000000000..91755b8fcc --- /dev/null +++ b/gst/gstcaps.c @@ -0,0 +1,328 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * 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. + */ + +#include +#include + +void +_gst_caps_initialize (void) +{ +} + +static GstCapsEntry * +gst_caps_create_entry (GstCapsFactory factory, gint *skipped) +{ + GstCapsFactoryEntry tag; + GstCapsEntry *entry; + guint i=0; + + entry = g_new0 (GstCapsEntry, 1); + + tag = factory[i++]; + switch (GPOINTER_TO_INT (tag)) { + case GST_CAPS_INT_ID: + entry->capstype = GST_CAPS_INT_ID_NUM; + entry->data.int_data = GPOINTER_TO_INT (factory[i++]); + break; + case GST_CAPS_INT_RANGE_ID: + entry->capstype = GST_CAPS_INT_RANGE_ID_NUM; + entry->data.int_range_data.min = GPOINTER_TO_INT (factory[i++]); + entry->data.int_range_data.max = GPOINTER_TO_INT (factory[i++]); + break; + case GST_CAPS_LIST_ID: + g_print("gstcaps: list not allowed in list\n"); + break; + default: + g_print("gstcaps: unknown caps id found\n"); + g_free (entry); + entry = NULL; + break; + } + + *skipped = i; + + return entry; +} + + +static gint +caps_compare_func (gconstpointer a, + gconstpointer b) +{ + GstCapsEntry *entry1 = (GstCapsEntry *)a; + GstCapsEntry *entry2 = (GstCapsEntry *)b; + + return (entry1->propid - entry2->propid); +} + +/** + * gst_caps_register: + * @factory: the factory to register + * + * Register the factory. + * + * Returns: The registered capability + */ +GstCaps * +gst_caps_register (GstCapsFactory factory) +{ + GstCapsFactoryEntry tag; + gint i = 0; + guint16 typeid; + GstCaps *caps; + gint skipped; + + g_return_val_if_fail (factory != NULL, NULL); + + tag = factory[i++]; + + g_return_val_if_fail (tag != NULL, NULL); + + typeid = gst_type_find_by_mime ((gchar *)tag); + if (typeid == 0) { + GstTypeFactory *factory = g_new0 (GstTypeFactory, 1); + + factory->mime = g_strdup ((gchar *)tag); + factory->exts = NULL; + factory->typefindfunc = NULL; + + typeid = gst_type_register (factory); + } + + caps = g_new0 (GstCaps, 1); + g_return_val_if_fail (caps != NULL, NULL); + + caps->id = typeid; + caps->properties = NULL; + + tag = factory[i++]; + + while (tag) { + GQuark quark; + GstCapsEntry *entry; + + quark = g_quark_from_string ((gchar *)tag); + + tag = factory[i]; + switch (GPOINTER_TO_INT (tag)) { + case GST_CAPS_LIST_ID: + { + GstCapsEntry *list_entry; + + entry = g_new0 (GstCapsEntry, 1); + entry->propid = quark; + entry->capstype = GST_CAPS_LIST_ID_NUM; + entry->data.list_data.entries = NULL; + + i++; // skip list tag + tag = factory[i]; + while (tag) { + list_entry = gst_caps_create_entry (&factory[i], &skipped); + i += skipped; + tag = factory[i]; + entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, list_entry); + } + entry->data.list_data.entries = g_list_reverse (entry->data.list_data.entries); + i++; //skip NULL (list end) + break; + } + default: + { + entry = gst_caps_create_entry (&factory[i], &skipped); + entry->propid = quark; + i += skipped; + break; + } + } + caps->properties = g_slist_insert_sorted (caps->properties, entry, caps_compare_func); + + tag = factory[i++]; + } + + return caps; +} + +static void +gst_caps_dump_entry_func (GstCapsEntry *entry) +{ + switch (entry->capstype) { + case GST_CAPS_INT_ID_NUM: + g_print("gstcaps: int %d\n", entry->data.int_data); + break; + case GST_CAPS_INT_RANGE_ID_NUM: + g_print("gstcaps: int range %d %d\n", + entry->data.int_range_data.min, + entry->data.int_range_data.max); + break; + case GST_CAPS_INT32_ID_NUM: + g_print("gstcaps: int32 %d\n", entry->data.int_data); + break; + case GST_CAPS_BOOL_ID_NUM: + g_print("gstcaps: boolean %d\n", entry->data.bool_data); + break; + default: + g_print("gstcaps: **illegal entry**\n"); + break; + } +} + +static void +gst_caps_dump_list_func (gpointer entry, + gpointer list_entry) +{ + gst_caps_dump_entry_func ((GstCapsEntry *)entry); +} + +static void +gst_caps_dump_func (gpointer data, + gpointer user_data) +{ + GstCapsEntry *entry; + + entry = (GstCapsEntry *)data; + + g_print("gstcaps: property type \"%s\"\n", g_quark_to_string (entry->propid)); + + switch (entry->capstype) { + case GST_CAPS_LIST_ID_NUM: + { + g_print("gstcaps: list type (\n"); + g_list_foreach (entry->data.list_data.entries, gst_caps_dump_list_func, entry); + g_print("gstcaps: )\n"); + break; + } + default: + gst_caps_dump_entry_func (entry); + break; + } +} + +/** + * gst_caps_dump: + * @caps: the capability to dump + * + * Dumps the contents of the capabilty one the console + */ +void +gst_caps_dump (GstCaps *caps) +{ + g_return_if_fail (caps != NULL); + + g_print("gstcaps: {\ngstcaps: mime type \"%d\"\n", caps->id); + + g_slist_foreach (caps->properties, gst_caps_dump_func, caps); + g_print("gstcaps: }\n"); +} + +static gboolean +gst_caps_entry_check_compatibility (GstCapsEntry *entry1, GstCapsEntry *entry2) +{ + g_print ("compare: %s %s\n", g_quark_to_string (entry1->propid), + g_quark_to_string (entry2->propid)); +} + +/** + * gst_caps_check_compatibility: + * @fromcaps: a capabilty + * @tocaps: a capabilty + * + * Checks whether two capabilities are compatible + * + * Returns: true if compatible, false otherwise + */ +gboolean +gst_caps_check_compatibility (GstCaps *fromcaps, GstCaps *tocaps) +{ + GSList *sourcelist; + GSList *sinklist; + gint missing = 0; + gint more = 0; + + g_return_val_if_fail (fromcaps != NULL, FALSE); + g_return_val_if_fail (tocaps != NULL, FALSE); + + if (fromcaps->id != tocaps->id) + return FALSE; + + sourcelist = fromcaps->properties; + sinklist = tocaps->properties; + + while (sourcelist && sinklist) { + GstCapsEntry *entry1; + GstCapsEntry *entry2; + + entry1 = (GstCapsEntry *)sourcelist->data; + entry2 = (GstCapsEntry *)sinklist->data; + + while (entry1->propid < entry2->propid) { + g_print ("source is more specific in \"%s\"\n", g_quark_to_string (entry1->propid)); + more++; + sourcelist = g_slist_next (sourcelist); + if (sourcelist) entry1 = (GstCapsEntry *)sourcelist->data; + else goto end; + } + while (entry1->propid > entry2->propid) { + g_print ("source has missing property \"%s\"\n", g_quark_to_string (entry2->propid)); + missing++; + sinklist = g_slist_next (sinklist); + if (sinklist) entry2 = (GstCapsEntry *)sinklist->data; + else goto end; + } + + gst_caps_entry_check_compatibility (entry1, entry2); + + sourcelist = g_slist_next (sourcelist); + sinklist = g_slist_next (sinklist); + } +end: + + if (missing) + return FALSE; + + return TRUE; +} + +/** + * gst_caps_register_va: + * @factory: the factories to register + * + * Register the given factories. + * + * Returns: A list of the registered factories + */ +GList * +gst_caps_register_va (GstCapsFactory factory, ...) +{ + va_list var_args; + GstCapsFactoryEntry *current_factory; + + va_start (var_args, factory); + + current_factory = (GstCapsFactoryEntry *) factory; + + while (current_factory) { + gst_caps_register (current_factory); + + current_factory = va_arg (var_args, GstCapsFactoryEntry *); + } + + va_end(var_args); + + return NULL; +} diff --git a/gst/gstcaps.h b/gst/gstcaps.h new file mode 100644 index 0000000000..50950ccd8a --- /dev/null +++ b/gst/gstcaps.h @@ -0,0 +1,68 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * 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. + */ + + +#ifndef __GST_CAPS_H__ +#define __GST_CAPS_H__ + +#include + +typedef struct _GstCaps GstCaps; +typedef gpointer GstCapsFactoryEntry; +typedef GstCapsFactoryEntry GstCapsFactory[]; + +typedef enum { + GST_CAPS_END_ID_NUM = 0, + GST_CAPS_LIST_ID_NUM, + GST_CAPS_INT_ID_NUM, + GST_CAPS_INT_RANGE_ID_NUM, + GST_CAPS_INT32_ID_NUM, + GST_CAPS_BOOL_ID_NUM, +} GstCapsId; + +#define GST_CAPS_LIST_ID GINT_TO_POINTER(GST_CAPS_LIST_ID_NUM) +#define GST_CAPS_INT_ID GINT_TO_POINTER(GST_CAPS_INT_ID_NUM) +#define GST_CAPS_INT_RANGE_ID GINT_TO_POINTER(GST_CAPS_INT_RANGE_ID_NUM) +#define GST_CAPS_INT32_ID GINT_TO_POINTER(GST_CAPS_INT32_ID_NUM) +#define GST_CAPS_BOOL_ID GINT_TO_POINTER(GST_CAPS_BOOL_ID_NUM) + +#define GST_CAPS_LIST(a...) GST_CAPS_LIST_ID,##a,NULL +#define GST_CAPS_INT(a) GST_CAPS_INT_ID,(GINT_TO_POINTER(a)) +#define GST_CAPS_INT_RANGE(a,b) GST_CAPS_INT_RANGE_ID,(GINT_TO_POINTER(a)),(GINT_TO_POINTER(b)) +#define GST_CAPS_INT32(a) GST_CAPS_INT_ID,(GINT_TO_POINTER(a)) +#define GST_CAPS_BOOLEAN(a) GST_CAPS_BOOL_ID,(GINT_TO_POINTER(a)) + + +struct _GstCaps { + guint16 id; /* type id (major type) */ + + GSList *properties; /* properties for this capability */ +}; + +/* initialize the subsystem */ +void _gst_caps_initialize (void); + +GstCaps* gst_caps_register (GstCapsFactory factory); +GList* gst_caps_register_va (GstCapsFactory factory,...); + +void gst_caps_dump (GstCaps *caps); + +gboolean gst_caps_check_compatibility (GstCaps *caps1, GstCaps *caps2); + +#endif /* __GST_CAPS_H__ */ diff --git a/gst/gstcapsprivate.h b/gst/gstcapsprivate.h new file mode 100644 index 0000000000..978e4e6f92 --- /dev/null +++ b/gst/gstcapsprivate.h @@ -0,0 +1,49 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * 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. + */ + + +#ifndef __GST_CAPS_PRIV_H__ +#define __GST_CAPS_PRIV_H__ + +#include + +typedef struct _GstCapsEntry GstCapsEntry; + +struct _GstCapsEntry { + GQuark propid; + GstCapsId capstype; + + union { + /* flat values */ + gboolean bool_data; + guint32 fourcc_data; + gint int_data; + + /* structured values */ + struct { + GList *entries; + } list_data; + struct { + gint min; + gint max; + } int_range_data; + } data; +}; + +#endif /* __GST_CAPS_PRIV_H__ */ diff --git a/gst/gstpad.c b/gst/gstpad.c index 135a88ff91..81cde7d194 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -97,7 +97,6 @@ gst_pad_class_init (GstPadClass *klass) static void gst_pad_init (GstPad *pad) { - pad->type = 0; pad->direction = GST_PAD_UNKNOWN; pad->peer = NULL; pad->chainfunc = NULL; @@ -107,6 +106,7 @@ gst_pad_init (GstPad *pad) pad->qosfunc = NULL; pad->parent = NULL; pad->ghostparents = NULL; + pad->types = NULL; } static void @@ -645,22 +645,28 @@ gst_pad_get_ghost_parents (GstPad *pad) } /** - * gst_pad_get_type_id: - * @pad: the pad to get the type id from + * gst_pad_get_type_ids: + * @pad: the pad to get the type ids from * - * get the type of this pad + * get the list of types for this pad * - * Returns: the type of this pad + * Returns: a GList of types of this pad */ -guint16 -gst_pad_get_type_id (GstPad *pad) +GList* +gst_pad_get_type_ids (GstPad *pad) { g_return_val_if_fail (pad != NULL, 0); g_return_val_if_fail (GST_IS_PAD (pad), 0); - return pad->type; + return pad->types; +} +// FIXME remove... +void +gst_pad_set_type_id (GstPad *pad, + guint16 id) +{ + gst_pad_add_type_id (pad, id); } - /** * gst_pad_set_type_id: * @pad: the pad to set the type id to @@ -669,14 +675,14 @@ gst_pad_get_type_id (GstPad *pad) * set the type of this pad */ void -gst_pad_set_type_id (GstPad *pad, +gst_pad_add_type_id (GstPad *pad, guint16 id) { g_return_if_fail (pad != NULL); g_return_if_fail (GST_IS_PAD (pad)); g_return_if_fail (gst_type_find_by_id (id) != NULL); - pad->type = id; + g_list_append(pad->types, GINT_TO_POINTER((gint)id)); } /** diff --git a/gst/gstpad.h b/gst/gstpad.h index 1875eff910..ad0b97a088 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -68,7 +68,7 @@ struct _GstPad { GstObject object; gchar *name; - guint16 type; + GList *types; GstPadDirection direction; @@ -104,8 +104,11 @@ void gst_pad_set_chain_function (GstPad *pad, GstPadChainFunction chain); void gst_pad_set_pull_function (GstPad *pad, GstPadPullFunction pull); void gst_pad_set_qos_function (GstPad *pad, GstPadQoSFunction qos); -guint16 gst_pad_get_type_id (GstPad *pad); -void gst_pad_set_type_id (GstPad *pad, guint16 id); +// FIXME is here for backward compatibility until we have GstCaps working... +void gst_pad_set_type_id (GstPad *pad, guint16 id); + +GList* gst_pad_get_type_ids (GstPad *pad); +void gst_pad_add_type_id (GstPad *pad, guint16 id); void gst_pad_set_name (GstPad *pad, const gchar *name); const gchar* gst_pad_get_name (GstPad *pad); diff --git a/gst/gstpipeline.c b/gst/gstpipeline.c index d3c70c37e2..610da96310 100644 --- a/gst/gstpipeline.c +++ b/gst/gstpipeline.c @@ -169,7 +169,7 @@ gst_pipeline_typefind (GstPipeline *pipeline, GstElement *element) if (found) { type_id = gst_util_get_int_arg (GTK_OBJECT (typefind), "type"); - gst_pad_set_type_id (gst_element_get_pad (element, "src"), type_id); + gst_pad_add_type_id (gst_element_get_pad (element, "src"), type_id); } gst_pad_disconnect (gst_element_get_pad (element, "src"), @@ -184,25 +184,28 @@ static void gst_pipeline_pads_autoplug_func (GstElement *src, GstPad *pad, GstElement *sink) { GList *sinkpads; - GstPad *sinkpad; gboolean connected = FALSE; + guint16 type; - g_print("gstpipeline: autoplug pad connect function type %d for \"%s\" to \"%s\"\n", pad->type, + type = ((GstType *)pad->types->data)->id; + + g_print("gstpipeline: autoplug pad connect function type %d for \"%s\" to \"%s\"\n", type, gst_element_get_name(src), gst_element_get_name(sink)); sinkpads = gst_element_get_pad_list(sink); while (sinkpads) { - sinkpad = (GstPad *)sinkpads->data; + GstPad *sinkpad = (GstPad *)sinkpads->data; + guint16 sinktype = ((GstType *)sinkpad->types->data)->id; // if we have a match, connect the pads - if (sinkpad->type == pad->type && + if (sinktype == type && sinkpad->direction == GST_PAD_SINK && !GST_PAD_CONNECTED(sinkpad)) { gst_pad_connect(pad, sinkpad); g_print("gstpipeline: autoconnect pad \"%s\" (%d) in element %s <-> ", pad->name, - pad->type, gst_element_get_name(src)); - g_print("pad \"%s\" (%d) in element %s\n", sinkpad->name, sinkpad->type, + type, gst_element_get_name(src)); + g_print("pad \"%s\" (%d) in element %s\n", sinkpad->name, sinktype, gst_element_get_name(sink)); connected = TRUE; break; @@ -211,7 +214,7 @@ gst_pipeline_pads_autoplug_func (GstElement *src, GstPad *pad, GstElement *sink) } if (!connected) { - g_print("gstpipeline: no path to sinks for type %d\n", pad->type); + g_print("gstpipeline: no path to sinks for type %d\n", type); } } @@ -225,24 +228,29 @@ gst_pipeline_pads_autoplug (GstElement *src, GstElement *sink) while (srcpads) { GstPad *srcpad = (GstPad *)srcpads->data; - GstPad *sinkpad; + guint16 srctype = 0; + if (srcpad) + srctype = ((GstType *)srcpad->types->data)->id; if (srcpad->direction == GST_PAD_SRC && !GST_PAD_CONNECTED(srcpad)) { sinkpads = gst_element_get_pad_list(sink); // FIXME could O(n) if the types were sorted... while (sinkpads) { - sinkpad = (GstPad *)sinkpads->data; + GstPad *sinkpad = (GstPad *)sinkpads->data; + guint16 sinktype = 0; + if (srcpad) + sinktype = ((GstType *)sinkpad->types->data)->id; // if we have a match, connect the pads - if (sinkpad->type == srcpad->type && + if (sinktype == srctype && sinkpad->direction == GST_PAD_SINK && !GST_PAD_CONNECTED(sinkpad)) { gst_pad_connect(srcpad, sinkpad); g_print("gstpipeline: autoconnect pad \"%s\" (%d) in element %s <-> ", - srcpad->name, srcpad->type, gst_element_get_name(src)); + srcpad->name, srctype, gst_element_get_name(src)); g_print("pad \"%s\" (%d) in element %s\n", sinkpad->name, - sinkpad->type, gst_element_get_name(sink)); + sinktype, gst_element_get_name(sink)); connected = TRUE; goto end; } @@ -391,7 +399,11 @@ gst_pipeline_autoplug (GstPipeline *pipeline) pad = (GstPad *)pads->data; if (pad->direction == GST_PAD_SINK) { - sink_type = gst_pad_get_type_id(pad); + GList *types = gst_pad_get_type_ids(pad); + if (types) + sink_type = GPOINTER_TO_INT (types->data); + else + sink_type = 0; break; } @@ -485,13 +497,15 @@ differ: sinkpad = (GstPad *)sinkpads->data; // FIXME connect matching pads, not just the first one... + /* if (sinkpad->direction == GST_PAD_SINK && !GST_PAD_CONNECTED(sinkpad)) { - // the queue has the types of the element it connects + // the queue has the type of the elements it connects srcpad->type = sinkpad->type; gst_element_get_pad(queue, "sink")->type = sinkpad->type; break; } + */ sinkpads = g_list_next(sinkpads); } gst_pipeline_pads_autoplug(thesrcelement, queue);