mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 13:41:48 +00:00
687173ffc0
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.
856 lines
18 KiB
C
856 lines
18 KiB
C
|
|
#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");
|
|
}
|
|
}
|
|
}
|
|
}
|