- Make the return GList of gst_element_get_pad_list as const
[platform/upstream/gstreamer.git] / gst / gstscheduler.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wim.taymans@chello.be>
4  *
5  * gstscheduler.c: Default scheduling code for most cases
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #define CLASS(obj)      GST_SCHEDULER_CLASS (G_OBJECT_GET_CLASS (obj))
24
25 #include "gst_private.h"
26
27 #include "gstsystemclock.h"
28 #include "gstscheduler.h"
29 #include "gstlog.h"
30 #include "gstregistry.h"
31
32 static void     gst_scheduler_class_init        (GstSchedulerClass *klass);
33 static void     gst_scheduler_init              (GstScheduler *sched);
34
35 static GstObjectClass *parent_class = NULL;
36
37 static gchar *_default_name = NULL;
38
39 GType
40 gst_scheduler_get_type (void)
41 {
42   static GType _gst_scheduler_type = 0;
43
44   if (!_gst_scheduler_type) {
45     static const GTypeInfo scheduler_info = {
46       sizeof (GstSchedulerClass),
47       NULL,
48       NULL,
49       (GClassInitFunc) gst_scheduler_class_init,
50       NULL,
51       NULL,
52       sizeof (GstScheduler),
53       0,
54       (GInstanceInitFunc) gst_scheduler_init,
55       NULL
56     };
57
58     _gst_scheduler_type = g_type_register_static (GST_TYPE_OBJECT, "GstScheduler", 
59                     &scheduler_info, G_TYPE_FLAG_ABSTRACT);
60   }
61   return _gst_scheduler_type;
62 }
63
64 static void
65 gst_scheduler_class_init (GstSchedulerClass *klass)
66 {
67   parent_class = g_type_class_ref (GST_TYPE_OBJECT);
68 }
69
70 static void
71 gst_scheduler_init (GstScheduler *sched)
72 {
73   sched->clock_providers = NULL;
74   sched->clock_receivers = NULL;
75   sched->schedulers = NULL;
76   sched->state = GST_SCHEDULER_STATE_NONE;
77   sched->parent = NULL;
78   sched->parent_sched = NULL;
79   sched->clock = NULL;
80 }
81
82 /**
83  * gst_scheduler_setup:
84  * @sched: the scheduler
85  *
86  * Prepare the scheduler.
87  */
88 void
89 gst_scheduler_setup (GstScheduler *sched)
90 {
91   g_return_if_fail (GST_IS_SCHEDULER (sched));
92
93   if (CLASS (sched)->setup)
94     CLASS (sched)->setup (sched);
95 }
96
97 /**
98  * gst_scheduler_get_preferred_stack:
99  * @sched: a #GstScheduler to query.
100  * @stack: the pointer to store the location of the preferred stack in.
101  * @size: the pointer to store the size of the preferred stack in.
102  *
103  * Gets the preferred stack location and size of this scheduler.
104  *
105  * Returns: TRUE if the scheduler suggested a preferred stacksize and location.
106  */
107 gboolean
108 gst_scheduler_get_preferred_stack (GstScheduler *sched, gpointer *stack, gulong *size)
109 {
110   g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
111
112   if (CLASS (sched)->get_preferred_stack)
113     return CLASS (sched)->get_preferred_stack (sched, stack, size);
114   
115   return FALSE;
116 }
117
118 /**
119  * gst_scheduler_reset:
120  * @sched: a #GstScheduler to reset.
121  *
122  * Reset the schedulers.
123  */
124 void
125 gst_scheduler_reset (GstScheduler *sched)
126 {
127   g_return_if_fail (GST_IS_SCHEDULER (sched));
128
129   if (CLASS (sched)->reset)
130     CLASS (sched)->reset (sched);
131 }
132
133 /**
134  * gst_scheduler_pad_connect:
135  * @sched: the scheduler
136  * @srcpad: the srcpad to connect
137  * @sinkpad: the sinkpad to connect to
138  *
139  * Connect the srcpad to the given sinkpad.
140  */
141 void
142 gst_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad)
143 {
144   g_return_if_fail (GST_IS_SCHEDULER (sched));
145   g_return_if_fail (GST_IS_PAD (srcpad));
146   g_return_if_fail (GST_IS_PAD (sinkpad));
147
148   if (CLASS (sched)->pad_connect)
149     CLASS (sched)->pad_connect (sched, srcpad, sinkpad);
150 }
151
152 /**
153  * gst_scheduler_pad_disconnect:
154  * @sched: the scheduler
155  * @srcpad: the srcpad to disconnect
156  * @sinkpad: the sinkpad to disconnect from
157  *
158  * Disconnect the srcpad to the given sinkpad.
159  */
160 void
161 gst_scheduler_pad_disconnect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad)
162 {
163   g_return_if_fail (GST_IS_SCHEDULER (sched));
164   g_return_if_fail (GST_IS_PAD (srcpad));
165   g_return_if_fail (GST_IS_PAD (sinkpad));
166
167   if (CLASS (sched)->pad_disconnect)
168     CLASS (sched)->pad_disconnect (sched, srcpad, sinkpad);
169 }
170
171 /**
172  * gst_scheduler_pad_select:
173  * @sched: the scheduler
174  * @padlist: the padlist to select on
175  *
176  * register the given padlist for a select operation. 
177  *
178  * Returns: the pad which received a buffer.
179  */
180 GstPad *
181 gst_scheduler_pad_select (GstScheduler *sched, GList *padlist)
182 {
183   g_return_val_if_fail (GST_IS_SCHEDULER (sched), NULL);
184   g_return_val_if_fail (padlist != NULL, NULL);
185
186   if (CLASS (sched)->pad_select)
187     CLASS (sched)->pad_select (sched, padlist);
188
189   return NULL;
190 }
191
192 /**
193  * gst_scheduler_add_element:
194  * @sched: the scheduler
195  * @element: the element to add to the scheduler
196  *
197  * Add an element to the scheduler.
198  */
199 void
200 gst_scheduler_add_element (GstScheduler *sched, GstElement *element)
201 {
202   g_return_if_fail (GST_IS_SCHEDULER (sched));
203   g_return_if_fail (GST_IS_ELEMENT (element));
204
205   if (element->getclockfunc) {
206     sched->clock_providers = g_list_prepend (sched->clock_providers, element);
207     GST_DEBUG (GST_CAT_CLOCK, "added clock provider %s", GST_ELEMENT_NAME (element));
208   }
209   if (element->setclockfunc) {
210     sched->clock_receivers = g_list_prepend (sched->clock_receivers, element);
211     GST_DEBUG (GST_CAT_CLOCK, "added clock receiver %s", GST_ELEMENT_NAME (element));
212   }
213
214   gst_element_set_scheduler (element, sched);
215
216   if (CLASS (sched)->add_element)
217     CLASS (sched)->add_element (sched, element);
218 }
219
220 /**
221  * gst_scheduler_remove_element:
222  * @sched: the scheduler
223  * @element: the element to remove
224  *
225  * Remove an element from the scheduler.
226  */
227 void
228 gst_scheduler_remove_element (GstScheduler *sched, GstElement *element)
229 {
230   g_return_if_fail (GST_IS_SCHEDULER (sched));
231   g_return_if_fail (GST_IS_ELEMENT (element));
232
233   sched->clock_providers = g_list_remove (sched->clock_providers, element);
234   sched->clock_receivers = g_list_remove (sched->clock_receivers, element);
235
236   gst_element_set_scheduler (element, NULL);
237
238   if (CLASS (sched)->remove_element)
239     CLASS (sched)->remove_element (sched, element);
240 }
241
242 /**
243  * gst_scheduler_state_transition:
244  * @sched: the scheduler
245  * @element: the element with the state transition
246  * @transition: the state transition
247  *
248  * Tell the scheduler that an element changed its state.
249  *
250  * Returns: a GstElementStateReturn indicating success or failure
251  * of the state transition.
252  */
253 GstElementStateReturn
254 gst_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition)
255 {
256   g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_STATE_FAILURE);
257   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
258
259   if (element == sched->parent && sched->parent_sched == NULL) {
260
261     switch (transition) {
262       case GST_STATE_READY_TO_PAUSED:
263       {
264         GstClock *clock = gst_scheduler_get_clock (sched);
265
266         if (clock)
267           gst_clock_reset (clock);
268
269         GST_DEBUG (GST_CAT_CLOCK, "scheduler READY to PAUSED clock is %p (%s)", clock, 
270                         (clock ? GST_OBJECT_NAME (clock) : "nil"));
271
272         sched->current_clock = clock;
273         break;
274       }
275       case GST_STATE_PAUSED_TO_PLAYING:
276       {
277         GstClock *clock = gst_scheduler_get_clock (sched);
278
279         GST_DEBUG (GST_CAT_CLOCK, "scheduler PAUSED to PLAYING clock is %p (%s)", clock, 
280                         (clock ? GST_OBJECT_NAME (clock) : "nil"));
281
282         sched->current_clock = clock;
283
284         gst_scheduler_set_clock (sched, sched->current_clock);
285         if (sched->current_clock) {
286           GST_DEBUG (GST_CAT_CLOCK, "enabling clock %p (%s)", sched->current_clock, 
287                         GST_OBJECT_NAME (sched->current_clock));
288           gst_clock_set_active (sched->current_clock, TRUE);
289         }
290         break;
291       }
292       case GST_STATE_PLAYING_TO_PAUSED:
293         if (sched->current_clock) {
294           GST_DEBUG (GST_CAT_CLOCK, "disabling clock %p (%s)", sched->current_clock, 
295                         GST_OBJECT_NAME (sched->current_clock));
296           gst_clock_set_active (sched->current_clock, FALSE);
297         }
298         break;
299     }
300   }
301
302   if (CLASS (sched)->state_transition)
303     return CLASS (sched)->state_transition (sched, element, transition);
304
305   return GST_STATE_SUCCESS;
306 }
307
308 /**
309  * gst_scheduler_add_scheduler:
310  * @sched: a  #GstScheduler to add to
311  * @sched2: the #GstScheduler to add
312  *
313  * Notifies the scheduler that it has to monitor this scheduler.
314  */
315 void
316 gst_scheduler_add_scheduler (GstScheduler *sched, GstScheduler *sched2)
317 {
318   g_return_if_fail (GST_IS_SCHEDULER (sched));
319   g_return_if_fail (GST_IS_SCHEDULER (sched2));
320
321   sched->schedulers = g_list_prepend (sched->schedulers, sched2);
322   sched2->parent_sched = sched;
323
324   if (CLASS (sched)->add_scheduler)
325     CLASS (sched)->add_scheduler (sched, sched2);
326 }
327
328 /**
329  * gst_scheduler_remove_scheduler:
330  * @sched: the scheduler
331  * @sched2: the scheduler to remove
332  *
333  a Notifies the scheduler that it can stop monitoring this scheduler.
334  */
335 void
336 gst_scheduler_remove_scheduler (GstScheduler *sched, GstScheduler *sched2)
337 {
338   g_return_if_fail (GST_IS_SCHEDULER (sched));
339   g_return_if_fail (GST_IS_SCHEDULER (sched2));
340
341   sched->schedulers = g_list_remove (sched->schedulers, sched2);
342   sched2->parent_sched = NULL;
343
344   if (CLASS (sched)->remove_scheduler)
345     CLASS (sched)->remove_scheduler (sched, sched2);
346 }
347
348 /**
349  * gst_scheduler_lock_element:
350  * @sched: the scheduler
351  * @element: the element to lock
352  *
353  * Acquire a lock on the given element in the given scheduler.
354  */
355 void
356 gst_scheduler_lock_element (GstScheduler *sched, GstElement *element)
357 {
358   g_return_if_fail (GST_IS_SCHEDULER (sched));
359   g_return_if_fail (GST_IS_ELEMENT (element));
360
361   if (CLASS (sched)->lock_element)
362     CLASS (sched)->lock_element (sched, element);
363 }
364
365 /**
366  * gst_scheduler_unlock_element:
367  * @sched: the scheduler
368  * @element: the element to unlock
369  *
370  * Release the lock on the given element in the given scheduler.
371  */
372 void
373 gst_scheduler_unlock_element (GstScheduler *sched, GstElement *element)
374 {
375   g_return_if_fail (GST_IS_SCHEDULER (sched));
376   g_return_if_fail (GST_IS_ELEMENT (element));
377
378   if (CLASS (sched)->unlock_element)
379     CLASS (sched)->unlock_element (sched, element);
380 }
381
382 /**
383  * gst_scheduler_error:
384  * @sched: the scheduler
385  * @element: the element with the error
386  *
387  * Tell the scheduler an element was in error
388  */
389 void
390 gst_scheduler_error (GstScheduler *sched, GstElement *element)
391 {
392   g_return_if_fail (GST_IS_SCHEDULER (sched));
393   g_return_if_fail (GST_IS_ELEMENT (element));
394
395   if (CLASS (sched)->error)
396     CLASS (sched)->error (sched, element);
397 }
398
399 /**
400  * gst_scheduler_yield:
401  * @sched: the scheduler
402  * @element: the element requesting a yield
403  *
404  * Tell the scheduler to schedule another element.
405  */
406 void
407 gst_scheduler_yield (GstScheduler *sched, GstElement *element)
408 {
409   g_return_if_fail (GST_IS_SCHEDULER (sched));
410   g_return_if_fail (GST_IS_ELEMENT (element));
411
412   if (CLASS (sched)->yield)
413     CLASS (sched)->yield (sched, element);
414 }
415
416 /**
417  * gst_scheduler_interrupt:
418  * @sched: the scheduler
419  * @element: the element requesting an interrupt
420  *
421  * Tell the scheduler to interrupt execution of this element.
422  *
423  * Returns: TRUE if the element should return NULL from the chain/get
424  * function.
425  */
426 gboolean
427 gst_scheduler_interrupt (GstScheduler *sched, GstElement *element)
428 {
429   g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
430   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
431
432   if (CLASS (sched)->interrupt)
433     return CLASS (sched)->interrupt (sched, element);
434
435   return FALSE;
436 }
437
438 /**
439  * gst_scheduler_get_clock:
440  * @sched: the scheduler
441  *
442  * Get the current clock used by the scheduler
443  *
444  * Returns: a GstClock
445  */
446 GstClock*
447 gst_scheduler_get_clock (GstScheduler *sched)
448 {
449   GstClock *clock = NULL;
450   
451   /* if we have a fixed clock, use that one */
452   if (GST_FLAG_IS_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK)) {
453     clock = sched->clock;  
454
455     GST_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)", clock, 
456                         (clock ? GST_OBJECT_NAME (clock) : "nil"));
457   }
458   else {
459     GList *schedulers = sched->schedulers;
460     GList *providers = sched->clock_providers;
461
462     /* try to get a clock from one of the schedulers we manage first */
463     while (schedulers) {
464       GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
465       
466       clock = gst_scheduler_get_clock (scheduler);
467       if (clock)
468         break;
469
470       schedulers = g_list_next (schedulers);
471     }
472     /* still no clock, try to find one in the providers */
473     while (!clock && providers) {
474       clock = gst_element_get_clock (GST_ELEMENT (providers->data));
475
476       providers = g_list_next (providers);
477     }
478     /* still no clock, use a system clock */
479     if (!clock && sched->parent_sched == NULL) {
480       clock = gst_system_clock_obtain ();
481     }
482   }
483   GST_DEBUG (GST_CAT_CLOCK, "scheduler selected clock %p (%s)", clock, 
484                 (clock ? GST_OBJECT_NAME (clock) : "nil"));
485
486   return clock;
487 }
488
489 /**
490  * gst_scheduler_use_clock:
491  * @sched: the scheduler
492  * @clock: the clock to use
493  *
494  * Force the scheduler to use the given clock. The scheduler will
495  * always use the given clock even if new clock providers are added
496  * to this scheduler.
497  */
498 void
499 gst_scheduler_use_clock (GstScheduler *sched, GstClock *clock)
500 {
501   g_return_if_fail (sched != NULL);
502   g_return_if_fail (GST_IS_SCHEDULER (sched));
503
504   GST_FLAG_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
505   sched->clock = clock;
506
507   GST_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)", clock, 
508                 (clock ? GST_OBJECT_NAME (clock) : "nil"));
509 }
510
511 /**
512  * gst_scheduler_set_clock:
513  * @sched: the scheduler
514  * @clock: the clock to set
515  *
516  * Set the clock for the scheduler. The clock will be distributed 
517  * to all the elements managed by the scheduler. 
518  */
519 void
520 gst_scheduler_set_clock (GstScheduler *sched, GstClock *clock)
521 {
522   GList *receivers;
523   GList *schedulers;
524
525   g_return_if_fail (sched != NULL);
526   g_return_if_fail (GST_IS_SCHEDULER (sched));
527
528   receivers = sched->clock_receivers;
529   schedulers = sched->schedulers;
530
531   sched->current_clock = clock;
532
533   while (receivers) {
534     GstElement *element = GST_ELEMENT (receivers->data);
535
536     GST_DEBUG (GST_CAT_CLOCK, "scheduler setting clock %p (%s) on element %s", clock, 
537                 (clock ? GST_OBJECT_NAME (clock) : "nil"), GST_ELEMENT_NAME (element));
538     gst_element_set_clock (element, clock);
539     receivers = g_list_next (receivers);
540   }
541   while (schedulers) {
542     GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
543
544     GST_DEBUG (GST_CAT_CLOCK, "scheduler setting clock %p (%s) on scheduler %p", clock, 
545                 (clock ? GST_OBJECT_NAME (clock) : "nil"), scheduler);
546     gst_scheduler_set_clock (scheduler, clock);
547     schedulers = g_list_next (schedulers);
548   }
549 }
550
551 /**
552  * gst_scheduler_auto_clock:
553  * @sched: the scheduler
554  *
555  * Let the scheduler select a clock automatically.
556  */
557 void
558 gst_scheduler_auto_clock (GstScheduler *sched)
559 {
560   g_return_if_fail (sched != NULL);
561   g_return_if_fail (GST_IS_SCHEDULER (sched));
562
563   GST_FLAG_UNSET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
564   sched->clock = NULL;
565
566   GST_DEBUG (GST_CAT_CLOCK, "scheduler using automatic clock");
567 }
568
569 /**
570  * gst_scheduler_clock_wait:
571  * @sched: the scheduler
572  * @element: the element that wants to wait
573  * @clock: the clock to use
574  * @time: the time to wait for
575  * @jitter: the time difference between requested time and actual time
576  *
577  * Wait till the clock reaches a specific time
578  *
579  * Returns: the status of the operation
580  */
581 GstClockReturn
582 gst_scheduler_clock_wait (GstScheduler *sched, GstElement *element, GstClock *clock, GstClockTime time,
583                 GstClockTimeDiff *jitter)
584 {
585   g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_CLOCK_ERROR);
586
587   if (CLASS (sched)->clock_wait)
588     return CLASS (sched)->clock_wait (sched, element, clock, time, jitter);
589   else
590     return gst_clock_wait (clock, time, jitter);
591
592   return GST_CLOCK_TIMEOUT;
593 }
594
595 /**
596  * gst_scheduler_iterate:
597  * @sched: the scheduler
598  *
599  * Perform one iteration on the scheduler.
600  *
601  * Returns: a boolean indicating something usefull has happened.
602  */
603 gboolean
604 gst_scheduler_iterate (GstScheduler *sched)
605 {
606   g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
607
608   if (CLASS (sched)->iterate)
609     return CLASS (sched)->iterate (sched);
610
611   return FALSE;
612 }
613
614
615 /**
616  * gst_scheduler_show:
617  * @sched: the scheduler
618  *
619  * Dump the state of the scheduler
620  */
621 void
622 gst_scheduler_show (GstScheduler *sched)
623 {
624   g_return_if_fail (GST_IS_SCHEDULER (sched));
625
626   if (CLASS (sched)->show)
627     CLASS (sched)->show (sched);
628 }
629
630 /*
631  * Factory stuff starts here
632  *
633  */
634 static void             gst_scheduler_factory_class_init                (GstSchedulerFactoryClass *klass);
635 static void             gst_scheduler_factory_init              (GstSchedulerFactory *factory);
636
637 static GstPluginFeatureClass *factory_parent_class = NULL;
638 /* static guint gst_scheduler_factory_signals[LAST_SIGNAL] = { 0 }; */
639
640 GType 
641 gst_scheduler_factory_get_type (void) 
642 {
643   static GType schedulerfactory_type = 0;
644
645   if (!schedulerfactory_type) {
646     static const GTypeInfo schedulerfactory_info = {
647       sizeof (GstSchedulerFactoryClass),
648       NULL,
649       NULL,
650       (GClassInitFunc) gst_scheduler_factory_class_init,
651       NULL,
652       NULL,
653       sizeof(GstSchedulerFactory),
654       0,
655       (GInstanceInitFunc) gst_scheduler_factory_init,
656       NULL
657     };
658     schedulerfactory_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE, 
659                                                   "GstSchedulerFactory", &schedulerfactory_info, 0);
660   }
661   return schedulerfactory_type;
662 }
663
664 static void
665 gst_scheduler_factory_class_init (GstSchedulerFactoryClass *klass)
666 {
667   GObjectClass *gobject_class;
668   GstObjectClass *gstobject_class;
669   GstPluginFeatureClass *gstpluginfeature_class;
670
671   gobject_class = (GObjectClass*)klass;
672   gstobject_class = (GstObjectClass*)klass;
673   gstpluginfeature_class = (GstPluginFeatureClass*) klass;
674
675   factory_parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE);
676
677   if (!_default_name)
678     _default_name = g_strdup ("basicomega");
679 }
680
681 static void
682 gst_scheduler_factory_init (GstSchedulerFactory *factory)
683 {
684 }
685         
686
687 /**
688  * gst_scheduler_factory_new:
689  * @name: name of schedulerfactory to create
690  * @longdesc: long description of schedulerfactory to create
691  * @type: the gtk type of the GstScheduler element of this factory
692  *
693  * Create a new schedulerfactory with the given parameters
694  *
695  * Returns: a new #GstSchedulerFactory.
696  */
697 GstSchedulerFactory*
698 gst_scheduler_factory_new (const gchar *name, const gchar *longdesc, GType type)
699 {
700   GstSchedulerFactory *factory;
701
702   g_return_val_if_fail(name != NULL, NULL);
703   factory = gst_scheduler_factory_find (name);
704   if (!factory) {
705     factory = GST_SCHEDULER_FACTORY (g_object_new (GST_TYPE_SCHEDULER_FACTORY, NULL));
706   }
707
708   GST_PLUGIN_FEATURE_NAME (factory) = g_strdup (name);
709   if (factory->longdesc)
710     g_free (factory->longdesc);
711   factory->longdesc = g_strdup (longdesc);
712   factory->type = type;
713
714   return factory;
715 }
716
717 /**
718  * gst_scheduler_factory_destroy:
719  * @factory: factory to destroy
720  *
721  * Removes the scheduler from the global list.
722  */
723 void
724 gst_scheduler_factory_destroy (GstSchedulerFactory *factory)
725 {
726   g_return_if_fail (factory != NULL);
727
728   /* we don't free the struct bacause someone might  have a handle to it.. */
729 }
730
731 /**
732  * gst_scheduler_factory_find:
733  * @name: name of schedulerfactory to find
734  *
735  * Search for an schedulerfactory of the given name.
736  *
737  * Returns: #GstSchedulerFactory if found, NULL otherwise
738  */
739 GstSchedulerFactory*
740 gst_scheduler_factory_find (const gchar *name)
741 {
742   GstPluginFeature *feature;
743
744   g_return_val_if_fail(name != NULL, NULL);
745
746   GST_DEBUG (0,"gstscheduler: find \"%s\"", name);
747
748   feature = gst_registry_pool_find_feature (name, GST_TYPE_SCHEDULER_FACTORY);
749   if (feature)
750     return GST_SCHEDULER_FACTORY (feature);
751
752   return NULL;
753 }
754
755 /**
756  * gst_scheduler_factory_create:
757  * @factory: the factory used to create the instance
758  * @parent: the parent element of this scheduler
759  *
760  * Create a new #GstScheduler instance from the 
761  * given schedulerfactory with the given parent. @parent will
762  * have its scheduler set to the returned #GstScheduler instance.
763  *
764  * Returns: A new #GstScheduler instance with a reference count of %1.
765  */
766 GstScheduler*
767 gst_scheduler_factory_create (GstSchedulerFactory *factory, GstElement *parent)
768 {
769   GstScheduler *new = NULL;
770
771   g_return_val_if_fail (factory != NULL, NULL);
772   g_return_val_if_fail (parent != NULL, NULL);
773
774   if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
775     g_return_val_if_fail (factory->type != 0, NULL);
776
777     new = GST_SCHEDULER (g_object_new (factory->type, NULL));
778     new->parent = parent;
779
780     GST_ELEMENT_SCHED (parent) = new;
781
782     /* let's refcount the scheduler */
783     gst_object_ref (GST_OBJECT (new));
784     gst_object_sink (GST_OBJECT (new));
785   }
786
787   return new;
788 }
789
790 /**
791  * gst_scheduler_factory_make:
792  * @name: the name of the factory used to create the instance
793  * @parent: the parent element of this scheduler
794  *
795  * Create a new #GstScheduler instance from the 
796  * schedulerfactory with the given name and parent. @parent will
797  * have its scheduler set to the returned #GstScheduler instance.
798  * If %NULL is passed as @name, the default scheduler name will
799  * be used.
800  *
801  * Returns: A new #GstScheduler instance with a reference count of %1.
802  */
803 GstScheduler*
804 gst_scheduler_factory_make (const gchar *name, GstElement *parent)
805 {
806   GstSchedulerFactory *factory;
807   const gchar *default_name = gst_scheduler_factory_get_default_name ();
808
809   if (name)
810     factory = gst_scheduler_factory_find (name);
811   else
812   {
813     /* FIXME: do better error handling */
814     if (default_name == NULL)
815       g_error ("No default scheduler name - do you have a registry ?");
816     factory = gst_scheduler_factory_find (default_name);
817   }
818
819   if (factory == NULL)
820     return NULL;
821
822   return gst_scheduler_factory_create (factory, parent);
823 }
824
825 /**
826  * gst_scheduler_factory_set_default_name:
827  * @name: the name of the factory used as a default
828  *
829  * Set the default schedulerfactory name.
830  */
831 void
832 gst_scheduler_factory_set_default_name (const gchar* name)
833 {
834   if (_default_name)
835     g_free (_default_name);
836
837   _default_name = g_strdup (name);
838 }
839
840 /**
841  * gst_scheduler_factory_get_default_name:
842  *
843  * Get the default schedulerfactory name.
844  *
845  * Returns: the name of the default scheduler.
846  */
847 const gchar*
848 gst_scheduler_factory_get_default_name (void)
849 {
850   return _default_name;
851 }