2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 //#define GST_DEBUG_ENABLED
22 #include "gstscheduler.h"
27 gst_bin_loopfunc_wrapper (int argc,char *argv[])
29 GstElement *element = GST_ELEMENT (argv);
30 G_GNUC_UNUSED const gchar *name = gst_element_get_name (element);
32 DEBUG_ENTER("(%d,'%s')",argc,name);
35 DEBUG("calling loopfunc %s for element %s\n",
36 GST_DEBUG_FUNCPTR_NAME (element->loopfunc),name);
37 (element->loopfunc) (element);
38 DEBUG("element %s ended loop function\n", name);
39 } while (!GST_ELEMENT_IS_COTHREAD_STOPPING(element));
40 GST_FLAG_UNSET(element,GST_ELEMENT_COTHREAD_STOPPING);
42 DEBUG_LEAVE("(%d,'%s')",argc,name);
47 gst_bin_chain_wrapper (int argc,char *argv[])
49 GstElement *element = GST_ELEMENT (argv);
50 G_GNUC_UNUSED const gchar *name = gst_element_get_name (element);
55 DEBUG_ENTER("(\"%s\")",name);
56 DEBUG("stepping through pads\n");
60 pad = GST_PAD (pads->data);
61 pads = g_list_next (pads);
62 if (pad->direction == GST_PAD_SINK) {
63 DEBUG("pulling a buffer from %s:%s\n", name, gst_pad_get_name (pad));
64 buf = gst_pad_pull (pad);
65 DEBUG("calling chain function of %s:%s\n", name, gst_pad_get_name (pad));
66 (pad->chainfunc) (pad,buf);
67 DEBUG("calling chain function of %s:%s done\n", name, gst_pad_get_name (pad));
70 } while (!GST_ELEMENT_IS_COTHREAD_STOPPING(element));
71 GST_FLAG_UNSET(element,GST_ELEMENT_COTHREAD_STOPPING);
73 DEBUG_LEAVE("(%d,'%s')",argc,name);
78 gst_bin_src_wrapper (int argc,char *argv[])
80 GstElement *element = GST_ELEMENT (argv);
84 G_GNUC_UNUSED const gchar *name = gst_element_get_name (element);
86 DEBUG_ENTER("(%d,\"%s\")",argc,name);
91 pad = GST_PAD (pads->data);
92 if (pad->direction == GST_PAD_SRC) {
93 // region_struct *region = cothread_get_data (element->threadstate, "region");
94 DEBUG("calling _getfunc for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
96 //gst_src_push_region (GST_SRC (element), region->offset, region->size);
97 // if (pad->getregionfunc == NULL)
98 // fprintf(stderr,"error, no getregionfunc in \"%s\"\n", name);
99 // buf = (pad->getregionfunc)(pad, region->offset, region->size);
101 if (pad->getfunc == NULL)
102 fprintf(stderr,"error, no getfunc in \"%s\"\n", name);
103 buf = (pad->getfunc)(pad);
106 DEBUG("calling gst_pad_push on pad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
107 gst_pad_push (pad, buf);
109 pads = g_list_next(pads);
111 } while (!GST_ELEMENT_IS_COTHREAD_STOPPING(element));
112 GST_FLAG_UNSET(element,GST_ELEMENT_COTHREAD_STOPPING);
119 gst_bin_pushfunc_proxy (GstPad *pad, GstBuffer *buf)
121 cothread_state *threadstate = GST_ELEMENT(pad->parent)->threadstate;
122 DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
123 DEBUG("putting buffer %p in peer's pen\n",buf);
124 pad->peer->bufpen = buf;
125 DEBUG("switching to %p (@%p)\n",threadstate,&(GST_ELEMENT(pad->parent)->threadstate));
126 cothread_switch (threadstate);
127 DEBUG("done switching\n");
131 gst_bin_pullfunc_proxy (GstPad *pad)
135 cothread_state *threadstate = GST_ELEMENT(pad->parent)->threadstate;
136 DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
137 if (pad->bufpen == NULL) {
138 DEBUG("switching to %p (@%p)\n",threadstate,&(GST_ELEMENT(pad->parent)->threadstate));
139 cothread_switch (threadstate);
141 DEBUG("done switching\n");
148 gst_bin_chainfunc_proxy (GstPad *pad)
157 gst_bin_pullregionfunc_proxy (GstPad *pad,
161 // region_struct region;
162 cothread_state *threadstate;
164 DEBUG_ENTER("%s:%s,%ld,%ld",GST_DEBUG_PAD_NAME(pad),offset,size);
166 // region.offset = offset;
167 // region.size = size;
169 // threadstate = GST_ELEMENT(pad->parent)->threadstate;
170 // cothread_set_data (threadstate, "region", ®ion);
171 cothread_switch (threadstate);
172 // cothread_set_data (threadstate, "region", NULL);
177 gst_schedule_cothreaded_chain (GstBin *bin, _GstBinChain *chain) {
180 cothread_func wrapper_function;
184 DEBUG("chain is using cothreads\n");
186 // first create thread context
187 if (bin->threadcontext == NULL) {
188 DEBUG("initializing cothread context\n");
189 bin->threadcontext = cothread_init ();
192 // walk through all the chain's elements
193 elements = chain->elements;
195 element = GST_ELEMENT (elements->data);
196 elements = g_list_next (elements);
198 // start out without a wrapper function, we select it later
199 wrapper_function = NULL;
201 // if the element has a loopfunc...
202 if (element->loopfunc != NULL) {
203 wrapper_function = GST_DEBUG_FUNCPTR(gst_bin_loopfunc_wrapper);
204 DEBUG("\nelement '%s' is a loop-based\n",gst_element_get_name(element));
206 // otherwise we need to decide what kind of cothread
207 // if it's not DECOUPLED, we decide based on whether it's a source or not
208 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
209 // if it doesn't have any sinks, it must be a source (duh)
210 if (element->numsinkpads == 0) {
211 wrapper_function = GST_DEBUG_FUNCPTR(gst_bin_src_wrapper);
212 DEBUG("\nelement '%s' is a source, using _src_wrapper\n",gst_element_get_name(element));
214 wrapper_function = GST_DEBUG_FUNCPTR(gst_bin_chain_wrapper);
215 DEBUG("\nelement '%s' is a filter, using _chain_wrapper\n",gst_element_get_name(element));
220 // now we have to walk through the pads to set up their state
221 pads = gst_element_get_pad_list (element);
223 pad = GST_PAD (pads->data);
224 pads = g_list_next (pads);
226 // if the element is DECOUPLED or outside the manager, we have to chain
227 if ((wrapper_function == NULL) ||
228 (GST_ELEMENT(pad->peer->parent)->manager != GST_ELEMENT(bin))) {
229 // set the chain proxies
230 if (gst_pad_get_direction (pad) == GST_PAD_SINK) {
231 DEBUG("copying chain function into push proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
232 pad->pushfunc = pad->chainfunc;
234 DEBUG("copying get function into pull proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
235 pad->pullfunc = pad->getfunc;
236 pad->pullregionfunc = pad->getregionfunc;
239 // otherwise we really are a cothread
241 if (gst_pad_get_direction (pad) == GST_PAD_SINK) {
242 DEBUG("setting cothreaded push proxy for sinkpad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
243 pad->pushfunc = GST_DEBUG_FUNCPTR(gst_bin_pushfunc_proxy);
245 DEBUG("setting cothreaded pull proxy for srcpad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
246 pad->pullfunc = GST_DEBUG_FUNCPTR(gst_bin_pullfunc_proxy);
251 // need to set up the cothread now
252 if (wrapper_function != NULL) {
253 if (element->threadstate == NULL) {
254 element->threadstate = cothread_create (bin->threadcontext);
255 DEBUG("created cothread %p for '%s'\n",element->threadstate,gst_element_get_name(element));
257 cothread_setfunc (element->threadstate, wrapper_function, 0, (char **)element);
258 DEBUG("set wrapper function for '%s' to &%s\n",gst_element_get_name(element),
259 GST_DEBUG_FUNCPTR_NAME(wrapper_function));
265 gst_schedule_chained_chain (GstBin *bin, _GstBinChain *chain) {
271 DEBUG("chain entered\n");
272 // walk through all the elements
273 elements = chain->elements;
275 element = GST_ELEMENT (elements->data);
276 elements = g_list_next (elements);
278 // walk through all the pads
279 pads = gst_element_get_pad_list (element);
281 pad = GST_PAD (pads->data);
282 pads = g_list_next (pads);
284 if (gst_pad_get_direction (pad) == GST_PAD_SINK) {
285 DEBUG("copying chain function into push proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
286 pad->pushfunc = pad->chainfunc;
288 DEBUG("copying get function into pull proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
289 pad->pullfunc = pad->getfunc;
290 pad->pullregionfunc = pad->getregionfunc;
296 static void gst_bin_schedule_cleanup(GstBin *bin) {
300 chains = bin->chains;
302 chain = (_GstBinChain *)(chains->data);
303 chains = g_list_next(chains);
305 g_list_free(chain->elements);
306 g_list_free(chain->entries);
310 g_list_free(bin->chains);
315 void gst_bin_schedule_func(GstBin *bin) {
316 // GstElement *manager;
319 // const gchar *elementname;
320 GSList *pending = NULL;
321 // GstBin *pending_bin;
324 // GstElement *peer_manager;
328 DEBUG_SET_STRING("(\"%s\")",gst_element_get_name (GST_ELEMENT (bin)));
331 gst_bin_schedule_cleanup(bin);
333 // next we have to find all the separate scheduling chains
334 DEBUG("\nattempting to find scheduling chains...\n");
335 // first make a copy of the managed_elements we can mess with
336 elements = g_list_copy (bin->managed_elements);
337 // we have to repeat until the list is empty to get all chains
339 element = GST_ELEMENT (elements->data);
341 // if this is a DECOUPLED element
342 if (GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
343 // skip this element entirely
344 DEBUG("skipping '%s' because it's decoupled\n",gst_element_get_name(element));
345 elements = g_list_next (elements);
349 DEBUG("starting with element '%s'\n",gst_element_get_name(element));
351 // prime the pending list with the first element off the top
352 pending = g_slist_prepend (NULL, element);
353 // and remove that one from the main list
354 elements = g_list_remove (elements, element);
356 // create a chain structure
357 chain = g_new0 (_GstBinChain, 1);
359 // for each pending element, walk the pipeline
361 // retrieve the top of the stack and pop it
362 element = GST_ELEMENT (pending->data);
363 pending = g_slist_remove (pending, element);
365 // add ourselves to the chain's list of elements
366 DEBUG("adding '%s' to chain\n",gst_element_get_name(element));
367 chain->elements = g_list_prepend (chain->elements, element);
368 chain->num_elements++;
369 // set the cothreads flag as appropriate
370 if (GST_FLAG_IS_SET (element, GST_ELEMENT_USE_COTHREAD))
371 chain->need_cothreads = TRUE;
372 if (bin->use_cothreads == TRUE)
373 chain->need_cothreads = TRUE;
375 // if we're managed by the current bin, and we're not decoupled,
376 // go find all the peers and add them to the list of elements to check
377 if ((element->manager == GST_ELEMENT(bin)) &&
378 !GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
379 // remove ourselves from the outer list of all managed elements
380 // DEBUG("removing '%s' from list of possible elements\n",gst_element_get_name(element));
381 elements = g_list_remove (elements, element);
383 // if this element is a source, add it as an entry
384 if (element->numsinkpads == 0) {
385 chain->entries = g_list_prepend (chain->entries, element);
386 DEBUG("added '%s' as SRC entry into the chain\n",gst_element_get_name(element));
389 // now we have to walk the pads to find peers
390 pads = gst_element_get_pad_list (element);
392 pad = GST_PAD (pads->data);
393 pads = g_list_next (pads);
394 DEBUG("have pad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
396 DEBUG("peer pad %p\n", pad->peer);
397 // only bother with if the pad's peer's parent is this bin or it's DECOUPLED
398 // only add it if it's in the list of un-visited elements still
399 if ((g_list_find (elements, pad->peer->parent) != NULL) ||
400 GST_FLAG_IS_SET (pad->peer->parent, GST_ELEMENT_DECOUPLED)) {
401 // add the peer element to the pending list
402 DEBUG("adding '%s' to list of pending elements\n",gst_element_get_name(GST_ELEMENT(pad->peer->parent)));
403 pending = g_slist_prepend (pending, GST_ELEMENT(pad->peer->parent));
405 // if this is a sink pad, then the element on the other side is an entry
406 if ((gst_pad_get_direction (pad) == GST_PAD_SINK) &&
407 (GST_FLAG_IS_SET (pad->peer->parent, GST_ELEMENT_DECOUPLED))) {
408 chain->entries = g_list_prepend (chain->entries, pad->peer->parent);
409 DEBUG("added '%s' as DECOUPLED entry into the chain\n",gst_element_get_name(GST_ELEMENT(pad->peer->parent)));
412 DEBUG("element '%s' has already been dealt with\n",gst_element_get_name(GST_ELEMENT(pad->peer->parent)));
417 // add the chain to the bin
418 DEBUG("have chain with %d elements: ",chain->num_elements);
419 { GList *elements = chain->elements;
421 element = GST_ELEMENT (elements->data);
422 elements = g_list_next(elements);
423 DEBUG_NOPREFIX("%s, ",gst_element_get_name(element));
426 DEBUG_NOPREFIX("\n");
427 bin->chains = g_list_prepend (bin->chains, chain);
430 // free up the list in case it's full of DECOUPLED elements
431 g_list_free (elements);
433 DEBUG("\nwe have %d chains to schedule\n",bin->num_chains);
435 // now we have to go through all the chains and schedule them
436 chains = bin->chains;
438 chain = (_GstBinChain *)(chains->data);
439 chains = g_list_next (chains);
441 // schedule as appropriate
442 if (chain->need_cothreads) {
443 gst_schedule_cothreaded_chain (bin,chain);
445 gst_schedule_chained_chain (bin,chain);
449 DEBUG_LEAVE("(\"%s\")",gst_element_get_name(GST_ELEMENT(bin)));
454 // ***** check for possible connections outside
455 // get the pad's peer
456 peer = gst_pad_get_peer (pad);
457 // FIXME this should be an error condition, if not disabled
459 // get the parent of the peer of the pad
460 outside = GST_ELEMENT (gst_pad_get_parent (peer));
461 // FIXME this should *really* be an error condition
463 // if it's a source or connection and it's not ours...
464 if ((GST_IS_SRC (outside) || GST_IS_CONNECTION (outside)) &&
465 (gst_object_get_parent (GST_OBJECT (outside)) != GST_OBJECT (bin))) {
466 if (gst_pad_get_direction (pad) == GST_PAD_SINK) {
467 DEBUG("dealing with outside source element %s\n",gst_element_get_name(outside));
468 // DEBUG("PUNT: copying pullfunc ptr from %s:%s to %s:%s (@ %p)\n",
469 //GST_DEBUG_PAD_NAME(pad->peer),GST_DEBUG_PAD_NAME(pad),&pad->pullfunc);
470 // pad->pullfunc = pad->peer->pullfunc;
471 // DEBUG("PUNT: setting pushfunc proxy to fake proxy on %s:%s\n",GST_DEBUG_PAD_NAME(pad->peer));
472 // pad->peer->pushfunc = GST_DEBUG_FUNCPTR(gst_bin_pushfunc_fake_proxy);
473 pad->pullfunc = GST_DEBUG_FUNCPTR(gst_bin_pullfunc_proxy);
483 } else if (GST_IS_SRC (element)) {
484 DEBUG("adding '%s' as entry point, because it's a source\n",gst_element_get_name (element));
485 bin->entries = g_list_prepend (bin->entries,element);
487 cothread_setfunc(element->threadstate,gst_bin_src_wrapper,0,(char **)element);
490 pads = gst_element_get_pad_list (element);
492 pad = GST_PAD(pads->data);
494 if (gst_pad_get_direction (pad) == GST_PAD_SINK) {
495 DEBUG("setting push proxy for sinkpad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
496 // set the proxy functions
497 pad->pushfunc = GST_DEBUG_FUNCPTR(gst_bin_pushfunc_proxy);
498 DEBUG("pushfunc %p = gst_bin_pushfunc_proxy %p\n",&pad->pushfunc,gst_bin_pushfunc_proxy);
499 } else if (gst_pad_get_direction (pad) == GST_PAD_SRC) {
500 DEBUG("setting pull proxies for srcpad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
501 // set the proxy functions
502 pad->pullfunc = GST_DEBUG_FUNCPTR(gst_bin_pullfunc_proxy);
503 DEBUG("pad->pullfunc(@%p) = gst_bin_pullfunc_proxy(@%p)\n",
504 &pad->pullfunc,gst_bin_pullfunc_proxy);
505 pad->pullregionfunc = GST_DEBUG_FUNCPTR(gst_bin_pullregionfunc_proxy);
507 pads = g_list_next (pads);
509 elements = g_list_next (elements);
511 // if there are no entries, we have to pick one at random
512 if (bin->num_entries == 0)
513 bin->entries = g_list_prepend (bin->entries, GST_ELEMENT(bin->children->data));
516 DEBUG("don't need cothreads, looking for entry points\n");
517 // we have to find which elements will drive an iteration
518 elements = bin->children;
520 element = GST_ELEMENT (elements->data);
521 DEBUG("found element \"%s\"\n", gst_element_get_name (element));
522 if (GST_IS_BIN (element)) {
523 gst_bin_create_plan (GST_BIN (element));
525 if (GST_IS_SRC (element)) {
526 DEBUG("adding '%s' as entry point, because it's a source\n",gst_element_get_name (element));
527 bin->entries = g_list_prepend (bin->entries, element);
531 // go through all the pads, set pointers, and check for connections
532 pads = gst_element_get_pad_list (element);
534 pad = GST_PAD (pads->data);
536 if (gst_pad_get_direction (pad) == GST_PAD_SINK) {
537 DEBUG("found SINK pad %s:%s\n", GST_DEBUG_PAD_NAME(pad));
539 // copy the peer's chain function, easy enough
540 DEBUG("copying peer's chainfunc to %s:%s's pushfunc\n",GST_DEBUG_PAD_NAME(pad));
541 pad->pushfunc = GST_DEBUG_FUNCPTR(pad->peer->chainfunc);
543 // need to walk through and check for outside connections
544 //FIXME need to do this for all pads
545 // get the pad's peer
546 peer = gst_pad_get_peer (pad);
548 DEBUG("found SINK pad %s has no peer\n", gst_pad_get_name (pad));
551 // get the parent of the peer of the pad
552 outside = GST_ELEMENT (gst_pad_get_parent (peer));
554 // if it's a connection and it's not ours...
555 if (GST_IS_CONNECTION (outside) &&
556 (gst_object_get_parent (GST_OBJECT (outside)) != GST_OBJECT (bin))) {
557 gst_info("gstbin: element \"%s\" is the external source Connection "
558 "for internal element \"%s\"\n",
559 gst_element_get_name (GST_ELEMENT (outside)),
560 gst_element_get_name (GST_ELEMENT (element)));
561 bin->entries = g_list_prepend (bin->entries, outside);
566 DEBUG("found pad %s\n", gst_pad_get_name (pad));
568 pads = g_list_next (pads);
571 elements = g_list_next (elements);
579 // If cothreads are needed, we need to not only find elements but
580 // set up cothread states and various proxy functions.
581 if (bin->need_cothreads) {
582 DEBUG("bin is using cothreads\n");
584 // first create thread context
585 if (bin->threadcontext == NULL) {
586 DEBUG("initializing cothread context\n");
587 bin->threadcontext = cothread_init ();
590 // walk through all the children
591 elements = bin->managed_elements;
593 element = GST_ELEMENT (elements->data);
594 elements = g_list_next (elements);
596 // start out with a NULL warpper function, we'll set it if we want a cothread
597 wrapper_function = NULL;
599 // have to decide if we need to or can use a cothreads, and if so which wrapper
600 // first of all, if there's a loopfunc, the decision's already made
601 if (element->loopfunc != NULL) {
602 wrapper_function = GST_DEBUG_FUNCPTR(gst_bin_loopfunc_wrapper);
603 DEBUG("element %s is a loopfunc, must use a cothread\n",gst_element_get_name(element));
605 // otherwise we need to decide if it needs a cothread
606 // if it's complex, or cothreads are preferred and it's *not* decoupled, cothread it
607 if (GST_FLAG_IS_SET (element,GST_ELEMENT_COMPLEX) ||
608 (GST_FLAG_IS_SET (bin,GST_BIN_FLAG_PREFER_COTHREADS) &&
609 !GST_FLAG_IS_SET (element,GST_ELEMENT_DECOUPLED))) {
610 // base it on whether we're going to loop through source or sink pads
611 if (element->numsinkpads == 0)
612 wrapper_function = GST_DEBUG_FUNCPTR(gst_bin_src_wrapper);
614 wrapper_function = GST_DEBUG_FUNCPTR(gst_bin_chain_wrapper);
618 // walk through the all the pads for this element, setting proxy functions
619 // the selection of proxy functions depends on whether we're in a cothread or not
620 pads = gst_element_get_pad_list (element);
622 pad = GST_PAD (pads->data);
623 pads = g_list_next (pads);
625 // check to see if someone else gets to set up the element
626 peer_manager = GST_ELEMENT((pad)->peer->parent)->manager;
627 if (peer_manager != GST_ELEMENT(bin)) {
628 DEBUG("WARNING: pad %s:%s is connected outside of bin\n",GST_DEBUG_PAD_NAME(pad));
631 // if the wrapper_function is set, we need to use the proxy functions
632 if (wrapper_function != NULL) {
633 // set up proxy functions
634 if (gst_pad_get_direction (pad) == GST_PAD_SINK) {
635 DEBUG("setting push proxy for sinkpad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
636 pad->pushfunc = GST_DEBUG_FUNCPTR(gst_bin_pushfunc_proxy);
637 } else if (gst_pad_get_direction (pad) == GST_PAD_SRC) {
638 DEBUG("setting pull proxy for srcpad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
639 pad->pullfunc = GST_DEBUG_FUNCPTR(gst_bin_pullfunc_proxy);
642 // otherwise we need to set up for 'traditional' chaining
643 if (gst_pad_get_direction (pad) == GST_PAD_SINK) {
644 // we can just copy the chain function, since it shares the prototype
645 DEBUG("copying chain function into push proxy for %s:%s\n",
646 GST_DEBUG_PAD_NAME(pad));
647 pad->pushfunc = pad->chainfunc;
648 } else if (gst_pad_get_direction (pad) == GST_PAD_SRC) {
649 // we can just copy the get function, since it shares the prototype
650 DEBUG("copying get function into pull proxy for %s:%s\n",
651 GST_DEBUG_PAD_NAME(pad));
652 pad->pullfunc = pad->getfunc;
657 // if a loopfunc has been specified, create and set up a cothread
658 if (wrapper_function != NULL) {
659 if (element->threadstate == NULL) {
660 element->threadstate = cothread_create (bin->threadcontext);
661 DEBUG("created cothread %p (@%p) for \"%s\"\n",element->threadstate,
662 &element->threadstate,gst_element_get_name(element));
664 cothread_setfunc (element->threadstate, wrapper_function, 0, (char **)element);
665 DEBUG("set wrapper function for \"%s\" to &%s\n",gst_element_get_name(element),
666 GST_DEBUG_FUNCPTR_NAME(wrapper_function));
669 // // HACK: if the element isn't decoupled, it's an entry
670 // if (!GST_FLAG_IS_SET(element,GST_ELEMENT_DECOUPLED))
671 // bin->entries = g_list_append(bin->entries, element);
674 // otherwise, cothreads are not needed
676 DEBUG("bin is chained, no cothreads needed\n");
678 elements = bin->managed_elements;
680 element = GST_ELEMENT (elements->data);
681 elements = g_list_next (elements);
683 pads = gst_element_get_pad_list (element);
685 pad = GST_PAD (pads->data);
686 pads = g_list_next (pads);
688 if (gst_pad_get_direction (pad) == GST_PAD_SINK) {
689 DEBUG("copying chain function into push proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
690 pad->pushfunc = pad->chainfunc;
692 DEBUG("copying get function into pull proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
693 pad->pullfunc = pad->getfunc;