noinst_HEADERS = \
gst_private.h \
gstarch.h \
- gstpropsprivate.h \
cothreads.h
libgstreamer_la_CFLAGS = -D_GNU_SOURCE -DGST_CONFIG_DIR=\""$(GST_CONFIG_DIR)"\" \
$(LIBGST_CFLAGS) \
-D_GNU_SOURCE \
-DG_LOG_DOMAIN=g_log_domain_gstreamer \
- -DGST_CONFIG_DIR=\""$(GST_CONFIG_DIR)"\"
+ -DGST_CONFIG_DIR=\""$(GST_CONFIG_DIR)"\"
# the compiler shoots cothreads.c in the head at -O6
-libcothreads_la_CFLAGS = $(libgstreamer_la_CFLAGS) -O2
+libcothreads_la_CFLAGS = $(libgstreamer_la_CFLAGS) -O2
libgstreamer_la_LIBADD = $(LIBGST_LIBS)
-libgstreamer_la_LDFLAGS = @GST_LT_LDFLAGS@ -version-info @GST_LIBVERSION@
+libgstreamer_la_LDFLAGS = @GST_LT_LDFLAGS@ -version-info @GST_LIBVERSION@
EXTRA_DIST = ROADMAP
ARG_NUM_SINKS,
ARG_SILENT,
ARG_DUMP,
+ ARG_SYNC,
ARG_LAST_MESSAGE,
};
static void gst_fakesink_class_init (GstFakeSinkClass *klass);
static void gst_fakesink_init (GstFakeSink *fakesink);
+static void gst_fakesink_set_clock (GstElement *element, GstClock *clock);
static GstPad* gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ, const
gchar *unused);
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SINKS,
- g_param_spec_int ("num_sinks", "num_sinks", "num_sinks",
+ g_param_spec_int ("num_sinks", "Number of sinks", "The number of sinkpads",
1, G_MAXINT, 1, G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
g_param_spec_string ("last_message", "last_message", "last_message",
NULL, G_PARAM_READABLE));
-
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SYNC,
+ g_param_spec_boolean("sync","Sync","Sync on the clock",
+ FALSE, G_PARAM_READWRITE)); /* CHECKME */
gst_element_class_install_std_props (
GST_ELEMENT_CLASS (klass),
fakesink->silent = FALSE;
fakesink->dump = FALSE;
+ fakesink->sync = FALSE;
fakesink->last_message = NULL;
+
+ GST_ELEMENT (fakesink)->setclockfunc = gst_fakesink_set_clock;
}
+static void
+gst_fakesink_set_clock (GstElement *element, GstClock *clock)
+{
+ GstFakeSink *sink;
+
+ sink = GST_FAKESINK (element);
+
+ sink->clock = clock;
+}
+
static GstPad*
gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused)
{
case ARG_DUMP:
sink->dump = g_value_get_boolean (value);
break;
+ case ARG_SYNC:
+ sink->sync = g_value_get_boolean (value);
+ break;
default:
break;
}
case ARG_DUMP:
g_value_set_boolean (value, sink->dump);
break;
+ case ARG_SYNC:
+ g_value_set_boolean (value, sink->sync);
+ break;
case ARG_LAST_MESSAGE:
g_value_set_string (value, sink->last_message);
break;
fakesink = GST_FAKESINK (gst_pad_get_parent (pad));
+ if (fakesink->sync) {
+ gst_element_clock_wait (GST_ELEMENT (fakesink), fakesink->clock, GST_BUFFER_TIMESTAMP (buf));
+ }
+
if (!fakesink->silent) {
- if (fakesink->last_message)
- g_free (fakesink->last_message);
+ g_free (fakesink->last_message);
fakesink->last_message = g_strdup_printf ("chain ******* (%s:%s)< (%d bytes, %lld) %p",
GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
typedef struct _GstFakeSinkClass GstFakeSinkClass;
struct _GstFakeSink {
- GstElement element;
+ GstElement element;
- gboolean silent;
- gboolean dump;
- gchar *last_message;
+ gboolean silent;
+ gboolean dump;
+ gboolean sync;
+ GstClock *clock;
+
+ gchar *last_message;
};
struct _GstFakeSinkClass {
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
src->buffer_count = GST_EVENT_SEEK_OFFSET (event);
+
if (!GST_EVENT_SEEK_FLUSH (event)) {
gst_event_free (event);
break;
gboolean silent;
gboolean dump;
gboolean need_flush;
- gchar *last_message;
+
+ gchar *last_message;
};
struct _GstFakeSrcClass {
"(C) 1999",
};
-/*#define fs_print(format,args...) g_print(format, ## args)*/
+/*#define fs_print(format,args...) g_print(format, ## args) */
#define fs_print(format,args...)
/* FileSrc signals and args */
/* we're done, return the buffer */
src->curoffset += GST_BUFFER_SIZE(buf);
- g_object_notify (G_OBJECT (src), "offset");
+ //g_object_notify (G_OBJECT (src), "offset");
return buf;
}
/* now notify of the changes */
g_object_freeze_notify (G_OBJECT (src));
g_object_notify (G_OBJECT (src), "filesize");
- g_object_notify (G_OBJECT (src), "offset");
+ //g_object_notify (G_OBJECT (src), "offset");
g_object_thaw_notify (G_OBJECT (src));
GST_FLAG_SET (src, GST_FILESRC_OPEN);
/* and notify that things changed */
g_object_freeze_notify (G_OBJECT (src));
g_object_notify (G_OBJECT (src), "filesize");
- g_object_notify (G_OBJECT (src), "offset");
+ //g_object_notify (G_OBJECT (src), "offset");
g_object_thaw_notify (G_OBJECT (src));
if (src->mapbuf)
GList *pads;
g_return_val_if_fail (GST_IS_TEE (element), NULL);
-
+
if (templ->direction != GST_PAD_SRC) {
g_warning ("gsttee: request new pad that is not a SRC pad\n");
return NULL;
#include <gst/gstpad.h>
#include <gst/gstbuffer.h>
#include <gst/gstcpu.h>
-#include <gst/gstsystemclock.h>
#include <gst/gstelement.h>
#include <gst/gstbin.h>
#include <gst/gstpipeline.h>
return gst_elementfactory_make ("bin", name);
}
-static inline void
-gst_bin_reset_element_sched (GstElement * element, GstScheduler * sched)
-{
- GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "resetting element's scheduler");
-
- gst_element_set_sched (element, sched);
-}
-
-
-static void
-gst_bin_get_clock_elements (GstBin *bin, GList **needing, GList **providing)
-{
- GList *children = gst_bin_get_list (bin);
-
- while (children) {
- GstElement *child = GST_ELEMENT (children->data);
-
- if (GST_IS_BIN (child)) {
- gst_bin_get_clock_elements (GST_BIN (child), needing, providing);
- }
- if (child->getclockfunc) {
- *providing = g_list_prepend (*providing, child);
- }
- if (child->setclockfunc) {
- *needing = g_list_prepend (*needing, child);
- }
-
- children = g_list_next (children);
- }
-}
-
-static void
-gst_bin_distribute_clock (GstBin *bin, GList *needing, GstClock *clock)
-{
- while (needing) {
- GST_DEBUG (GST_CAT_CLOCK, "setting clock on %s", GST_ELEMENT_NAME (needing->data));
- gst_element_set_clock (GST_ELEMENT (needing->data), clock);
-
- needing = g_list_next (needing);
- }
-}
-
-static void
-gst_bin_distribute_clocks (GstBin *bin)
-{
- GList *needing = NULL, *providing = NULL;
- GstClock *clock;
-
- gst_bin_get_clock_elements (bin, &needing, &providing);
-
- if (GST_FLAG_IS_SET (bin, GST_BIN_FLAG_FIXED_CLOCK)) {
- clock = bin->clock;
- }
- else if (providing) {
- clock = gst_element_get_clock (GST_ELEMENT (providing->data));
- }
- else {
- GST_DEBUG (GST_CAT_CLOCK, "no clock provided, using default clock");
- clock = gst_system_clock_obtain ();
- }
-
- GST_BIN_CLOCK (bin) = clock;
- gst_bin_distribute_clock (bin, needing, clock);
-}
-
GstClock*
gst_bin_get_clock (GstBin *bin)
{
g_return_val_if_fail (bin != NULL, NULL);
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
- return GST_BIN_CLOCK (bin);
+ if (GST_ELEMENT_SCHED (bin))
+ return gst_scheduler_get_clock (GST_ELEMENT_SCHED (bin));
+
+ return NULL;
}
void
g_return_if_fail (bin != NULL);
g_return_if_fail (GST_IS_BIN (bin));
- GST_FLAG_SET (bin, GST_BIN_FLAG_FIXED_CLOCK);
- GST_BIN_CLOCK (bin) = clock;
+ if (GST_ELEMENT_SCHED (bin))
+ gst_scheduler_use_clock (GST_ELEMENT_SCHED (bin), clock);
}
void
g_return_if_fail (bin != NULL);
g_return_if_fail (GST_IS_BIN (bin));
- GST_FLAG_UNSET (bin, GST_BIN_FLAG_FIXED_CLOCK);
- GST_BIN_CLOCK (bin) = NULL;
+ if (GST_ELEMENT_SCHED (bin))
+ gst_scheduler_auto_clock (GST_ELEMENT_SCHED (bin));
}
static void
-gst_bin_set_element_sched (GstElement * element, GstScheduler * sched)
+gst_bin_set_element_sched (GstElement *element, GstScheduler *sched)
{
GList *children;
GstElement *child;
if (GST_IS_BIN (element)) {
if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is already a manager, not resetting");
+ gst_scheduler_add_scheduler (sched, GST_ELEMENT_SCHED (element));
return;
}
gst_bin_set_element_sched (child, sched);
}
-
}
/* otherwise, if it's just a regular old element */
else {
static void
-gst_bin_unset_element_sched (GstElement * element)
+gst_bin_unset_element_sched (GstElement *element, GstScheduler *sched)
{
GList *children;
GstElement *child;
return;
}
- GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from it sched %p",
+ GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from its sched %p",
GST_ELEMENT_NAME (element), GST_ELEMENT_SCHED (element));
/* if it's actually a Bin */
if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element,
"child is already a manager, not unsetting sched");
+ if (sched) {
+ gst_scheduler_remove_scheduler (sched, GST_ELEMENT_SCHED (element));
+ }
return;
}
-
- gst_scheduler_remove_element (GST_ELEMENT_SCHED (element), element);
-
/* for each child, remove them from their schedule */
children = GST_BIN (element)->children;
while (children) {
child = GST_ELEMENT (children->data);
children = g_list_next (children);
- gst_bin_unset_element_sched (child);
+ gst_bin_unset_element_sched (child, sched);
}
+ gst_scheduler_remove_element (GST_ELEMENT_SCHED (element), element);
}
/* otherwise, if it's just a regular old element */
else {
* add a reference.
*/
void
-gst_bin_add (GstBin * bin, GstElement * element)
+gst_bin_add (GstBin *bin, GstElement *element)
{
gint state_idx = 0;
GstElementState state;
+ GstScheduler *sched;
g_return_if_fail (bin != NULL);
g_return_if_fail (GST_IS_BIN (bin));
/* now we have to deal with manager stuff
* we can only do this if there's a scheduler:
* if we're not a manager, and aren't attached to anything, we have no sched (yet) */
- if (GST_IS_BIN (element) && GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
- GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is a manager");
- }
- else if (GST_ELEMENT_SCHED (bin) != NULL) {
- gst_bin_set_element_sched (element, GST_ELEMENT_SCHED (bin));
+ sched = GST_ELEMENT_SCHED (bin);
+ if (sched) {
+ gst_bin_set_element_sched (element, sched);
}
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "added child \"%s\"", GST_ELEMENT_NAME (element));
* Remove the element from its associated bin, unparenting as well.
*/
void
-gst_bin_remove (GstBin * bin, GstElement * element)
+gst_bin_remove (GstBin *bin, GstElement *element)
{
gint state_idx = 0;
GstElementState state;
}
/* remove this element from the list of managed elements */
- gst_bin_unset_element_sched (element);
+ gst_bin_unset_element_sched (element, GST_ELEMENT_SCHED (bin));
/* now remove the element from the list of elements */
bin->children = g_list_remove (bin->children, element);
GST_LOCK (bin);
bin->child_states[old_idx]--;
bin->child_states[new_idx]++;
-
+
for (i = GST_NUM_STATES - 1; i >= 0; i--) {
if (bin->child_states[i] != 0) {
gint state = (1 << i);
GST_INFO (GST_CAT_STATES, "bin %s need state change to %s",
GST_ELEMENT_NAME (bin), gst_element_statename (state));
GST_STATE_PENDING (bin) = state;
+ GST_UNLOCK (bin);
gst_bin_change_state_norecurse (bin);
+ return;
}
break;
}
GST_INFO_ELEMENT (GST_CAT_STATES, element, "changing childrens' state from %s to %s",
gst_element_statename (old_state), gst_element_statename (pending));
+ if (pending == GST_STATE_VOID_PENDING)
+ return GST_STATE_SUCCESS;
+
children = bin->children;
+
while (children) {
child = GST_ELEMENT (children->data);
children = g_list_next (children);
}
}
- if (GST_ELEMENT_SCHED (bin) != NULL && GST_ELEMENT_PARENT (bin) == NULL) {
- switch (transition) {
- case GST_STATE_NULL_TO_READY:
- gst_bin_distribute_clocks (bin);
- break;
- case GST_STATE_READY_TO_PAUSED:
- if (GST_BIN_CLOCK (bin))
- gst_clock_reset (GST_BIN_CLOCK (bin));
- break;
- case GST_STATE_PAUSED_TO_PLAYING:
- gst_bin_distribute_clocks (bin);
- if (GST_BIN_CLOCK (bin))
- gst_clock_activate (GST_BIN_CLOCK (bin), TRUE);
- break;
- case GST_STATE_PLAYING_TO_PAUSED:
- if (GST_BIN_CLOCK (bin))
- gst_clock_activate (GST_BIN_CLOCK (bin), FALSE);
- break;
- }
- }
-
-
GST_INFO_ELEMENT (GST_CAT_STATES, element, "done changing bin's state from %s to %s, now in %s",
gst_element_statename (old_state),
gst_element_statename (pending),
# define GST_BIN_CLASS GST_BIN_CLASS_CAST
#endif
-#define GST_BIN_CLOCK_PROVIDERS(bin) (GST_BIN(bin)->clock_providers)
-#define GST_BIN_CLOCK_RECEIVERS(bin) (GST_BIN(bin)->clock_receivers)
-#define GST_BIN_CLOCK(bin) (GST_BIN(bin)->clock)
-
typedef enum {
/* this bin is a manager of child elements, i.e. a pipeline or thread */
GST_BIN_FLAG_MANAGER = GST_ELEMENT_FLAG_LAST,
GstElementState child_states[GST_NUM_STATES];
- GstClock *clock;
-
gpointer sched_private;
};
/* one of our childs signaled a state change */
void gst_bin_child_state_change (GstBin *bin, GstElementState oldstate,
GstElementState newstate, GstElement *child);
-/* one of our childs signaled an error */
-void gst_bin_child_error (GstBin *bin, GstElement *child);
-
#ifdef __cplusplus
}
#include "gstcaps.h"
#include "gsttype.h"
-#include "gstpropsprivate.h"
-
static GMemChunk *_gst_caps_chunk;
static GMutex *_gst_caps_chunk_lock;
+GType _gst_caps_type;
+
void
_gst_caps_initialize (void)
{
sizeof (GstCaps), sizeof (GstCaps) * 256,
G_ALLOC_AND_FREE);
_gst_caps_chunk_lock = g_mutex_new ();
+
+ _gst_caps_type = g_boxed_type_register_static ("GstCaps",
+ (GBoxedCopyFunc) gst_caps_ref,
+ (GBoxedFreeFunc) gst_caps_unref);
+
}
static guint16
caps->properties = props;
caps->next = NULL;
caps->refcount = 1;
- caps->lock = g_mutex_new ();
if (props)
caps->fixed = props->fixed;
else
if (caps == NULL)
return;
- GST_CAPS_LOCK (caps);
next = caps->next;
- GST_CAPS_UNLOCK (caps);
- g_mutex_free (caps->lock);
gst_props_unref (caps->properties);
g_free (caps->name);
g_mutex_lock (_gst_caps_chunk_lock);
g_return_val_if_fail (caps->refcount > 0, NULL);
- GST_CAPS_LOCK (caps);
caps->refcount--;
zero = (caps->refcount == 0);
next = &caps->next;
- GST_CAPS_UNLOCK (caps);
if (*next)
*next = gst_caps_unref (*next);
{
g_return_val_if_fail (caps != NULL, NULL);
- GST_CAPS_LOCK (caps);
caps->refcount++;
- GST_CAPS_UNLOCK (caps);
return caps;
}
g_return_val_if_fail (caps != NULL, NULL);
- GST_CAPS_LOCK (caps);
needcopy = (caps->refcount > 1);
- GST_CAPS_UNLOCK (caps);
if (needcopy) {
new = gst_caps_copy (caps);
g_mutex_unlock (_gst_caps_chunk_lock);
caps->refcount = 1;
- caps->lock = g_mutex_new ();
caps->next = NULL;
caps->fixed = TRUE;
typedef struct _GstCaps GstCaps;
+extern GType _gst_caps_type;
+
+#define GST_TYPE_CAPS (_get_caps_type)
+
+
#define GST_CAPS(caps) \
((GstCaps *)(caps))
-#define GST_CAPS_LOCK(caps) (g_mutex_lock(GST_CAPS(caps)->lock))
-#define GST_CAPS_TRYLOCK(caps) (g_mutex_trylock(GST_CAPS(caps)->lock))
-#define GST_CAPS_UNLOCK(caps) (g_mutex_unlock(GST_CAPS(caps)->lock))
-
#define GST_CAPS_IS_FIXED(caps) ((caps)->fixed)
#define GST_CAPS_IS_CHAINED(caps) ((caps)->next)
guint16 id; /* type id (major type) */
guint refcount;
- GMutex *lock; /* global lock for this capability */
gboolean fixed; /* this caps doesn't contain variable properties */
GstProps *properties; /* properties for this capability */
GstProps* gst_caps_get_props (GstCaps *caps);
#define gst_caps_set(caps, name, args...) gst_props_set ((caps)->properties, name, args)
+#define gst_caps_get(caps, name, args...) gst_props_get ((caps)->properties, name, args)
-#define gst_caps_get_int(caps, name) gst_props_get_int ((caps)->properties, name)
-#define gst_caps_get_float(caps, name) gst_props_get_float ((caps)->properties, name)
-#define gst_caps_get_fourcc_int(caps, name) gst_props_get_fourcc_int ((caps)->properties, name)
-#define gst_caps_get_boolean(caps, name) gst_props_get_boolean ((caps)->properties, name)
-#define gst_caps_get_string(caps, name) gst_props_get_string ((caps)->properties, name)
+#define gst_caps_get_int(caps,name,res) gst_props_entry_get_int(gst_props_get_entry((caps)->properties,name),res)
+#define gst_caps_get_float(caps,name,res) gst_props_entry_get_float(gst_props_get_entry((caps)->properties,name),res)
+#define gst_caps_get_fourcc_int(caps,name,res) gst_props_entry_get_fourcc_int(gst_props_get_entry((caps)->properties,name),res)
+#define gst_caps_get_boolean(caps,name,res) gst_props_entry_get_boolean(gst_props_get_entry((caps)->properties,name),res)
+#define gst_caps_get_string(caps,name,res) gst_props_entry_get_string(gst_props_get_entry((caps)->properties,name),res)
#define gst_caps_has_property(caps, name) gst_props_has_property ((caps)->properties, name)
+#define gst_caps_has_property_typed(caps, name) gst_props_has_property_typed ((caps)->properties, name)
#define gst_caps_has_fixed_property(caps, name) gst_props_has_fixed_property ((caps)->properties, name)
GstCaps* gst_caps_get_by_name (GstCaps *caps, const gchar *name);
#define CLASS(clock) GST_CLOCK_CLASS (G_OBJECT_GET_CLASS (clock))
+static GMemChunk *_gst_clock_entries_chunk;
+static GMutex *_gst_clock_entries_chunk_lock;
+static GList *_gst_clock_entries_pool;
static void gst_clock_class_init (GstClockClass *klass);
static void gst_clock_init (GstClock *clock);
+
static GstObjectClass *parent_class = NULL;
/* static guint gst_clock_signals[LAST_SIGNAL] = { 0 }; */
+typedef struct _GstClockEntry GstClockEntry;
+
+static void gst_clock_free_entry (GstClock *clock, GstClockEntry *entry);
+
+typedef enum {
+ GST_ENTRY_OK,
+ GST_ENTRY_RESTART,
+} GstEntryStatus;
+
+struct _GstClockEntry {
+ GstClockTime time;
+ GstEntryStatus status;
+ GstClockCallback func;
+ gpointer user_data;
+ GMutex *lock;
+ GCond *cond;
+};
+
+#define GST_CLOCK_ENTRY(entry) ((GstClockEntry *)(entry))
+#define GST_CLOCK_ENTRY_TIME(entry) (((GstClockEntry *)(entry))->time)
+#define GST_CLOCK_ENTRY_LOCK(entry) (g_mutex_lock ((entry)->lock))
+#define GST_CLOCK_ENTRY_UNLOCK(entry) (g_mutex_unlock ((entry)->lock))
+#define GST_CLOCK_ENTRY_SIGNAL(entry) (g_cond_signal ((entry)->cond))
+#define GST_CLOCK_ENTRY_WAIT(entry) (g_cond_wait (entry->cond, entry->lock))
+#define GST_CLOCK_ENTRY_TIMED_WAIT(entry, time) (g_cond_timed_wait (entry->cond, entry->lock, (time)))
+
+static GstClockEntry*
+gst_clock_entry_new (GstClockTime time,
+ GstClockCallback func, gpointer user_data)
+{
+ GstClockEntry *entry;
+
+ g_mutex_lock (_gst_clock_entries_chunk_lock);
+ if (_gst_clock_entries_pool) {
+ entry = GST_CLOCK_ENTRY (_gst_clock_entries_pool->data);
+
+ _gst_clock_entries_pool = g_list_remove (_gst_clock_entries_pool, entry);
+ g_mutex_unlock (_gst_clock_entries_chunk_lock);
+ }
+ else {
+ entry = g_mem_chunk_alloc (_gst_clock_entries_chunk);
+ g_mutex_unlock (_gst_clock_entries_chunk_lock);
+
+ entry->lock = g_mutex_new ();
+ entry->cond = g_cond_new ();
+ }
+ entry->time = time;
+ entry->func = func;
+ entry->user_data = user_data;
+
+ return entry;
+}
+
+static gint
+clock_compare_func (gconstpointer a,
+ gconstpointer b)
+{
+ GstClockEntry *entry1 = (GstClockEntry *)a;
+ GstClockEntry *entry2 = (GstClockEntry *)b;
+
+ return (entry1->time - entry2->time);
+}
+
GType
gst_clock_get_type (void)
{
if (!clock_type) {
static const GTypeInfo clock_info = {
- sizeof (GstObjectClass),
+ sizeof (GstClockClass),
NULL,
NULL,
(GClassInitFunc) gst_clock_class_init,
NULL,
NULL,
- sizeof (GstObject),
+ sizeof (GstClock),
4,
(GInstanceInitFunc) gst_clock_init,
NULL
};
clock_type = g_type_register_static (GST_TYPE_OBJECT, "GstClock",
- &clock_info, G_TYPE_FLAG_ABSTRACT);
+ &clock_info, G_TYPE_FLAG_ABSTRACT);
}
return clock_type;
}
gstobject_class = (GstObjectClass*) klass;
parent_class = g_type_class_ref (GST_TYPE_OBJECT);
+
+ _gst_clock_entries_chunk = g_mem_chunk_new ("GstClockEntries",
+ sizeof (GstClockEntry), sizeof (GstClockEntry) * 32,
+ G_ALLOC_AND_FREE);
+ _gst_clock_entries_chunk_lock = g_mutex_new ();
+ _gst_clock_entries_pool = NULL;
}
static void
clock->speed = 1.0;
clock->active = FALSE;
clock->start_time = 0;
+ clock->last_time = 0;
+ clock->entries = NULL;
+ clock->async_supported = FALSE;
clock->active_mutex = g_mutex_new ();
clock->active_cond = g_cond_new ();
}
+gboolean
+gst_clock_async_supported (GstClock *clock)
+{
+ g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
+
+ return clock->async_supported;
+}
+
+
void
gst_clock_reset (GstClock *clock)
{
+ GstClockTime time = 0LL;
+
g_return_if_fail (GST_IS_CLOCK (clock));
- clock->start_time = 0;
- clock->active = FALSE;
+ if (CLASS (clock)->get_internal_time) {
+ time = CLASS (clock)->get_internal_time (clock);
+ }
- if (CLASS (clock)->reset)
- CLASS (clock)->reset (clock);
+ GST_LOCK (clock);
+ clock->active = FALSE;
+ clock->start_time = time;
+ clock->last_time = 0LL;
+ GST_UNLOCK (clock);
}
void
gst_clock_activate (GstClock *clock, gboolean active)
{
+ GstClockTime time = 0LL;
+
g_return_if_fail (GST_IS_CLOCK (clock));
clock->active = active;
+
+ if (CLASS (clock)->get_internal_time) {
+ time = CLASS (clock)->get_internal_time (clock);
+ }
- if (CLASS (clock)->activate)
- CLASS (clock)->activate (clock, active);
+ GST_LOCK (clock);
+ if (active) {
+ clock->start_time = time - clock->last_time;;
+ }
+ else {
+ clock->last_time = time - clock->start_time;
+ }
+ GST_UNLOCK (clock);
g_mutex_lock (clock->active_mutex);
- g_cond_signal (clock->active_cond);
+ g_cond_broadcast (clock->active_cond);
g_mutex_unlock (clock->active_mutex);
-
}
gboolean
return clock->active;
}
-void
-gst_clock_set_time (GstClock *clock, GstClockTime time)
-{
- g_return_if_fail (GST_IS_CLOCK (clock));
-
- if (CLASS (clock)->set_time)
- CLASS (clock)->set_time (clock, time);
-}
-
GstClockTime
gst_clock_get_time (GstClock *clock)
{
+ GstClockTime ret = 0LL;
+
g_return_val_if_fail (GST_IS_CLOCK (clock), 0LL);
- if (CLASS (clock)->get_time)
- return CLASS (clock)->get_time (clock);
+ if (!clock->active) {
+ /* clock is not activen return previous time */
+ ret = clock->last_time;
+ }
+ else {
+ if (CLASS (clock)->get_internal_time) {
+ ret = CLASS (clock)->get_internal_time (clock) - clock->start_time;
+ }
+ /* make sure the time is increasing, else return last_time */
+ if (ret < clock->last_time) {
+ ret = clock->last_time;
+ }
+ else {
+ clock->last_time = ret;
+ }
+ }
- return 0LL;
+ return ret;
}
-GstClockReturn
-gst_clock_wait (GstClock *clock, GstClockTime time)
+static GstClockID
+gst_clock_wait_async_func (GstClock *clock, GstClockTime time,
+ GstClockCallback func, gpointer user_data)
{
- g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_STOPPED);
+ GstClockEntry *entry = NULL;
+ g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);
if (!clock->active) {
g_mutex_lock (clock->active_mutex);
g_cond_wait (clock->active_cond, clock->active_mutex);
g_mutex_unlock (clock->active_mutex);
}
- if (CLASS (clock)->wait)
- return CLASS (clock)->wait (clock, time);
- return GST_CLOCK_TIMEOUT;
+ entry = gst_clock_entry_new (time, func, user_data);
+
+ GST_LOCK (clock);
+ clock->entries = g_list_insert_sorted (clock->entries, entry, clock_compare_func);
+ GST_UNLOCK (clock);
+
+ return entry;
+}
+
+GstClockReturn
+gst_clock_wait (GstClock *clock, GstClockTime time)
+{
+ GstClockID id;
+ GstClockReturn res;
+
+ g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_STOPPED);
+
+ id = gst_clock_wait_async_func (clock, time, NULL, NULL);
+ res = gst_clock_wait_id (clock, id);
+
+ return res;
+}
+
+GstClockID
+gst_clock_wait_async (GstClock *clock, GstClockTime time,
+ GstClockCallback func, gpointer user_data)
+{
+ g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);
+
+ if (clock->async_supported) {
+ return gst_clock_wait_async_func (clock, time, func, user_data);
+ }
+ return NULL;
+}
+
+static void
+gst_clock_unlock_func (GstClock *clock, GstClockTime time, GstClockID id, gpointer user_data)
+{
+ GstClockEntry *entry = (GstClockEntry *) id;
+
+ GST_CLOCK_ENTRY_LOCK (entry);
+ GST_CLOCK_ENTRY_SIGNAL (entry);
+ GST_CLOCK_ENTRY_UNLOCK (entry);
+}
+
+GstClockReturn
+gst_clock_wait_id (GstClock *clock, GstClockID id)
+{
+ GstClockReturn res = GST_CLOCK_TIMEOUT;
+ GstClockEntry *entry = (GstClockEntry *) id;
+ GstClockTime current_real, current, target;
+ GTimeVal timeval;
+
+ g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_ERROR);
+ g_return_val_if_fail (entry, GST_CLOCK_ERROR);
+
+ current = gst_clock_get_time (clock);
+
+ g_get_current_time (&timeval);
+ current_real = GST_TIMEVAL_TO_TIME (timeval);
+
+ GST_CLOCK_ENTRY_LOCK (entry);
+ entry->func = gst_clock_unlock_func;
+ target = GST_CLOCK_ENTRY_TIME (entry) - current + current_real;
+
+ //g_print ("%lld %lld %lld\n", target, current, current_real);
+
+ if (target > current_real) {
+ timeval.tv_usec = target % 1000000;
+ timeval.tv_sec = target / 1000000;
+
+ GST_CLOCK_ENTRY_TIMED_WAIT (entry, &timeval);
+ }
+ GST_CLOCK_ENTRY_UNLOCK (entry);
+
+ gst_clock_free_entry (clock, entry);
+
+ return res;
+}
+
+GstClockID
+gst_clock_get_next_id (GstClock *clock)
+{
+ GstClockEntry *entry = NULL;
+
+ GST_LOCK (clock);
+ if (clock->entries)
+ entry = GST_CLOCK_ENTRY (clock->entries->data);
+ GST_UNLOCK (clock);
+
+ return (GstClockID *) entry;
+}
+
+GstClockTime
+gst_clock_id_get_time (GstClockID id)
+{
+ return GST_CLOCK_ENTRY_TIME (id);
+}
+
+static void
+gst_clock_free_entry (GstClock *clock, GstClockEntry *entry)
+{
+ GST_LOCK (clock);
+ clock->entries = g_list_remove (clock->entries, entry);
+ GST_UNLOCK (clock);
+
+ g_mutex_lock (_gst_clock_entries_chunk_lock);
+ _gst_clock_entries_pool = g_list_prepend (_gst_clock_entries_pool, entry);
+ g_mutex_unlock (_gst_clock_entries_chunk_lock);
+}
+
+void
+gst_clock_unlock_id (GstClock *clock, GstClockID id)
+{
+ GstClockEntry *entry = (GstClockEntry *) id;
+
+ if (entry->func)
+ entry->func (clock, gst_clock_get_time (clock), id, entry->user_data);
+
+ gst_clock_free_entry (clock, entry);
}
void
if (CLASS (clock)->get_resolution)
return CLASS (clock)->get_resolution (clock);
- return 0LL;
+ return 1LL;
}
GstObject object;
GstClockTime start_time;
+ GstClockTime last_time;
gdouble speed;
gboolean active;
+ GList *entries;
+ gboolean async_supported;
GMutex *active_mutex;
GCond *active_cond;
GstObjectClass parent_class;
/* vtable */
- void (*activate) (GstClock *clock, gboolean active);
- void (*reset) (GstClock *clock);
-
- void (*set_time) (GstClock *clock, GstClockTime time);
- GstClockTime (*get_time) (GstClock *clock);
-
- GstClockReturn (*wait) (GstClock *clock, GstClockTime time);
- GstClockID (*wait_async) (GstClock *clock, GstClockTime time,
- GstClockCallback func, gpointer user_data);
- void (*cancel_wait_async) (GstClock *clock, GstClockID id);
- GstClockID (*notify_async) (GstClock *clock, GstClockTime interval,
- GstClockCallback func, gpointer user_data);
- void (*remove_notify_async) (GstClock *clock, GstClockID id);
-
+ GstClockTime (*get_internal_time) (GstClock *clock);
+
void (*set_resolution) (GstClock *clock, guint64 resolution);
guint64 (*get_resolution) (GstClock *clock);
void gst_clock_activate (GstClock *clock, gboolean active);
gboolean gst_clock_is_active (GstClock *clock);
void gst_clock_reset (GstClock *clock);
+gboolean gst_clock_async_supported (GstClock *clock);
-void gst_clock_set_time (GstClock *clock, GstClockTime time);
GstClockTime gst_clock_get_time (GstClock *clock);
GstClockReturn gst_clock_wait (GstClock *clock, GstClockTime time);
GstClockID gst_clock_notify_async (GstClock *clock, GstClockTime interval,
GstClockCallback func, gpointer user_data);
void gst_clock_remove_notify_async (GstClock *clock, GstClockID id);
+GstClockReturn gst_clock_wait_id (GstClock *clock, GstClockID id);
+
+GstClockID gst_clock_get_next_id (GstClock *clock);
+void gst_clock_unlock_id (GstClock *clock, GstClockID id);
+
+GstClockTime gst_clock_id_get_time (GstClockID id);
void gst_clock_set_resolution (GstClock *clock, guint64 resolution);
guint64 gst_clock_get_resolution (GstClock *clock);
g_return_val_if_fail (element != NULL, GST_CLOCK_ERROR);
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_ERROR);
- /* FIXME inform the scheduler */
- return gst_clock_wait (clock, time);
+ if (GST_ELEMENT_SCHED (element)) {
+ return gst_scheduler_clock_wait (GST_ELEMENT_SCHED (element), element, clock, time);
+ }
+ else
+ return GST_CLOCK_TIMEOUT;
}
/**
/* look through the list, matching by name */
walk = element->pads;
while (walk) {
- GstPad *pad = GST_PAD(walk->data);
+ GstPad *pad;
+
+ pad = GST_PAD(walk->data);
if (!strcmp (GST_PAD_NAME(pad), name)) {
GST_INFO(GST_CAT_ELEMENT_PADS,"found pad %s:%s",GST_DEBUG_PAD_NAME(pad));
return pad;
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
g_return_val_if_fail (name != NULL, NULL);
+
if (strstr (name, "%")) {
templ = gst_element_get_padtemplate_by_name (element, name);
req_name = NULL;
}
/**
- * gst_element_info:
- * @element: Element with the info
- * @info: String describing the info
- * @...: arguments for the string.
- *
- * This function is used internally by elements to signal an info
- * condition. It results in the "info" signal.
- */
-void
-gst_element_info (GstElement *element, const gchar *info, ...)
-{
- g_warning ("The function gst_element_info is gone. Use g_object_notify instead.");
-}
-
-
-/**
- * gst_element_send_event:
- * @element: Element generating the event
- * @event: the event to send
- *
- * This function is deprecated and doesn't work anymore.
- */
-void
-gst_element_send_event (GstElement *element, GstEvent *event)
-{
- g_warning ("The function gst_element_send_event is gone. Use g_object_notify instead.");
-}
-
-/**
* gst_element_get_state:
* @element: element to get state of
*
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
- GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "setting state from %s to %s\n",
- gst_element_statename (GST_STATE (element)),
- gst_element_statename (state));
-
/* start with the current state */
curpending = GST_STATE(element);
+ GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "setting state from %s to %s\n",
+ gst_element_statename (curpending),
+ gst_element_statename (state));
+
/* loop until the final requested state is set */
while (GST_STATE (element) != state && GST_STATE (element) != GST_STATE_VOID_PENDING) {
/* move the curpending state in the correct direction */
/* FIXME: should probably check to see that we don't already have one */
GST_STATE_PENDING (element) = curpending;
- if (curpending != state)
+ if (curpending != state) {
GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "intermediate: setting state to %s\n",
gst_element_statename (curpending));
+ }
/* call the state change function so it can set the state */
oclass = CLASS (element);
/* Last thing we do is verify that a successful state change really
* did change the state... */
if (GST_STATE (element) != curpending) {
- GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "element claimed state-change success, but state didn't change\n");
+ GST_DEBUG_ELEMENT (GST_CAT_STATES, element,
+ "element claimed state-change success, but state didn't change %s, %s <-> %s\n",
+ gst_element_statename (GST_STATE (element)),
+ gst_element_statename (GST_STATE_PENDING (element)),
+ gst_element_statename (curpending));
return GST_STATE_FAILURE;
}
break;
}
}
- g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE],
- 0, old_state, GST_STATE (element));
-
parent = GST_ELEMENT_PARENT (element);
/* tell our parent about the state change */
gst_bin_child_state_change (GST_BIN (parent), old_state, GST_STATE (element), element);
}
+ g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE],
+ 0, old_state, GST_STATE (element));
+
/* signal the state change in case somebody is waiting for us */
g_mutex_lock (element->state_mutex);
g_cond_signal (element->state_cond);
*/
void
gst_element_set_sched (GstElement *element,
- GstScheduler *sched)
+ GstScheduler *sched)
{
g_return_if_fail (GST_IS_ELEMENT (element));
* a new loopfunc to be assigned, this should be no problem.
*/
void
-gst_element_set_loop_function(GstElement *element,
- GstElementLoopFunction loop)
+gst_element_set_loop_function (GstElement *element,
+ GstElementLoopFunction loop)
{
g_return_if_fail (GST_IS_ELEMENT (element));
#define GST_NUM_STATES 4
-
/* NOTE: this probably should be done with an #ifdef to decide
* whether to safe-cast or to just do the non-checking cast.
*/
GstElementStateReturn (*change_state) (GstElement *element);
/* request a new pad */
GstPad* (*request_new_pad) (GstElement *element, GstPadTemplate *templ, const gchar* name);
- void (*send_event) (GstElement *element, GstEvent *event);
};
void gst_element_class_add_padtemplate (GstElementClass *klass, GstPadTemplate *templ);
void gst_element_set_eos (GstElement *element);
-void gst_element_send_event (GstElement *element, GstEvent *event);
-
+void gst_element_error (GstElement *element, const gchar *error, ...);
GstElementState gst_element_get_state (GstElement *element);
gint gst_element_set_state (GstElement *element, GstElementState state);
const gchar* gst_element_statename (GstElementState state);
-void gst_element_info (GstElement *element, const gchar *info, ...);
-void gst_element_error (GstElement *element, const gchar *error, ...);
-
GstElementFactory* gst_element_get_factory (GstElement *element);
void gst_element_class_install_std_props (GstElementClass *klass,
realsink = GST_PAD_REALIZE (sinkpad);
g_return_if_fail (GST_RPAD_PEER (realsrc) != NULL);
- g_return_if_fail (GST_RPAD_PEER (realsink) != NULL);
+ g_return_if_fail (GST_RPAD_PEER (realsink) == realsrc);
if ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SINK) &&
(GST_RPAD_DIRECTION (realsink) == GST_PAD_SRC)) {
debug_string = "DELAYED";
break;
default:
- g_warning ("unknown return code from connect function of pad %s:%s",
- GST_DEBUG_PAD_NAME (pad));
+ g_warning ("unknown return code from connect function of pad %s:%s %d",
+ GST_DEBUG_PAD_NAME (pad), res);
return GST_PAD_CONNECT_REFUSED;
}
GST_INFO (GST_CAT_CAPS, "proxy connect to pad %s:%s",
GST_DEBUG_PAD_NAME (realpad));
- if (peer && !gst_pad_try_set_caps_func (peer, caps, TRUE))
+ if (peer && gst_pad_try_set_caps_func (peer, caps, TRUE) < 0)
return GST_PAD_CONNECT_REFUSED;
- if (!gst_pad_try_set_caps_func (realpad, caps, FALSE))
+ if (gst_pad_try_set_caps_func (realpad, caps, FALSE) < 0)
return GST_PAD_CONNECT_REFUSED;
return GST_PAD_CONNECT_OK;
extern GType _gst_real_pad_type;
extern GType _gst_ghost_pad_type;
-/*#define GST_TYPE_PARANOID */
+#define GST_TYPE_PARANOID
/*
* Pad base class
} GstRegionType;
typedef enum {
- GST_PAD_CONNECT_REFUSED = 0,
- GST_PAD_CONNECT_OK = 1,
- GST_PAD_CONNECT_DONE = 2,
- GST_PAD_CONNECT_DELAYED = 3,
+ GST_PAD_CONNECT_REFUSED = -1,
+ GST_PAD_CONNECT_DELAYED = 0,
+ GST_PAD_CONNECT_OK = 1,
+ GST_PAD_CONNECT_DONE = 2,
} GstPadConnectReturn;
/* this defines the functions used to chain buffers
#include "gstlog.h"
#include "gstprops.h"
-#include "gstpropsprivate.h"
+
+GType _gst_props_type;
+
+#define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_TYPE)
+
+struct _GstPropsEntry {
+ GQuark propid;
+ GstPropsType propstype;
+
+ union {
+ /* flat values */
+ gboolean bool_data;
+ guint32 fourcc_data;
+ gint int_data;
+ gfloat float_data;
+
+ /* structured values */
+ struct {
+ GList *entries;
+ } list_data;
+ struct {
+ gchar *string;
+ } string_data;
+ struct {
+ gint min;
+ gint max;
+ } int_range_data;
+ struct {
+ gfloat min;
+ gfloat max;
+ } float_range_data;
+ } data;
+};
static GMemChunk *_gst_props_entries_chunk;
static GMutex *_gst_props_entries_chunk_lock;
sizeof (GstProps), sizeof (GstProps) * 256,
G_ALLOC_AND_FREE);
_gst_props_chunk_lock = g_mutex_new ();
+
+ _gst_props_type = g_boxed_type_register_static ("GstProps",
+ (GBoxedCopyFunc) gst_props_ref,
+ (GBoxedFreeFunc) gst_props_unref);
+
}
static void
const gchar *name = g_quark_to_string (entry->propid);
switch (entry->propstype) {
- case GST_PROPS_INT_ID:
- GST_DEBUG (GST_CAT_PROPERTIES, "%s: int %d", name, entry->data.int_data);
+ case GST_PROPS_INT_TYPE:
+ GST_DEBUG (GST_CAT_PROPERTIES, "%s: int %d\n", name, entry->data.int_data);
break;
- case GST_PROPS_FLOAT_ID:
- GST_DEBUG (GST_CAT_PROPERTIES, "%s: float %f", name, entry->data.float_data);
+ case GST_PROPS_FLOAT_TYPE:
+ GST_DEBUG (GST_CAT_PROPERTIES, "%s: float %f\n", name, entry->data.float_data);
break;
- case GST_PROPS_FOURCC_ID:
- GST_DEBUG (GST_CAT_PROPERTIES, "%s: fourcc %4.4s", name, (gchar*)&entry->data.fourcc_data);
+ case GST_PROPS_FOURCC_TYPE:
+ GST_DEBUG (GST_CAT_PROPERTIES, "%s: fourcc %4.4s\n", name, (gchar*)&entry->data.fourcc_data);
break;
- case GST_PROPS_BOOL_ID:
- GST_DEBUG (GST_CAT_PROPERTIES, "%s: bool %d", name, entry->data.bool_data);
+ case GST_PROPS_BOOL_TYPE:
+ GST_DEBUG (GST_CAT_PROPERTIES, "%s: bool %d\n", name, entry->data.bool_data);
break;
- case GST_PROPS_STRING_ID:
- GST_DEBUG (GST_CAT_PROPERTIES, "%s: string %s", name, entry->data.string_data.string);
+ case GST_PROPS_STRING_TYPE:
+ GST_DEBUG (GST_CAT_PROPERTIES, "%s: string %s\n", name, entry->data.string_data.string);
break;
- case GST_PROPS_INT_RANGE_ID:
- GST_DEBUG (GST_CAT_PROPERTIES, "%s: int range %d-%d", name, entry->data.int_range_data.min,
+ case GST_PROPS_INT_RANGE_TYPE:
+ GST_DEBUG (GST_CAT_PROPERTIES, "%s: int range %d-%d\n", name, entry->data.int_range_data.min,
entry->data.int_range_data.max);
break;
- case GST_PROPS_FLOAT_RANGE_ID:
- GST_DEBUG (GST_CAT_PROPERTIES, "%s: float range %f-%f", name, entry->data.float_range_data.min,
+ case GST_PROPS_FLOAT_RANGE_TYPE:
+ GST_DEBUG (GST_CAT_PROPERTIES, "%s: float range %f-%f\n", name, entry->data.float_range_data.min,
entry->data.float_range_data.max);
break;
- case GST_PROPS_LIST_ID:
- GST_DEBUG (GST_CAT_PROPERTIES, "[list]");
+ case GST_PROPS_LIST_TYPE:
+ GST_DEBUG (GST_CAT_PROPERTIES, "[list]\n");
{
GList *entries = entry->data.list_data.entries;
*/
#define GST_PROPS_ENTRY_FILL(entry, var_args) \
G_STMT_START { \
- entry->propstype = va_arg (var_args, GstPropsId); \
+ entry->propstype = va_arg (var_args, GstPropsType); \
\
switch (entry->propstype) { \
- case GST_PROPS_INT_ID: \
+ case GST_PROPS_INT_TYPE: \
entry->data.int_data = va_arg (var_args, gint); \
break; \
- case GST_PROPS_INT_RANGE_ID: \
+ case GST_PROPS_INT_RANGE_TYPE: \
entry->data.int_range_data.min = va_arg (var_args, gint); \
entry->data.int_range_data.max = va_arg (var_args, gint); \
break; \
- case GST_PROPS_FLOAT_ID: \
+ case GST_PROPS_FLOAT_TYPE: \
entry->data.float_data = va_arg (var_args, gdouble); \
break; \
- case GST_PROPS_FLOAT_RANGE_ID: \
+ case GST_PROPS_FLOAT_RANGE_TYPE: \
entry->data.float_range_data.min = va_arg (var_args, gdouble); \
entry->data.float_range_data.max = va_arg (var_args, gdouble); \
break; \
- case GST_PROPS_FOURCC_ID: \
+ case GST_PROPS_FOURCC_TYPE: \
entry->data.fourcc_data = va_arg (var_args, gulong); \
break; \
- case GST_PROPS_BOOL_ID: \
+ case GST_PROPS_BOOL_TYPE: \
entry->data.bool_data = va_arg (var_args, gboolean); \
break; \
- case GST_PROPS_STRING_ID: \
+ case GST_PROPS_STRING_TYPE: \
entry->data.string_data.string = g_strdup (va_arg (var_args, gchar*)); \
break; \
default: \
} \
} G_STMT_END
+
+#define GST_PROPS_ENTRY_READ(entry, var_args, safe, result) \
+G_STMT_START { \
+ *result = TRUE; \
+ \
+ if (safe) { \
+ GstPropsType propstype = va_arg (var_args, GstPropsType); \
+ if (propstype != entry->propstype) { \
+ *result = FALSE; \
+ } \
+ } \
+ if (*result) { \
+ switch (entry->propstype) { \
+ case GST_PROPS_INT_TYPE: \
+ *(va_arg (var_args, gint*)) = entry->data.int_data; \
+ break; \
+ case GST_PROPS_INT_RANGE_TYPE: \
+ *(va_arg (var_args, gint*)) = entry->data.int_range_data.min; \
+ *(va_arg (var_args, gint*)) = entry->data.int_range_data.max; \
+ break; \
+ case GST_PROPS_FLOAT_TYPE: \
+ *(va_arg (var_args, gfloat*)) = entry->data.float_data; \
+ break; \
+ case GST_PROPS_FLOAT_RANGE_TYPE: \
+ *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.min; \
+ *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.max; \
+ break; \
+ case GST_PROPS_FOURCC_TYPE: \
+ *(va_arg (var_args, guint32*)) = entry->data.fourcc_data; \
+ break; \
+ case GST_PROPS_BOOL_TYPE: \
+ *(va_arg (var_args, gboolean*)) = entry->data.bool_data; \
+ break; \
+ case GST_PROPS_STRING_TYPE: \
+ *(va_arg (var_args, gchar**)) = entry->data.string_data.string; \
+ break; \
+ case GST_PROPS_LIST_TYPE: \
+ *(va_arg (var_args, GList**)) = entry->data.list_data.entries; \
+ break; \
+ default: \
+ *result = FALSE; \
+ break; \
+ } \
+ } \
+} G_STMT_END
+
static GstPropsEntry*
gst_props_alloc_entry (void)
{
gst_props_entry_destroy (GstPropsEntry *entry)
{
switch (entry->propstype) {
- case GST_PROPS_STRING_ID:
+ case GST_PROPS_STRING_TYPE:
g_free (entry->data.string_data.string);
break;
- case GST_PROPS_LIST_ID:
+ case GST_PROPS_LIST_TYPE:
{
GList *entries = entry->data.list_data.entries;
gint new_min, new_max, old_min, old_max;
gboolean can_merge = FALSE;
- if (newentry->propstype == GST_PROPS_INT_ID) {
+ if (newentry->propstype == GST_PROPS_INT_TYPE) {
new_min = newentry->data.int_data;
new_max = newentry->data.int_data;
} else {
new_max = newentry->data.int_range_data.max;
}
- if (oldentry->propstype == GST_PROPS_INT_ID) {
+ if (oldentry->propstype == GST_PROPS_INT_TYPE) {
old_min = oldentry->data.int_data;
old_max = oldentry->data.int_data;
} else {
if (can_merge) {
if (new_min == new_max) {
- newentry->propstype = GST_PROPS_INT_ID;
+ newentry->propstype = GST_PROPS_INT_TYPE;
newentry->data.int_data = new_min;
} else {
- newentry->propstype = GST_PROPS_INT_RANGE_ID;
+ newentry->propstype = GST_PROPS_INT_RANGE_TYPE;
newentry->data.int_range_data.min = new_min;
newentry->data.int_range_data.max = new_max;
}
GST_PROPS_ENTRY_FILL (entry, var_args);
switch (entry->propstype) {
- case GST_PROPS_INT_ID:
- case GST_PROPS_INT_RANGE_ID:
+ case GST_PROPS_INT_TYPE:
+ case GST_PROPS_INT_RANGE_TYPE:
entry_type = GST_PROPS_LIST_T_INTS;
break;
- case GST_PROPS_FLOAT_ID:
- case GST_PROPS_FLOAT_RANGE_ID:
+ case GST_PROPS_FLOAT_TYPE:
+ case GST_PROPS_FLOAT_RANGE_TYPE:
entry_type = GST_PROPS_LIST_T_FLOATS;
break;
- case GST_PROPS_FOURCC_ID:
- case GST_PROPS_BOOL_ID:
- case GST_PROPS_STRING_ID:
+ case GST_PROPS_FOURCC_TYPE:
+ case GST_PROPS_BOOL_TYPE:
+ case GST_PROPS_STRING_TYPE:
entry_type = GST_PROPS_LIST_T_MISC;
break;
- case GST_PROPS_LIST_ID:
+ case GST_PROPS_LIST_TYPE:
g_return_val_if_fail (inlist == FALSE, NULL);
inlist = TRUE;
list_entry = entry;
list_type = GST_PROPS_LIST_T_UNSET;
list_entry->data.list_data.entries = NULL;
break;
- case GST_PROPS_END_ID:
+ case GST_PROPS_END_TYPE:
g_return_val_if_fail (inlist == TRUE, NULL);
/* if list was of size 1, replace the list by a the item it contains */
newentry = gst_props_alloc_entry ();
memcpy (newentry, entry, sizeof (GstPropsEntry));
- if (entry->propstype == GST_PROPS_LIST_ID) {
+ if (entry->propstype == GST_PROPS_LIST_TYPE) {
newentry->data.list_data.entries = gst_props_list_copy (entry->data.list_data.entries);
}
- else if (entry->propstype == GST_PROPS_STRING_ID) {
+ else if (entry->propstype == GST_PROPS_STRING_TYPE) {
newentry->data.string_data.string = g_strdup (entry->data.string_data.string);
}
return new;
}
-static GstPropsEntry*
-gst_props_get_entry_func (GstProps *props, const gchar *name)
+const GstPropsEntry*
+gst_props_get_entry (GstProps *props, const gchar *name)
{
GList *lentry;
GQuark quark;
gboolean
gst_props_has_property (GstProps *props, const gchar *name)
{
- return (gst_props_get_entry_func (props, name) != NULL);
+ return (gst_props_get_entry (props, name) != NULL);
}
-/**
- * gst_props_get_int:
- * @props: the props to get the int value from
- * @name: the name of the props entry to get.
- *
- * Get the named entry as an integer.
- *
- * Returns: the integer value of the named entry, 0 if not found.
- */
-gint
-gst_props_get_int (GstProps *props, const gchar *name)
+gboolean
+gst_props_has_property_typed (GstProps *props, const gchar *name, GstPropsType type)
{
- GstPropsEntry *thisentry;
+ const GstPropsEntry *entry;
- thisentry = gst_props_get_entry_func (props, name);
+ entry = gst_props_get_entry (props, name);
+ if (!entry)
+ return FALSE;
- if (thisentry) {
- return thisentry->data.int_data;
- }
- else {
- g_warning ("props: property %s not found", name);
- }
- return 0;
+ return (entry->propstype == type);
}
-/**
- * gst_props_get_float:
- * @props: the props to get the float value from
- * @name: the name of the props entry to get.
- *
- * Get the named entry as a float.
- *
- * Returns: the float value of the named entry, 0.0 if not found.
- */
-gfloat
-gst_props_get_float (GstProps *props, const gchar *name)
+gboolean
+gst_props_has_fixed_property (GstProps *props, const gchar *name)
{
- GstPropsEntry *thisentry;
+ const GstPropsEntry *entry;
- thisentry = gst_props_get_entry_func (props, name);
+ entry = gst_props_get_entry (props, name);
+ if (!entry)
+ return FALSE;
- if (thisentry) {
- return thisentry->data.float_data;
- }
- else {
- g_warning ("props: property %s not found", name);
- }
- return 0.0F;
+ return !GST_PROPS_ENTRY_IS_VARIABLE (entry);
}
-/**
- * gst_props_get_fourcc_int:
- * @props: the props to get the fourcc value from
- * @name: the name of the props entry to get.
- *
- * Get the named entry as a gulong fourcc.
- *
- * Returns: the fourcc value of the named entry, 0 if not found.
- */
-gulong
-gst_props_get_fourcc_int (GstProps *props, const gchar *name)
+GstPropsType
+gst_props_entry_get_type (const GstPropsEntry *entry)
{
- GstPropsEntry *thisentry;
+ g_return_val_if_fail (entry != NULL, GST_PROPS_INVALID_TYPE);
- thisentry = gst_props_get_entry_func (props, name);
+ return entry->propstype;
+}
- if (thisentry) {
- return thisentry->data.fourcc_data;
- }
- else {
- g_warning ("props: property %s not found", name);
- }
- return 0;
+const gchar*
+gst_props_entry_get_name (const GstPropsEntry *entry)
+{
+ g_return_val_if_fail (entry != NULL, NULL);
+
+ return g_quark_to_string (entry->propid);
}
-/**
- * gst_props_get_boolean:
- * @props: the props to get the fourcc value from
- * @name: the name of the props entry to get.
- *
- * Get the named entry as a boolean value.
- *
- * Returns: the boolean value of the named entry, 0 if not found.
- */
gboolean
-gst_props_get_boolean (GstProps *props, const gchar *name)
+gst_props_entry_is_fixed (const GstPropsEntry *entry)
+{
+ g_return_val_if_fail (entry != NULL, FALSE);
+
+ return !GST_PROPS_ENTRY_IS_VARIABLE (entry);
+}
+
+static gboolean
+gst_props_entry_getv (const GstPropsEntry *entry, gboolean safe, va_list var_args)
{
- GstPropsEntry *thisentry;
+ gboolean result;
- thisentry = gst_props_get_entry_func (props, name);
+ GST_PROPS_ENTRY_READ (entry, var_args, safe, &result);
- if (thisentry) {
- return thisentry->data.bool_data;
- }
- else {
- g_warning ("props: property %s not found", name);
- }
- return 0;
+ return result;
}
-/**
- * gst_props_get_string:
- * @props: the props to get the fourcc value from
- * @name: the name of the props entry to get.
- *
- * Get the named entry as a string value.
- *
- * Returns: the string value of the named entry, NULL if not found.
- */
-const gchar*
-gst_props_get_string (GstProps *props, const gchar *name)
+gboolean
+gst_props_entry_get (const GstPropsEntry *entry, ...)
+{
+ gboolean result;
+ va_list var_args;
+
+ g_return_val_if_fail (entry != NULL, FALSE);
+
+ va_start (var_args, entry);
+ result = gst_props_entry_getv (entry, FALSE, var_args);
+ va_end (var_args);
+
+ return result;
+}
+
+static gboolean
+gst_props_entry_get_safe (const GstPropsEntry *entry, ...)
{
- GstPropsEntry *thisentry;
+ gboolean result;
+ va_list var_args;
- thisentry = gst_props_get_entry_func (props, name);
+ g_return_val_if_fail (entry != NULL, FALSE);
- if (thisentry) {
- return thisentry->data.string_data.string;
- }
- else {
- g_warning ("props: property %s not found", name);
+ va_start (var_args, entry);
+ result = gst_props_entry_getv (entry, TRUE, var_args);
+ va_end (var_args);
+
+ return result;
+}
+
+gboolean
+gst_props_get (GstProps *props, gchar *first_name, ...)
+{
+ va_list var_args;
+
+ va_start (var_args, first_name);
+
+ while (first_name) {
+ const GstPropsEntry *entry = gst_props_get_entry (props, first_name);
+ gboolean result;
+
+ if (!entry) return FALSE;
+ GST_PROPS_ENTRY_READ (entry, var_args, FALSE, &result);
+ if (!result) return FALSE;
+
+ first_name = va_arg (var_args, gchar *);
}
- return NULL;
+ va_end (var_args);
+
+ return TRUE;
+}
+
+gboolean
+gst_props_entry_get_int (const GstPropsEntry *entry, gint *val)
+{
+ return gst_props_entry_get_safe (entry, GST_PROPS_INT_TYPE, val);
+}
+
+gboolean
+gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val)
+{
+ return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_TYPE, val);
+}
+
+gboolean
+gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val)
+{
+ return gst_props_entry_get_safe (entry, GST_PROPS_FOURCC_TYPE, val);
+}
+
+gboolean
+gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val)
+{
+ return gst_props_entry_get_safe (entry, GST_PROPS_BOOL_TYPE, val);
+}
+
+gboolean
+gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val)
+{
+ return gst_props_entry_get_safe (entry, GST_PROPS_STRING_TYPE, val);
+}
+
+gboolean
+gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max)
+{
+ return gst_props_entry_get_safe (entry, GST_PROPS_INT_RANGE_TYPE, min, max);
}
+gboolean
+gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat *max)
+{
+ return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_RANGE_TYPE, min, max);
+}
+
+gboolean
+gst_props_entry_get_list (const GstPropsEntry *entry, const GList **val)
+{
+ return gst_props_entry_get_safe (entry, GST_PROPS_LIST_TYPE, val);
+}
+
+
/**
* gst_props_merge:
* @props: the property to merge into
GST_DEBUG (GST_CAT_PROPERTIES,"compare: %s %s", g_quark_to_string (entry1->propid),
g_quark_to_string (entry2->propid));
- if (entry2->propstype == GST_PROPS_LIST_ID && entry1->propstype != GST_PROPS_LIST_ID) {
+ if (entry2->propstype == GST_PROPS_LIST_TYPE && entry1->propstype != GST_PROPS_LIST_TYPE) {
return gst_props_entry_check_list_compatibility (entry1, entry2);
}
switch (entry1->propstype) {
- case GST_PROPS_LIST_ID:
+ case GST_PROPS_LIST_TYPE:
{
GList *entrylist = entry1->data.list_data.entries;
gboolean valid = TRUE; /* innocent until proven guilty */
return valid;
}
- case GST_PROPS_INT_RANGE_ID:
+ case GST_PROPS_INT_RANGE_TYPE:
switch (entry2->propstype) {
/* a - b <---> a - c */
- case GST_PROPS_INT_RANGE_ID:
+ case GST_PROPS_INT_RANGE_TYPE:
return (entry2->data.int_range_data.min <= entry1->data.int_range_data.min &&
entry2->data.int_range_data.max >= entry1->data.int_range_data.max);
default:
break;
}
break;
- case GST_PROPS_FLOAT_RANGE_ID:
+ case GST_PROPS_FLOAT_RANGE_TYPE:
switch (entry2->propstype) {
/* a - b <---> a - c */
- case GST_PROPS_FLOAT_RANGE_ID:
+ case GST_PROPS_FLOAT_RANGE_TYPE:
return (entry2->data.float_range_data.min <= entry1->data.float_range_data.min &&
entry2->data.float_range_data.max >= entry1->data.float_range_data.max);
default:
break;
}
break;
- case GST_PROPS_FOURCC_ID:
+ case GST_PROPS_FOURCC_TYPE:
switch (entry2->propstype) {
/* b <---> a */
- case GST_PROPS_FOURCC_ID:
- GST_DEBUG(GST_CAT_PROPERTIES,"\"%4.4s\" <--> \"%4.4s\" ?",
+ case GST_PROPS_FOURCC_TYPE:
+ GST_DEBUG(GST_CAT_PROPERTIES,"\"%4.4s\" <--> \"%4.4s\" ?\n",
(char*) &entry2->data.fourcc_data, (char*) &entry1->data.fourcc_data);
return (entry2->data.fourcc_data == entry1->data.fourcc_data);
default:
break;
}
break;
- case GST_PROPS_INT_ID:
+ case GST_PROPS_INT_TYPE:
switch (entry2->propstype) {
/* b <---> a - d */
- case GST_PROPS_INT_RANGE_ID:
- GST_DEBUG(GST_CAT_PROPERTIES,"%d <= %d <= %d ?",entry2->data.int_range_data.min,
+ case GST_PROPS_INT_RANGE_TYPE:
+ GST_DEBUG(GST_CAT_PROPERTIES,"%d <= %d <= %d ?\n",entry2->data.int_range_data.min,
entry1->data.int_data,entry2->data.int_range_data.max);
return (entry2->data.int_range_data.min <= entry1->data.int_data &&
entry2->data.int_range_data.max >= entry1->data.int_data);
/* b <---> a */
- case GST_PROPS_INT_ID:
- GST_DEBUG(GST_CAT_PROPERTIES,"%d == %d ?",entry1->data.int_data,entry2->data.int_data);
+ case GST_PROPS_INT_TYPE:
+ GST_DEBUG(GST_CAT_PROPERTIES,"%d == %d ?\n",entry1->data.int_data,entry2->data.int_data);
return (entry2->data.int_data == entry1->data.int_data);
default:
break;
}
break;
- case GST_PROPS_FLOAT_ID:
+ case GST_PROPS_FLOAT_TYPE:
switch (entry2->propstype) {
/* b <---> a - d */
- case GST_PROPS_FLOAT_RANGE_ID:
+ case GST_PROPS_FLOAT_RANGE_TYPE:
return (entry2->data.float_range_data.min <= entry1->data.float_data &&
entry2->data.float_range_data.max >= entry1->data.float_data);
/* b <---> a */
- case GST_PROPS_FLOAT_ID:
+ case GST_PROPS_FLOAT_TYPE:
return (entry2->data.float_data == entry1->data.float_data);
default:
break;
}
break;
- case GST_PROPS_BOOL_ID:
+ case GST_PROPS_BOOL_TYPE:
switch (entry2->propstype) {
/* t <---> t */
- case GST_PROPS_BOOL_ID:
+ case GST_PROPS_BOOL_TYPE:
return (entry2->data.bool_data == entry1->data.bool_data);
default:
break;
}
- case GST_PROPS_STRING_ID:
+ case GST_PROPS_STRING_TYPE:
switch (entry2->propstype) {
/* t <---> t */
- case GST_PROPS_STRING_ID:
- GST_DEBUG(GST_CAT_PROPERTIES,"\"%s\" <--> \"%s\" ?",
+ case GST_PROPS_STRING_TYPE:
+ GST_DEBUG(GST_CAT_PROPERTIES,"\"%s\" <--> \"%s\" ?\n",
entry2->data.string_data.string, entry1->data.string_data.string);
return (!strcmp (entry2->data.string_data.string, entry1->data.string_data.string));
default:
/* try to move the ranges and lists first */
switch (entry2->propstype) {
- case GST_PROPS_INT_RANGE_ID:
- case GST_PROPS_FLOAT_RANGE_ID:
- case GST_PROPS_LIST_ID:
+ case GST_PROPS_INT_RANGE_TYPE:
+ case GST_PROPS_FLOAT_RANGE_TYPE:
+ case GST_PROPS_LIST_TYPE:
{
GstPropsEntry *temp;
}
switch (entry1->propstype) {
- case GST_PROPS_LIST_ID:
+ case GST_PROPS_LIST_TYPE:
{
GList *entrylist = entry1->data.list_data.entries;
GList *intersection = NULL;
intersectentry = gst_props_entry_intersect (entry2, entry);
if (intersectentry) {
- if (intersectentry->propstype == GST_PROPS_LIST_ID) {
+ if (intersectentry->propstype == GST_PROPS_LIST_TYPE) {
intersection = g_list_concat (intersection, intersectentry->data.list_data.entries);
/* set the list to NULL because the entries are concatenated to the above
* list and we don't want to free them */
else {
result = gst_props_alloc_entry ();
result->propid = entry1->propid;
- result->propstype = GST_PROPS_LIST_ID;
+ result->propstype = GST_PROPS_LIST_TYPE;
result->data.list_data.entries = g_list_reverse (intersection);
}
}
return result;
}
- case GST_PROPS_INT_RANGE_ID:
+ case GST_PROPS_INT_RANGE_TYPE:
switch (entry2->propstype) {
/* a - b <---> a - c */
- case GST_PROPS_INT_RANGE_ID:
+ case GST_PROPS_INT_RANGE_TYPE:
{
gint lower = MAX (entry1->data.int_range_data.min, entry2->data.int_range_data.min);
gint upper = MIN (entry1->data.int_range_data.max, entry2->data.int_range_data.max);
result->propid = entry1->propid;
if (lower == upper) {
- result->propstype = GST_PROPS_INT_ID;
+ result->propstype = GST_PROPS_INT_TYPE;
result->data.int_data = lower;
}
else {
- result->propstype = GST_PROPS_INT_RANGE_ID;
+ result->propstype = GST_PROPS_INT_RANGE_TYPE;
result->data.int_range_data.min = lower;
result->data.int_range_data.max = upper;
}
}
break;
}
- case GST_PROPS_LIST_ID:
+ case GST_PROPS_LIST_TYPE:
{
GList *entries = entry2->data.list_data.entries;
result = gst_props_alloc_entry ();
result->propid = entry1->propid;
- result->propstype = GST_PROPS_LIST_ID;
+ result->propstype = GST_PROPS_LIST_TYPE;
result->data.list_data.entries = NULL;
while (entries) {
GstPropsEntry * this = (GstPropsEntry *)entries->data;
- if (this->propstype != GST_PROPS_INT_ID) {
+ if (this->propstype != GST_PROPS_INT_TYPE) {
/* no hope, this list doesn't even contain ints! */
gst_props_entry_destroy (result);
result = NULL;
}
break;
}
- case GST_PROPS_INT_ID:
+ case GST_PROPS_INT_TYPE:
{
if (entry1->data.int_range_data.min <= entry2->data.int_data &&
entry1->data.int_range_data.max >= entry2->data.int_data) {
break;
}
break;
- case GST_PROPS_FLOAT_RANGE_ID:
+ case GST_PROPS_FLOAT_RANGE_TYPE:
switch (entry2->propstype) {
/* a - b <---> a - c */
- case GST_PROPS_FLOAT_RANGE_ID:
+ case GST_PROPS_FLOAT_RANGE_TYPE:
{
gfloat lower = MAX (entry1->data.float_range_data.min, entry2->data.float_range_data.min);
gfloat upper = MIN (entry1->data.float_range_data.max, entry2->data.float_range_data.max);
result->propid = entry1->propid;
if (lower == upper) {
- result->propstype = GST_PROPS_FLOAT_ID;
+ result->propstype = GST_PROPS_FLOAT_TYPE;
result->data.float_data = lower;
}
else {
- result->propstype = GST_PROPS_FLOAT_RANGE_ID;
+ result->propstype = GST_PROPS_FLOAT_RANGE_TYPE;
result->data.float_range_data.min = lower;
result->data.float_range_data.max = upper;
}
}
break;
}
- case GST_PROPS_FLOAT_ID:
+ case GST_PROPS_FLOAT_TYPE:
if (entry1->data.float_range_data.min <= entry2->data.float_data &&
entry1->data.float_range_data.max >= entry2->data.float_data) {
result = gst_props_entry_copy (entry2);
break;
}
break;
- case GST_PROPS_FOURCC_ID:
+ case GST_PROPS_FOURCC_TYPE:
switch (entry2->propstype) {
/* b <---> a */
- case GST_PROPS_FOURCC_ID:
+ case GST_PROPS_FOURCC_TYPE:
if (entry1->data.fourcc_data == entry2->data.fourcc_data)
result = gst_props_entry_copy (entry1);
default:
break;
}
break;
- case GST_PROPS_INT_ID:
+ case GST_PROPS_INT_TYPE:
switch (entry2->propstype) {
/* b <---> a */
- case GST_PROPS_INT_ID:
+ case GST_PROPS_INT_TYPE:
if (entry1->data.int_data == entry2->data.int_data)
result = gst_props_entry_copy (entry1);
default:
break;
}
break;
- case GST_PROPS_FLOAT_ID:
+ case GST_PROPS_FLOAT_TYPE:
switch (entry2->propstype) {
/* b <---> a */
- case GST_PROPS_FLOAT_ID:
+ case GST_PROPS_FLOAT_TYPE:
if (entry1->data.float_data == entry2->data.float_data)
result = gst_props_entry_copy (entry1);
default:
break;
}
break;
- case GST_PROPS_BOOL_ID:
+ case GST_PROPS_BOOL_TYPE:
switch (entry2->propstype) {
/* t <---> t */
- case GST_PROPS_BOOL_ID:
+ case GST_PROPS_BOOL_TYPE:
if (entry1->data.bool_data == entry2->data.bool_data)
result = gst_props_entry_copy (entry1);
default:
break;
}
- case GST_PROPS_STRING_ID:
+ case GST_PROPS_STRING_TYPE:
switch (entry2->propstype) {
/* t <---> t */
- case GST_PROPS_STRING_ID:
+ case GST_PROPS_STRING_TYPE:
if (!strcmp (entry1->data.string_data.string, entry2->data.string_data.string))
result = gst_props_entry_copy (entry1);
default:
while (entries) {
GstPropsEntry *entry = (GstPropsEntry *) entries->data;
- if (entry->propstype == GST_PROPS_LIST_ID) {
+ if (entry->propstype == GST_PROPS_LIST_TYPE) {
GList *list_entries = entry->data.list_data.entries;
while (list_entries) {
gchar *str;
switch (entry->propstype) {
- case GST_PROPS_INT_ID:
+ case GST_PROPS_INT_TYPE:
subtree = xmlNewChild (parent, NULL, "int", NULL);
xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
str = g_strdup_printf ("%d", entry->data.int_data);
xmlNewProp (subtree, "value", str);
g_free(str);
break;
- case GST_PROPS_INT_RANGE_ID:
+ case GST_PROPS_INT_RANGE_TYPE:
subtree = xmlNewChild (parent, NULL, "range", NULL);
xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
str = g_strdup_printf ("%d", entry->data.int_range_data.min);
xmlNewProp (subtree, "max", str);
g_free(str);
break;
- case GST_PROPS_FLOAT_ID:
+ case GST_PROPS_FLOAT_TYPE:
subtree = xmlNewChild (parent, NULL, "float", NULL);
xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
str = g_strdup_printf ("%f", entry->data.float_data);
xmlNewProp (subtree, "value", str);
g_free(str);
break;
- case GST_PROPS_FLOAT_RANGE_ID:
+ case GST_PROPS_FLOAT_RANGE_TYPE:
subtree = xmlNewChild (parent, NULL, "floatrange", NULL);
xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
str = g_strdup_printf ("%f", entry->data.float_range_data.min);
xmlNewProp (subtree, "max", str);
g_free(str);
break;
- case GST_PROPS_FOURCC_ID:
+ case GST_PROPS_FOURCC_TYPE:
str = g_strdup_printf ("%4.4s", (gchar *)&entry->data.fourcc_data);
xmlAddChild (parent, xmlNewComment (str));
g_free(str);
xmlNewProp (subtree, "hexvalue", str);
g_free(str);
break;
- case GST_PROPS_BOOL_ID:
+ case GST_PROPS_BOOL_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"));
break;
- case GST_PROPS_STRING_ID:
+ case GST_PROPS_STRING_TYPE:
subtree = xmlNewChild (parent, NULL, "string", NULL);
xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
xmlNewProp (subtree, "value", entry->data.string_data.string);
GstPropsEntry *entry = (GstPropsEntry *) proplist->data;
switch (entry->propstype) {
- case GST_PROPS_LIST_ID:
+ case GST_PROPS_LIST_TYPE:
subtree = xmlNewChild (parent, NULL, "list", NULL);
xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
g_list_foreach (entry->data.list_data.entries, (GFunc) gst_props_save_thyself_func, subtree);
entry = gst_props_alloc_entry ();
if (!strcmp(field->name, "int")) {
- entry->propstype = GST_PROPS_INT_ID;
+ entry->propstype = GST_PROPS_INT_TYPE;
prop = xmlGetProp(field, "name");
entry->propid = g_quark_from_string (prop);
g_free (prop);
g_free (prop);
}
else if (!strcmp(field->name, "range")) {
- entry->propstype = GST_PROPS_INT_RANGE_ID;
+ entry->propstype = GST_PROPS_INT_RANGE_TYPE;
prop = xmlGetProp(field, "name");
entry->propid = g_quark_from_string (prop);
g_free (prop);
g_free (prop);
}
else if (!strcmp(field->name, "float")) {
- entry->propstype = GST_PROPS_FLOAT_ID;
+ entry->propstype = GST_PROPS_FLOAT_TYPE;
prop = xmlGetProp(field, "name");
entry->propid = g_quark_from_string (prop);
g_free (prop);
g_free (prop);
}
else if (!strcmp(field->name, "floatrange")) {
- entry->propstype = GST_PROPS_FLOAT_RANGE_ID;
+ entry->propstype = GST_PROPS_FLOAT_RANGE_TYPE;
prop = xmlGetProp(field, "name");
entry->propid = g_quark_from_string (prop);
g_free (prop);
g_free (prop);
}
else if (!strcmp(field->name, "boolean")) {
- entry->propstype = GST_PROPS_BOOL_ID;
+ entry->propstype = GST_PROPS_BOOL_TYPE;
prop = xmlGetProp(field, "name");
entry->propid = g_quark_from_string (prop);
g_free (prop);
g_free (prop);
}
else if (!strcmp(field->name, "fourcc")) {
- entry->propstype = GST_PROPS_FOURCC_ID;
+ entry->propstype = GST_PROPS_FOURCC_TYPE;
prop = xmlGetProp(field, "name");
entry->propid = g_quark_from_string (prop);
g_free (prop);
g_free (prop);
}
else if (!strcmp(field->name, "string")) {
- entry->propstype = GST_PROPS_STRING_ID;
+ entry->propstype = GST_PROPS_STRING_TYPE;
prop = xmlGetProp(field, "name");
entry->propid = g_quark_from_string (prop);
g_free (prop);
prop = xmlGetProp (field, "name");
entry->propid = g_quark_from_string (prop);
g_free (prop);
- entry->propstype = GST_PROPS_LIST_ID;
+ entry->propstype = GST_PROPS_LIST_TYPE;
entry->data.list_data.entries = NULL;
while (subfield) {
#include <gst/gstconfig.h>
-#include <glib.h>
+#include <glib-object.h>
typedef struct _GstProps GstProps;
+extern GType _gst_props_type;
+
+#define GST_TYPE_PROPS (_get_props_type)
typedef enum {
- GST_PROPS_END_ID = 0,
- GST_PROPS_INT_ID,
- GST_PROPS_FLOAT_ID,
- GST_PROPS_FOURCC_ID,
- GST_PROPS_BOOL_ID,
- GST_PROPS_STRING_ID,
+ GST_PROPS_END_TYPE = 0,
+
+ GST_PROPS_INVALID_TYPE,
+
+ GST_PROPS_INT_TYPE,
+ GST_PROPS_FLOAT_TYPE,
+ GST_PROPS_FOURCC_TYPE,
+ GST_PROPS_BOOL_TYPE,
+ GST_PROPS_STRING_TYPE,
- GST_PROPS_VAR_ID, /* after this marker start the variable properties */
+ GST_PROPS_VAR_TYPE, /* after this marker start the variable properties */
- GST_PROPS_LIST_ID,
- GST_PROPS_FLOAT_RANGE_ID,
- GST_PROPS_INT_RANGE_ID,
+ GST_PROPS_LIST_TYPE,
+ GST_PROPS_FLOAT_RANGE_TYPE,
+ GST_PROPS_INT_RANGE_TYPE,
- GST_PROPS_LAST_ID = GST_PROPS_END_ID + 16,
-} GstPropsId;
+ GST_PROPS_LAST_TYPE = GST_PROPS_END_TYPE + 16,
+} GstPropsType;
#define GST_MAKE_FOURCC(a,b,c,d) ((a)|(b)<<8|(c)<<16|(d)<<24)
#define GST_STR_FOURCC(f) (((f)[0])|((f)[1]<<8)|((f)[2]<<16)|((f)[3]<<24))
-#define GST_PROPS_LIST(a...) GST_PROPS_LIST_ID,##a,NULL
-#define GST_PROPS_INT(a) GST_PROPS_INT_ID,(a)
-#define GST_PROPS_INT_RANGE(a,b) GST_PROPS_INT_RANGE_ID,(a),(b)
-#define GST_PROPS_FLOAT(a) GST_PROPS_FLOAT_ID,(a)
-#define GST_PROPS_FLOAT_RANGE(a,b) GST_PROPS_FLOAT_RANGE_ID,(a),(b)
-#define GST_PROPS_FOURCC(a) GST_PROPS_FOURCC_ID,(a)
-#define GST_PROPS_BOOLEAN(a) GST_PROPS_BOOL_ID,(a)
-#define GST_PROPS_STRING(a) GST_PROPS_STRING_ID,(a)
+#define GST_PROPS_LIST(a...) GST_PROPS_LIST_TYPE,##a,NULL
+#define GST_PROPS_INT(a) GST_PROPS_INT_TYPE,(a)
+#define GST_PROPS_INT_RANGE(a,b) GST_PROPS_INT_RANGE_TYPE,(a),(b)
+#define GST_PROPS_FLOAT(a) GST_PROPS_FLOAT_TYPE,(a)
+#define GST_PROPS_FLOAT_RANGE(a,b) GST_PROPS_FLOAT_RANGE_TYPE,(a),(b)
+#define GST_PROPS_FOURCC(a) GST_PROPS_FOURCC_TYPE,(a)
+#define GST_PROPS_BOOLEAN(a) GST_PROPS_BOOL_TYPE,(a)
+#define GST_PROPS_STRING(a) GST_PROPS_STRING_TYPE,(a)
#define GST_PROPS_INT_POSITIVE GST_PROPS_INT_RANGE(0,G_MAXINT)
#define GST_PROPS_INT_NEGATIVE GST_PROPS_INT_RANGE(G_MININT,0)
#define GST_PROPS_INT_ANY GST_PROPS_INT_RANGE(G_MININT,G_MAXINT)
+typedef struct _GstPropsEntry GstPropsEntry;
struct _GstProps {
gint refcount;
- GMutex *lock;
gboolean fixed;
GList *properties; /* real properties for this property */
};
/* initialize the subsystem */
-void _gst_props_initialize (void);
+void _gst_props_initialize (void);
+
+GstProps* gst_props_new (const gchar *firstname, ...);
+GstProps* gst_props_newv (const gchar *firstname, va_list var_args);
+
+void gst_props_unref (GstProps *props);
+void gst_props_ref (GstProps *props);
+void gst_props_destroy (GstProps *props);
-GstProps* gst_props_new (const gchar *firstname, ...);
-GstProps* gst_props_newv (const gchar *firstname, va_list var_args);
+void gst_props_debug (GstProps *props);
-void gst_props_unref (GstProps *props);
-void gst_props_ref (GstProps *props);
-void gst_props_destroy (GstProps *props);
+GstProps* gst_props_copy (GstProps *props);
+GstProps* gst_props_copy_on_write (GstProps *props);
-void gst_props_debug (GstProps *props);
+GstProps* gst_props_merge (GstProps *props, GstProps *tomerge);
-GstProps* gst_props_copy (GstProps *props);
-GstProps* gst_props_copy_on_write (GstProps *props);
+gboolean gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops);
+GstProps* gst_props_intersect (GstProps *props1, GstProps *props2);
+GList* gst_props_normalize (GstProps *props);
-GstProps* gst_props_merge (GstProps *props, GstProps *tomerge);
+GstProps* gst_props_set (GstProps *props, const gchar *name, ...);
+gboolean gst_props_get (GstProps *props, gchar *first_name, ...);
-gboolean gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops);
-GstProps* gst_props_intersect (GstProps *props1, GstProps *props2);
-GList* gst_props_normalize (GstProps *props);
+gboolean gst_props_has_property (GstProps *props, const gchar *name);
+gboolean gst_props_has_property_typed (GstProps *props, const gchar *name, GstPropsType type);
+gboolean gst_props_has_fixed_property (GstProps *props, const gchar *name);
-GstProps* gst_props_set (GstProps *props, const gchar *name, ...);
-gboolean gst_props_has_property (GstProps *props, const gchar *name);
+/* working with props entries */
+const GstPropsEntry* gst_props_get_entry (GstProps *props, const gchar *name);
+GstPropsType gst_props_entry_get_type (const GstPropsEntry *entry);
+const gchar* gst_props_entry_get_name (const GstPropsEntry *entry);
+gboolean gst_props_entry_is_fixed (const GstPropsEntry *entry);
+
+gboolean gst_props_entry_get (const GstPropsEntry *props, ...);
+
+gboolean gst_props_entry_get_int (const GstPropsEntry *entry, gint *val);
+gboolean gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val);
+gboolean gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val);
+gboolean gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val);
+gboolean gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val);
+gboolean gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max);
+gboolean gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat *max);
+gboolean gst_props_entry_get_list (const GstPropsEntry *entry, const GList **val);
-gint gst_props_get_int (GstProps *props, const gchar *name);
-gfloat gst_props_get_float (GstProps *props, const gchar *name);
-gulong gst_props_get_fourcc_int (GstProps *props, const gchar *name);
-gboolean gst_props_get_boolean (GstProps *props, const gchar *name);
-const gchar* gst_props_get_string (GstProps *props, const gchar *name);
#ifndef GST_DISABLE_LOADSAVE
-xmlNodePtr gst_props_save_thyself (GstProps *props, xmlNodePtr parent);
-GstProps* gst_props_load_thyself (xmlNodePtr parent);
+xmlNodePtr gst_props_save_thyself (GstProps *props, xmlNodePtr parent);
+GstProps* gst_props_load_thyself (xmlNodePtr parent);
#endif
+
+
#endif /* __GST_PROPS_H__ */
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2000 Wim Taymans <wtay@chello.be>
- *
- * gstpropsprivate.h: Private header for properties subsystem
- *
- * 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_PROPS_PRIV_H__
-#define __GST_PROPS_PRIV_H__
-
-#include <gst/gstprops.h>
-
-#define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_ID)
-
-typedef struct _GstPropsEntry GstPropsEntry;
-
-struct _GstPropsEntry {
- GQuark propid;
- GstPropsId propstype;
-
- union {
- /* flat values */
- gboolean bool_data;
- guint32 fourcc_data;
- gint int_data;
- gfloat float_data;
-
- /* structured values */
- struct {
- GList *entries;
- } list_data;
- struct {
- gchar *string;
- } string_data;
- struct {
- gint min;
- gint max;
- } int_range_data;
- struct {
- gfloat min;
- gfloat max;
- } float_range_data;
- } data;
-};
-
-#endif /* __GST_PROPS_PRIV_H__ */
static GstBufferPool* gst_queue_get_bufferpool (GstPad *pad);
static void gst_queue_locked_flush (GstQueue *queue);
-static void gst_queue_flush (GstQueue *queue);
static GstElementStateReturn gst_queue_change_state (GstElement *element);
}
static void
-gst_queue_flush (GstQueue *queue)
-{
- g_mutex_lock (queue->qlock);
- gst_queue_locked_flush (queue);
- g_mutex_unlock (queue->qlock);
-}
-
-
-static void
gst_queue_chain (GstPad *pad, GstBuffer *buf)
{
GstQueue *queue;
return;
}
else {
- gst_element_info (GST_ELEMENT (queue), "waiting for the app to restart source pad elements");
+ g_print ("%s: waiting for the app to restart source pad elements\n", GST_ELEMENT_NAME (queue));
}
}
goto restart;
}
else {
- gst_element_info (GST_ELEMENT (queue), "waiting for the app to restart sink pad elements");
+ g_print ("%s: waiting for the app to restart source pad elements\n", GST_ELEMENT_NAME (queue));
}
}
#include "gst_private.h"
+#include "gstsystemclock.h"
#include "gstscheduler.h"
static void gst_scheduler_class_init (GstSchedulerClass *klass);
static void
gst_scheduler_init (GstScheduler *sched)
{
+ sched->clock_providers = NULL;
+ sched->clock_receivers = NULL;
+ sched->schedulers = NULL;
+ sched->state = GST_SCHEDULER_STATE_NONE;
+ sched->parent = NULL;
+ sched->parent_sched = NULL;
+ sched->clock = NULL;
}
/**
g_return_if_fail (GST_IS_SCHEDULER (sched));
g_return_if_fail (GST_IS_ELEMENT (element));
+ if (element->getclockfunc) {
+ sched->clock_providers = g_list_prepend (sched->clock_providers, element);
+ }
+ if (element->setclockfunc) {
+ sched->clock_receivers = g_list_prepend (sched->clock_receivers, element);
+ }
+
if (CLASS (sched)->add_element)
CLASS (sched)->add_element (sched, element);
}
/**
+ * gst_scheduler_remove_element:
+ * @sched: the schedulerr
+ * @element: the element to remov
+ *
+ * Remove an element from the schedulerr.
+ */
+void
+gst_scheduler_remove_element (GstScheduler *sched, GstElement *element)
+{
+ GList *pads;
+
+ g_return_if_fail (GST_IS_SCHEDULER (sched));
+ g_return_if_fail (GST_IS_ELEMENT (element));
+
+ sched->clock_providers = g_list_remove (sched->clock_providers, element);
+ sched->clock_receivers = g_list_remove (sched->clock_receivers, element);
+
+ if (CLASS (sched)->remove_element)
+ CLASS (sched)->remove_element (sched, element);
+
+ for (pads = element->pads; pads; pads = pads->next) {
+ GstPad *pad = GST_PAD (pads->data);
+
+ if (GST_IS_REAL_PAD (pad)) {
+ gst_pad_unset_sched (GST_PAD (pads->data));
+ }
+ }
+}
+
+/**
* gst_scheduler_state_transition:
* @sched: the scheduler
* @element: the element with the state transition
g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_STATE_FAILURE);
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
+ if (element == sched->parent && sched->parent_sched == NULL) {
+
+ switch (transition) {
+ case GST_STATE_READY_TO_PAUSED:
+ {
+ GstClock *clock = gst_scheduler_get_clock (sched);
+
+ if (clock)
+ gst_clock_reset (clock);
+
+ sched->current_clock = clock;
+ break;
+ }
+ case GST_STATE_PAUSED_TO_PLAYING:
+ {
+ gst_scheduler_set_clock (sched, sched->current_clock);
+ if (sched->current_clock)
+ gst_clock_activate (sched->current_clock, TRUE);
+ break;
+ }
+ case GST_STATE_PLAYING_TO_PAUSED:
+ if (sched->current_clock)
+ gst_clock_activate (sched->current_clock, FALSE);
+ break;
+ }
+ }
+
if (CLASS (sched)->state_transition)
return CLASS (sched)->state_transition (sched, element, transition);
return GST_STATE_SUCCESS;
}
-/**
- * gst_scheduler_remove_element:
- * @sched: the schedulerr
- * @element: the element to remov
- *
- * Remove an element from the schedulerr.
- */
void
-gst_scheduler_remove_element (GstScheduler *sched, GstElement *element)
+gst_scheduler_add_scheduler (GstScheduler *sched, GstScheduler *sched2)
{
- GList *pads;
-
g_return_if_fail (GST_IS_SCHEDULER (sched));
- g_return_if_fail (GST_IS_ELEMENT (element));
+ g_return_if_fail (GST_IS_SCHEDULER (sched2));
- if (CLASS (sched)->remove_element)
- CLASS (sched)->remove_element (sched, element);
-
- for (pads = element->pads; pads; pads = pads->next) {
- GstPad *pad = GST_PAD (pads->data);
-
- if (GST_IS_REAL_PAD (pad)) {
- gst_pad_unset_sched (GST_PAD (pads->data));
- }
- }
+ sched->schedulers = g_list_prepend (sched->schedulers, sched2);
+ sched2->parent_sched = sched;
+
+ if (CLASS (sched)->add_scheduler)
+ CLASS (sched)->add_scheduler (sched, sched2);
}
+void
+gst_scheduler_remove_scheduler (GstScheduler *sched, GstScheduler *sched2)
+{
+ g_return_if_fail (GST_IS_SCHEDULER (sched));
+ g_return_if_fail (GST_IS_SCHEDULER (sched2));
+
+ sched->schedulers = g_list_remove (sched->schedulers, sched2);
+ sched2->parent_sched = NULL;
+
+ if (CLASS (sched)->remove_scheduler)
+ CLASS (sched)->remove_scheduler (sched, sched2);
+}
+
+
/**
* gst_scheduler_lock_element:
* @sched: the scheduler
return FALSE;
}
+GstClock*
+gst_scheduler_get_clock (GstScheduler *sched)
+{
+ GstClock *clock = NULL;
+
+ if (GST_FLAG_IS_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK)) {
+ clock = sched->clock;
+ }
+ else {
+ if (sched->schedulers) {
+ GList *schedulers = sched->schedulers;
+
+ while (schedulers) {
+ GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
+
+ clock = gst_scheduler_get_clock (scheduler);
+ if (clock)
+ break;
+
+ schedulers = g_list_next (schedulers);
+ }
+ }
+ if (!clock && sched->clock_providers) {
+ clock = gst_element_get_clock (GST_ELEMENT (sched->clock_providers->data));
+ }
+ if (!clock && sched->parent_sched == NULL) {
+ clock = gst_system_clock_obtain ();
+ }
+ }
+
+ return clock;
+}
+
+void
+gst_scheduler_use_clock (GstScheduler *sched, GstClock *clock)
+{
+ g_return_if_fail (sched != NULL);
+ g_return_if_fail (GST_IS_SCHEDULER (sched));
+
+ GST_FLAG_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
+ sched->clock = clock;
+}
+
+void
+gst_scheduler_set_clock (GstScheduler *sched, GstClock *clock)
+{
+ GList *receivers;
+ GList *schedulers;
+
+ g_return_if_fail (sched != NULL);
+ g_return_if_fail (GST_IS_SCHEDULER (sched));
+
+ receivers = sched->clock_receivers;
+ schedulers = sched->schedulers;
+
+ sched->current_clock = clock;
+
+ while (receivers) {
+ GstElement *element = GST_ELEMENT (receivers->data);
+
+ gst_element_set_clock (element, clock);
+ receivers = g_list_next (receivers);
+ }
+ while (schedulers) {
+ GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
+
+ gst_scheduler_set_clock (scheduler, clock);
+ schedulers = g_list_next (schedulers);
+ }
+}
+
+void
+gst_scheduler_auto_clock (GstScheduler *sched)
+{
+ g_return_if_fail (sched != NULL);
+ g_return_if_fail (GST_IS_SCHEDULER (sched));
+
+ GST_FLAG_UNSET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
+ sched->clock = NULL;
+}
+
+/**
+ * gst_scheduler_clock_wait:
+ * @sched: the scheduler
+ *
+ * Perform one iteration on the schedulerr.
+ *
+ * Returns: a boolean indicating something usefull has happened.
+ */
+GstClockReturn
+gst_scheduler_clock_wait (GstScheduler *sched, GstElement *element, GstClock *clock, GstClockTime time)
+{
+ g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_CLOCK_ERROR);
+
+ if (CLASS (sched)->clock_wait)
+ return CLASS (sched)->clock_wait (sched, element, clock, time);
+
+ return GST_CLOCK_TIMEOUT;
+}
+
/**
* gst_scheduler_iterate:
* @sched: the scheduler
#define GST_IS_SCHEDULER_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SCHEDULER))
+typedef enum {
+ /* this scheduler works with a fixed clock */
+ GST_SCHEDULER_FLAG_FIXED_CLOCK = GST_OBJECT_FLAG_LAST,
+
+ /* padding */
+ GST_SCHEDULER_FLAG_LAST = GST_OBJECT_FLAG_LAST + 4,
+} GstSchedulerFlags;
#define GST_SCHEDULER_PARENT(sched) ((sched)->parent)
#define GST_SCHEDULER_STATE(sched) ((sched)->state)
} GstSchedulerState;
struct _GstScheduler {
- GstObject object;
+ GstObject object;
+
+ GstElement *parent;
+ GstScheduler *parent_sched;
- GstElement *parent;
+ GstSchedulerState state;
+ GstClock *clock;
+ GstClock *current_clock;
- GstSchedulerState state;
+ GList *clock_providers;
+ GList *clock_receivers;
+
+ GList *schedulers;
};
struct _GstSchedulerClass {
void (*reset) (GstScheduler *sched);
void (*add_element) (GstScheduler *sched, GstElement *element);
void (*remove_element) (GstScheduler *sched, GstElement *element);
+ void (*add_scheduler) (GstScheduler *sched, GstScheduler *sched2);
+ void (*remove_scheduler) (GstScheduler *sched, GstScheduler *sched2);
GstElementStateReturn (*state_transition) (GstScheduler *sched, GstElement *element, gint transition);
void (*lock_element) (GstScheduler *sched, GstElement *element);
void (*unlock_element) (GstScheduler *sched, GstElement *element);
void (*pad_connect) (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
void (*pad_disconnect) (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
void (*pad_select) (GstScheduler *sched, GList *padlist);
+ GstClockReturn (*clock_wait) (GstScheduler *sched, GstElement *element,
+ GstClock *clock, GstClockTime time);
GstSchedulerState (*iterate) (GstScheduler *sched);
/* for debugging */
void (*show) (GstScheduler *sched);
void gst_scheduler_reset (GstScheduler *sched);
void gst_scheduler_add_element (GstScheduler *sched, GstElement *element);
void gst_scheduler_remove_element (GstScheduler *sched, GstElement *element);
+void gst_scheduler_add_scheduler (GstScheduler *sched, GstScheduler *sched2);
+void gst_scheduler_remove_scheduler (GstScheduler *sched, GstScheduler *sched2);
GstElementStateReturn gst_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition);
void gst_scheduler_lock_element (GstScheduler *sched, GstElement *element);
void gst_scheduler_unlock_element (GstScheduler *sched, GstElement *element);
void gst_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
void gst_scheduler_pad_disconnect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
GstPad* gst_scheduler_pad_select (GstScheduler *sched, GList *padlist);
+GstClock* gst_scheduler_get_clock (GstScheduler *sched);
+GstClock* gst_scheduler_get_clock (GstScheduler *sched);
+GstClockReturn gst_scheduler_clock_wait (GstScheduler *sched, GstElement *element,
+ GstClock *clock, GstClockTime time);
gboolean gst_scheduler_iterate (GstScheduler *sched);
+void gst_scheduler_use_clock (GstScheduler *sched, GstClock *clock);
+void gst_scheduler_set_clock (GstScheduler *sched, GstClock *clock);
+GstClock* gst_scheduler_get_clock (GstScheduler *sched);
+void gst_scheduler_auto_clock (GstScheduler *sched);
+
void gst_scheduler_show (GstScheduler *sched);
/*
static void gst_system_clock_class_init (GstSystemClockClass *klass);
static void gst_system_clock_init (GstSystemClock *clock);
-static void gst_system_clock_activate (GstClock *clock, gboolean active);
-static void gst_system_clock_reset (GstClock *clock);
-static void gst_system_clock_set_time (GstClock *clock, GstClockTime time);
-static GstClockTime gst_system_clock_get_time (GstClock *clock);
-static GstClockReturn gst_system_clock_wait (GstClock *clock, GstClockTime time);
+static GstClockTime gst_system_clock_get_internal_time (GstClock *clock);
static guint64 gst_system_clock_get_resolution (GstClock *clock);
parent_class = g_type_class_ref (GST_TYPE_CLOCK);
- gstclock_class->activate = gst_system_clock_activate;
- gstclock_class->reset = gst_system_clock_reset;
- gstclock_class->set_time = gst_system_clock_set_time;
- gstclock_class->get_time = gst_system_clock_get_time;
- gstclock_class->wait = gst_system_clock_wait;
+ gstclock_class->get_internal_time = gst_system_clock_get_internal_time;
gstclock_class->get_resolution = gst_system_clock_get_resolution;
}
return _the_system_clock;
}
-static void
-gst_system_clock_activate (GstClock *clock, gboolean active)
-{
- GTimeVal timeval;
- GstSystemClock *sys_clock = GST_SYSTEM_CLOCK (clock);
-
- g_get_current_time (&timeval);
- GST_LOCK (clock);
- if (active) {
- sys_clock->absolute_start = GST_TIMEVAL_TO_TIME (timeval) - sys_clock->current_time;;
- }
- else {
- sys_clock->current_time = GST_TIMEVAL_TO_TIME (timeval) - sys_clock->absolute_start;
- }
- GST_UNLOCK (clock);
-}
-
-static void
-gst_system_clock_set_time (GstClock *clock, GstClockTime time)
-{
- GTimeVal timeval;
- GstSystemClock *sys_clock = GST_SYSTEM_CLOCK (clock);
-
- g_get_current_time (&timeval);
-
- GST_LOCK (clock);
- sys_clock->absolute_start = GST_TIMEVAL_TO_TIME (timeval) - time;
- sys_clock->current_time = time;
- GST_UNLOCK (clock);
-}
-
-static void
-gst_system_clock_reset (GstClock *clock)
-{
- gst_system_clock_set_time (clock, 0LL);
-}
-
static GstClockTime
-gst_system_clock_get_time (GstClock *clock)
-{
- GstSystemClock *sys_clock = GST_SYSTEM_CLOCK (clock);
- GstClockTime res;
-
- if (!clock->active) {
- GST_LOCK (clock);
- res = sys_clock->current_time;
- }
- else {
- GTimeVal timeval;
-
- g_get_current_time (&timeval);
-
- GST_LOCK (clock);
- res = GST_TIMEVAL_TO_TIME (timeval) - sys_clock->absolute_start;
- }
- GST_UNLOCK (clock);
-
- return res;
-}
-
-static GstClockReturn
-gst_system_clock_wait (GstClock *clock, GstClockTime time)
+gst_system_clock_get_internal_time (GstClock *clock)
{
- GstClockTime target;
GTimeVal timeval;
- GCond *cond = g_cond_new ();
- GstSystemClock *sys_clock = GST_SYSTEM_CLOCK (clock);
- GstClockReturn ret;
-
- GST_LOCK (clock);
- target = time + sys_clock->absolute_start;
-
- timeval.tv_usec = target % 1000000;
- timeval.tv_sec = target / 1000000;
-
- g_cond_timed_wait (cond, GST_GET_LOCK (clock), &timeval);
- GST_UNLOCK (clock);
-
- ret = GST_CLOCK_TIMEOUT;
-
- g_cond_free (cond);
-
- return ret;
+ g_get_current_time (&timeval);
+ return GST_TIMEVAL_TO_TIME (timeval);
}
static guint64
struct _GstSystemClock {
GstClock clock;
-
- GstClockTime absolute_start;
- GstClockTime current_time;
};
struct _GstSystemClockClass {
/* we're a manager by default */
GST_FLAG_SET (thread, GST_BIN_FLAG_MANAGER);
+ GST_FLAG_SET (thread, GST_BIN_SELF_SCHEDULABLE);
schedname = gst_schedulerfactory_get_default_name ();
}
/**
- * gst_util_get_widget_property:
- * @object: the object to query
- * @argname: the name of the argument
- *
- * Retrieves a property of an object as a widget.
- *
- * Returns: the property of the object
- */
-/* COMMENTED OUT BECAUSE WE HAVE NO MORE gtk.h
-GtkWidget*
-gst_util_get_widget_property (GObject *object, const gchar *argname)
-{
- GtkArg arg;
-
- arg.name = argname;
- gtk_object_getv(G_OBJECT(object),1,&arg);
-
- return GTK_WIDGET(G_VALUE_OBJECT(arg));
-}
-*/
-
-/**
* gst_util_dump_mem:
* @mem: a pointer to the memory to dump
* @size: the size of the memory block to dump
#include "gstpad.h"
#include "gsttype.h"
#include "gstprops.h"
-#include "gstpropsprivate.h"
static void
string_append_indent (GString * str, gint count)
}
static void
-gst_print_props (GString * buf, gint indent, GList * props, gboolean showname)
+gst_print_props (GString *buf, gint indent, GList *props, gboolean showname)
{
GList *elem;
guint width = 0;
+ GstPropsType type;
if (showname)
for (elem = props; elem; elem = g_list_next (elem)) {
GstPropsEntry *prop = elem->data;
- const gchar *name = g_quark_to_string (prop->propid);
+ const gchar *name = gst_props_entry_get_name (prop);
if (width < strlen (name))
width = strlen (name);
string_append_indent (buf, indent);
if (showname) {
- const gchar *name = g_quark_to_string (prop->propid);
+ const gchar *name = gst_props_entry_get_name (prop);
g_string_append (buf, name);
string_append_indent (buf, 2 + width - strlen (name));
}
- switch (prop->propstype) {
- case GST_PROPS_INT_ID:
- g_string_append_printf (buf, "%d (int)\n", prop->data.int_data);
+ type = gst_props_entry_get_type (prop);
+ switch (type) {
+ case GST_PROPS_INT_TYPE:
+ {
+ gint val;
+ gst_props_entry_get_int (prop, &val);
+ g_string_append_printf (buf, "%d (int)\n", val);
break;
- case GST_PROPS_INT_RANGE_ID:
- g_string_append_printf (buf, "%d - %d (int)\n",
- prop->data.int_range_data.min, prop->data.int_range_data.max);
+ }
+ case GST_PROPS_INT_RANGE_TYPE:
+ {
+ gint min, max;
+ gst_props_entry_get_int_range (prop, &min, &max);
+ g_string_append_printf (buf, "%d - %d (int)\n", min, max);
break;
- case GST_PROPS_FLOAT_ID:
- g_string_append_printf (buf, "%f (float)\n", prop->data.float_data);
+ }
+ case GST_PROPS_FLOAT_TYPE:
+ {
+ gfloat val;
+ gst_props_entry_get_float (prop, &val);
+ g_string_append_printf (buf, "%f (float)\n", val);
break;
- case GST_PROPS_FLOAT_RANGE_ID:
- g_string_append_printf (buf, "%f - %f (float)\n",
- prop->data.float_range_data.min, prop->data.float_range_data.max);
+ }
+ case GST_PROPS_FLOAT_RANGE_TYPE:
+ {
+ gfloat min, max;
+ gst_props_entry_get_float_range (prop, &min, &max);
+ g_string_append_printf (buf, "%f - %f (float)\n", min, max);
break;
- case GST_PROPS_BOOL_ID:
- g_string_append_printf (buf, "%s\n", prop->data.bool_data ? "TRUE" : "FALSE");
+ }
+ case GST_PROPS_BOOL_TYPE:
+ {
+ gboolean val;
+ gst_props_entry_get_boolean (prop, &val);
+ g_string_append_printf (buf, "%s\n", val ? "TRUE" : "FALSE");
break;
- case GST_PROPS_STRING_ID:
- g_string_append_printf (buf, "\"%s\"\n", prop->data.string_data.string);
+ }
+ case GST_PROPS_STRING_TYPE:
+ {
+ const gchar *val;
+ gst_props_entry_get_string (prop, &val);
+ g_string_append_printf (buf, "\"%s\"\n", val);
break;
- case GST_PROPS_FOURCC_ID:
+ }
+ case GST_PROPS_FOURCC_TYPE:
+ {
+ guint32 val;
+ gst_props_entry_get_fourcc_int (prop, &val);
g_string_append_printf (buf, "'%c%c%c%c' (fourcc)\n",
- prop->data.fourcc_data & 0xff,
- prop->data.fourcc_data >> 8 & 0xff,
- prop->data.fourcc_data >> 16 & 0xff,
- prop->data.fourcc_data >> 24 & 0xff);
+ (gchar)( val & 0xff),
+ (gchar)((val >> 8) & 0xff),
+ (gchar)((val >> 16) & 0xff),
+ (gchar)((val >> 24) & 0xff));
break;
- case GST_PROPS_LIST_ID:
- gst_print_props (buf, indent + 2, prop->data.list_data.entries, FALSE);
+ }
+ case GST_PROPS_LIST_TYPE:
+ {
+ const GList *list;
+ gst_props_entry_get_list (prop, &list);
+ gst_print_props (buf, indent + 2, (GList *)list, FALSE);
break;
+ }
default:
- g_string_append_printf (buf, "unknown proptype %d\n", prop->propstype);
+ g_string_append_printf (buf, "unknown proptype %d\n", type);
break;
}
}
gdouble gst_util_get_double_arg (GObject *object, const gchar *argname);
const gchar* gst_util_get_string_arg (GObject *object, const gchar *argname);
gpointer gst_util_get_pointer_arg (GObject *object, const gchar *argname);
-/*GtkWidget* gst_util_get_widget_property (GObject *object, const gchar *argname);*/
-void gst_util_set_value_from_string(GValue *value, const gchar *value_str);
+void gst_util_set_value_from_string (GValue *value, const gchar *value_str);
void gst_util_set_object_arg (GObject *object, const gchar *name, const gchar *value);
void gst_util_dump_mem (guchar *mem, guint size);
plugindir = $(libdir)/gst
-plugin_LTLIBRARIES = libgstbasicscheduler.la libgststandardscheduler.la
+plugin_LTLIBRARIES = libgstbasicscheduler.la libgststandardscheduler.la libgstfastscheduler.la
libgstbasicscheduler_la_SOURCES = gstbasicscheduler.c
libgstbasicscheduler_la_CFLAGS = $(GST_CFLAGS)
libgststandardscheduler_la_LIBADD = $(top_builddir)/libs/ext/cothreads/cothreads/libcothreads-gthreads.la
libgststandardscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstfastscheduler_la_SOURCES = gstfastscheduler.c
+libgstfastscheduler_la_CFLAGS = $(GST_CFLAGS)
+libgstfastscheduler_la_LIBADD = $(GST_LIBS) ../libcothreads.la
+libgstfastscheduler_la_LDFLAGS = @GST_LT_LDFLAGS@
+
## this is a REALLY evil hack
## but we need to keep it as long as we have libs/gst and libs/ext
$(top_builddir)/libs/ext/cothreads/cothreads/libcothreads-gthreads.la:
typedef enum {
/* something important has changed inside the scheduler */
- GST_BASIC_SCHEDULER_CHANGE = GST_OBJECT_FLAG_LAST,
+ GST_BASIC_SCHEDULER_CHANGE = GST_SCHEDULER_FLAG_LAST,
} GstBasicSchedulerFlags;
struct _GstBasicScheduler {
static void gst_basic_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
static void gst_basic_scheduler_pad_disconnect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
static GstPad* gst_basic_scheduler_pad_select (GstScheduler *sched, GList *padlist);
+static GstClockReturn gst_basic_scheduler_clock_wait (GstScheduler *sched, GstElement *element,
+ GstClock *clock, GstClockTime time);
static GstSchedulerState
gst_basic_scheduler_iterate (GstScheduler *sched);
gstscheduler_class->pad_connect = GST_DEBUG_FUNCPTR (gst_basic_scheduler_pad_connect);
gstscheduler_class->pad_disconnect = GST_DEBUG_FUNCPTR (gst_basic_scheduler_pad_disconnect);
gstscheduler_class->pad_select = GST_DEBUG_FUNCPTR (gst_basic_scheduler_pad_select);
+ gstscheduler_class->clock_wait = GST_DEBUG_FUNCPTR (gst_basic_scheduler_clock_wait);
gstscheduler_class->iterate = GST_DEBUG_FUNCPTR (gst_basic_scheduler_iterate);
gstscheduler_class->show = GST_DEBUG_FUNCPTR (gst_basic_scheduler_show);
if (GST_RPAD_PEER (peer) != (GstRealPad *) pad) {
GST_DEBUG (GST_CAT_DATAFLOW, "new pad in mid-switch!");
pad = (GstPad *) GST_RPAD_PEER (peer);
+ if (!pad) {
+ gst_element_error (GST_ELEMENT (GST_PAD_PARENT (peer)), "pad unconnected");
+ }
}
}
GST_DEBUG (GST_CAT_DATAFLOW, "done switching");
if (!GST_IS_REAL_PAD (pad))
continue;
- peerpad = GST_PAD (GST_RPAD_PEER (pad));
+ peerpad = GST_PAD_PEER (pad);
/* if the element is DECOUPLED or outside the manager, we have to chain */
if ((wrapper_function == NULL) ||
/* notify the scheduler that something changed */
GST_FLAG_SET(chain->sched, GST_BASIC_SCHEDULER_CHANGE);
+ //GST_FLAG_UNSET(element, GST_ELEMENT_COTHREAD_STOPPING);
/* reschedule the chain */
return gst_basic_scheduler_cothreaded_chain (GST_BIN (GST_SCHEDULER (chain->sched)->parent), chain);
/* notify the scheduler that something changed */
GST_FLAG_SET(chain->sched, GST_BASIC_SCHEDULER_CHANGE);
+ GST_FLAG_SET(element, GST_ELEMENT_COTHREAD_STOPPING);
/* reschedule the chain */
/* FIXME this should be done only if manager state != NULL */
/* find what chain the element is in */
chain = gst_basic_scheduler_find_chain (bsched, element);
- if (GST_ELEMENT_IS_COTHREAD_STOPPING (element)) {
- GstElement *entry = GST_ELEMENT (cothread_get_private (cothread_current ()));
-
- if (entry == element) {
- g_warning ("removing currently running element! %s", GST_ELEMENT_NAME (entry));
- }
- else if (entry) {
- GST_INFO (GST_CAT_SCHEDULING, "moving stopping to element \"%s\"",
- GST_ELEMENT_NAME (entry));
- GST_FLAG_SET (entry, GST_ELEMENT_COTHREAD_STOPPING);
- }
- }
-
/* remove it from its chain */
gst_basic_scheduler_chain_remove_element (chain, element);
return pad;
}
+static GstClockReturn
+gst_basic_scheduler_clock_wait (GstScheduler *sched, GstElement *element,
+ GstClock *clock, GstClockTime time)
+{
+ return gst_clock_wait (clock, time);
+}
+
static GstSchedulerState
gst_basic_scheduler_iterate (GstScheduler * sched)
{
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ *
+ * gstscheduler.c: Default scheduling code for most cases
+ *
+ * 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.
+ */
+
+/*#define GST_DEBUG_ENABLED */
+#include <gst/gst.h>
+#include <../cothreads.h>
+
+typedef struct _GstSchedulerChain GstSchedulerChain;
+
+#define GST_PAD_THREADSTATE(pad) (cothread_state*) (GST_PAD_CAST (pad)->sched_private)
+#define GST_ELEMENT_THREADSTATE(elem) (cothread_state*) (GST_ELEMENT_CAST (elem)->sched_private)
+#define GST_BIN_THREADCONTEXT(bin) (cothread_context*) (GST_BIN_CAST (bin)->sched_private)
+
+#define GST_ELEMENT_COTHREAD_STOPPING GST_ELEMENT_SCHEDULER_PRIVATE1
+#define GST_ELEMENT_IS_COTHREAD_STOPPING(element) GST_FLAG_IS_SET((element), GST_ELEMENT_COTHREAD_STOPPING)
+#define GST_ELEMENT_INTERRUPTED GST_ELEMENT_SCHEDULER_PRIVATE2
+#define GST_ELEMENT_IS_INTERRUPTED(element) GST_FLAG_IS_SET((element), GST_ELEMENT_INTERRUPTED)
+
+typedef struct _GstFastScheduler GstFastScheduler;
+typedef struct _GstFastSchedulerClass GstFastSchedulerClass;
+
+struct _GstSchedulerChain {
+ GstFastScheduler *sched;
+
+ GList *disabled;
+
+ GList *elements;
+ gint num_elements;
+
+ GstElement *entry;
+
+ GList *cothreaded_elements;
+ gint num_cothreaded;
+
+ gboolean schedule;
+};
+
+#define GST_TYPE_FAST_SCHEDULER \
+ (gst_fast_scheduler_get_type())
+#define GST_FAST_SCHEDULER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FAST_SCHEDULER,GstFastScheduler))
+#define GST_FAST_SCHEDULER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FAST_SCHEDULER,GstFastSchedulerClass))
+#define GST_IS_FAST_SCHEDULER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FAST_SCHEDULER))
+#define GST_IS_FAST_SCHEDULER_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FAST_SCHEDULER))
+
+#define GST_FAST_SCHEDULER_CAST(sched) ((GstFastScheduler *)(sched))
+
+typedef enum {
+ GST_FAST_SCHEDULER_STATE_NONE,
+ GST_FAST_SCHEDULER_STATE_STOPPED,
+ GST_FAST_SCHEDULER_STATE_ERROR,
+ GST_FAST_SCHEDULER_STATE_RUNNING,
+} GstFastSchedulerState;
+
+struct _GstFastScheduler {
+ GstScheduler parent;
+
+ GList *elements;
+ gint num_elements;
+
+ GList *chains;
+ gint num_chains;
+
+ GstFastSchedulerState state;
+
+};
+
+struct _GstFastSchedulerClass {
+ GstSchedulerClass parent_class;
+};
+
+static GType _gst_fast_scheduler_type = 0;
+
+static void gst_fast_scheduler_class_init (GstFastSchedulerClass * klass);
+static void gst_fast_scheduler_init (GstFastScheduler * scheduler);
+
+static void gst_fast_scheduler_dispose (GObject *object);
+
+static void gst_fast_scheduler_setup (GstScheduler *sched);
+static void gst_fast_scheduler_reset (GstScheduler *sched);
+static void gst_fast_scheduler_add_element (GstScheduler *sched, GstElement *element);
+static void gst_fast_scheduler_remove_element (GstScheduler *sched, GstElement *element);
+static GstElementStateReturn
+ gst_fast_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition);
+static void gst_fast_scheduler_lock_element (GstScheduler *sched, GstElement *element);
+static void gst_fast_scheduler_unlock_element (GstScheduler *sched, GstElement *element);
+static void gst_fast_scheduler_yield (GstScheduler *sched, GstElement *element);
+static gboolean gst_fast_scheduler_interrupt (GstScheduler *sched, GstElement *element);
+static void gst_fast_scheduler_error (GstScheduler *sched, GstElement *element);
+static void gst_fast_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
+static void gst_fast_scheduler_pad_disconnect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
+static GstPad* gst_fast_scheduler_pad_select (GstScheduler *sched, GList *padlist);
+static GstSchedulerState
+ gst_fast_scheduler_iterate (GstScheduler *sched);
+
+static void gst_fast_scheduler_show (GstScheduler *sched);
+
+static GstSchedulerClass *parent_class = NULL;
+
+static GType
+gst_fast_scheduler_get_type (void)
+{
+ if (!_gst_fast_scheduler_type) {
+ static const GTypeInfo scheduler_info = {
+ sizeof (GstFastSchedulerClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gst_fast_scheduler_class_init,
+ NULL,
+ NULL,
+ sizeof (GstFastScheduler),
+ 0,
+ (GInstanceInitFunc) gst_fast_scheduler_init,
+ NULL
+ };
+
+ _gst_fast_scheduler_type = g_type_register_static (GST_TYPE_SCHEDULER, "GstFastScheduler", &scheduler_info, 0);
+ }
+ return _gst_fast_scheduler_type;
+}
+
+static void
+gst_fast_scheduler_class_init (GstFastSchedulerClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstObjectClass *gstobject_class;
+ GstSchedulerClass *gstscheduler_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gstobject_class = (GstObjectClass*)klass;
+ gstscheduler_class = (GstSchedulerClass*)klass;
+
+ parent_class = g_type_class_ref (GST_TYPE_SCHEDULER);
+
+ gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_fast_scheduler_dispose);
+
+ gstscheduler_class->setup = GST_DEBUG_FUNCPTR (gst_fast_scheduler_setup);
+ gstscheduler_class->reset = GST_DEBUG_FUNCPTR (gst_fast_scheduler_reset);
+ gstscheduler_class->add_element = GST_DEBUG_FUNCPTR (gst_fast_scheduler_add_element);
+ gstscheduler_class->remove_element = GST_DEBUG_FUNCPTR (gst_fast_scheduler_remove_element);
+ gstscheduler_class->state_transition = GST_DEBUG_FUNCPTR (gst_fast_scheduler_state_transition);
+ gstscheduler_class->lock_element = GST_DEBUG_FUNCPTR (gst_fast_scheduler_lock_element);
+ gstscheduler_class->unlock_element = GST_DEBUG_FUNCPTR (gst_fast_scheduler_unlock_element);
+ gstscheduler_class->yield = GST_DEBUG_FUNCPTR (gst_fast_scheduler_yield);
+ gstscheduler_class->interrupt = GST_DEBUG_FUNCPTR (gst_fast_scheduler_interrupt);
+ gstscheduler_class->error = GST_DEBUG_FUNCPTR (gst_fast_scheduler_error);
+ gstscheduler_class->pad_connect = GST_DEBUG_FUNCPTR (gst_fast_scheduler_pad_connect);
+ gstscheduler_class->pad_disconnect = GST_DEBUG_FUNCPTR (gst_fast_scheduler_pad_disconnect);
+ gstscheduler_class->pad_select = GST_DEBUG_FUNCPTR (gst_fast_scheduler_pad_select);
+ gstscheduler_class->iterate = GST_DEBUG_FUNCPTR (gst_fast_scheduler_iterate);
+}
+
+static void
+gst_fast_scheduler_init (GstFastScheduler *scheduler)
+{
+ scheduler->elements = NULL;
+ scheduler->num_elements = 0;
+ scheduler->chains = NULL;
+ scheduler->num_chains = 0;
+}
+
+static void
+gst_fast_scheduler_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstSchedulerFactory *factory;
+
+ gst_plugin_set_longname (plugin, "A fast scheduler");
+
+ factory = gst_schedulerfactory_new ("fast",
+ "A fast scheduler, it uses cothreads",
+ gst_fast_scheduler_get_type());
+
+ if (factory != NULL) {
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+ }
+ else {
+ g_warning ("could not register scheduler: fast");
+ }
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "gstfastscheduler",
+ plugin_init
+};
+
+static int
+gst_fast_scheduler_loopfunc_wrapper (int argc, char *argv[])
+{
+ GstElement *element = GST_ELEMENT_CAST (argv);
+ G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element);
+
+ GST_DEBUG_ENTER ("(%d,'%s')", argc, name);
+
+ do {
+ GST_DEBUG (GST_CAT_DATAFLOW, "calling loopfunc %s for element %s\n",
+ GST_DEBUG_FUNCPTR_NAME (element->loopfunc), name);
+ (element->loopfunc) (element);
+ GST_DEBUG (GST_CAT_DATAFLOW, "element %s ended loop function\n", name);
+
+ } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element));
+ GST_FLAG_UNSET (element, GST_ELEMENT_COTHREAD_STOPPING);
+
+ GST_DEBUG_LEAVE ("(%d,'%s')", argc, name);
+ return 0;
+}
+
+static void
+gst_fast_scheduler_chainfunc_proxy (GstPad *pad, GstBuffer *buffer)
+{
+ GstElement *element = GST_PAD_PARENT (pad);
+
+ GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad));
+
+ GST_RPAD_BUFPEN (pad) = buffer;
+
+ while (GST_RPAD_BUFPEN (pad) != NULL) {
+ if (GST_ELEMENT_THREADSTATE (element)) {
+ cothread_switch (GST_ELEMENT_THREADSTATE (element));
+ }
+ else {
+ g_assert_not_reached();
+ }
+ }
+ GST_DEBUG_LEAVE ("(%s:%s)", GST_DEBUG_PAD_NAME (pad));
+}
+
+static GstBuffer*
+gst_fast_scheduler_getfunc_proxy (GstPad *pad)
+{
+ GstElement *element = GST_PAD_PARENT (pad);
+ GstPad *peer = GST_PAD_CAST (GST_RPAD_PEER (pad));
+ GstBuffer *buf;
+
+ GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad));
+
+ while (GST_RPAD_BUFPEN (peer) == NULL) {
+ if (GST_ELEMENT_THREADSTATE (element)) {
+ cothread_switch (GST_ELEMENT_THREADSTATE (element));
+ }
+ else {
+ g_assert_not_reached();
+ }
+ }
+
+ GST_DEBUG_LEAVE ("(%s:%s)", GST_DEBUG_PAD_NAME (pad));
+ buf = GST_RPAD_BUFPEN (peer);
+ GST_RPAD_BUFPEN (peer) = NULL;
+
+ return buf;
+}
+
+static gboolean
+gst_fast_scheduler_cothreaded_element (GstBin * bin, GstElement *element)
+{
+ GList *elements;
+ cothread_func wrapper_function;
+ GList *pads;
+
+ GST_DEBUG (GST_CAT_SCHEDULING, "element is using COTHREADS\n");
+
+ g_assert (GST_BIN_THREADCONTEXT (bin) != NULL);
+
+ wrapper_function = GST_DEBUG_FUNCPTR (gst_fast_scheduler_loopfunc_wrapper);
+
+ if (GST_ELEMENT_THREADSTATE (element) == NULL) {
+ GST_ELEMENT_THREADSTATE (element) = cothread_create (GST_BIN_THREADCONTEXT (bin));
+ if (GST_ELEMENT_THREADSTATE (element) == NULL) {
+ gst_element_error (element, "could not create cothread for \"%s\"",
+ GST_ELEMENT_NAME (element), NULL);
+ return FALSE;
+ }
+ GST_DEBUG (GST_CAT_SCHEDULING, "created cothread %p for '%s'\n",
+ GST_ELEMENT_THREADSTATE (element),
+ GST_ELEMENT_NAME (element));
+ cothread_setfunc (GST_ELEMENT_THREADSTATE (element), wrapper_function, 0, (char **) element);
+ GST_DEBUG (GST_CAT_SCHEDULING, "set wrapper function for '%s' to &%s\n",
+ GST_ELEMENT_NAME (element), GST_DEBUG_FUNCPTR_NAME (wrapper_function));
+ }
+
+ pads = gst_element_get_pad_list (element);
+
+ while (pads) {
+ GstPad *pad = GST_PAD_CAST (pads->data);
+ pads = g_list_next (pads);
+
+ if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
+ GST_DEBUG (GST_CAT_SCHEDULING, "setting gethandler to getfunc_proxy for %s:%s\n", GST_DEBUG_PAD_NAME (pad));
+ GST_RPAD_GETHANDLER (pad) = gst_fast_scheduler_getfunc_proxy;
+ }
+ else {
+ GST_DEBUG (GST_CAT_SCHEDULING, "setting chainhandler to chainfunc_proxy for %s:%s\n", GST_DEBUG_PAD_NAME (pad));
+ GST_RPAD_CHAINHANDLER (pad) = gst_fast_scheduler_chainfunc_proxy;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gst_fast_scheduler_chained_element (GstBin *bin, GstElement *element) {
+ GList *pads;
+ GstPad *pad;
+
+ GST_DEBUG (GST_CAT_SCHEDULING,"chain entered\n");
+
+ // walk through all the pads
+ pads = gst_element_get_pad_list (element);
+ while (pads) {
+ pad = GST_PAD (pads->data);
+ pads = g_list_next (pads);
+ if (!GST_IS_REAL_PAD (pad))
+ continue;
+
+ if (GST_RPAD_DIRECTION (pad) == GST_PAD_SINK) {
+ GST_DEBUG (GST_CAT_SCHEDULING,"copying chain function into chain handler for %s:%s\n",GST_DEBUG_PAD_NAME (pad));
+ GST_RPAD_CHAINHANDLER (pad) = GST_RPAD_CHAINFUNC (pad);
+ } else {
+ GST_DEBUG (GST_CAT_SCHEDULING,"copying get function into get handler for %s:%s\n",GST_DEBUG_PAD_NAME (pad));
+ if (!GST_RPAD_GETFUNC (pad))
+ GST_RPAD_GETHANDLER (pad) = gst_fast_scheduler_getfunc_proxy;
+ else
+ GST_RPAD_GETHANDLER (pad) = GST_RPAD_GETFUNC (pad);
+ }
+ }
+
+ return TRUE;
+}
+
+
+static GstSchedulerChain *
+gst_fast_scheduler_chain_new (GstFastScheduler * sched)
+{
+ GstSchedulerChain *chain = g_new (GstSchedulerChain, 1);
+
+ /* initialize the chain with sane values */
+ chain->sched = sched;
+ chain->disabled = NULL;
+ chain->elements = NULL;
+ chain->num_elements = 0;
+ chain->entry = NULL;
+ chain->cothreaded_elements = NULL;
+ chain->num_cothreaded = 0;
+ chain->schedule = FALSE;
+
+ /* add the chain to the schedulers' list of chains */
+ sched->chains = g_list_prepend (sched->chains, chain);
+ sched->num_chains++;
+
+ GST_INFO (GST_CAT_SCHEDULING, "created new chain %p, now are %d chains in sched %p",
+ chain, sched->num_chains, sched);
+
+ return chain;
+}
+
+static void
+gst_fast_scheduler_chain_destroy (GstSchedulerChain * chain)
+{
+ GstFastScheduler *sched = chain->sched;
+
+
+ /* remove the chain from the schedulers' list of chains */
+ sched->chains = g_list_remove (sched->chains, chain);
+ sched->num_chains--;
+
+ /* destroy the chain */
+ g_list_free (chain->disabled); /* should be empty... */
+ g_list_free (chain->elements); /* ditto */
+
+ GST_INFO (GST_CAT_SCHEDULING, "destroyed chain %p, now are %d chains in sched %p", chain,
+ sched->num_chains, sched);
+
+ g_free (chain);
+}
+
+static gboolean
+gst_fast_scheduler_chain_enable_element (GstSchedulerChain * chain, GstElement * element)
+{
+ GST_INFO (GST_CAT_SCHEDULING, "enabling element \"%s\" in chain %p, %d cothreaded elements",
+ GST_ELEMENT_NAME (element), chain, chain->num_cothreaded);
+
+ /* remove from disabled list */
+ chain->disabled = g_list_remove (chain->disabled, element);
+
+ /* add to elements list */
+ chain->elements = g_list_prepend (chain->elements, element);
+
+ /* reschedule the chain */
+ if (element->loopfunc) {
+ chain->cothreaded_elements = g_list_prepend (chain->cothreaded_elements, element);
+ chain->num_cothreaded++;
+
+ return gst_fast_scheduler_cothreaded_element (GST_BIN (GST_SCHEDULER (chain->sched)->parent), element);
+ }
+ else {
+ if (element->numsinkpads == 0 || GST_ELEMENT_IS_DECOUPLED (element)) {
+ chain->entry = element;
+ }
+
+ return gst_fast_scheduler_chained_element (GST_BIN (GST_SCHEDULER (chain->sched)->parent), element);
+ }
+}
+
+static void
+gst_fast_scheduler_chain_disable_element (GstSchedulerChain * chain, GstElement * element)
+{
+ GST_INFO (GST_CAT_SCHEDULING, "disabling element \"%s\" in chain %p", GST_ELEMENT_NAME (element),
+ chain);
+
+ /* remove from elements list */
+ chain->elements = g_list_remove (chain->elements, element);
+
+ /* add to disabled list */
+ chain->disabled = g_list_prepend (chain->disabled, element);
+
+ if (element->loopfunc) {
+ chain->cothreaded_elements = g_list_remove (chain->cothreaded_elements, element);
+ chain->num_cothreaded--;
+ }
+ else {
+ if (chain->entry == element)
+ chain->entry = NULL;
+ }
+}
+
+static void
+gst_fast_scheduler_chain_add_element (GstSchedulerChain * chain, GstElement * element)
+{
+ GST_INFO (GST_CAT_SCHEDULING, "adding element \"%s\" to chain %p", GST_ELEMENT_NAME (element),
+ chain);
+
+ /* set the sched pointer for the element */
+ element->sched = GST_SCHEDULER (chain->sched);
+
+ /* add the element to the list of 'disabled' elements */
+ chain->disabled = g_list_prepend (chain->disabled, element);
+ chain->num_elements++;
+}
+
+static void
+gst_fast_scheduler_chain_remove_element (GstSchedulerChain * chain, GstElement * element)
+{
+ GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from chain %p", GST_ELEMENT_NAME (element),
+ chain);
+
+ /* if it's active, deactivate it */
+ if (g_list_find (chain->elements, element)) {
+ gst_fast_scheduler_chain_disable_element (chain, element);
+ }
+ /* we have to check for a threadstate here because a queue doesn't have one */
+ if (GST_ELEMENT_THREADSTATE (element)) {
+ cothread_free (GST_ELEMENT_THREADSTATE (element));
+ GST_ELEMENT_THREADSTATE (element) = NULL;
+ }
+
+ /* remove the element from the list of elements */
+ chain->disabled = g_list_remove (chain->disabled, element);
+ chain->num_elements--;
+
+ /* if there are no more elements in the chain, destroy the chain */
+ if (chain->num_elements == 0)
+ gst_fast_scheduler_chain_destroy (chain);
+}
+
+static void
+gst_fast_scheduler_chain_elements (GstFastScheduler * sched, GstElement * element1, GstElement * element2)
+{
+ GList *chains;
+ GstSchedulerChain *chain;
+ GstSchedulerChain *chain1 = NULL, *chain2 = NULL;
+ GstElement *element;
+
+ /* first find the chains that hold the two */
+ chains = sched->chains;
+ while (chains) {
+ chain = (GstSchedulerChain *) (chains->data);
+ chains = g_list_next (chains);
+
+ if (g_list_find (chain->disabled, element1))
+ chain1 = chain;
+ else if (g_list_find (chain->elements, element1))
+ chain1 = chain;
+
+ if (g_list_find (chain->disabled, element2))
+ chain2 = chain;
+ else if (g_list_find (chain->elements, element2))
+ chain2 = chain;
+ }
+
+ /* first check to see if they're in the same chain, we're done if that's the case */
+ if ((chain1 != NULL) && (chain1 == chain2)) {
+ GST_INFO (GST_CAT_SCHEDULING, "elements are already in the same chain");
+ return;
+ }
+
+ /* now, if neither element has a chain, create one */
+ if ((chain1 == NULL) && (chain2 == NULL)) {
+ GST_INFO (GST_CAT_SCHEDULING, "creating new chain to hold two new elements");
+ chain = gst_fast_scheduler_chain_new (sched);
+ gst_fast_scheduler_chain_add_element (chain, element1);
+ gst_fast_scheduler_chain_add_element (chain, element2);
+
+ /* otherwise if both have chains already, join them */
+ }
+ else if ((chain1 != NULL) && (chain2 != NULL)) {
+ GST_INFO (GST_CAT_SCHEDULING, "merging chain %p into chain %p", chain2, chain1);
+ /* take the contents of chain2 and merge them into chain1 */
+ chain1->disabled = g_list_concat (chain1->disabled, g_list_copy (chain2->disabled));
+ chain1->elements = g_list_concat (chain1->elements, g_list_copy (chain2->elements));
+ //chain1->cothreaded_elements = g_list_concat (chain1->cothreaded_elements, g_list_copy (chain2->cothreaded_elements));
+ chain1->num_elements += chain2->num_elements;
+ //chain1->num_cothreaded += chain2->num_cothreaded;
+
+ gst_fast_scheduler_chain_destroy (chain2);
+
+ /* otherwise one has a chain already, the other doesn't */
+ }
+ else {
+ /* pick out which one has the chain, and which doesn't */
+ if (chain1 != NULL)
+ chain = chain1, element = element2;
+ else
+ chain = chain2, element = element1;
+
+ GST_INFO (GST_CAT_SCHEDULING, "adding element to existing chain");
+ gst_fast_scheduler_chain_add_element (chain, element);
+ }
+}
+
+
+/* find the chain within the scheduler that holds the element, if any */
+static GstSchedulerChain *
+gst_fast_scheduler_find_chain (GstFastScheduler * sched, GstElement * element)
+{
+ GList *chains;
+ GstSchedulerChain *chain;
+
+ GST_INFO (GST_CAT_SCHEDULING, "searching for element \"%s\" in chains",
+ GST_ELEMENT_NAME (element));
+
+ chains = sched->chains;
+ while (chains) {
+ chain = (GstSchedulerChain *) (chains->data);
+ chains = g_list_next (chains);
+
+ if (g_list_find (chain->elements, element))
+ return chain;
+ if (g_list_find (chain->disabled, element))
+ return chain;
+ }
+
+ return NULL;
+}
+
+static void
+gst_fast_scheduler_chain_recursive_add (GstSchedulerChain * chain, GstElement * element)
+{
+ GList *pads;
+ GstPad *pad;
+ GstElement *peerelement;
+
+ /* add the element to the chain */
+ gst_fast_scheduler_chain_add_element (chain, element);
+
+ GST_DEBUG (GST_CAT_SCHEDULING, "recursing on element \"%s\"\n", GST_ELEMENT_NAME (element));
+ /* now go through all the pads and see which peers can be added */
+ pads = element->pads;
+ while (pads) {
+ pad = GST_PAD (pads->data);
+ pads = g_list_next (pads);
+
+ GST_DEBUG (GST_CAT_SCHEDULING, "have pad %s:%s, checking for valid peer\n",
+ GST_DEBUG_PAD_NAME (pad));
+ /* if the peer exists and could be in the same chain */
+ if (GST_PAD_PEER (pad)) {
+ GST_DEBUG (GST_CAT_SCHEDULING, "has peer %s:%s\n", GST_DEBUG_PAD_NAME (GST_PAD_PEER (pad)));
+ peerelement = GST_PAD_PARENT (GST_PAD_PEER (pad));
+ if (GST_ELEMENT_SCHED (GST_PAD_PARENT (pad)) == GST_ELEMENT_SCHED (peerelement)) {
+ GST_DEBUG (GST_CAT_SCHEDULING, "peer \"%s\" is valid for same chain\n",
+ GST_ELEMENT_NAME (peerelement));
+ /* if it's not already in a chain, add it to this one */
+ if (gst_fast_scheduler_find_chain (chain->sched, peerelement) == NULL) {
+ gst_fast_scheduler_chain_recursive_add (chain, peerelement);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Entry points for this scheduler.
+ */
+static void
+gst_fast_scheduler_setup (GstScheduler *sched)
+{
+ GstBin *bin = GST_BIN (sched->parent);
+
+ /* first create thread context */
+ if (GST_BIN_THREADCONTEXT (bin) == NULL) {
+ GST_DEBUG (GST_CAT_SCHEDULING, "initializing cothread context\n");
+ GST_BIN_THREADCONTEXT (bin) = cothread_context_init ();
+ }
+}
+
+static void
+gst_fast_scheduler_reset (GstScheduler *sched)
+{
+ cothread_context *ctx;
+ GstBin *bin = GST_BIN (GST_SCHEDULER_PARENT (sched));
+ GList *elements = GST_FAST_SCHEDULER_CAST (sched)->elements;
+ GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched);
+
+ while (elements) {
+ GST_ELEMENT_THREADSTATE (elements->data) = NULL;
+ elements = g_list_next (elements);
+ }
+
+ ctx = GST_BIN_THREADCONTEXT (GST_SCHEDULER_PARENT (sched));
+
+ cothread_context_free (ctx);
+
+ GST_BIN_THREADCONTEXT (GST_SCHEDULER_PARENT (sched)) = NULL;
+}
+
+static void
+gst_fast_scheduler_add_element (GstScheduler * sched, GstElement * element)
+{
+ GList *pads;
+ GstPad *pad;
+ GstElement *peerelement;
+ GstSchedulerChain *chain;
+ GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched);
+
+ /* if it's already in this scheduler, don't bother doing anything */
+ if (GST_ELEMENT_SCHED (element) == sched)
+ return;
+
+ GST_INFO (GST_CAT_SCHEDULING, "adding element \"%s\" to scheduler", GST_ELEMENT_NAME (element));
+
+ /* if the element already has a different scheduler, remove the element from it */
+ if (GST_ELEMENT_SCHED (element)) {
+ gst_fast_scheduler_remove_element (GST_ELEMENT_SCHED (element), element);
+ }
+
+ /* set the sched pointer in the element itself */
+ GST_ELEMENT_SCHED (element) = sched;
+
+ /* only deal with elements after this point, not bins */
+ /* exception is made for Bin's that are schedulable, like the autoplugger */
+ if (GST_IS_BIN (element) && !GST_FLAG_IS_SET (element, GST_BIN_SELF_SCHEDULABLE))
+ return;
+
+ /* first add it to the list of elements that are to be scheduled */
+ bsched->elements = g_list_prepend (bsched->elements, element);
+ bsched->num_elements++;
+
+ /* create a chain to hold it, and add */
+ chain = gst_fast_scheduler_chain_new (bsched);
+ gst_fast_scheduler_chain_add_element (chain, element);
+
+ /* set the sched pointer in all the pads */
+ pads = element->pads;
+ while (pads) {
+ pad = GST_PAD (pads->data);
+ pads = g_list_next (pads);
+
+ /* we only operate on real pads */
+ if (!GST_IS_REAL_PAD (pad))
+ continue;
+
+ /* set the pad's sched pointer */
+ gst_pad_set_sched (pad, sched);
+
+ /* if the peer element exists and is a candidate */
+ if (GST_PAD_PEER (pad)) {
+ peerelement = GST_PAD_PARENT (GST_PAD_PEER (pad));
+ if (GST_ELEMENT_SCHED (element) == GST_ELEMENT_SCHED (peerelement)) {
+ GST_INFO (GST_CAT_SCHEDULING, "peer is in same scheduler, chaining together");
+ /* make sure that the two elements are in the same chain */
+ gst_fast_scheduler_chain_elements (bsched, element, peerelement);
+ }
+ }
+ }
+}
+
+static void
+gst_fast_scheduler_remove_element (GstScheduler * sched, GstElement * element)
+{
+ GstSchedulerChain *chain;
+ GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched);
+
+ if (g_list_find (bsched->elements, element)) {
+ GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from scheduler",
+ GST_ELEMENT_NAME (element));
+
+ /* find what chain the element is in */
+ chain = gst_fast_scheduler_find_chain (bsched, element);
+
+ /* remove it from its chain */
+ gst_fast_scheduler_chain_remove_element (chain, element);
+
+ /* remove it from the list of elements */
+ bsched->elements = g_list_remove (bsched->elements, element);
+ bsched->num_elements--;
+
+ /* unset the scheduler pointer in the element */
+ GST_ELEMENT_SCHED (element) = NULL;
+ }
+}
+
+static GstElementStateReturn
+gst_fast_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition)
+{
+ GstSchedulerChain *chain;
+ GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched);
+
+ /* check if our parent changed state */
+ if (GST_SCHEDULER_PARENT (sched) == element) {
+ GST_INFO (GST_CAT_SCHEDULING, "parent \"%s\" changed state", GST_ELEMENT_NAME (element));
+ if (transition == GST_STATE_PLAYING_TO_PAUSED) {
+ GST_INFO (GST_CAT_SCHEDULING, "setting scheduler state to stopped");
+ GST_SCHEDULER_STATE (sched) = GST_SCHEDULER_STATE_STOPPED;
+ }
+ else if (transition == GST_STATE_PAUSED_TO_PLAYING) {
+ GST_INFO (GST_CAT_SCHEDULING, "setting scheduler state to running");
+ GST_SCHEDULER_STATE (sched) = GST_SCHEDULER_STATE_RUNNING;
+ }
+ else {
+ GST_INFO (GST_CAT_SCHEDULING, "no interesting state change, doing nothing");
+ }
+ }
+ else if (transition == GST_STATE_PLAYING_TO_PAUSED ||
+ transition == GST_STATE_PAUSED_TO_PLAYING) {
+ /* find the chain the element is in */
+ chain = gst_fast_scheduler_find_chain (bsched, element);
+
+ /* remove it from the chain */
+ if (chain) {
+ if (transition == GST_STATE_PLAYING_TO_PAUSED) {
+ gst_fast_scheduler_chain_disable_element (chain, element);
+ }
+ else if (transition == GST_STATE_PAUSED_TO_PLAYING) {
+ if (!gst_fast_scheduler_chain_enable_element (chain, element)) {
+ GST_INFO (GST_CAT_SCHEDULING, "could not enable element \"%s\"", GST_ELEMENT_NAME (element));
+ return GST_STATE_FAILURE;
+ }
+ }
+ }
+ else {
+ GST_INFO (GST_CAT_SCHEDULING, "element \"%s\" not found in any chain, no state change", GST_ELEMENT_NAME (element));
+ }
+ }
+
+ return GST_STATE_SUCCESS;
+}
+
+static void
+gst_fast_scheduler_lock_element (GstScheduler * sched, GstElement * element)
+{
+ if (GST_ELEMENT_THREADSTATE (element))
+ cothread_lock (GST_ELEMENT_THREADSTATE (element));
+}
+
+static void
+gst_fast_scheduler_unlock_element (GstScheduler * sched, GstElement * element)
+{
+ if (GST_ELEMENT_THREADSTATE (element))
+ cothread_unlock (GST_ELEMENT_THREADSTATE (element));
+}
+
+static void
+gst_fast_scheduler_yield (GstScheduler *sched, GstElement *element)
+{
+ if (GST_ELEMENT_IS_COTHREAD_STOPPING (element)) {
+ cothread_switch (cothread_current_main ());
+ }
+}
+
+static gboolean
+gst_fast_scheduler_interrupt (GstScheduler *sched, GstElement *element)
+{
+ if (cothread_current () != cothread_current_main()) {
+ cothread_switch (cothread_current_main ());
+ return FALSE;
+ }
+ GST_FLAG_SET (element, GST_ELEMENT_INTERRUPTED);
+ return TRUE;
+}
+
+static void
+gst_fast_scheduler_error (GstScheduler *sched, GstElement *element)
+{
+ GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched);
+ GstSchedulerChain *chain;
+
+ chain = gst_fast_scheduler_find_chain (bsched, element);
+ if (chain)
+ gst_fast_scheduler_chain_disable_element (chain, element);
+
+ GST_SCHEDULER_STATE (sched) = GST_SCHEDULER_STATE_ERROR;
+
+ gst_fast_scheduler_interrupt (sched, element);
+}
+
+static void
+gst_fast_scheduler_pad_connect (GstScheduler * sched, GstPad *srcpad, GstPad *sinkpad)
+{
+ GstElement *srcelement, *sinkelement;
+ GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched);
+
+ srcelement = GST_PAD_PARENT (srcpad);
+ g_return_if_fail (srcelement != NULL);
+ sinkelement = GST_PAD_PARENT (sinkpad);
+ g_return_if_fail (sinkelement != NULL);
+
+ GST_INFO (GST_CAT_SCHEDULING, "have pad connected callback on %s:%s to %s:%s",
+ GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
+ GST_DEBUG (GST_CAT_SCHEDULING, "srcpad sched is %p, sinkpad sched is %p\n",
+ GST_ELEMENT_SCHED (srcelement), GST_ELEMENT_SCHED (sinkelement));
+
+ if (GST_ELEMENT_SCHED (srcelement) == GST_ELEMENT_SCHED (sinkelement)) {
+ GST_INFO (GST_CAT_SCHEDULING, "peer %s:%s is in same scheduler, chaining together",
+ GST_DEBUG_PAD_NAME (sinkpad));
+ gst_fast_scheduler_chain_elements (bsched, srcelement, sinkelement);
+ }
+}
+
+static void
+gst_fast_scheduler_pad_disconnect (GstScheduler * sched, GstPad * srcpad, GstPad * sinkpad)
+{
+ GstSchedulerChain *chain;
+ GstElement *element1, *element2;
+ GstSchedulerChain *chain1, *chain2;
+ GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched);
+
+ GST_INFO (GST_CAT_SCHEDULING, "disconnecting pads %s:%s and %s:%s",
+ GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
+
+ /* we need to have the parent elements of each pad */
+ element1 = GST_ELEMENT_CAST (GST_PAD_PARENT (srcpad));
+ element2 = GST_ELEMENT_CAST (GST_PAD_PARENT (sinkpad));
+
+ /* first task is to remove the old chain they belonged to.
+ * this can be accomplished by taking either of the elements,
+ * since they are guaranteed to be in the same chain
+ * FIXME is it potentially better to make an attempt at splitting cleaner??
+ */
+ chain1 = gst_fast_scheduler_find_chain (bsched, element1);
+ chain2 = gst_fast_scheduler_find_chain (bsched, element2);
+
+ if (chain1 != chain2) {
+ /* elements not in the same chain don't need to be separated */
+ GST_INFO (GST_CAT_SCHEDULING, "elements not in the same chain");
+ return;
+ }
+
+ if (chain1) {
+ GST_INFO (GST_CAT_SCHEDULING, "destroying chain");
+ gst_fast_scheduler_chain_destroy (chain1);
+
+ /* now create a new chain to hold element1 and build it from scratch */
+ chain1 = gst_fast_scheduler_chain_new (bsched);
+ gst_fast_scheduler_chain_recursive_add (chain1, element1);
+ }
+
+ /* check the other element to see if it landed in the newly created chain */
+ if (gst_fast_scheduler_find_chain (bsched, element2) == NULL) {
+ /* if not in chain, create chain and build from scratch */
+ chain2 = gst_fast_scheduler_chain_new (bsched);
+ gst_fast_scheduler_chain_recursive_add (chain2, element2);
+ }
+}
+
+static GstPad *
+gst_fast_scheduler_pad_select (GstScheduler * sched, GList * padlist)
+{
+ GstPad *pad = NULL;
+ GList *padlist2 = padlist;
+
+ GST_INFO (GST_CAT_SCHEDULING, "imlement me!!");
+
+ return pad;
+}
+
+static GstSchedulerState
+gst_fast_scheduler_iterate (GstScheduler * sched)
+{
+ GstBin *bin = GST_BIN (sched->parent);
+ GList *chains;
+ GstSchedulerChain *chain;
+ GstElement *entry;
+ GList *elements;
+ gint scheduled = 0;
+ GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched);
+ GstSchedulerState state;
+
+ GST_DEBUG_ENTER ("(\"%s\")", GST_ELEMENT_NAME (bin));
+
+ /* step through all the chains */
+ chains = bsched->chains;
+
+ if (chains == NULL) {
+ GST_DEBUG (GST_CAT_DATAFLOW, "no chains!\n");
+
+ state = GST_SCHEDULER_STATE_STOPPED;
+
+ goto exit;
+ }
+
+ while (chains) {
+ chain = (GstSchedulerChain *) (chains->data);
+ chains = g_list_next (chains);
+
+ if (chain->elements == NULL) {
+ continue;
+ }
+
+ //if (chain->num_cothreaded > 1) {
+ if (FALSE) {
+ g_warning ("this scheduler can only deal with 1 cothreaded element in a chain");
+
+ state = GST_SCHEDULER_STATE_ERROR;
+
+ goto exit;
+ }
+ else if (chain->num_cothreaded != 0) {
+ /* we just pick the first cothreaded element */
+ GstElement *entry = GST_ELEMENT (chain->cothreaded_elements->data);
+
+ GST_DEBUG (GST_CAT_DATAFLOW, "starting iteration via cothreads\n");
+
+ GST_FLAG_SET (entry, GST_ELEMENT_COTHREAD_STOPPING);
+
+ GST_DEBUG (GST_CAT_DATAFLOW, "set COTHREAD_STOPPING flag on \"%s\"(@%p)\n",
+ GST_ELEMENT_NAME (entry), entry);
+
+ if (GST_ELEMENT_THREADSTATE (entry)) {
+ cothread_switch (GST_ELEMENT_THREADSTATE (entry));
+ }
+ else {
+ GST_DEBUG (GST_CAT_DATAFLOW, "cothread switch not possible, element has no threadstate\n");
+
+ GST_DEBUG (GST_CAT_DATAFLOW, "leaving (%s)\n", GST_ELEMENT_NAME (bin));
+
+ state = GST_SCHEDULER_STATE_ERROR;
+
+ goto exit;
+ }
+
+ GST_DEBUG (GST_CAT_SCHEDULING, "loopfunc of element %s ended\n", GST_ELEMENT_NAME (entry));
+
+ scheduled++;
+ }
+ else {
+ GstElement *entry = chain->entry;
+ if (entry) {
+ GList *pads = gst_element_get_pad_list (entry);
+
+ GST_DEBUG (GST_CAT_DATAFLOW, "starting chained iteration\n");
+
+ while (pads) {
+ GstPad *pad = GST_PAD_CAST (pads->data);
+ pads = g_list_next (pads);
+
+ if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
+ GstBuffer *buf;
+
+ buf = GST_RPAD_GETFUNC (pad) (pad);
+ if (GST_ELEMENT_IS_INTERRUPTED (entry)) {
+ GST_FLAG_UNSET (entry, GST_ELEMENT_INTERRUPTED);
+ break;
+ }
+ gst_pad_push (pad, buf);
+ scheduled++;
+ }
+ }
+ }
+ else {
+ GST_INFO (GST_CAT_DATAFLOW, "no entry found!!");
+
+ state = GST_SCHEDULER_STATE_ERROR;
+ goto exit;
+ }
+ }
+
+ state = GST_SCHEDULER_STATE (sched);
+
+ if (state != GST_SCHEDULER_STATE_RUNNING) {
+ GST_INFO (GST_CAT_DATAFLOW, "scheduler is not running, in state %d", state);
+
+ goto exit;
+ }
+ }
+
+ GST_DEBUG (GST_CAT_DATAFLOW, "leaving (%s)\n", GST_ELEMENT_NAME (bin));
+
+ if (scheduled == 0) {
+ GST_INFO (GST_CAT_DATAFLOW, "nothing was scheduled, return STOPPED");
+ state = GST_SCHEDULER_STATE_STOPPED;
+ }
+ else {
+ GST_INFO (GST_CAT_DATAFLOW, "scheduler still running, return RUNNING");
+ state = GST_SCHEDULER_STATE_RUNNING;
+ }
+
+exit:
+ GST_DEBUG (GST_CAT_DATAFLOW, "leaving (%s) %d\n", GST_ELEMENT_NAME (bin), state);
+
+ return state;
+}
+
+
+static void
+gst_fast_scheduler_show (GstScheduler * sched)
+{
+ GList *chains, *elements;
+ GstElement *element;
+ GstSchedulerChain *chain;
+ GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched);
+
+ if (sched == NULL) {
+ g_print ("scheduler doesn't exist for this element\n");
+ return;
+ }
+
+ g_return_if_fail (GST_IS_SCHEDULER (sched));
+
+ g_print ("SCHEDULER DUMP FOR MANAGING BIN \"%s\"\n", GST_ELEMENT_NAME (sched->parent));
+
+ g_print ("scheduler has %d elements in it: ", bsched->num_elements);
+ elements = bsched->elements;
+ while (elements) {
+ element = GST_ELEMENT (elements->data);
+ elements = g_list_next (elements);
+
+ g_print ("%s, ", GST_ELEMENT_NAME (element));
+ }
+ g_print ("\n");
+
+ g_print ("scheduler has %d chains in it\n", bsched->num_chains);
+ chains = bsched->chains;
+ while (chains) {
+ chain = (GstSchedulerChain *) (chains->data);
+ chains = g_list_next (chains);
+
+ g_print ("%p: ", chain);
+
+ elements = chain->disabled;
+ while (elements) {
+ element = GST_ELEMENT (elements->data);
+ elements = g_list_next (elements);
+
+ g_print ("!%s, ", GST_ELEMENT_NAME (element));
+ }
+
+ elements = chain->elements;
+ while (elements) {
+ element = GST_ELEMENT (elements->data);
+ elements = g_list_next (elements);
+
+ g_print ("%s, ", GST_ELEMENT_NAME (element));
+ }
+ g_print ("\n");
+ }
+}
ARG_NUM_SINKS,
ARG_SILENT,
ARG_DUMP,
+ ARG_SYNC,
ARG_LAST_MESSAGE,
};
static void gst_fakesink_class_init (GstFakeSinkClass *klass);
static void gst_fakesink_init (GstFakeSink *fakesink);
+static void gst_fakesink_set_clock (GstElement *element, GstClock *clock);
static GstPad* gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ, const
gchar *unused);
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SINKS,
- g_param_spec_int ("num_sinks", "num_sinks", "num_sinks",
+ g_param_spec_int ("num_sinks", "Number of sinks", "The number of sinkpads",
1, G_MAXINT, 1, G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
g_param_spec_string ("last_message", "last_message", "last_message",
NULL, G_PARAM_READABLE));
-
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SYNC,
+ g_param_spec_boolean("sync","Sync","Sync on the clock",
+ FALSE, G_PARAM_READWRITE)); /* CHECKME */
gst_element_class_install_std_props (
GST_ELEMENT_CLASS (klass),
fakesink->silent = FALSE;
fakesink->dump = FALSE;
+ fakesink->sync = FALSE;
fakesink->last_message = NULL;
+
+ GST_ELEMENT (fakesink)->setclockfunc = gst_fakesink_set_clock;
}
+static void
+gst_fakesink_set_clock (GstElement *element, GstClock *clock)
+{
+ GstFakeSink *sink;
+
+ sink = GST_FAKESINK (element);
+
+ sink->clock = clock;
+}
+
static GstPad*
gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused)
{
case ARG_DUMP:
sink->dump = g_value_get_boolean (value);
break;
+ case ARG_SYNC:
+ sink->sync = g_value_get_boolean (value);
+ break;
default:
break;
}
case ARG_DUMP:
g_value_set_boolean (value, sink->dump);
break;
+ case ARG_SYNC:
+ g_value_set_boolean (value, sink->sync);
+ break;
case ARG_LAST_MESSAGE:
g_value_set_string (value, sink->last_message);
break;
fakesink = GST_FAKESINK (gst_pad_get_parent (pad));
+ if (fakesink->sync) {
+ gst_element_clock_wait (GST_ELEMENT (fakesink), fakesink->clock, GST_BUFFER_TIMESTAMP (buf));
+ }
+
if (!fakesink->silent) {
- if (fakesink->last_message)
- g_free (fakesink->last_message);
+ g_free (fakesink->last_message);
fakesink->last_message = g_strdup_printf ("chain ******* (%s:%s)< (%d bytes, %lld) %p",
GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
typedef struct _GstFakeSinkClass GstFakeSinkClass;
struct _GstFakeSink {
- GstElement element;
+ GstElement element;
- gboolean silent;
- gboolean dump;
- gchar *last_message;
+ gboolean silent;
+ gboolean dump;
+ gboolean sync;
+ GstClock *clock;
+
+ gchar *last_message;
};
struct _GstFakeSinkClass {
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
src->buffer_count = GST_EVENT_SEEK_OFFSET (event);
+
if (!GST_EVENT_SEEK_FLUSH (event)) {
gst_event_free (event);
break;
gboolean silent;
gboolean dump;
gboolean need_flush;
- gchar *last_message;
+
+ gchar *last_message;
};
struct _GstFakeSrcClass {
"(C) 1999",
};
-/*#define fs_print(format,args...) g_print(format, ## args)*/
+/*#define fs_print(format,args...) g_print(format, ## args) */
#define fs_print(format,args...)
/* FileSrc signals and args */
/* we're done, return the buffer */
src->curoffset += GST_BUFFER_SIZE(buf);
- g_object_notify (G_OBJECT (src), "offset");
+ //g_object_notify (G_OBJECT (src), "offset");
return buf;
}
/* now notify of the changes */
g_object_freeze_notify (G_OBJECT (src));
g_object_notify (G_OBJECT (src), "filesize");
- g_object_notify (G_OBJECT (src), "offset");
+ //g_object_notify (G_OBJECT (src), "offset");
g_object_thaw_notify (G_OBJECT (src));
GST_FLAG_SET (src, GST_FILESRC_OPEN);
/* and notify that things changed */
g_object_freeze_notify (G_OBJECT (src));
g_object_notify (G_OBJECT (src), "filesize");
- g_object_notify (G_OBJECT (src), "offset");
+ //g_object_notify (G_OBJECT (src), "offset");
g_object_thaw_notify (G_OBJECT (src));
if (src->mapbuf)
static GstBufferPool* gst_queue_get_bufferpool (GstPad *pad);
static void gst_queue_locked_flush (GstQueue *queue);
-static void gst_queue_flush (GstQueue *queue);
static GstElementStateReturn gst_queue_change_state (GstElement *element);
}
static void
-gst_queue_flush (GstQueue *queue)
-{
- g_mutex_lock (queue->qlock);
- gst_queue_locked_flush (queue);
- g_mutex_unlock (queue->qlock);
-}
-
-
-static void
gst_queue_chain (GstPad *pad, GstBuffer *buf)
{
GstQueue *queue;
return;
}
else {
- gst_element_info (GST_ELEMENT (queue), "waiting for the app to restart source pad elements");
+ g_print ("%s: waiting for the app to restart source pad elements\n", GST_ELEMENT_NAME (queue));
}
}
goto restart;
}
else {
- gst_element_info (GST_ELEMENT (queue), "waiting for the app to restart sink pad elements");
+ g_print ("%s: waiting for the app to restart source pad elements\n", GST_ELEMENT_NAME (queue));
}
}
GList *pads;
g_return_val_if_fail (GST_IS_TEE (element), NULL);
-
+
if (templ->direction != GST_PAD_SRC) {
g_warning ("gsttee: request new pad that is not a SRC pad\n");
return NULL;