From: David Schleef Date: Wed, 30 Mar 2005 03:57:39 +0000 (+0000) Subject: A little example program to show how trigger-based elements can work. X-Git-Tag: RELEASE-0_9_2~583 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=687173ffc06976de408394437af4d4c15179c04a;p=platform%2Fupstream%2Fgstreamer.git A little example program to show how trigger-based elements can work. Original commit message from CVS: * configure.ac: * testsuite/trigger/Makefile.am: * testsuite/trigger/trigger.c: A little example program to show how trigger-based elements can work. --- diff --git a/ChangeLog b/ChangeLog index 040875e..389d09c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2005-03-29 David Schleef + + * configure.ac: + * testsuite/trigger/Makefile.am: + * testsuite/trigger/trigger.c: A little example program to show + how trigger-based elements can work. + 2005-03-29 Wim Taymans * gst/base/Makefile.am: diff --git a/configure.ac b/configure.ac index e5ca119..7855bbd 100644 --- a/configure.ac +++ b/configure.ac @@ -697,6 +697,7 @@ testsuite/schedulers/Makefile testsuite/states/Makefile testsuite/tags/Makefile testsuite/threads/Makefile +testsuite/trigger/Makefile examples/Makefile examples/cutter/Makefile examples/helloworld/Makefile diff --git a/tests/old/testsuite/trigger/Makefile.am b/tests/old/testsuite/trigger/Makefile.am new file mode 100644 index 0000000..ef85850 --- /dev/null +++ b/tests/old/testsuite/trigger/Makefile.am @@ -0,0 +1,9 @@ + + +noinst_PROGRAMS = trigger + +trigger_SOURCES = trigger.c +trigger_CFLAGS = $(GST_OBJ_CFLAGS) +trigger_LDADD = $(GST_OBJS_LIBS) $(GLIB_LIBS) + + diff --git a/tests/old/testsuite/trigger/trigger.c b/tests/old/testsuite/trigger/trigger.c new file mode 100644 index 0000000..dba91bf --- /dev/null +++ b/tests/old/testsuite/trigger/trigger.c @@ -0,0 +1,856 @@ + +#include +#include +#include +#include +#include + +#define INFINITY 1e10 + +typedef struct _Element Element; +typedef struct _Feature Feature; +typedef struct _ElementInfo ElementInfo; + +enum +{ + PAD_SRC, + PAD_SINK, + FD, + TIME +}; + +struct _Element +{ + char *name; + GList *features; + int type; + gboolean init; + gboolean idle; + + void (*iterate) (Element * element); + void (*caps_iterate) (Element * element); + + int state; +}; + +struct _Feature +{ + char *name; + int type; + + Element *parent; + + gboolean waiting; + gboolean ready; + + /* for pads */ + gboolean bufpen; + Feature *peer; + GstCaps *caps; + + /* for fds */ + double next_time; + double interval; +}; + +struct _ElementInfo +{ + char *type_name; + void (*iterate) (Element * element); + void (*caps_iterate) (Element * element); +}; + +GList *elements; + +void run (void); +void dump (void); +void dump_element (Element * e); + +Element *element_factory_make (const char *type); +Element *element_factory_make_full (const char *type, const char *name); +void element_link (const char *name1, const char *name2); +void element_link_full (const char *name1, const char *padname1, + const char *name2, const char *padname2); +Element *element_get (const char *name); +gboolean element_ready (Element * e); +gboolean feature_is_ready (Feature * f); +double element_next_time (Element * e); + +Feature *feature_create (Element * e, int type, const char *name); +Feature *feature_get (Element * e, const char *name); +gboolean feature_ready (Element * e, const char *name); + +void fakesrc_iterate (Element * element); +void identity_iterate (Element * element); +void fakesink_iterate (Element * element); +void audiosink_iterate (Element * element); +void mad_iterate (Element * element); +void queue_iterate (Element * element); +void videosink_iterate (Element * element); +void tee_iterate (Element * element); + +void fakesrc_caps (Element * element); +void identity_caps (Element * element); +void fakesink_caps (Element * element); +void audiosink_caps (Element * element); +void mad_caps (Element * element); +void queue_caps (Element * element); +void videosink_caps (Element * element); +void tee_caps (Element * element); + +double time; + +int +main (int argc, char *argv[]) +{ + int x = 8; + + switch (x) { + case 0: + /* fakesrc ! fakesink */ + element_factory_make ("fakesrc"); + element_factory_make ("fakesink"); + element_link ("fakesrc", "fakesink"); + break; + case 1: + /* fakesrc ! identity ! fakesink */ + element_factory_make ("fakesrc"); + element_factory_make ("identity"); + element_factory_make ("fakesink"); + + element_link ("fakesrc", "identity"); + element_link ("identity", "fakesink"); + break; + case 2: + /* fakesrc ! identity ! identity ! fakesink */ + element_factory_make ("fakesrc"); + element_factory_make_full ("identity", "identity0"); + element_factory_make_full ("identity", "identity1"); + element_factory_make ("fakesink"); + + element_link ("fakesrc", "identity0"); + element_link ("identity0", "identity1"); + element_link ("identity1", "fakesink"); + break; + case 3: + /* fakesrc ! audiosink */ + element_factory_make ("fakesrc"); + element_factory_make ("audiosink"); + + element_link ("fakesrc", "audiosink"); + break; + case 4: + /* fakesrc ! mad ! fakesink */ + element_factory_make ("fakesrc"); + element_factory_make ("mad"); + element_factory_make ("fakesink"); + + element_link ("fakesrc", "mad"); + element_link ("mad", "fakesink"); + break; + case 5: + /* fakesrc ! queue ! fakesink */ + element_factory_make ("fakesrc"); + element_factory_make ("queue"); + element_factory_make ("fakesink"); + + element_link ("fakesrc", "queue"); + element_link ("queue", "fakesink"); + break; + case 6: + /* fakesrc ! queue ! audiosink */ + element_factory_make ("fakesrc"); + element_factory_make ("queue"); + element_factory_make ("audiosink"); + + element_link ("fakesrc", "queue"); + element_link ("queue", "audiosink"); + break; + case 7: + /* fakesrc ! videosink */ + element_factory_make ("fakesrc"); + element_factory_make ("videosink"); + + element_link ("fakesrc", "videosink"); + break; + case 8: + /* fakesrc ! tee ! videosink tee0.src2 ! videosink */ + element_factory_make ("fakesrc"); + element_factory_make ("tee"); + element_factory_make_full ("videosink", "vs0"); + element_factory_make_full ("videosink", "vs1"); + + element_link ("fakesrc", "tee"); + element_link_full ("tee", "src1", "vs0", "sink"); + element_link_full ("tee", "src2", "vs1", "sink"); + break; + } + + run (); + + return 0; +} + +void +run (void) +{ + int iter = 0; + + while (iter < 20) { + Element *e; + GList *l; + gboolean did_something = FALSE; + double ent = INFINITY; + + g_print ("iteration %d time %g\n", iter, time); + for (l = g_list_first (elements); l; l = g_list_next (l)) { + double nt; + + e = l->data; + if (element_ready (e)) { + g_print ("%s: is ready, iterating\n", e->name); + e->iterate (e); + did_something = TRUE; + } else { + g_print ("%s: is not ready\n", e->name); + } + nt = element_next_time (e); + if (nt < ent) { + ent = nt; + } + } + if (did_something == FALSE) { + if (ent < INFINITY) { + g_print ("nothing to do, waiting for %g\n", ent); + time = ent; + } else { + g_print ("ERROR: deadlock\n"); + exit (1); + } + } + iter++; + } + +} + +void +dump (void) +{ + Element *e; + GList *l; + + for (l = g_list_first (elements); l; l = g_list_next (l)) { + e = l->data; + dump_element (e); + } +} + +void +dump_element (Element * e) +{ + Feature *f; + GList *m; + + g_print ("%s:\n", e->name); + for (m = g_list_first (e->features); m; m = g_list_next (m)) { + f = m->data; + g_print (" %s:\n", f->name); + g_print (" type %d\n", f->type); + g_print (" ready %d\n", f->ready); + g_print (" waiting %d\n", f->waiting); + + } +} + +/* Element */ + +const ElementInfo element_types[] = { + {"fakesrc", fakesrc_iterate}, + {"identity", identity_iterate}, + {"fakesink", fakesink_iterate}, + {"audiosink", audiosink_iterate}, + {"mad", mad_iterate}, + {"queue", queue_iterate}, + {"videosink", videosink_iterate}, + {"tee", tee_iterate}, + {NULL, NULL} +}; + +Element * +element_factory_make (const char *type) +{ + return element_factory_make_full (type, type); +} + +Element * +element_factory_make_full (const char *type, const char *name) +{ + int i; + Element *e = g_new0 (Element, 1); + + for (i = 0; element_types[i].type_name; i++) { + if (strcmp (type, element_types[i].type_name) == 0) { + e->type = i; + e->iterate = element_types[i].iterate; + e->caps_iterate = element_types[i].iterate; + e->iterate (e); + e->name = g_strdup (name); + + elements = g_list_append (elements, e); + + return e; + } + } + + g_print ("ERROR: element type %s not found\n", type); + return NULL; +} + +void +element_link (const char *name1, const char *name2) +{ + element_link_full (name1, "src", name2, "sink"); +} + +void +element_link_full (const char *name1, const char *padname1, const char *name2, + const char *padname2) +{ + Element *e1, *e2; + Feature *pad1, *pad2; + + e1 = element_get (name1); + e2 = element_get (name2); + + pad1 = feature_get (e1, padname1); + pad2 = feature_get (e2, padname2); + + pad1->peer = pad2; + pad2->peer = pad1; + +} + +Element * +element_get (const char *name) +{ + GList *l; + + for (l = g_list_first (elements); l; l = g_list_next (l)) { + Element *e = l->data; + + if (strcmp (name, e->name) == 0) + return e; + } + + g_print ("ERROR: element_get(%s) element not found\n", name); + return NULL; +} + +gboolean +element_ready (Element * e) +{ + GList *l; + + //dump_element(e); + if (e->idle) + return TRUE; + for (l = g_list_first (e->features); l; l = g_list_next (l)) { + Feature *f = l->data; + + if (f->waiting && feature_is_ready (f)) { + g_print ("element %s is ready because feature %s is ready\n", + e->name, f->name); + return TRUE; + } + } + return FALSE; +} + +double +element_next_time (Element * e) +{ + GList *l; + double ent = INFINITY; + + for (l = g_list_first (e->features); l; l = g_list_next (l)) { + Feature *f = l->data; + + if (f->type == FD || f->type == TIME) { + if (f->next_time < ent) { + ent = f->next_time; + } + } + } + return ent; +} + +/* Feature */ + +Feature * +feature_get (Element * e, const char *name) +{ + GList *l; + + for (l = g_list_first (e->features); l; l = g_list_next (l)) { + Feature *f = l->data; + + if (strcmp (name, f->name) == 0) + return f; + } + + g_print ("ERROR: feature_get(%s): feature not found\n", name); + return NULL; +} + +Feature * +feature_create (Element * e, int type, const char *name) +{ + Feature *f = g_new0 (Feature, 1); + + f->name = g_strdup (name); + f->type = type; + + e->features = g_list_append (e->features, f); + + return f; +} + +void +feature_wait (Element * e, const char *name, gboolean wait) +{ + Feature *f = feature_get (e, name); + + f->waiting = wait; + switch (f->type) { + case PAD_SRC: + if (f->peer) { + f->peer->ready = wait && f->peer->bufpen; + } + break; + case PAD_SINK: + if (f->peer) { + f->peer->ready = wait && f->bufpen; + } + break; + } +} + +gboolean +feature_ready (Element * e, const char *name) +{ + Feature *f = feature_get (e, name); + + return feature_is_ready (f); +} + +gboolean +feature_is_ready (Feature * f) +{ + switch (f->type) { + case PAD_SRC: + if (f->peer) { + return f->peer->waiting && !f->peer->bufpen; + } + break; + case PAD_SINK: + if (f->peer) { + return f->peer->waiting && f->bufpen; + } + break; + case FD: + g_print ("testing %g <= %g\n", f->next_time, time); + if (f->next_time <= time) { + return TRUE; + } else { + return FALSE; + } + break; + case TIME: + g_print ("testing %g <= %g\n", f->next_time, time); + if (f->next_time <= time) { + return TRUE; + } else { + return FALSE; + } + break; + } + + return FALSE; +} + +void +pad_push (Element * e, const char *name) +{ + Feature *f = feature_get (e, name); + + g_assert (f->type == PAD_SRC); + + g_print ("pushing pad on %s:%s\n", e->name, name); + if (f->peer->bufpen) { + g_print ("ERROR: push when bufpen full link\n"); + exit (0); + } + f->peer->bufpen = TRUE; + f->peer->ready = f->waiting; + f->ready = FALSE; +} + +void +pad_pull (Element * e, const char *name) +{ + Feature *f = feature_get (e, name); + + g_assert (f->type == PAD_SINK); + + g_print ("pulling pad on %s:%s\n", e->name, name); + if (!f->bufpen) { + g_print ("ERROR: pull when bufpen empty\n"); + exit (0); + } + f->bufpen = FALSE; + f->ready = FALSE; + f->peer->ready = f->waiting; +} + +void +fd_push (Element * e, const char *name) +{ + Feature *f = feature_get (e, name); + + g_assert (f->type == FD); + + g_print ("pushing to fd %s:%s\n", e->name, name); + if (time < f->next_time) { + g_print ("ERROR: push too early\n"); + exit (0); + } + f->next_time += f->interval; +} + +void +fd_start (Element * e, const char *name, double interval) +{ + Feature *f = feature_get (e, name); + + g_assert (f->type == FD); + + f->interval = interval; + f->next_time = f->interval; +} + +void +time_start (Element * e, const char *name, double interval) +{ + Feature *f = feature_get (e, name); + + g_assert (f->type == TIME); + + f->interval = interval; + f->next_time = f->interval; +} + +void +time_increment (Element * e, const char *name, double interval) +{ + Feature *f = feature_get (e, name); + + g_assert (f->type == TIME); + + f->interval = interval; + f->next_time += f->interval; +} + +/* elements */ + +void +fakesrc_iterate (Element * element) +{ + //Event *event; + + if (!element->init) { + feature_create (element, PAD_SRC, "src"); + + feature_wait (element, "src", TRUE); + + element->init = TRUE; + return; + } + + pad_push (element, "src"); +} + +void +identity_iterate (Element * element) +{ + if (!element->init) { + feature_create (element, PAD_SINK, "sink"); + feature_create (element, PAD_SRC, "src"); + + feature_wait (element, "sink", FALSE); + feature_wait (element, "src", TRUE); + + element->init = TRUE; + return; + } + + if (feature_ready (element, "sink") && feature_ready (element, "src")) { + pad_pull (element, "sink"); + pad_push (element, "src"); + feature_wait (element, "sink", FALSE); + feature_wait (element, "src", TRUE); + } else { + if (feature_ready (element, "sink")) { + g_print ("ERROR: assert not reached\n"); + feature_wait (element, "src", TRUE); + feature_wait (element, "sink", FALSE); + } + if (feature_ready (element, "src")) { + feature_wait (element, "src", FALSE); + feature_wait (element, "sink", TRUE); + } + } +} + +void +fakesink_iterate (Element * element) +{ + if (!element->init) { + feature_create (element, PAD_SINK, "sink"); + + element->idle = TRUE; + element->init = TRUE; + return; + } + + if (feature_ready (element, "sink")) { + pad_pull (element, "sink"); + g_print ("FAKESINK\n"); + } else { + feature_wait (element, "sink", TRUE); + element->idle = FALSE; + } + +} + +void +audiosink_iterate (Element * element) +{ + if (!element->init) { + Feature *f; + + feature_create (element, PAD_SINK, "sink"); + f = feature_create (element, FD, "fd"); + fd_start (element, "fd", 1024 / 44100.0); + + feature_wait (element, "fd", TRUE); + + element->init = TRUE; + return; + } + + if (feature_ready (element, "fd")) { + if (feature_ready (element, "sink")) { + pad_pull (element, "sink"); + fd_push (element, "fd"); + g_print ("AUDIOSINK\n"); + feature_wait (element, "fd", TRUE); + feature_wait (element, "sink", FALSE); + } else { + feature_wait (element, "fd", FALSE); + feature_wait (element, "sink", TRUE); + } + } else { + g_print ("ERROR: assert not reached\n"); + + feature_wait (element, "sink", FALSE); + feature_wait (element, "fd", TRUE); + } + +} + +void +mad_iterate (Element * element) +{ + if (!element->init) { + feature_create (element, PAD_SINK, "sink"); + feature_create (element, PAD_SRC, "src"); + + element->state = 0; + feature_wait (element, "sink", FALSE); + feature_wait (element, "src", TRUE); + + element->init = TRUE; + return; + } + + if (element->state > 0) { + if (feature_ready (element, "src")) { + pad_push (element, "src"); + element->state--; + if (element->state > 0) { + feature_wait (element, "sink", FALSE); + feature_wait (element, "src", TRUE); + } else { + feature_wait (element, "sink", FALSE); + feature_wait (element, "src", TRUE); + } + } else { + g_print ("ERROR: assert not reached\n"); + } + } else { + if (feature_ready (element, "sink")) { + pad_pull (element, "sink"); + element->state += 5; + pad_push (element, "src"); + element->state--; + feature_wait (element, "sink", FALSE); + feature_wait (element, "src", TRUE); + } else { + feature_wait (element, "sink", TRUE); + feature_wait (element, "src", FALSE); + } + } +} + +void +queue_iterate (Element * element) +{ + if (!element->init) { + feature_create (element, PAD_SINK, "sink"); + feature_create (element, PAD_SRC, "src"); + + element->state = 0; + feature_wait (element, "sink", FALSE); + feature_wait (element, "src", TRUE); + + element->init = TRUE; + return; + } + + if (feature_ready (element, "sink") && element->state < 5) { + pad_pull (element, "sink"); + element->state++; + } + if (feature_ready (element, "src") && element->state > 0) { + pad_push (element, "src"); + element->state--; + } + + if (element->state < 5) { + feature_wait (element, "sink", TRUE); + } else { + feature_wait (element, "sink", FALSE); + } + if (element->state > 0) { + feature_wait (element, "src", TRUE); + } else { + feature_wait (element, "src", FALSE); + } +} + +void +demux_iterate (Element * element) +{ + if (!element->init) { + feature_create (element, PAD_SINK, "sink"); + feature_create (element, PAD_SRC, "video_src"); + feature_create (element, PAD_SRC, "audio_src"); + + feature_wait (element, "sink", TRUE); + feature_wait (element, "video_src", FALSE); + feature_wait (element, "audio_src", FALSE); + + element->init = TRUE; + return; + } +#if 0 + /* demux waits for a buffer on the sinkpad, then queues buffers and + * eventually pushes them to sinkpads */ + if (feautre_ready (element, "sink") &&) { + + } +#endif + +} + +void +videosink_iterate (Element * element) +{ + if (!element->init) { + Feature *f; + + feature_create (element, PAD_SINK, "sink"); + f = feature_create (element, TIME, "time"); + time_start (element, "time", 1 / 25.0); + + feature_wait (element, "sink", TRUE); + feature_wait (element, "time", FALSE); + + element->init = TRUE; + return; + } + + /* this version hold the buffer in the bufpen */ + if (feature_ready (element, "sink")) { + if (feature_ready (element, "time")) { + pad_pull (element, "sink"); + g_print ("VIDEOSINK\n"); + time_increment (element, "time", 1 / 25.0); + feature_wait (element, "time", FALSE); + feature_wait (element, "sink", TRUE); + } else { + feature_wait (element, "time", TRUE); + feature_wait (element, "sink", FALSE); + } + } else { + g_print ("ERROR: assert not reached\n"); + } +} + +void +tee_iterate (Element * element) +{ + if (!element->init) { + feature_create (element, PAD_SINK, "sink"); + feature_create (element, PAD_SRC, "src1"); + feature_create (element, PAD_SRC, "src2"); + + feature_wait (element, "sink", FALSE); + feature_wait (element, "src1", TRUE); + feature_wait (element, "src2", TRUE); + + element->init = TRUE; + return; + } + + /* this version hold the buffer in the bufpen */ + if (feature_ready (element, "sink")) { + pad_pull (element, "sink"); + pad_push (element, "src1"); + pad_push (element, "src2"); + + feature_wait (element, "sink", FALSE); + feature_wait (element, "src1", TRUE); + feature_wait (element, "src2", TRUE); + } else { + if (feature_ready (element, "src1")) { + if (feature_ready (element, "src2")) { + feature_wait (element, "sink", TRUE); + feature_wait (element, "src1", FALSE); + feature_wait (element, "src2", FALSE); + } else { + feature_wait (element, "sink", FALSE); + feature_wait (element, "src1", FALSE); + feature_wait (element, "src2", TRUE); + } + } else { + if (feature_ready (element, "src2")) { + feature_wait (element, "sink", FALSE); + feature_wait (element, "src1", TRUE); + feature_wait (element, "src2", FALSE); + } else { + g_print ("ERROR: assert not reached\n"); + } + } + } +} diff --git a/testsuite/trigger/Makefile.am b/testsuite/trigger/Makefile.am new file mode 100644 index 0000000..ef85850 --- /dev/null +++ b/testsuite/trigger/Makefile.am @@ -0,0 +1,9 @@ + + +noinst_PROGRAMS = trigger + +trigger_SOURCES = trigger.c +trigger_CFLAGS = $(GST_OBJ_CFLAGS) +trigger_LDADD = $(GST_OBJS_LIBS) $(GLIB_LIBS) + + diff --git a/testsuite/trigger/trigger.c b/testsuite/trigger/trigger.c new file mode 100644 index 0000000..dba91bf --- /dev/null +++ b/testsuite/trigger/trigger.c @@ -0,0 +1,856 @@ + +#include +#include +#include +#include +#include + +#define INFINITY 1e10 + +typedef struct _Element Element; +typedef struct _Feature Feature; +typedef struct _ElementInfo ElementInfo; + +enum +{ + PAD_SRC, + PAD_SINK, + FD, + TIME +}; + +struct _Element +{ + char *name; + GList *features; + int type; + gboolean init; + gboolean idle; + + void (*iterate) (Element * element); + void (*caps_iterate) (Element * element); + + int state; +}; + +struct _Feature +{ + char *name; + int type; + + Element *parent; + + gboolean waiting; + gboolean ready; + + /* for pads */ + gboolean bufpen; + Feature *peer; + GstCaps *caps; + + /* for fds */ + double next_time; + double interval; +}; + +struct _ElementInfo +{ + char *type_name; + void (*iterate) (Element * element); + void (*caps_iterate) (Element * element); +}; + +GList *elements; + +void run (void); +void dump (void); +void dump_element (Element * e); + +Element *element_factory_make (const char *type); +Element *element_factory_make_full (const char *type, const char *name); +void element_link (const char *name1, const char *name2); +void element_link_full (const char *name1, const char *padname1, + const char *name2, const char *padname2); +Element *element_get (const char *name); +gboolean element_ready (Element * e); +gboolean feature_is_ready (Feature * f); +double element_next_time (Element * e); + +Feature *feature_create (Element * e, int type, const char *name); +Feature *feature_get (Element * e, const char *name); +gboolean feature_ready (Element * e, const char *name); + +void fakesrc_iterate (Element * element); +void identity_iterate (Element * element); +void fakesink_iterate (Element * element); +void audiosink_iterate (Element * element); +void mad_iterate (Element * element); +void queue_iterate (Element * element); +void videosink_iterate (Element * element); +void tee_iterate (Element * element); + +void fakesrc_caps (Element * element); +void identity_caps (Element * element); +void fakesink_caps (Element * element); +void audiosink_caps (Element * element); +void mad_caps (Element * element); +void queue_caps (Element * element); +void videosink_caps (Element * element); +void tee_caps (Element * element); + +double time; + +int +main (int argc, char *argv[]) +{ + int x = 8; + + switch (x) { + case 0: + /* fakesrc ! fakesink */ + element_factory_make ("fakesrc"); + element_factory_make ("fakesink"); + element_link ("fakesrc", "fakesink"); + break; + case 1: + /* fakesrc ! identity ! fakesink */ + element_factory_make ("fakesrc"); + element_factory_make ("identity"); + element_factory_make ("fakesink"); + + element_link ("fakesrc", "identity"); + element_link ("identity", "fakesink"); + break; + case 2: + /* fakesrc ! identity ! identity ! fakesink */ + element_factory_make ("fakesrc"); + element_factory_make_full ("identity", "identity0"); + element_factory_make_full ("identity", "identity1"); + element_factory_make ("fakesink"); + + element_link ("fakesrc", "identity0"); + element_link ("identity0", "identity1"); + element_link ("identity1", "fakesink"); + break; + case 3: + /* fakesrc ! audiosink */ + element_factory_make ("fakesrc"); + element_factory_make ("audiosink"); + + element_link ("fakesrc", "audiosink"); + break; + case 4: + /* fakesrc ! mad ! fakesink */ + element_factory_make ("fakesrc"); + element_factory_make ("mad"); + element_factory_make ("fakesink"); + + element_link ("fakesrc", "mad"); + element_link ("mad", "fakesink"); + break; + case 5: + /* fakesrc ! queue ! fakesink */ + element_factory_make ("fakesrc"); + element_factory_make ("queue"); + element_factory_make ("fakesink"); + + element_link ("fakesrc", "queue"); + element_link ("queue", "fakesink"); + break; + case 6: + /* fakesrc ! queue ! audiosink */ + element_factory_make ("fakesrc"); + element_factory_make ("queue"); + element_factory_make ("audiosink"); + + element_link ("fakesrc", "queue"); + element_link ("queue", "audiosink"); + break; + case 7: + /* fakesrc ! videosink */ + element_factory_make ("fakesrc"); + element_factory_make ("videosink"); + + element_link ("fakesrc", "videosink"); + break; + case 8: + /* fakesrc ! tee ! videosink tee0.src2 ! videosink */ + element_factory_make ("fakesrc"); + element_factory_make ("tee"); + element_factory_make_full ("videosink", "vs0"); + element_factory_make_full ("videosink", "vs1"); + + element_link ("fakesrc", "tee"); + element_link_full ("tee", "src1", "vs0", "sink"); + element_link_full ("tee", "src2", "vs1", "sink"); + break; + } + + run (); + + return 0; +} + +void +run (void) +{ + int iter = 0; + + while (iter < 20) { + Element *e; + GList *l; + gboolean did_something = FALSE; + double ent = INFINITY; + + g_print ("iteration %d time %g\n", iter, time); + for (l = g_list_first (elements); l; l = g_list_next (l)) { + double nt; + + e = l->data; + if (element_ready (e)) { + g_print ("%s: is ready, iterating\n", e->name); + e->iterate (e); + did_something = TRUE; + } else { + g_print ("%s: is not ready\n", e->name); + } + nt = element_next_time (e); + if (nt < ent) { + ent = nt; + } + } + if (did_something == FALSE) { + if (ent < INFINITY) { + g_print ("nothing to do, waiting for %g\n", ent); + time = ent; + } else { + g_print ("ERROR: deadlock\n"); + exit (1); + } + } + iter++; + } + +} + +void +dump (void) +{ + Element *e; + GList *l; + + for (l = g_list_first (elements); l; l = g_list_next (l)) { + e = l->data; + dump_element (e); + } +} + +void +dump_element (Element * e) +{ + Feature *f; + GList *m; + + g_print ("%s:\n", e->name); + for (m = g_list_first (e->features); m; m = g_list_next (m)) { + f = m->data; + g_print (" %s:\n", f->name); + g_print (" type %d\n", f->type); + g_print (" ready %d\n", f->ready); + g_print (" waiting %d\n", f->waiting); + + } +} + +/* Element */ + +const ElementInfo element_types[] = { + {"fakesrc", fakesrc_iterate}, + {"identity", identity_iterate}, + {"fakesink", fakesink_iterate}, + {"audiosink", audiosink_iterate}, + {"mad", mad_iterate}, + {"queue", queue_iterate}, + {"videosink", videosink_iterate}, + {"tee", tee_iterate}, + {NULL, NULL} +}; + +Element * +element_factory_make (const char *type) +{ + return element_factory_make_full (type, type); +} + +Element * +element_factory_make_full (const char *type, const char *name) +{ + int i; + Element *e = g_new0 (Element, 1); + + for (i = 0; element_types[i].type_name; i++) { + if (strcmp (type, element_types[i].type_name) == 0) { + e->type = i; + e->iterate = element_types[i].iterate; + e->caps_iterate = element_types[i].iterate; + e->iterate (e); + e->name = g_strdup (name); + + elements = g_list_append (elements, e); + + return e; + } + } + + g_print ("ERROR: element type %s not found\n", type); + return NULL; +} + +void +element_link (const char *name1, const char *name2) +{ + element_link_full (name1, "src", name2, "sink"); +} + +void +element_link_full (const char *name1, const char *padname1, const char *name2, + const char *padname2) +{ + Element *e1, *e2; + Feature *pad1, *pad2; + + e1 = element_get (name1); + e2 = element_get (name2); + + pad1 = feature_get (e1, padname1); + pad2 = feature_get (e2, padname2); + + pad1->peer = pad2; + pad2->peer = pad1; + +} + +Element * +element_get (const char *name) +{ + GList *l; + + for (l = g_list_first (elements); l; l = g_list_next (l)) { + Element *e = l->data; + + if (strcmp (name, e->name) == 0) + return e; + } + + g_print ("ERROR: element_get(%s) element not found\n", name); + return NULL; +} + +gboolean +element_ready (Element * e) +{ + GList *l; + + //dump_element(e); + if (e->idle) + return TRUE; + for (l = g_list_first (e->features); l; l = g_list_next (l)) { + Feature *f = l->data; + + if (f->waiting && feature_is_ready (f)) { + g_print ("element %s is ready because feature %s is ready\n", + e->name, f->name); + return TRUE; + } + } + return FALSE; +} + +double +element_next_time (Element * e) +{ + GList *l; + double ent = INFINITY; + + for (l = g_list_first (e->features); l; l = g_list_next (l)) { + Feature *f = l->data; + + if (f->type == FD || f->type == TIME) { + if (f->next_time < ent) { + ent = f->next_time; + } + } + } + return ent; +} + +/* Feature */ + +Feature * +feature_get (Element * e, const char *name) +{ + GList *l; + + for (l = g_list_first (e->features); l; l = g_list_next (l)) { + Feature *f = l->data; + + if (strcmp (name, f->name) == 0) + return f; + } + + g_print ("ERROR: feature_get(%s): feature not found\n", name); + return NULL; +} + +Feature * +feature_create (Element * e, int type, const char *name) +{ + Feature *f = g_new0 (Feature, 1); + + f->name = g_strdup (name); + f->type = type; + + e->features = g_list_append (e->features, f); + + return f; +} + +void +feature_wait (Element * e, const char *name, gboolean wait) +{ + Feature *f = feature_get (e, name); + + f->waiting = wait; + switch (f->type) { + case PAD_SRC: + if (f->peer) { + f->peer->ready = wait && f->peer->bufpen; + } + break; + case PAD_SINK: + if (f->peer) { + f->peer->ready = wait && f->bufpen; + } + break; + } +} + +gboolean +feature_ready (Element * e, const char *name) +{ + Feature *f = feature_get (e, name); + + return feature_is_ready (f); +} + +gboolean +feature_is_ready (Feature * f) +{ + switch (f->type) { + case PAD_SRC: + if (f->peer) { + return f->peer->waiting && !f->peer->bufpen; + } + break; + case PAD_SINK: + if (f->peer) { + return f->peer->waiting && f->bufpen; + } + break; + case FD: + g_print ("testing %g <= %g\n", f->next_time, time); + if (f->next_time <= time) { + return TRUE; + } else { + return FALSE; + } + break; + case TIME: + g_print ("testing %g <= %g\n", f->next_time, time); + if (f->next_time <= time) { + return TRUE; + } else { + return FALSE; + } + break; + } + + return FALSE; +} + +void +pad_push (Element * e, const char *name) +{ + Feature *f = feature_get (e, name); + + g_assert (f->type == PAD_SRC); + + g_print ("pushing pad on %s:%s\n", e->name, name); + if (f->peer->bufpen) { + g_print ("ERROR: push when bufpen full link\n"); + exit (0); + } + f->peer->bufpen = TRUE; + f->peer->ready = f->waiting; + f->ready = FALSE; +} + +void +pad_pull (Element * e, const char *name) +{ + Feature *f = feature_get (e, name); + + g_assert (f->type == PAD_SINK); + + g_print ("pulling pad on %s:%s\n", e->name, name); + if (!f->bufpen) { + g_print ("ERROR: pull when bufpen empty\n"); + exit (0); + } + f->bufpen = FALSE; + f->ready = FALSE; + f->peer->ready = f->waiting; +} + +void +fd_push (Element * e, const char *name) +{ + Feature *f = feature_get (e, name); + + g_assert (f->type == FD); + + g_print ("pushing to fd %s:%s\n", e->name, name); + if (time < f->next_time) { + g_print ("ERROR: push too early\n"); + exit (0); + } + f->next_time += f->interval; +} + +void +fd_start (Element * e, const char *name, double interval) +{ + Feature *f = feature_get (e, name); + + g_assert (f->type == FD); + + f->interval = interval; + f->next_time = f->interval; +} + +void +time_start (Element * e, const char *name, double interval) +{ + Feature *f = feature_get (e, name); + + g_assert (f->type == TIME); + + f->interval = interval; + f->next_time = f->interval; +} + +void +time_increment (Element * e, const char *name, double interval) +{ + Feature *f = feature_get (e, name); + + g_assert (f->type == TIME); + + f->interval = interval; + f->next_time += f->interval; +} + +/* elements */ + +void +fakesrc_iterate (Element * element) +{ + //Event *event; + + if (!element->init) { + feature_create (element, PAD_SRC, "src"); + + feature_wait (element, "src", TRUE); + + element->init = TRUE; + return; + } + + pad_push (element, "src"); +} + +void +identity_iterate (Element * element) +{ + if (!element->init) { + feature_create (element, PAD_SINK, "sink"); + feature_create (element, PAD_SRC, "src"); + + feature_wait (element, "sink", FALSE); + feature_wait (element, "src", TRUE); + + element->init = TRUE; + return; + } + + if (feature_ready (element, "sink") && feature_ready (element, "src")) { + pad_pull (element, "sink"); + pad_push (element, "src"); + feature_wait (element, "sink", FALSE); + feature_wait (element, "src", TRUE); + } else { + if (feature_ready (element, "sink")) { + g_print ("ERROR: assert not reached\n"); + feature_wait (element, "src", TRUE); + feature_wait (element, "sink", FALSE); + } + if (feature_ready (element, "src")) { + feature_wait (element, "src", FALSE); + feature_wait (element, "sink", TRUE); + } + } +} + +void +fakesink_iterate (Element * element) +{ + if (!element->init) { + feature_create (element, PAD_SINK, "sink"); + + element->idle = TRUE; + element->init = TRUE; + return; + } + + if (feature_ready (element, "sink")) { + pad_pull (element, "sink"); + g_print ("FAKESINK\n"); + } else { + feature_wait (element, "sink", TRUE); + element->idle = FALSE; + } + +} + +void +audiosink_iterate (Element * element) +{ + if (!element->init) { + Feature *f; + + feature_create (element, PAD_SINK, "sink"); + f = feature_create (element, FD, "fd"); + fd_start (element, "fd", 1024 / 44100.0); + + feature_wait (element, "fd", TRUE); + + element->init = TRUE; + return; + } + + if (feature_ready (element, "fd")) { + if (feature_ready (element, "sink")) { + pad_pull (element, "sink"); + fd_push (element, "fd"); + g_print ("AUDIOSINK\n"); + feature_wait (element, "fd", TRUE); + feature_wait (element, "sink", FALSE); + } else { + feature_wait (element, "fd", FALSE); + feature_wait (element, "sink", TRUE); + } + } else { + g_print ("ERROR: assert not reached\n"); + + feature_wait (element, "sink", FALSE); + feature_wait (element, "fd", TRUE); + } + +} + +void +mad_iterate (Element * element) +{ + if (!element->init) { + feature_create (element, PAD_SINK, "sink"); + feature_create (element, PAD_SRC, "src"); + + element->state = 0; + feature_wait (element, "sink", FALSE); + feature_wait (element, "src", TRUE); + + element->init = TRUE; + return; + } + + if (element->state > 0) { + if (feature_ready (element, "src")) { + pad_push (element, "src"); + element->state--; + if (element->state > 0) { + feature_wait (element, "sink", FALSE); + feature_wait (element, "src", TRUE); + } else { + feature_wait (element, "sink", FALSE); + feature_wait (element, "src", TRUE); + } + } else { + g_print ("ERROR: assert not reached\n"); + } + } else { + if (feature_ready (element, "sink")) { + pad_pull (element, "sink"); + element->state += 5; + pad_push (element, "src"); + element->state--; + feature_wait (element, "sink", FALSE); + feature_wait (element, "src", TRUE); + } else { + feature_wait (element, "sink", TRUE); + feature_wait (element, "src", FALSE); + } + } +} + +void +queue_iterate (Element * element) +{ + if (!element->init) { + feature_create (element, PAD_SINK, "sink"); + feature_create (element, PAD_SRC, "src"); + + element->state = 0; + feature_wait (element, "sink", FALSE); + feature_wait (element, "src", TRUE); + + element->init = TRUE; + return; + } + + if (feature_ready (element, "sink") && element->state < 5) { + pad_pull (element, "sink"); + element->state++; + } + if (feature_ready (element, "src") && element->state > 0) { + pad_push (element, "src"); + element->state--; + } + + if (element->state < 5) { + feature_wait (element, "sink", TRUE); + } else { + feature_wait (element, "sink", FALSE); + } + if (element->state > 0) { + feature_wait (element, "src", TRUE); + } else { + feature_wait (element, "src", FALSE); + } +} + +void +demux_iterate (Element * element) +{ + if (!element->init) { + feature_create (element, PAD_SINK, "sink"); + feature_create (element, PAD_SRC, "video_src"); + feature_create (element, PAD_SRC, "audio_src"); + + feature_wait (element, "sink", TRUE); + feature_wait (element, "video_src", FALSE); + feature_wait (element, "audio_src", FALSE); + + element->init = TRUE; + return; + } +#if 0 + /* demux waits for a buffer on the sinkpad, then queues buffers and + * eventually pushes them to sinkpads */ + if (feautre_ready (element, "sink") &&) { + + } +#endif + +} + +void +videosink_iterate (Element * element) +{ + if (!element->init) { + Feature *f; + + feature_create (element, PAD_SINK, "sink"); + f = feature_create (element, TIME, "time"); + time_start (element, "time", 1 / 25.0); + + feature_wait (element, "sink", TRUE); + feature_wait (element, "time", FALSE); + + element->init = TRUE; + return; + } + + /* this version hold the buffer in the bufpen */ + if (feature_ready (element, "sink")) { + if (feature_ready (element, "time")) { + pad_pull (element, "sink"); + g_print ("VIDEOSINK\n"); + time_increment (element, "time", 1 / 25.0); + feature_wait (element, "time", FALSE); + feature_wait (element, "sink", TRUE); + } else { + feature_wait (element, "time", TRUE); + feature_wait (element, "sink", FALSE); + } + } else { + g_print ("ERROR: assert not reached\n"); + } +} + +void +tee_iterate (Element * element) +{ + if (!element->init) { + feature_create (element, PAD_SINK, "sink"); + feature_create (element, PAD_SRC, "src1"); + feature_create (element, PAD_SRC, "src2"); + + feature_wait (element, "sink", FALSE); + feature_wait (element, "src1", TRUE); + feature_wait (element, "src2", TRUE); + + element->init = TRUE; + return; + } + + /* this version hold the buffer in the bufpen */ + if (feature_ready (element, "sink")) { + pad_pull (element, "sink"); + pad_push (element, "src1"); + pad_push (element, "src2"); + + feature_wait (element, "sink", FALSE); + feature_wait (element, "src1", TRUE); + feature_wait (element, "src2", TRUE); + } else { + if (feature_ready (element, "src1")) { + if (feature_ready (element, "src2")) { + feature_wait (element, "sink", TRUE); + feature_wait (element, "src1", FALSE); + feature_wait (element, "src2", FALSE); + } else { + feature_wait (element, "sink", FALSE); + feature_wait (element, "src1", FALSE); + feature_wait (element, "src2", TRUE); + } + } else { + if (feature_ready (element, "src2")) { + feature_wait (element, "sink", FALSE); + feature_wait (element, "src1", TRUE); + feature_wait (element, "src2", FALSE); + } else { + g_print ("ERROR: assert not reached\n"); + } + } + } +}