From a48bce0ad64edd7a90d1462e9778ce0406674b15 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 27 Nov 2002 20:47:39 +0000 Subject: [PATCH] - Added first attempt at general caching mechanism (GstTimeCache renamed to GstCache) Original commit message from CVS: - Added first attempt at general caching mechanism (GstTimeCache renamed to GstCache) - Some more clocking checks and updates (waiting on GST_CLOCK_TIME_NONE returns immediatly instead of blocking forever) - Moved clock get/set functions to element class instead of instance. - Added cache methods on elements. - Renamed GST_PROPS_BOOL_TYPE to GST_PROPS_BOOLEAN_TYPE to make it more consistent with gst_props_get/set_boolean and GST_PROPS_BOOLEAN. - Give short stats about plugins in gst-inspect. --- common | 2 +- gst/Makefile.am | 4 +- gst/elements/gstfakesink.c | 3 +- gst/gst.h | 2 +- gst/gstcache.c | 407 ++++++++++++++++++++++++++++++++++++++++ gst/gstcache.h | 182 ++++++++++++++++++ gst/gstclock.c | 31 ++- gst/gstelement.c | 71 ++++++- gst/gstelement.h | 19 +- gst/gstprops.c | 26 +-- gst/gstprops.h | 4 +- gst/gstscheduler.c | 4 +- gst/gstutils.c | 2 +- gst/registries/gstxmlregistry.c | 2 +- plugins/elements/gstfakesink.c | 3 +- tools/gst-inspect.c | 41 +++- 16 files changed, 761 insertions(+), 42 deletions(-) create mode 100644 gst/gstcache.c create mode 100644 gst/gstcache.h diff --git a/common b/common index 1ca7d9a..f2d9b99 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 1ca7d9a20180cab830f4383cde5ba932338e50b1 +Subproject commit f2d9b99515c73da09bfe307d273d320f79a226da diff --git a/gst/Makefile.am b/gst/Makefile.am index a073d32..9ba5942 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -56,6 +56,7 @@ libgstreamer_la_SOURCES = \ gstbin.c \ gstbuffer.c \ gstbufferpool-default.c \ + gstcache.c \ gstcaps.c \ gstclock.c \ gstcpu.c \ @@ -83,7 +84,6 @@ libgstreamer_la_SOURCES = \ $(GST_TYPEFIND_SRC) \ gstutils.c \ gstregistry.c \ - gsttimecache.c \ $(GST_PARSE_SRC) \ $(GSTARCH_SRCS) \ $(GST_LOADSAVE_SRC) @@ -103,6 +103,7 @@ gst_headers = \ gstbin.h \ gstbuffer.h \ gstbufferpool-default.h \ + gstcache.h \ gstcaps.h \ gstclock.h \ gstcpu.h \ @@ -129,7 +130,6 @@ gst_headers = \ gsttypefind.h \ gstutils.h \ gstregistry.h \ - gsttimecache.h \ gstparse.h \ gstxml.h diff --git a/gst/elements/gstfakesink.c b/gst/elements/gstfakesink.c index 36bc664..2185f28 100644 --- a/gst/elements/gstfakesink.c +++ b/gst/elements/gstfakesink.c @@ -134,6 +134,7 @@ gst_fakesink_class_init (GstFakeSinkClass *klass) gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesink_get_property); gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR (gst_fakesink_request_new_pad); + gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_fakesink_set_clock); } static void @@ -150,8 +151,6 @@ gst_fakesink_init (GstFakeSink *fakesink) fakesink->sync = FALSE; fakesink->last_message = NULL; - GST_ELEMENT (fakesink)->setclockfunc = gst_fakesink_set_clock; - GST_FLAG_SET (fakesink, GST_ELEMENT_EVENT_AWARE); } diff --git a/gst/gst.h b/gst/gst.h index 01c10dd..ca13b20 100644 --- a/gst/gst.h +++ b/gst/gst.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -49,7 +50,6 @@ #include #include #include -#include #include #include #include diff --git a/gst/gstcache.c b/gst/gstcache.c new file mode 100644 index 0000000..ffa8309 --- /dev/null +++ b/gst/gstcache.c @@ -0,0 +1,407 @@ +/* GStreamer + * Copyright (C) 2001 RidgeRun (http://www.ridgerun.com/) + * Written by Erik Walthinsen + * + * gstcache.c: Cache for mappings and other data + * + * 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 "gstlog.h" +#include "gst_private.h" + +#include "gstcache.h" + +/* Cache signals and args */ +enum { + ENTRY_ADDED, + LAST_SIGNAL +}; + +enum { + ARG_0, + /* FILL ME */ +}; + +static void gst_cache_class_init (GstCacheClass *klass); +static void gst_cache_init (GstCache *tc); + +#define CLASS(cache) GST_CACHE_CLASS (G_OBJECT_GET_CLASS (cache)) + +static GstObject *parent_class = NULL; +static guint gst_cache_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_cache_get_type(void) { + static GType tc_type = 0; + + if (!tc_type) { + static const GTypeInfo tc_info = { + sizeof(GstCacheClass), + NULL, + NULL, + (GClassInitFunc)gst_cache_class_init, + NULL, + NULL, + sizeof(GstCache), + 1, + (GInstanceInitFunc)gst_cache_init, + NULL + }; + tc_type = g_type_register_static(GST_TYPE_OBJECT, "GstCache", &tc_info, 0); + } + return tc_type; +} + +static void +gst_cache_class_init (GstCacheClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + parent_class = g_type_class_ref(GST_TYPE_OBJECT); + + gst_cache_signals[ENTRY_ADDED] = + g_signal_new ("entry_added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstCacheClass, entry_added), NULL, NULL, + gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, + G_TYPE_POINTER); +} + +static GstCacheGroup * +gst_cache_group_new(guint groupnum) +{ + GstCacheGroup *tcgroup = g_new(GstCacheGroup,1); + + tcgroup->groupnum = groupnum; + tcgroup->entries = NULL; + tcgroup->certainty = GST_CACHE_UNKNOWN; + tcgroup->peergroup = -1; + + GST_DEBUG(0, "created new cache group %d",groupnum); + + return tcgroup; +} + +static void +gst_cache_init (GstCache *tc) +{ + tc->curgroup = gst_cache_group_new(0); + tc->maxgroup = 0; + tc->groups = g_list_prepend(NULL, tc->curgroup); + + tc->writers = g_hash_table_new (NULL, NULL); + tc->last_id = 0; + + GST_DEBUG(0, "created new cache"); +} + +/** + * gst_cache_new: + * + * Create a new tilecache object + * + * Returns: a new cache object + */ +GstCache * +gst_cache_new() +{ + GstCache *tc; + + tc = g_object_new (gst_cache_get_type (), NULL); + + return tc; +} + +/** + * gst_cache_get_group: + * @tc: the cache to get the current group from + * + * Get the id of the current group. + * + * Returns: the id of the current group. + */ +gint +gst_cache_get_group(GstCache *tc) +{ + return tc->curgroup->groupnum; +} + +/** + * gst_cache_new_group: + * @tc: the cache to create the new group in + * + * Create a new group for the given cache. It will be + * set as the current group. + * + * Returns: the id of the newly created group. + */ +gint +gst_cache_new_group(GstCache *tc) +{ + tc->curgroup = gst_cache_group_new(++tc->maxgroup); + tc->groups = g_list_append(tc->groups,tc->curgroup); + GST_DEBUG(0, "created new group %d in cache",tc->maxgroup); + return tc->maxgroup; +} + +/** + * gst_cache_set_group: + * @tc: the cache to set the new group in + * @groupnum: the groupnumber to set + * + * Set the current groupnumber to the given argument. + * + * Returns: TRUE if the operation succeeded, FALSE if the group + * did not exist. + */ +gboolean +gst_cache_set_group(GstCache *tc, gint groupnum) +{ + GList *list; + GstCacheGroup *tcgroup; + + /* first check for null change */ + if (groupnum == tc->curgroup->groupnum) + return TRUE; + + /* else search for the proper group */ + list = tc->groups; + while (list) { + tcgroup = (GstCacheGroup *)(list->data); + list = g_list_next(list); + if (tcgroup->groupnum == groupnum) { + tc->curgroup = tcgroup; + GST_DEBUG(0, "switched to cache group %d", tcgroup->groupnum); + return TRUE; + } + } + + /* couldn't find the group in question */ + GST_DEBUG(0, "couldn't find cache group %d",groupnum); + return FALSE; +} + +/** + * gst_cache_set_certainty: + * @tc: the cache to set the certainty on + * @certainty: the certainty to set + * + * Set the certainty of the given cache. + */ +void +gst_cache_set_certainty(GstCache *tc, GstCacheCertainty certainty) +{ + tc->curgroup->certainty = certainty; +} + +/** + * gst_cache_get_certainty: + * @tc: the cache to get the certainty of + * + * Get the certainty of the given cache. + * + * Returns: the certainty of the cache. + */ +GstCacheCertainty +gst_cache_get_certainty(GstCache *tc) +{ + return tc->curgroup->certainty; +} + + +/** + * gst_cache_add_format: + * @tc: the cache to add the entry to + * @id: the id of the cache writer + * @format: the format to add to the cache + * + * Adds a format entry into the cache. This function is + * used to map dynamic GstFormat ids to their original + * format key. + * + * Returns: a pointer to the newly added entry in the cache. + */ +GstCacheEntry* +gst_cache_add_format (GstCache *tc, gint id, GstFormat format) +{ + GstCacheEntry *entry; + const GstFormatDefinition* def; + + g_return_val_if_fail (GST_IS_CACHE (tc), NULL); + g_return_val_if_fail (format != 0, NULL); + + entry = g_new0 (GstCacheEntry, 1); + entry->type = GST_CACHE_ENTRY_FORMAT; + entry->id = id; + entry->data.format.format = format; + def = gst_format_get_details (format); + entry->data.format.key = def->nick; + + g_signal_emit (G_OBJECT (tc), gst_cache_signals[ENTRY_ADDED], 0, entry); + + return entry; +} + +/** + * gst_cache_add_id: + * @tc: the cache to add the entry to + * @id: the id of the cache writer + * @description: the description of the cache writer + * + * Returns: a pointer to the newly added entry in the cache. + */ +GstCacheEntry* +gst_cache_add_id (GstCache *tc, gint id, gchar *description) +{ + GstCacheEntry *entry; + + g_return_val_if_fail (GST_IS_CACHE (tc), NULL); + g_return_val_if_fail (description != NULL, NULL); + + entry = g_new0 (GstCacheEntry, 1); + entry->type = GST_CACHE_ENTRY_ID; + entry->id = id; + entry->data.id.description = description; + + g_signal_emit (G_OBJECT (tc), gst_cache_signals[ENTRY_ADDED], 0, entry); + + return entry; +} + +/** + * gst_cache_get_writer_id: + * @tc: the cache to get a unique write id for + * @writer: the GstObject to allocate an id for + * @id: a pointer to a gint to hold the id + * + * Before entries can be added to the cache, a writer + * should obtain a unique id. The methods to add new entries + * to the cache require this id as an argument. + * + * The application or a GstCache subclass can implement + * custom functions to map the writer object to an id. + * + * Returns: TRUE if the writer would be mapped to an id. + */ +gboolean +gst_cache_get_writer_id (GstCache *tc, GstObject *writer, gint *id) +{ + gchar *writer_string = NULL; + gboolean success = FALSE; + GstCacheEntry *entry; + + g_return_val_if_fail (GST_IS_CACHE (tc), FALSE); + g_return_val_if_fail (GST_IS_OBJECT (writer), FALSE); + g_return_val_if_fail (id, FALSE); + + *id = -1; + + entry = g_hash_table_lookup (tc->writers, writer); + if (entry == NULL) { + *id = tc->last_id; + + writer_string = gst_object_get_path_string (writer); + + gst_cache_add_id (tc, *id, writer_string); + tc->last_id++; + g_hash_table_insert (tc->writers, writer, entry); + } + + if (CLASS (tc)->resolve_writer) { + success = CLASS (tc)->resolve_writer (tc, writer, id, &writer_string); + } + + if (tc->resolver) { + success = tc->resolver (tc, writer, id, &writer_string, tc->user_data); + } + + return success; +} + +/** + * gst_cache_add_association: + * @tc: the cache to add the entry to + * @id: the id of the cache writer + * @format: the format of the value + * @value: the value + * @...: other format/value pairs or 0 to end the list + * + * Associate given format/value pairs with eachother. + * + * Returns: a pointer to the newly added entry in the cache. + */ +GstCacheEntry* +gst_cache_add_association (GstCache *tc, gint id, GstAssocFlags flags, + GstFormat format, gint64 value, ...) +{ + va_list args; + GstCacheAssociation *assoc; + GstCacheEntry *entry; + gulong size; + gint nassocs = 0; + GstFormat cur_format; + + g_return_val_if_fail (GST_IS_CACHE (tc), NULL); + g_return_val_if_fail (format != 0, NULL); + + va_start (args, value); + + cur_format = format; + + while (cur_format) { + nassocs++; + cur_format = va_arg (args, GstFormat); + if (cur_format) + va_arg (args, gint64); + } + va_end (args); + + /* make room for two assoc */ + size = sizeof (GstCacheEntry) + (sizeof (GstCacheAssociation) * nassocs); + + entry = g_malloc (size); + + entry->type = GST_CACHE_ENTRY_ASSOCIATION; + entry->id = id; + entry->data.assoc.flags = flags; + assoc = (GstCacheAssociation *) (((guint8 *) entry) + sizeof (GstCacheEntry)); + entry->data.assoc.assocs = assoc; + entry->data.assoc.nassocs = nassocs; + + va_start (args, value); + while (format) { + assoc->format = format; + assoc->value = value; + + assoc++; + + format = va_arg (args, GstFormat); + if (format) + value = va_arg (args, gint64); + } + va_end (args); + + if (CLASS (tc)->add_entry) + CLASS (tc)->add_entry (tc, entry); + + g_signal_emit (G_OBJECT (tc), gst_cache_signals[ENTRY_ADDED], 0, entry); + + return entry; +} diff --git a/gst/gstcache.h b/gst/gstcache.h new file mode 100644 index 0000000..50bd951 --- /dev/null +++ b/gst/gstcache.h @@ -0,0 +1,182 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstcache.h: Header for GstCache + * + * 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_CACHE_H__ +#define __GST_CACHE_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_CACHE (gst_cache_get_type ()) +#define GST_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CACHE, GstCache)) +#define GST_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CACHE, GstCacheClass)) +#define GST_IS_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CACHE)) +#define GST_IS_CACHE_CLASS(obj) (GST_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CACHE)) + +typedef struct _GstCacheEntry GstCacheEntry; +typedef struct _GstCacheGroup GstCacheGroup; +typedef struct _GstCache GstCache; +typedef struct _GstCacheClass GstCacheClass; + +typedef enum { + GST_CACHE_UNKNOWN, + GST_CACHE_CERTAIN, + GST_CACHE_FUZZY +} GstCacheCertainty; + +typedef enum { + GST_CACHE_ENTRY_ID, + GST_CACHE_ENTRY_ASSOCIATION, + GST_CACHE_ENTRY_OBJECT, + GST_CACHE_ENTRY_FORMAT, +} GstCacheEntryType; + +#define GST_CACHE_NASSOCS(entry) ((entry)->data.assoc.nassocs) +#define GST_CACHE_ASSOC_FLAGS(entry) ((entry)->data.assoc.flags) +#define GST_CACHE_ASSOC_FORMAT(entry,i) ((entry)->data.assoc.assocs[(i)].format) +#define GST_CACHE_ASSOC_VALUE(entry,i) ((entry)->data.assoc.assocs[(i)].value) + +typedef struct _GstCacheAssociation GstCacheAssociation; + +struct _GstCacheAssociation { + GstFormat format; + gint64 value; +}; + +typedef enum { + GST_ACCOCIATION_FLAG_NONE = 0, + GST_ACCOCIATION_FLAG_KEY_UNIT = (1 << 0), +} GstAssocFlags; + +#define GST_CACHE_FORMAT_FORMAT(entry) ((entry)->data.format.format) +#define GST_CACHE_FORMAT_KEY(entry) ((entry)->data.format.key) + +#define GST_CACHE_ID_DESCRIPTION(entry) ((entry)->data.id.description) + +struct _GstCacheEntry { + GstCacheEntryType type; + gint id; + + union { + struct { + gchar *description; + } id; + struct { + gint nassocs; + GstCacheAssociation + *assocs; + GstAssocFlags flags; + } assoc; + struct { + gchar *key; + GType type; + gpointer object; + } object; + struct { + GstFormat format; + gchar *key; + } format; + } data; +}; + +struct _GstCacheGroup { + /* unique ID of group in cache */ + gint groupnum; + + /* list of entries */ + GList *entries; + + /* the certainty level of the group */ + GstCacheCertainty certainty; + + /* peer group that contains more certain entries */ + gint peergroup; +}; + +typedef gboolean (*GstCacheWriterResolver) (GstCache *cache, + GstObject *writer, + gint *writer_id, + gchar **writer_string, + gpointer user_data); +struct _GstCache { + GstObject object; + + GList *groups; + GstCacheGroup *curgroup; + gint maxgroup; + + GstCacheWriterResolver resolver; + gpointer user_data; + + GHashTable *writers; + gint last_id; +}; + +struct _GstCacheClass { + GstObjectClass parent_class; + + gboolean (*resolve_writer) (GstCache *cache, GstObject *writer, + gint *writer_id, gchar **writer_string); + + /* abstract methods */ + void (*add_entry) (GstCache *cache, GstCacheEntry *entry); + void (*remove_entry) (GstCache *cache, GstCacheEntry *entry); + void (*modify_entry) (GstCache *cache, GstCacheEntry *oldentry, + GstCacheEntry *new_entry); + + GstCacheEntry* (*get_entry) (GstCache *cache); + + /* signals */ + void (*entry_added) (GstCache *cache, GstCacheEntry *entry); + void (*entry_removed) (GstCache *cache, GstCacheEntry *entry); + void (*entry_modified) (GstCache *cache, GstCacheEntry *oldentry, + GstCacheEntry *new_entry); +}; + +GType gst_cache_get_type (void); +GstCache* gst_cache_new (void); + +gint gst_cache_get_group (GstCache *cache); +gint gst_cache_new_group (GstCache *cache); +gboolean gst_cache_set_group (GstCache *cache, gint groupnum); + +void gst_cache_set_certainty (GstCache *cache, + GstCacheCertainty certainty); +GstCacheCertainty gst_cache_get_certainty (GstCache *cache); + +gboolean gst_cache_get_writer_id (GstCache *cache, GstObject *writer, gint *id); + +GstCacheEntry* gst_cache_add_format (GstCache *cache, gint id, GstFormat format); +GstCacheEntry* gst_cache_add_association (GstCache *cache, gint id, GstAssocFlags flags, + GstFormat format, gint64 value, ...); +GstCacheEntry* gst_cache_add_object (GstCache *cache, gint id, gchar *key, + GType type, gpointer object); +GstCacheEntry* gst_cache_add_id (GstCache *cache, gint id, + gchar *description); + + +G_END_DECLS + +#endif /* __GST_CACHE_H__ */ diff --git a/gst/gstclock.c b/gst/gstclock.c index bbb8098..da315a1 100644 --- a/gst/gstclock.c +++ b/gst/gstclock.c @@ -83,6 +83,8 @@ gst_clock_entry_new (GstClock *clock, GstClockTime time, GstClockID gst_clock_new_single_shot_id (GstClock *clock, GstClockTime time) { + g_return_val_if_fail (GST_IS_CLOCK (clock), NULL); + return gst_clock_entry_new (clock, time, GST_CLOCK_TIME_NONE, @@ -105,6 +107,10 @@ GstClockID gst_clock_new_periodic_id (GstClock *clock, GstClockTime start_time, GstClockTime interval) { + g_return_val_if_fail (GST_IS_CLOCK (clock), NULL); + g_return_val_if_fail (start_time != GST_CLOCK_TIME_NONE, NULL); + g_return_val_if_fail (interval != 0, NULL); + return gst_clock_entry_new (clock, start_time, interval, @@ -149,8 +155,14 @@ gst_clock_id_wait (GstClockID id, GstClockTimeDiff *jitter) g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR); entry = (GstClockEntry *) id; - clock = GST_CLOCK_ENTRY_CLOCK (entry); requested = GST_CLOCK_ENTRY_TIME (entry); + + if (requested == GST_CLOCK_TIME_NONE) { + res = GST_CLOCK_TIMEOUT; + goto done; + } + + clock = GST_CLOCK_ENTRY_CLOCK (entry); if (CLASS (clock)->wait) { GstClockTime now; @@ -170,6 +182,7 @@ gst_clock_id_wait (GstClockID id, GstClockTimeDiff *jitter) } } +done: if (entry->type == GST_CLOCK_ENTRY_SINGLE) { gst_clock_id_free (id); } @@ -188,7 +201,7 @@ gst_clock_id_wait (GstClockID id, GstClockTimeDiff *jitter) * when the clock has reached the given time. A ClockID is returned * that can be used to cancel the request. * - * Returns: the clock id or NULL when async notification is not supported. + * Returns: the result of the non blocking wait. */ GstClockReturn gst_clock_id_wait_async (GstClockID id, @@ -199,10 +212,16 @@ gst_clock_id_wait_async (GstClockID id, GstClockReturn res = GST_CLOCK_UNSUPPORTED; g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR); + g_return_val_if_fail (func != NULL, GST_CLOCK_ERROR); entry = (GstClockEntry *) id; clock = entry->clock; + if (GST_CLOCK_ENTRY_TIME (entry) == GST_CLOCK_TIME_NONE) { + (func) (clock, GST_CLOCK_TIME_NONE, id, user_data); + return GST_CLOCK_TIMEOUT; + } + if (CLASS (clock)->wait_async) { res = CLASS (clock)->wait_async (clock, entry, func, user_data); } @@ -243,6 +262,8 @@ gst_clock_id_unschedule (GstClockID id) void gst_clock_id_free (GstClockID id) { + g_return_if_fail (id != NULL); + gst_mem_chunk_free (_gst_clock_entries_chunk, id); } @@ -389,6 +410,7 @@ guint64 gst_clock_set_resolution (GstClock *clock, guint64 resolution) { g_return_val_if_fail (GST_IS_CLOCK (clock), 0LL); + g_return_val_if_fail (resolution != 0, 0LL); if (CLASS (clock)->change_resolution) clock->resolution = CLASS (clock)->change_resolution (clock, clock->resolution, resolution); @@ -510,6 +532,9 @@ gst_clock_handle_discont (GstClock *clock, guint64 time) GST_DEBUG (GST_CAT_CLOCK, "clock discont %llu %llu %d", time, clock->start_time, clock->accept_discont); + if (time == GST_CLOCK_TIME_NONE) + return TRUE; + GST_LOCK (clock); if (clock->accept_discont) { if (CLASS (clock)->get_internal_time) { @@ -585,6 +610,8 @@ gst_clock_get_next_id (GstClock *clock) { GstClockEntry *entry = NULL; + g_return_val_if_fail (GST_IS_CLOCK (clock), NULL); + GST_LOCK (clock); if (clock->entries) entry = GST_CLOCK_ENTRY (clock->entries->data); diff --git a/gst/gstelement.c b/gst/gstelement.c index 73ed744..0130a11 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -742,6 +742,38 @@ gst_element_get_parent (GstElement *element) } /** + * gst_element_requires_clock: + * @element: a #GstElement to query + * + * Query if the element requiresd a clock + * + * Returns: TRUE if the element requires a clock + */ +gboolean +gst_element_requires_clock (GstElement *element) +{ + g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); + + return (CLASS (element)->set_clock != NULL); +} + +/** + * gst_element_provides_clock: + * @element: a #GstElement to query + * + * Query if the element provides a clock + * + * Returns: TRUE if the element provides a clock + */ +gboolean +gst_element_provides_clock (GstElement *element) +{ + g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); + + return (CLASS (element)->get_clock != NULL); +} + +/** * gst_element_set_clock: * @element: a #GstElement to set the clock for. * @clock: the #GstClock to set for the element. @@ -751,11 +783,10 @@ gst_element_get_parent (GstElement *element) void gst_element_set_clock (GstElement *element, GstClock *clock) { - g_return_if_fail (element != NULL); g_return_if_fail (GST_IS_ELEMENT (element)); - if (element->setclockfunc) - element->setclockfunc (element, clock); + if (CLASS (element)->set_clock) + CLASS (element)->set_clock (element, clock); element->clock = clock; } @@ -774,8 +805,8 @@ gst_element_get_clock (GstElement *element) g_return_val_if_fail (element != NULL, NULL); g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); - if (element->getclockfunc) - return element->getclockfunc (element); + if (CLASS (element)->get_clock) + return CLASS (element)->get_clock (element); return NULL; } @@ -796,7 +827,6 @@ gst_element_clock_wait (GstElement *element, GstClock *clock, GstClockTime time, { GstClockReturn res; - g_return_val_if_fail (element != NULL, GST_CLOCK_ERROR); g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_ERROR); if (GST_ELEMENT_SCHED (element)) { @@ -808,6 +838,35 @@ gst_element_clock_wait (GstElement *element, GstClock *clock, GstClockTime time, return res; } +gboolean +gst_element_is_cachable (GstElement *element) +{ + g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); + + return (CLASS (element)->set_cache != NULL); +} + +void +gst_element_set_cache (GstElement *element, GstCache *cache) +{ + g_return_if_fail (GST_IS_ELEMENT (element)); + g_return_if_fail (GST_IS_CACHE (cache)); + + if (CLASS (element)->set_cache) + CLASS (element)->set_cache (element, cache); +} + +GstCache* +gst_element_get_cache (GstElement *element) +{ + g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); + + if (CLASS (element)->get_cache) + return CLASS (element)->get_cache (element); + + return NULL; +} + /** * gst_element_release_locks: diff --git a/gst/gstelement.h b/gst/gstelement.h index a826640..c0f17f0 100644 --- a/gst/gstelement.h +++ b/gst/gstelement.h @@ -30,6 +30,7 @@ #include #include #include +#include G_BEGIN_DECLS @@ -109,8 +110,6 @@ typedef struct _GstElementFactory GstElementFactory; typedef struct _GstElementFactoryClass GstElementFactoryClass; typedef void (*GstElementLoopFunction) (GstElement *element); -typedef void (*GstElementSetClockFunction) (GstElement *element, GstClock *clock); -typedef GstClock* (*GstElementGetClockFunction) (GstElement *element); typedef void (*GstElementPreRunFunction) (GstElement *element); typedef void (*GstElementPostRunFunction) (GstElement *element); @@ -125,8 +124,6 @@ struct _GstElement { GstScheduler *sched; gpointer sched_private; - GstElementSetClockFunction setclockfunc; - GstElementGetClockFunction getclockfunc; GstClock *clock; GstClockTime base_time; @@ -176,6 +173,12 @@ struct _GstElementClass { /* request a new pad */ GstPad* (*request_new_pad) (GstElement *element, GstPadTemplate *templ, const gchar* name); void (*release_pad) (GstElement *element, GstPad *pad); + /* set/get clocks */ + GstClock* (*get_clock) (GstElement *element); + void (*set_clock) (GstElement *element, GstClock *clock); + /* cache */ + GstCache* (*get_cache) (GstElement *element); + void (*set_cache) (GstElement *element, GstCache *cache); }; void gst_element_class_add_pad_template (GstElementClass *klass, GstPadTemplate *templ); @@ -214,10 +217,18 @@ const gchar* gst_element_get_name (GstElement *element); void gst_element_set_parent (GstElement *element, GstObject *parent); GstObject* gst_element_get_parent (GstElement *element); +/* clocking */ +gboolean gst_element_requires_clock (GstElement *element); +gboolean gst_element_provides_clock (GstElement *element); GstClock* gst_element_get_clock (GstElement *element); void gst_element_set_clock (GstElement *element, GstClock *clock); GstClockReturn gst_element_clock_wait (GstElement *element, GstClock *clock, GstClockTime time, GstClockTimeDiff *jitter); +/* caches */ +gboolean gst_element_is_cachable (GstElement *element); +void gst_element_set_cache (GstElement *element, GstCache *cache); +GstCache* gst_element_get_cache (GstElement *element); + gboolean gst_element_release_locks (GstElement *element); diff --git a/gst/gstprops.c b/gst/gstprops.c index 09bbf46..d187795 100644 --- a/gst/gstprops.c +++ b/gst/gstprops.c @@ -92,6 +92,10 @@ transform_func (const GValue *src_value, case GST_PROPS_FOURCC_TYPE: g_string_append_printf (result, "%s=(fourcc) '%4.4s'", name, (gchar *)&entry->data.fourcc_data); break; + case GST_PROPS_BOOLEAN_TYPE: + g_string_append_printf (result, "%s=(boolean) %s", name, + (entry->data.bool_data ? "TRUE" : "FALSE")); + break; default: break; } @@ -147,7 +151,7 @@ gst_props_debug_entry (GstPropsEntry *entry) (entry->data.fourcc_data>>16)&0xff, (entry->data.fourcc_data>>24)&0xff); break; - case GST_PROPS_BOOL_TYPE: + case GST_PROPS_BOOLEAN_TYPE: GST_DEBUG (GST_CAT_PROPERTIES, "%s: bool %d", name, entry->data.bool_data); break; case GST_PROPS_STRING_TYPE: @@ -223,7 +227,7 @@ G_STMT_START { \ case GST_PROPS_FOURCC_TYPE: \ entry->data.fourcc_data = va_arg (var_args, gulong); \ break; \ - case GST_PROPS_BOOL_TYPE: \ + case GST_PROPS_BOOLEAN_TYPE: \ entry->data.bool_data = va_arg (var_args, gboolean); \ break; \ case GST_PROPS_STRING_TYPE: \ @@ -269,7 +273,7 @@ G_STMT_START { \ case GST_PROPS_FOURCC_TYPE: \ *(va_arg (var_args, guint32*)) = entry->data.fourcc_data; \ break; \ - case GST_PROPS_BOOL_TYPE: \ + case GST_PROPS_BOOLEAN_TYPE: \ *(va_arg (var_args, gboolean*)) = entry->data.bool_data; \ break; \ case GST_PROPS_STRING_TYPE: \ @@ -606,7 +610,7 @@ gst_props_newv (const gchar *firstname, va_list var_args) entry_type = GST_PROPS_LIST_T_FLOATS; break; case GST_PROPS_FOURCC_TYPE: - case GST_PROPS_BOOL_TYPE: + case GST_PROPS_BOOLEAN_TYPE: case GST_PROPS_STRING_TYPE: entry_type = GST_PROPS_LIST_T_MISC; break; @@ -1179,7 +1183,7 @@ gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val) gboolean gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val) { - return gst_props_entry_get_safe (entry, GST_PROPS_BOOL_TYPE, val); + return gst_props_entry_get_safe (entry, GST_PROPS_BOOLEAN_TYPE, val); } /** @@ -1391,10 +1395,10 @@ gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry break; } break; - case GST_PROPS_BOOL_TYPE: + case GST_PROPS_BOOLEAN_TYPE: switch (entry2->propstype) { /* t <---> t */ - case GST_PROPS_BOOL_TYPE: + case GST_PROPS_BOOLEAN_TYPE: return (entry2->data.bool_data == entry1->data.bool_data); default: break; @@ -1669,10 +1673,10 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) break; } break; - case GST_PROPS_BOOL_TYPE: + case GST_PROPS_BOOLEAN_TYPE: switch (entry2->propstype) { /* t <---> t */ - case GST_PROPS_BOOL_TYPE: + case GST_PROPS_BOOLEAN_TYPE: if (entry1->data.bool_data == entry2->data.bool_data) result = gst_props_entry_copy (entry1); default: @@ -1928,7 +1932,7 @@ gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent) xmlNewProp (subtree, "hexvalue", str); g_free(str); break; - case GST_PROPS_BOOL_TYPE: + case GST_PROPS_BOOLEAN_TYPE: subtree = xmlNewChild (parent, NULL, "boolean", NULL); xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); xmlNewProp (subtree, "value", (entry->data.bool_data ? "true" : "false")); @@ -2035,7 +2039,7 @@ gst_props_load_thyself_func (xmlNodePtr field) g_free (prop); } else if (!strcmp(field->name, "boolean")) { - entry->propstype = GST_PROPS_BOOL_TYPE; + entry->propstype = GST_PROPS_BOOLEAN_TYPE; prop = xmlGetProp(field, "name"); entry->propid = g_quark_from_string (prop); g_free (prop); diff --git a/gst/gstprops.h b/gst/gstprops.h index 7b46bbd..df8c17a 100644 --- a/gst/gstprops.h +++ b/gst/gstprops.h @@ -43,7 +43,7 @@ typedef enum { GST_PROPS_INT_TYPE, GST_PROPS_FLOAT_TYPE, GST_PROPS_FOURCC_TYPE, - GST_PROPS_BOOL_TYPE, + GST_PROPS_BOOLEAN_TYPE, GST_PROPS_STRING_TYPE, GST_PROPS_VAR_TYPE, /* after this marker start the variable properties */ @@ -66,7 +66,7 @@ typedef enum { #define GST_PROPS_FLOAT(a) GST_PROPS_FLOAT_TYPE,((float)(a)) #define GST_PROPS_FLOAT_RANGE(a,b) GST_PROPS_FLOAT_RANGE_TYPE,((float)(a)),((float)(b)) #define GST_PROPS_FOURCC(a) GST_PROPS_FOURCC_TYPE,(a) -#define GST_PROPS_BOOLEAN(a) GST_PROPS_BOOL_TYPE,(a) +#define GST_PROPS_BOOLEAN(a) GST_PROPS_BOOLEAN_TYPE,(a) #define GST_PROPS_STRING(a) GST_PROPS_STRING_TYPE,(a) #define GST_PROPS_INT_POSITIVE GST_PROPS_INT_RANGE(0,G_MAXINT) diff --git a/gst/gstscheduler.c b/gst/gstscheduler.c index e27c415..3f4dcce 100644 --- a/gst/gstscheduler.c +++ b/gst/gstscheduler.c @@ -212,11 +212,11 @@ gst_scheduler_add_element (GstScheduler *sched, GstElement *element) /* if it's not inside this scheduler, it has to be NULL */ g_assert (GST_ELEMENT_SCHED (element) == NULL); - if (element->getclockfunc) { + if (gst_element_provides_clock (element)) { sched->clock_providers = g_list_prepend (sched->clock_providers, element); GST_DEBUG (GST_CAT_CLOCK, "added clock provider %s", GST_ELEMENT_NAME (element)); } - if (element->setclockfunc) { + if (gst_element_requires_clock (element)) { sched->clock_receivers = g_list_prepend (sched->clock_receivers, element); GST_DEBUG (GST_CAT_CLOCK, "added clock receiver %s", GST_ELEMENT_NAME (element)); } diff --git a/gst/gstutils.c b/gst/gstutils.c index d0691a3..3bb22d9 100644 --- a/gst/gstutils.c +++ b/gst/gstutils.c @@ -506,7 +506,7 @@ gst_print_props (GString *buf, gint indent, GList *props, gboolean showname) g_string_append_printf (buf, "%f - %f (float)\n", min, max); break; } - case GST_PROPS_BOOL_TYPE: + case GST_PROPS_BOOLEAN_TYPE: { gboolean val; gst_props_entry_get_boolean (prop, &val); diff --git a/gst/registries/gstxmlregistry.c b/gst/registries/gstxmlregistry.c index 8066adb..9ab0b47 100644 --- a/gst/registries/gstxmlregistry.c +++ b/gst/registries/gstxmlregistry.c @@ -1233,7 +1233,7 @@ gst_xml_registry_save_props_func (GstPropsEntry *entry, CLASS (xmlregistry)->save_func (xmlregistry, "\n", name, fourcc); break; } - case GST_PROPS_BOOL_TYPE: + case GST_PROPS_BOOLEAN_TYPE: { gboolean value; gst_props_entry_get_boolean (entry, &value); diff --git a/plugins/elements/gstfakesink.c b/plugins/elements/gstfakesink.c index 36bc664..2185f28 100644 --- a/plugins/elements/gstfakesink.c +++ b/plugins/elements/gstfakesink.c @@ -134,6 +134,7 @@ gst_fakesink_class_init (GstFakeSinkClass *klass) gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesink_get_property); gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR (gst_fakesink_request_new_pad); + gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_fakesink_set_clock); } static void @@ -150,8 +151,6 @@ gst_fakesink_init (GstFakeSink *fakesink) fakesink->sync = FALSE; fakesink->last_message = NULL; - GST_ELEMENT (fakesink)->setclockfunc = gst_fakesink_set_clock; - GST_FLAG_SET (fakesink, GST_ELEMENT_EVENT_AWARE); } diff --git a/tools/gst-inspect.c b/tools/gst-inspect.c index 529544f..b66a98a 100644 --- a/tools/gst-inspect.c +++ b/tools/gst-inspect.c @@ -43,7 +43,7 @@ print_prop (GstPropsEntry *prop, gboolean showname, const gchar *pfx) g_print("Float range: %f - %f\n", min, max); break; } - case GST_PROPS_BOOL_TYPE: + case GST_PROPS_BOOLEAN_TYPE: { gboolean val; gst_props_entry_get_boolean (prop, &val); @@ -571,22 +571,31 @@ print_element_info (GstElementFactory *factory) have_flags = FALSE; g_print ("\nClocking Interaction:\n"); - if (element->setclockfunc) { + if (gst_element_requires_clock (element)) { g_print (" element requires a clock\n"); have_flags = TRUE; } - if (element->getclockfunc) { + if (gst_element_provides_clock (element)) { GstClock *clock; clock = gst_element_get_clock (element); if (clock) g_print (" element provides a clock: %s\n", GST_OBJECT_NAME(clock)); + else + g_print (" element is supposed to provide a clock but returned NULL\n"); have_flags = TRUE; } if (!have_flags) { g_print (" none\n"); } + g_print ("\nCaching capabilities:\n"); + if (gst_element_is_cachable (element)) { + g_print (" element can do caching\n"); + } + else { + g_print (" none\n"); + } g_print ("\nPads:\n"); if (element->numpads) { @@ -841,6 +850,12 @@ static void print_plugin_info (GstPlugin *plugin) { GList *features; + gint num_features = 0; + gint num_elements = 0; + gint num_autoplug = 0; + gint num_types = 0; + gint num_schedulers = 0; + gint num_other = 0; g_print ("Plugin Details:\n"); g_print (" Name:\t\t%s\n", plugin->name); @@ -861,12 +876,14 @@ print_plugin_info (GstPlugin *plugin) factory = GST_ELEMENT_FACTORY (feature); g_print (" %s: %s\n", GST_OBJECT_NAME (factory), factory->details->longname); + num_elements++; } else if (GST_IS_AUTOPLUG_FACTORY (feature)) { GstAutoplugFactory *factory; factory = GST_AUTOPLUG_FACTORY (feature); g_print (" %s: %s\n", GST_OBJECT_NAME (factory), factory->longdesc); + num_autoplug++; } else if (GST_IS_TYPE_FACTORY (feature)) { GstTypeFactory *factory; @@ -877,21 +894,35 @@ print_plugin_info (GstPlugin *plugin) if (factory->typefindfunc) g_print (" Has typefind function: %s\n", GST_DEBUG_FUNCPTR_NAME (factory->typefindfunc)); + num_types++; } else if (GST_IS_SCHEDULER_FACTORY (feature)) { GstSchedulerFactory *factory; factory = GST_SCHEDULER_FACTORY (feature); g_print (" %s: %s\n", GST_OBJECT_NAME (factory), factory->longdesc); + num_schedulers++; } else { g_print (" %s (%s)\n", gst_object_get_name (GST_OBJECT (feature)), g_type_name (G_OBJECT_TYPE (feature))); + num_other++; } - - + num_features++; features = g_list_next (features); } + g_print ("\n %d features:\n", num_features); + if (num_elements > 0) + g_print (" +-- %d elements\n", num_elements); + if (num_autoplug > 0) + g_print (" +-- %d autopluggers\n", num_autoplug); + if (num_types > 0) + g_print (" +-- %d types\n", num_types); + if (num_schedulers > 0) + g_print (" +-- %d schedulers\n", num_schedulers); + if (num_other > 0) + g_print (" +-- %d other objects\n", num_other); + g_print ("\n"); } -- 2.7.4