ef9ed978f8e273ccb72498aa825cd69db9a01d81
[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 it's already in this scheduler, don't bother doing anything */
206   if (GST_ELEMENT_SCHED (element) == sched)
207     return;
208
209   /* if it's not inside this scheduler, it has to be NULL */
210   g_assert (GST_ELEMENT_SCHED (element) == NULL);
211
212   if (element->getclockfunc) {
213     sched->clock_providers = g_list_prepend (sched->clock_providers, element);
214     GST_DEBUG (GST_CAT_CLOCK, "added clock provider %s", GST_ELEMENT_NAME (element));
215   }
216   if (element->setclockfunc) {
217     sched->clock_receivers = g_list_prepend (sched->clock_receivers, element);
218     GST_DEBUG (GST_CAT_CLOCK, "added clock receiver %s", GST_ELEMENT_NAME (element));
219   }
220
221   gst_element_set_scheduler (element, sched);
222
223   if (CLASS (sched)->add_element)
224     CLASS (sched)->add_element (sched, element);
225 }
226
227 /**
228  * gst_scheduler_remove_element:
229  * @sched: the scheduler
230  * @element: the element to remove
231  *
232  * Remove an element from the scheduler.
233  */
234 void
235 gst_scheduler_remove_element (GstScheduler *sched, GstElement *element)
236 {
237   g_return_if_fail (GST_IS_SCHEDULER (sched));
238   g_return_if_fail (GST_IS_ELEMENT (element));
239
240   sched->clock_providers = g_list_remove (sched->clock_providers, element);
241   sched->clock_receivers = g_list_remove (sched->clock_receivers, element);
242
243   if (CLASS (sched)->remove_element)
244     CLASS (sched)->remove_element (sched, element);
245
246   gst_element_set_scheduler (element, NULL); 
247 }
248
249 /**
250  * gst_scheduler_state_transition:
251  * @sched: the scheduler
252  * @element: the element with the state transition
253  * @transition: the state transition
254  *
255  * Tell the scheduler that an element changed its state.
256  *
257  * Returns: a GstElementStateReturn indicating success or failure
258  * of the state transition.
259  */
260 GstElementStateReturn
261 gst_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition)
262 {
263   g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_STATE_FAILURE);
264   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
265
266   if (element == sched->parent && sched->parent_sched == NULL) {
267
268     switch (transition) {
269       case GST_STATE_READY_TO_PAUSED:
270       {
271         GstClock *clock = gst_scheduler_get_clock (sched);
272
273         if (clock)
274           gst_clock_reset (clock);
275
276         GST_DEBUG (GST_CAT_CLOCK, "scheduler READY to PAUSED clock is %p (%s)", clock, 
277                         (clock ? GST_OBJECT_NAME (clock) : "nil"));
278
279         sched->current_clock = clock;
280         break;
281       }
282       case GST_STATE_PAUSED_TO_PLAYING:
283       {
284         GstClock *clock = gst_scheduler_get_clock (sched);
285
286         GST_DEBUG (GST_CAT_CLOCK, "scheduler PAUSED to PLAYING clock is %p (%s)", clock, 
287                         (clock ? GST_OBJECT_NAME (clock) : "nil"));
288
289         sched->current_clock = clock;
290
291         gst_scheduler_set_clock (sched, sched->current_clock);
292         if (sched->current_clock) {
293           GST_DEBUG (GST_CAT_CLOCK, "enabling clock %p (%s)", sched->current_clock, 
294                         GST_OBJECT_NAME (sched->current_clock));
295           gst_clock_set_active (sched->current_clock, TRUE);
296         }
297         break;
298       }
299       case GST_STATE_PLAYING_TO_PAUSED:
300         if (sched->current_clock) {
301           GST_DEBUG (GST_CAT_CLOCK, "disabling clock %p (%s)", sched->current_clock, 
302                         GST_OBJECT_NAME (sched->current_clock));
303           gst_clock_set_active (sched->current_clock, FALSE);
304         }
305         break;
306     }
307   }
308
309   if (CLASS (sched)->state_transition)
310     return CLASS (sched)->state_transition (sched, element, transition);
311
312   return GST_STATE_SUCCESS;
313 }
314
315 /**
316  * gst_scheduler_add_scheduler:
317  * @sched: a  #GstScheduler to add to
318  * @sched2: the #GstScheduler to add
319  *
320  * Notifies the scheduler that it has to monitor this scheduler.
321  */
322 void
323 gst_scheduler_add_scheduler (GstScheduler *sched, GstScheduler *sched2)
324 {
325   g_return_if_fail (GST_IS_SCHEDULER (sched));
326   g_return_if_fail (GST_IS_SCHEDULER (sched2));
327
328   sched->schedulers = g_list_prepend (sched->schedulers, sched2);
329   sched2->parent_sched = sched;
330
331   if (CLASS (sched)->add_scheduler)
332     CLASS (sched)->add_scheduler (sched, sched2);
333 }
334
335 /**
336  * gst_scheduler_remove_scheduler:
337  * @sched: the scheduler
338  * @sched2: the scheduler to remove
339  *
340  a Notifies the scheduler that it can stop monitoring this scheduler.
341  */
342 void
343 gst_scheduler_remove_scheduler (GstScheduler *sched, GstScheduler *sched2)
344 {
345   g_return_if_fail (GST_IS_SCHEDULER (sched));
346   g_return_if_fail (GST_IS_SCHEDULER (sched2));
347
348   sched->schedulers = g_list_remove (sched->schedulers, sched2);
349   sched2->parent_sched = NULL;
350
351   if (CLASS (sched)->remove_scheduler)
352     CLASS (sched)->remove_scheduler (sched, sched2);
353 }
354
355 /**
356  * gst_scheduler_lock_element:
357  * @sched: the scheduler
358  * @element: the element to lock
359  *
360  * Acquire a lock on the given element in the given scheduler.
361  */
362 void
363 gst_scheduler_lock_element (GstScheduler *sched, GstElement *element)
364 {
365   g_return_if_fail (GST_IS_SCHEDULER (sched));
366   g_return_if_fail (GST_IS_ELEMENT (element));
367
368   if (CLASS (sched)->lock_element)
369     CLASS (sched)->lock_element (sched, element);
370 }
371
372 /**
373  * gst_scheduler_unlock_element:
374  * @sched: the scheduler
375  * @element: the element to unlock
376  *
377  * Release the lock on the given element in the given scheduler.
378  */
379 void
380 gst_scheduler_unlock_element (GstScheduler *sched, GstElement *element)
381 {
382   g_return_if_fail (GST_IS_SCHEDULER (sched));
383   g_return_if_fail (GST_IS_ELEMENT (element));
384
385   if (CLASS (sched)->unlock_element)
386     CLASS (sched)->unlock_element (sched, element);
387 }
388
389 /**
390  * gst_scheduler_error:
391  * @sched: the scheduler
392  * @element: the element with the error
393  *
394  * Tell the scheduler an element was in error
395  */
396 void
397 gst_scheduler_error (GstScheduler *sched, GstElement *element)
398 {
399   g_return_if_fail (GST_IS_SCHEDULER (sched));
400   g_return_if_fail (GST_IS_ELEMENT (element));
401
402   if (CLASS (sched)->error)
403     CLASS (sched)->error (sched, element);
404 }
405
406 /**
407  * gst_scheduler_yield:
408  * @sched: the scheduler
409  * @element: the element requesting a yield
410  *
411  * Tell the scheduler to schedule another element.
412  */
413 void
414 gst_scheduler_yield (GstScheduler *sched, GstElement *element)
415 {
416   g_return_if_fail (GST_IS_SCHEDULER (sched));
417   g_return_if_fail (GST_IS_ELEMENT (element));
418
419   if (CLASS (sched)->yield)
420     CLASS (sched)->yield (sched, element);
421 }
422
423 /**
424  * gst_scheduler_interrupt:
425  * @sched: the scheduler
426  * @element: the element requesting an interrupt
427  *
428  * Tell the scheduler to interrupt execution of this element.
429  *
430  * Returns: TRUE if the element should return NULL from the chain/get
431  * function.
432  */
433 gboolean
434 gst_scheduler_interrupt (GstScheduler *sched, GstElement *element)
435 {
436   g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
437   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
438
439   if (CLASS (sched)->interrupt)
440     return CLASS (sched)->interrupt (sched, element);
441
442   return FALSE;
443 }
444
445 /**
446  * gst_scheduler_get_clock:
447  * @sched: the scheduler
448  *
449  * Get the current clock used by the scheduler
450  *
451  * Returns: a GstClock
452  */
453 GstClock*
454 gst_scheduler_get_clock (GstScheduler *sched)
455 {
456   GstClock *clock = NULL;
457   
458   /* if we have a fixed clock, use that one */
459   if (GST_FLAG_IS_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK)) {
460     clock = sched->clock;  
461
462     GST_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)", clock, 
463                         (clock ? GST_OBJECT_NAME (clock) : "nil"));
464   }
465   else {
466     GList *schedulers = sched->schedulers;
467     GList *providers = sched->clock_providers;
468
469     /* try to get a clock from one of the schedulers we manage first */
470     while (schedulers) {
471       GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
472       
473       clock = gst_scheduler_get_clock (scheduler);
474       if (clock)
475         break;
476
477       schedulers = g_list_next (schedulers);
478     }
479     /* still no clock, try to find one in the providers */
480     while (!clock && providers) {
481       clock = gst_element_get_clock (GST_ELEMENT (providers->data));
482
483       providers = g_list_next (providers);
484     }
485     /* still no clock, use a system clock */
486     if (!clock && sched->parent_sched == NULL) {
487       clock = gst_system_clock_obtain ();
488     }
489   }
490   GST_DEBUG (GST_CAT_CLOCK, "scheduler selected clock %p (%s)", clock, 
491                 (clock ? GST_OBJECT_NAME (clock) : "nil"));
492
493   return clock;
494 }
495
496 /**
497  * gst_scheduler_use_clock:
498  * @sched: the scheduler
499  * @clock: the clock to use
500  *
501  * Force the scheduler to use the given clock. The scheduler will
502  * always use the given clock even if new clock providers are added
503  * to this scheduler.
504  */
505 void
506 gst_scheduler_use_clock (GstScheduler *sched, GstClock *clock)
507 {
508   g_return_if_fail (sched != NULL);
509   g_return_if_fail (GST_IS_SCHEDULER (sched));
510
511   GST_FLAG_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
512   sched->clock = clock;
513
514   GST_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)", clock, 
515                 (clock ? GST_OBJECT_NAME (clock) : "nil"));
516 }
517
518 /**
519  * gst_scheduler_set_clock:
520  * @sched: the scheduler
521  * @clock: the clock to set
522  *
523  * Set the clock for the scheduler. The clock will be distributed 
524  * to all the elements managed by the scheduler. 
525  */
526 void
527 gst_scheduler_set_clock (GstScheduler *sched, GstClock *clock)
528 {
529   GList *receivers;
530   GList *schedulers;
531
532   g_return_if_fail (sched != NULL);
533   g_return_if_fail (GST_IS_SCHEDULER (sched));
534
535   receivers = sched->clock_receivers;
536   schedulers = sched->schedulers;
537
538   sched->current_clock = clock;
539
540   while (receivers) {
541     GstElement *element = GST_ELEMENT (receivers->data);
542
543     GST_DEBUG (GST_CAT_CLOCK, "scheduler setting clock %p (%s) on element %s", clock, 
544                 (clock ? GST_OBJECT_NAME (clock) : "nil"), GST_ELEMENT_NAME (element));
545     gst_element_set_clock (element, clock);
546     receivers = g_list_next (receivers);
547   }
548   while (schedulers) {
549     GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
550
551     GST_DEBUG (GST_CAT_CLOCK, "scheduler setting clock %p (%s) on scheduler %p", clock, 
552                 (clock ? GST_OBJECT_NAME (clock) : "nil"), scheduler);
553     gst_scheduler_set_clock (scheduler, clock);
554     schedulers = g_list_next (schedulers);
555   }
556 }
557
558 /**
559  * gst_scheduler_auto_clock:
560  * @sched: the scheduler
561  *
562  * Let the scheduler select a clock automatically.
563  */
564 void
565 gst_scheduler_auto_clock (GstScheduler *sched)
566 {
567   g_return_if_fail (sched != NULL);
568   g_return_if_fail (GST_IS_SCHEDULER (sched));
569
570   GST_FLAG_UNSET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
571   sched->clock = NULL;
572
573   GST_DEBUG (GST_CAT_CLOCK, "scheduler using automatic clock");
574 }
575
576 /**
577  * gst_scheduler_clock_wait:
578  * @sched: the scheduler
579  * @element: the element that wants to wait
580  * @clock: the clock to use
581  * @time: the time to wait for
582  * @jitter: the time difference between requested time and actual time
583  *
584  * Wait till the clock reaches a specific time
585  *
586  * Returns: the status of the operation
587  */
588 GstClockReturn
589 gst_scheduler_clock_wait (GstScheduler *sched, GstElement *element, GstClock *clock, GstClockTime time,
590                 GstClockTimeDiff *jitter)
591 {
592   g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_CLOCK_ERROR);
593
594   if (CLASS (sched)->clock_wait)
595     return CLASS (sched)->clock_wait (sched, element, clock, time, jitter);
596   else
597     return gst_clock_wait (clock, time, jitter);
598
599   return GST_CLOCK_TIMEOUT;
600 }
601
602 /**
603  * gst_scheduler_iterate:
604  * @sched: the scheduler
605  *
606  * Perform one iteration on the scheduler.
607  *
608  * Returns: a boolean indicating something usefull has happened.
609  */
610 gboolean
611 gst_scheduler_iterate (GstScheduler *sched)
612 {
613   g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
614
615   if (CLASS (sched)->iterate)
616     return CLASS (sched)->iterate (sched);
617
618   return FALSE;
619 }
620
621
622 /**
623  * gst_scheduler_show:
624  * @sched: the scheduler
625  *
626  * Dump the state of the scheduler
627  */
628 void
629 gst_scheduler_show (GstScheduler *sched)
630 {
631   g_return_if_fail (GST_IS_SCHEDULER (sched));
632
633   if (CLASS (sched)->show)
634     CLASS (sched)->show (sched);
635 }
636
637 /*
638  * Factory stuff starts here
639  *
640  */
641 static void             gst_scheduler_factory_class_init                (GstSchedulerFactoryClass *klass);
642 static void             gst_scheduler_factory_init              (GstSchedulerFactory *factory);
643
644 static GstPluginFeatureClass *factory_parent_class = NULL;
645 /* static guint gst_scheduler_factory_signals[LAST_SIGNAL] = { 0 }; */
646
647 GType 
648 gst_scheduler_factory_get_type (void) 
649 {
650   static GType schedulerfactory_type = 0;
651
652   if (!schedulerfactory_type) {
653     static const GTypeInfo schedulerfactory_info = {
654       sizeof (GstSchedulerFactoryClass),
655       NULL,
656       NULL,
657       (GClassInitFunc) gst_scheduler_factory_class_init,
658       NULL,
659       NULL,
660       sizeof(GstSchedulerFactory),
661       0,
662       (GInstanceInitFunc) gst_scheduler_factory_init,
663       NULL
664     };
665     schedulerfactory_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE, 
666                                                   "GstSchedulerFactory", &schedulerfactory_info, 0);
667   }
668   return schedulerfactory_type;
669 }
670
671 static void
672 gst_scheduler_factory_class_init (GstSchedulerFactoryClass *klass)
673 {
674   GObjectClass *gobject_class;
675   GstObjectClass *gstobject_class;
676   GstPluginFeatureClass *gstpluginfeature_class;
677
678   gobject_class = (GObjectClass*)klass;
679   gstobject_class = (GstObjectClass*)klass;
680   gstpluginfeature_class = (GstPluginFeatureClass*) klass;
681
682   factory_parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE);
683
684   if (!_default_name)
685     _default_name = g_strdup ("basicomega");
686 }
687
688 static void
689 gst_scheduler_factory_init (GstSchedulerFactory *factory)
690 {
691 }
692         
693
694 /**
695  * gst_scheduler_factory_new:
696  * @name: name of schedulerfactory to create
697  * @longdesc: long description of schedulerfactory to create
698  * @type: the gtk type of the GstScheduler element of this factory
699  *
700  * Create a new schedulerfactory with the given parameters
701  *
702  * Returns: a new #GstSchedulerFactory.
703  */
704 GstSchedulerFactory*
705 gst_scheduler_factory_new (const gchar *name, const gchar *longdesc, GType type)
706 {
707   GstSchedulerFactory *factory;
708
709   g_return_val_if_fail(name != NULL, NULL);
710   factory = gst_scheduler_factory_find (name);
711   if (!factory) {
712     factory = GST_SCHEDULER_FACTORY (g_object_new (GST_TYPE_SCHEDULER_FACTORY, NULL));
713   }
714
715   GST_PLUGIN_FEATURE_NAME (factory) = g_strdup (name);
716   if (factory->longdesc)
717     g_free (factory->longdesc);
718   factory->longdesc = g_strdup (longdesc);
719   factory->type = type;
720
721   return factory;
722 }
723
724 /**
725  * gst_scheduler_factory_destroy:
726  * @factory: factory to destroy
727  *
728  * Removes the scheduler from the global list.
729  */
730 void
731 gst_scheduler_factory_destroy (GstSchedulerFactory *factory)
732 {
733   g_return_if_fail (factory != NULL);
734
735   /* we don't free the struct bacause someone might  have a handle to it.. */
736 }
737
738 /**
739  * gst_scheduler_factory_find:
740  * @name: name of schedulerfactory to find
741  *
742  * Search for an schedulerfactory of the given name.
743  *
744  * Returns: #GstSchedulerFactory if found, NULL otherwise
745  */
746 GstSchedulerFactory*
747 gst_scheduler_factory_find (const gchar *name)
748 {
749   GstPluginFeature *feature;
750
751   g_return_val_if_fail(name != NULL, NULL);
752
753   GST_DEBUG (0,"gstscheduler: find \"%s\"", name);
754
755   feature = gst_registry_pool_find_feature (name, GST_TYPE_SCHEDULER_FACTORY);
756   if (feature)
757     return GST_SCHEDULER_FACTORY (feature);
758
759   return NULL;
760 }
761
762 /**
763  * gst_scheduler_factory_create:
764  * @factory: the factory used to create the instance
765  * @parent: the parent element of this scheduler
766  *
767  * Create a new #GstScheduler instance from the 
768  * given schedulerfactory with the given parent. @parent will
769  * have its scheduler set to the returned #GstScheduler instance.
770  *
771  * Returns: A new #GstScheduler instance with a reference count of %1.
772  */
773 GstScheduler*
774 gst_scheduler_factory_create (GstSchedulerFactory *factory, GstElement *parent)
775 {
776   GstScheduler *new = NULL;
777
778   g_return_val_if_fail (factory != NULL, NULL);
779   g_return_val_if_fail (parent != NULL, NULL);
780
781   if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
782     g_return_val_if_fail (factory->type != 0, NULL);
783
784     new = GST_SCHEDULER (g_object_new (factory->type, NULL));
785     new->parent = parent;
786
787     GST_ELEMENT_SCHED (parent) = new;
788
789     /* let's refcount the scheduler */
790     gst_object_ref (GST_OBJECT (new));
791     gst_object_sink (GST_OBJECT (new));
792   }
793
794   return new;
795 }
796
797 /**
798  * gst_scheduler_factory_make:
799  * @name: the name of the factory used to create the instance
800  * @parent: the parent element of this scheduler
801  *
802  * Create a new #GstScheduler instance from the 
803  * schedulerfactory with the given name and parent. @parent will
804  * have its scheduler set to the returned #GstScheduler instance.
805  * If %NULL is passed as @name, the default scheduler name will
806  * be used.
807  *
808  * Returns: A new #GstScheduler instance with a reference count of %1.
809  */
810 GstScheduler*
811 gst_scheduler_factory_make (const gchar *name, GstElement *parent)
812 {
813   GstSchedulerFactory *factory;
814   const gchar *default_name = gst_scheduler_factory_get_default_name ();
815
816   if (name)
817     factory = gst_scheduler_factory_find (name);
818   else
819   {
820     /* FIXME: do better error handling */
821     if (default_name == NULL)
822       g_error ("No default scheduler name - do you have a registry ?");
823     factory = gst_scheduler_factory_find (default_name);
824   }
825
826   if (factory == NULL)
827     return NULL;
828
829   return gst_scheduler_factory_create (factory, parent);
830 }
831
832 /**
833  * gst_scheduler_factory_set_default_name:
834  * @name: the name of the factory used as a default
835  *
836  * Set the default schedulerfactory name.
837  */
838 void
839 gst_scheduler_factory_set_default_name (const gchar* name)
840 {
841   if (_default_name)
842     g_free (_default_name);
843
844   _default_name = g_strdup (name);
845 }
846
847 /**
848  * gst_scheduler_factory_get_default_name:
849  *
850  * Get the default schedulerfactory name.
851  *
852  * Returns: the name of the default scheduler.
853  */
854 const gchar*
855 gst_scheduler_factory_get_default_name (void)
856 {
857   return _default_name;
858 }