#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) { 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"); } } } }