Commit 687173ff authored by David Schleef's avatar David Schleef

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.
parent bb1be5f5
2005-03-29 David Schleef <ds@schleef.org>
* 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 <wim@fluendo.com>
* gst/base/Makefile.am:
......
......@@ -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
......
noinst_PROGRAMS = trigger
trigger_SOURCES = trigger.c
trigger_CFLAGS = $(GST_OBJ_CFLAGS)
trigger_LDADD = $(GST_OBJS_LIBS) $(GLIB_LIBS)
#include <glib.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <gst/gst.h>
#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) {