1615ada114151b9d9251197dec7d3bf88d606dd5
[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 #include "gst_private.h"
24
25 #include "gstsystemclock.h"
26 #include "gstscheduler.h"
27 #include "gstinfo.h"
28 #include "gstregistrypool.h"
29
30 static void gst_scheduler_class_init (GstSchedulerClass * klass);
31 static void gst_scheduler_init (GstScheduler * sched);
32 static void gst_scheduler_dispose (GObject * object);
33
34 static GstObjectClass *parent_class = NULL;
35
36 static gchar *_default_name = NULL;
37
38 GType
39 gst_scheduler_get_type (void)
40 {
41   static GType _gst_scheduler_type = 0;
42
43   if (!_gst_scheduler_type) {
44     static const GTypeInfo scheduler_info = {
45       sizeof (GstSchedulerClass),
46       NULL,
47       NULL,
48       (GClassInitFunc) gst_scheduler_class_init,
49       NULL,
50       NULL,
51       sizeof (GstScheduler),
52       0,
53       (GInstanceInitFunc) gst_scheduler_init,
54       NULL
55     };
56
57     _gst_scheduler_type =
58         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   GObjectClass *gobject_class;
68
69   gobject_class = (GObjectClass *) klass;
70
71   parent_class = g_type_class_ref (GST_TYPE_OBJECT);
72
73   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_scheduler_dispose);
74 }
75
76 static void
77 gst_scheduler_init (GstScheduler * sched)
78 {
79   sched->clock_providers = NULL;
80   sched->clock_receivers = NULL;
81   sched->schedulers = NULL;
82   sched->state = GST_SCHEDULER_STATE_NONE;
83   sched->parent = NULL;
84   sched->parent_sched = NULL;
85   sched->clock = NULL;
86 }
87
88 static void
89 gst_scheduler_dispose (GObject * object)
90 {
91   GstScheduler *sched = GST_SCHEDULER (object);
92
93   /* thse lists should all be NULL */
94   GST_DEBUG ("scheduler %p dispose %p %p %p",
95       object,
96       sched->clock_providers, sched->clock_receivers, sched->schedulers);
97
98   gst_object_replace ((GstObject **) & sched->current_clock, NULL);
99   gst_object_replace ((GstObject **) & sched->clock, NULL);
100
101   G_OBJECT_CLASS (parent_class)->dispose (object);
102 }
103
104 /**
105  * gst_scheduler_setup:
106  * @sched: the scheduler
107  *
108  * Prepare the scheduler.
109  */
110 void
111 gst_scheduler_setup (GstScheduler * sched)
112 {
113   GstSchedulerClass *sclass;
114
115   g_return_if_fail (GST_IS_SCHEDULER (sched));
116
117   sclass = GST_SCHEDULER_GET_CLASS (sched);
118
119   if (sclass->setup)
120     sclass->setup (sched);
121 }
122
123 /**
124  * gst_scheduler_reset:
125  * @sched: a #GstScheduler to reset.
126  *
127  * Reset the schedulers.
128  */
129 void
130 gst_scheduler_reset (GstScheduler * sched)
131 {
132   GstSchedulerClass *sclass;
133
134   g_return_if_fail (GST_IS_SCHEDULER (sched));
135
136   sclass = GST_SCHEDULER_GET_CLASS (sched);
137
138   if (sclass->reset)
139     sclass->reset (sched);
140 }
141
142 /**
143  * gst_scheduler_pad_link:
144  * @sched: the scheduler
145  * @srcpad: the srcpad to link
146  * @sinkpad: the sinkpad to link to
147  *
148  * Links the srcpad to the given sinkpad.
149  */
150 void
151 gst_scheduler_pad_link (GstScheduler * sched, GstPad * srcpad, GstPad * sinkpad)
152 {
153   GstSchedulerClass *sclass;
154
155   g_return_if_fail (GST_IS_SCHEDULER (sched));
156   g_return_if_fail (GST_IS_PAD (srcpad));
157   g_return_if_fail (GST_IS_PAD (sinkpad));
158
159   sclass = GST_SCHEDULER_GET_CLASS (sched);
160
161   if (sclass->pad_link)
162     sclass->pad_link (sched, srcpad, sinkpad);
163 }
164
165 /**
166  * gst_scheduler_pad_unlink:
167  * @sched: the scheduler
168  * @srcpad: the srcpad to unlink
169  * @sinkpad: the sinkpad to unlink from
170  *
171  * Unlinks the srcpad from the given sinkpad.
172  */
173 void
174 gst_scheduler_pad_unlink (GstScheduler * sched, GstPad * srcpad,
175     GstPad * sinkpad)
176 {
177   GstSchedulerClass *sclass;
178
179   g_return_if_fail (GST_IS_SCHEDULER (sched));
180   g_return_if_fail (GST_IS_PAD (srcpad));
181   g_return_if_fail (GST_IS_PAD (sinkpad));
182
183   sclass = GST_SCHEDULER_GET_CLASS (sched);
184
185   if (sclass->pad_unlink)
186     sclass->pad_unlink (sched, srcpad, sinkpad);
187 }
188
189 /**
190  * gst_scheduler_pad_select:
191  * @sched: the scheduler
192  * @padlist: the padlist to select on
193  *
194  * register the given padlist for a select operation. 
195  *
196  * Returns: the pad which received a buffer.
197  */
198 GstPad *
199 gst_scheduler_pad_select (GstScheduler * sched, GList * padlist)
200 {
201   g_return_val_if_fail (GST_IS_SCHEDULER (sched), NULL);
202   g_return_val_if_fail (padlist != NULL, NULL);
203
204   return NULL;
205 }
206
207 /**
208  * gst_scheduler_add_element:
209  * @sched: the scheduler
210  * @element: the element to add to the scheduler
211  *
212  * Add an element to the scheduler.
213  */
214 void
215 gst_scheduler_add_element (GstScheduler * sched, GstElement * element)
216 {
217   GstSchedulerClass *sclass;
218
219   g_return_if_fail (GST_IS_SCHEDULER (sched));
220   g_return_if_fail (GST_IS_ELEMENT (element));
221
222   /* if it's already in this scheduler, don't bother doing anything */
223   if (GST_ELEMENT_SCHED (element) == sched) {
224     GST_CAT_DEBUG (GST_CAT_SCHEDULING, "element %s already in scheduler %p",
225         GST_ELEMENT_NAME (element), sched);
226     return;
227   }
228
229   /* if it's not inside this scheduler, it has to be NULL */
230   g_assert (GST_ELEMENT_SCHED (element) == NULL);
231
232   if (gst_element_provides_clock (element)) {
233     sched->clock_providers = g_list_prepend (sched->clock_providers, element);
234     GST_CAT_DEBUG (GST_CAT_CLOCK, "added clock provider %s",
235         GST_ELEMENT_NAME (element));
236   }
237   if (gst_element_requires_clock (element)) {
238     sched->clock_receivers = g_list_prepend (sched->clock_receivers, element);
239     GST_CAT_DEBUG (GST_CAT_CLOCK, "added clock receiver %s",
240         GST_ELEMENT_NAME (element));
241   }
242
243   gst_element_set_scheduler (element, sched);
244
245   sclass = GST_SCHEDULER_GET_CLASS (sched);
246
247   if (sclass->add_element)
248     sclass->add_element (sched, element);
249 }
250
251 /**
252  * gst_scheduler_remove_element:
253  * @sched: the scheduler
254  * @element: the element to remove
255  *
256  * Remove an element from the scheduler.
257  */
258 void
259 gst_scheduler_remove_element (GstScheduler * sched, GstElement * element)
260 {
261   GstSchedulerClass *sclass;
262
263   g_return_if_fail (GST_IS_SCHEDULER (sched));
264   g_return_if_fail (GST_IS_ELEMENT (element));
265
266   sched->clock_providers = g_list_remove (sched->clock_providers, element);
267   sched->clock_receivers = g_list_remove (sched->clock_receivers, element);
268
269   sclass = GST_SCHEDULER_GET_CLASS (sched);
270
271   if (sclass->remove_element)
272     sclass->remove_element (sched, element);
273
274   gst_element_set_scheduler (element, NULL);
275 }
276
277 /**
278  * gst_scheduler_state_transition:
279  * @sched: the scheduler
280  * @element: the element with the state transition
281  * @transition: the state transition
282  *
283  * Tell the scheduler that an element changed its state.
284  *
285  * Returns: a GstElementStateReturn indicating success or failure
286  * of the state transition.
287  */
288 GstElementStateReturn
289 gst_scheduler_state_transition (GstScheduler * sched, GstElement * element,
290     gint transition)
291 {
292   GstSchedulerClass *sclass;
293
294   g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_STATE_FAILURE);
295   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
296
297   if (element == sched->parent && sched->parent_sched == NULL) {
298     switch (transition) {
299       case GST_STATE_READY_TO_PAUSED:
300       {
301         GstClock *clock = gst_scheduler_get_clock (sched);
302
303         GST_CAT_DEBUG (GST_CAT_CLOCK,
304             "scheduler READY to PAUSED clock is %p (%s)", clock,
305             (clock ? GST_OBJECT_NAME (clock) : "nil"));
306
307         gst_scheduler_set_clock (sched, clock);
308         break;
309       }
310     }
311   }
312
313   sclass = GST_SCHEDULER_GET_CLASS (sched);
314
315   if (sclass->state_transition)
316     return sclass->state_transition (sched, element, transition);
317
318   return GST_STATE_SUCCESS;
319 }
320
321 /**
322  * gst_scheduler_scheduling_change:
323  * @sched: the scheduler
324  * @element: the element that changed its scheduling strategy
325  *
326  * Tell the scheduler that an element changed its scheduling strategy.
327  * An element could, for example, change its loop function or changes
328  * from a loop based element to a chain based element.
329  */
330 void
331 gst_scheduler_scheduling_change (GstScheduler * sched, GstElement * element)
332 {
333   GstSchedulerClass *sclass;
334
335   g_return_if_fail (GST_IS_SCHEDULER (sched));
336   g_return_if_fail (GST_IS_ELEMENT (element));
337
338   sclass = GST_SCHEDULER_GET_CLASS (sched);
339
340   if (sclass->scheduling_change)
341     sclass->scheduling_change (sched, element);
342 }
343
344 /**
345  * gst_scheduler_add_scheduler:
346  * @sched: a  #GstScheduler to add to
347  * @sched2: the #GstScheduler to add
348  *
349  * Notifies the scheduler that it has to monitor this scheduler.
350  */
351 void
352 gst_scheduler_add_scheduler (GstScheduler * sched, GstScheduler * sched2)
353 {
354   GstSchedulerClass *sclass;
355
356   g_return_if_fail (GST_IS_SCHEDULER (sched));
357   g_return_if_fail (GST_IS_SCHEDULER (sched2));
358   g_return_if_fail (sched2->parent_sched == NULL);
359
360   GST_DEBUG ("gstscheduler: %p add scheduler %p", sched, sched2);
361
362   gst_object_ref (GST_OBJECT (sched2));
363   gst_object_ref (GST_OBJECT (sched));
364
365   sched->schedulers = g_list_prepend (sched->schedulers, sched2);
366   sched2->parent_sched = sched;
367
368   sclass = GST_SCHEDULER_GET_CLASS (sched);
369
370   if (sclass->add_scheduler)
371     sclass->add_scheduler (sched, sched2);
372 }
373
374 /**
375  * gst_scheduler_remove_scheduler:
376  * @sched: the scheduler
377  * @sched2: the scheduler to remove
378  *
379  a Notifies the scheduler that it can stop monitoring this scheduler.
380  */
381 void
382 gst_scheduler_remove_scheduler (GstScheduler * sched, GstScheduler * sched2)
383 {
384   GstSchedulerClass *sclass;
385
386   g_return_if_fail (GST_IS_SCHEDULER (sched));
387   g_return_if_fail (GST_IS_SCHEDULER (sched2));
388   g_return_if_fail (sched2->parent_sched == sched);
389
390   GST_DEBUG ("gstscheduler: %p remove scheduler %p", sched, sched2);
391
392   sclass = GST_SCHEDULER_GET_CLASS (sched);
393
394   if (sclass->remove_scheduler)
395     sclass->remove_scheduler (sched, sched2);
396
397   sched->schedulers = g_list_remove (sched->schedulers, sched2);
398   sched2->parent_sched = NULL;
399
400   gst_object_unref (GST_OBJECT (sched2));
401   gst_object_unref (GST_OBJECT (sched));
402 }
403
404 /**
405  * gst_scheduler_lock_element:
406  * @sched: the scheduler
407  * @element: the element to lock
408  *
409  * Acquire a lock on the given element in the given scheduler.
410  */
411 void
412 gst_scheduler_lock_element (GstScheduler * sched, GstElement * element)
413 {
414   g_return_if_fail (GST_IS_SCHEDULER (sched));
415   g_return_if_fail (GST_IS_ELEMENT (element));
416 }
417
418 /**
419  * gst_scheduler_unlock_element:
420  * @sched: the scheduler
421  * @element: the element to unlock
422  *
423  * Release the lock on the given element in the given scheduler.
424  */
425 void
426 gst_scheduler_unlock_element (GstScheduler * sched, GstElement * element)
427 {
428   GstSchedulerClass *sclass;
429
430   g_return_if_fail (GST_IS_SCHEDULER (sched));
431   g_return_if_fail (GST_IS_ELEMENT (element));
432
433   sclass = GST_SCHEDULER_GET_CLASS (sched);
434 }
435
436 /**
437  * gst_scheduler_error:
438  * @sched: the scheduler
439  * @element: the element with the error
440  *
441  * Tell the scheduler an element was in error
442  */
443 void
444 gst_scheduler_error (GstScheduler * sched, GstElement * element)
445 {
446   GstSchedulerClass *sclass;
447
448   g_return_if_fail (GST_IS_SCHEDULER (sched));
449   g_return_if_fail (GST_IS_ELEMENT (element));
450
451   sclass = GST_SCHEDULER_GET_CLASS (sched);
452
453   if (sclass->error)
454     sclass->error (sched, element);
455 }
456
457 /**
458  * gst_scheduler_yield:
459  * @sched: the scheduler
460  * @element: the element requesting a yield
461  *
462  * Tell the scheduler to schedule another element.
463  *
464  * Returns: TRUE if the element should save its state, FALSE
465  * if the scheduler can perform this action itself.
466  */
467 gboolean
468 gst_scheduler_yield (GstScheduler * sched, GstElement * element)
469 {
470   GstSchedulerClass *sclass;
471
472   g_return_val_if_fail (GST_IS_SCHEDULER (sched), TRUE);
473   g_return_val_if_fail (GST_IS_ELEMENT (element), TRUE);
474
475   sclass = GST_SCHEDULER_GET_CLASS (sched);
476
477   if (sclass->yield)
478     return sclass->yield (sched, element);
479
480   return TRUE;
481 }
482
483 /**
484  * gst_scheduler_interrupt:
485  * @sched: the scheduler
486  * @element: the element requesting an interrupt
487  *
488  * Tell the scheduler to interrupt execution of this element.
489  *
490  * Returns: TRUE if the element should return NULL from the chain/get
491  * function.
492  */
493 gboolean
494 gst_scheduler_interrupt (GstScheduler * sched, GstElement * element)
495 {
496   GstSchedulerClass *sclass;
497
498   g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
499   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
500
501   sclass = GST_SCHEDULER_GET_CLASS (sched);
502
503   if (sclass->interrupt)
504     return sclass->interrupt (sched, element);
505
506   return FALSE;
507 }
508
509 /**
510  * gst_scheduler_get_clock:
511  * @sched: the scheduler
512  *
513  * Gets the current clock used by the scheduler.
514  *
515  * Returns: a GstClock
516  */
517 GstClock *
518 gst_scheduler_get_clock (GstScheduler * sched)
519 {
520   GstClock *clock = NULL;
521
522   /* if we have a fixed clock, use that one */
523   if (GST_FLAG_IS_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK)) {
524     clock = sched->clock;
525
526     GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)",
527         clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
528   } else {
529     GList *schedulers = sched->schedulers;
530     GList *providers = sched->clock_providers;
531
532     /* try to get a clock from one of the schedulers we manage first */
533     while (schedulers) {
534       GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
535
536       clock = gst_scheduler_get_clock (scheduler);
537       if (clock) {
538         GST_CAT_DEBUG (GST_CAT_CLOCK,
539             "scheduler found managed sched clock %p (%s)",
540             clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
541         break;
542       }
543
544       schedulers = g_list_next (schedulers);
545     }
546     /* still no clock, try to find one in the providers */
547     while (!clock && providers) {
548       clock = gst_element_get_clock (GST_ELEMENT (providers->data));
549       if (clock)
550         GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler found provider clock: %p (%s)",
551             clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
552       providers = g_list_next (providers);
553     }
554     /* still no clock, use a system clock */
555     if (!clock && sched->parent_sched == NULL) {
556       clock = gst_system_clock_obtain ();
557       /* we unref since this function is not supposed to increase refcount
558        * of clock object returned; this is ok since the systemclock always
559        * has a refcount of at least one in the current code. */
560       gst_object_unref (GST_OBJECT (clock));
561       GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler obtained system clock: %p (%s)",
562           clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
563     }
564   }
565
566   return clock;
567 }
568
569 /**
570  * gst_scheduler_use_clock:
571  * @sched: the scheduler
572  * @clock: the clock to use
573  *
574  * Force the scheduler to use the given clock. The scheduler will
575  * always use the given clock even if new clock providers are added
576  * to this scheduler.
577  */
578 void
579 gst_scheduler_use_clock (GstScheduler * sched, GstClock * clock)
580 {
581   g_return_if_fail (sched != NULL);
582   g_return_if_fail (GST_IS_SCHEDULER (sched));
583
584   GST_FLAG_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
585
586   gst_object_replace ((GstObject **) & sched->clock, (GstObject *) clock);
587
588   GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)", clock,
589       (clock ? GST_OBJECT_NAME (clock) : "nil"));
590 }
591
592 /**
593  * gst_scheduler_set_clock:
594  * @sched: the scheduler
595  * @clock: the clock to set
596  *
597  * Set the clock for the scheduler. The clock will be distributed
598  * to all the elements managed by the scheduler.
599  */
600 void
601 gst_scheduler_set_clock (GstScheduler * sched, GstClock * clock)
602 {
603   GList *receivers;
604   GList *schedulers;
605
606   g_return_if_fail (sched != NULL);
607   g_return_if_fail (GST_IS_SCHEDULER (sched));
608
609   receivers = sched->clock_receivers;
610   schedulers = sched->schedulers;
611
612   gst_object_replace ((GstObject **) & sched->current_clock,
613       (GstObject *) clock);
614
615   while (receivers) {
616     GstElement *element = GST_ELEMENT (receivers->data);
617
618     GST_CAT_DEBUG (GST_CAT_CLOCK,
619         "scheduler setting clock %p (%s) on element %s", clock,
620         (clock ? GST_OBJECT_NAME (clock) : "nil"), GST_ELEMENT_NAME (element));
621
622     gst_element_set_clock (element, clock);
623     receivers = g_list_next (receivers);
624   }
625   while (schedulers) {
626     GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
627
628     GST_CAT_DEBUG (GST_CAT_CLOCK,
629         "scheduler setting clock %p (%s) on scheduler %p", clock,
630         (clock ? GST_OBJECT_NAME (clock) : "nil"), scheduler);
631     gst_scheduler_set_clock (scheduler, clock);
632     schedulers = g_list_next (schedulers);
633   }
634 }
635
636 /**
637  * gst_scheduler_auto_clock:
638  * @sched: the scheduler
639  *
640  * Let the scheduler select a clock automatically.
641  */
642 void
643 gst_scheduler_auto_clock (GstScheduler * sched)
644 {
645   g_return_if_fail (sched != NULL);
646   g_return_if_fail (GST_IS_SCHEDULER (sched));
647
648   GST_FLAG_UNSET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
649
650   gst_object_replace ((GstObject **) & sched->clock, NULL);
651
652   GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler using automatic clock");
653 }
654
655 GstClockReturn gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter);
656
657 /**
658  * gst_scheduler_clock_wait:
659  * @sched: the scheduler
660  * @element: the element that wants to wait
661  * @id: the clockid to use
662  * @jitter: the time difference between requested time and actual time
663  *
664  * Wait till the clock reaches a specific time. The ClockID can
665  * be obtained from #gst_clock_new_single_shot_id. 
666  *
667  * Returns: the status of the operation
668  */
669 GstClockReturn
670 gst_scheduler_clock_wait (GstScheduler * sched, GstElement * element,
671     GstClockID id, GstClockTimeDiff * jitter)
672 {
673   GstSchedulerClass *sclass;
674
675   g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_CLOCK_ERROR);
676   g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
677
678   sclass = GST_SCHEDULER_GET_CLASS (sched);
679
680   if (sclass->clock_wait)
681     return sclass->clock_wait (sched, element, id, jitter);
682   else
683     return gst_clock_id_wait (id, jitter);
684 }
685
686 /**
687  * gst_scheduler_iterate:
688  * @sched: the scheduler
689  *
690  * Perform one iteration on the scheduler.
691  *
692  * Returns: a boolean indicating something usefull has happened.
693  */
694 gboolean
695 gst_scheduler_iterate (GstScheduler * sched)
696 {
697   GstSchedulerClass *sclass;
698   gboolean res = FALSE;
699
700   g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
701
702   sclass = GST_SCHEDULER_GET_CLASS (sched);
703
704   if (sclass->iterate) {
705     res = sclass->iterate (sched);
706   }
707
708   return res;
709 }
710
711
712 /**
713  * gst_scheduler_show:
714  * @sched: the scheduler
715  *
716  * Dump the state of the scheduler
717  */
718 void
719 gst_scheduler_show (GstScheduler * sched)
720 {
721   GstSchedulerClass *sclass;
722
723   g_return_if_fail (GST_IS_SCHEDULER (sched));
724
725   sclass = GST_SCHEDULER_GET_CLASS (sched);
726
727   if (sclass->show)
728     sclass->show (sched);
729 }
730
731 /*
732  * Factory stuff starts here
733  *
734  */
735 static void gst_scheduler_factory_class_init (GstSchedulerFactoryClass * klass);
736 static void gst_scheduler_factory_init (GstSchedulerFactory * factory);
737
738 static GstPluginFeatureClass *factory_parent_class = NULL;
739
740 /* static guint gst_scheduler_factory_signals[LAST_SIGNAL] = { 0 }; */
741
742 GType
743 gst_scheduler_factory_get_type (void)
744 {
745   static GType schedulerfactory_type = 0;
746
747   if (!schedulerfactory_type) {
748     static const GTypeInfo schedulerfactory_info = {
749       sizeof (GstSchedulerFactoryClass),
750       NULL,
751       NULL,
752       (GClassInitFunc) gst_scheduler_factory_class_init,
753       NULL,
754       NULL,
755       sizeof (GstSchedulerFactory),
756       0,
757       (GInstanceInitFunc) gst_scheduler_factory_init,
758       NULL
759     };
760
761     schedulerfactory_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE,
762         "GstSchedulerFactory", &schedulerfactory_info, 0);
763   }
764   return schedulerfactory_type;
765 }
766
767 static void
768 gst_scheduler_factory_class_init (GstSchedulerFactoryClass * klass)
769 {
770   GObjectClass *gobject_class;
771   GstObjectClass *gstobject_class;
772   GstPluginFeatureClass *gstpluginfeature_class;
773
774   gobject_class = (GObjectClass *) klass;
775   gstobject_class = (GstObjectClass *) klass;
776   gstpluginfeature_class = (GstPluginFeatureClass *) klass;
777
778   factory_parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE);
779
780   if (!_default_name) {
781     if (g_getenv ("GST_SCHEDULER")) {
782       _default_name = g_strdup (g_getenv ("GST_SCHEDULER"));
783     } else {
784       _default_name = g_strdup (GST_SCHEDULER_DEFAULT_NAME);
785     }
786   }
787   g_assert (_default_name);
788 }
789
790 static void
791 gst_scheduler_factory_init (GstSchedulerFactory * factory)
792 {
793 }
794
795
796 /**
797  * gst_scheduler_register:
798  * @plugin: a #GstPlugin
799  * @name: name of the scheduler to register
800  * @longdesc: description of the scheduler
801  * @type: #GType of the scheduler to register
802  *
803  * Registers a scheduler with GStreamer.
804  *
805  * Returns: TRUE, if the registering succeeded, FALSE on error.
806  *
807  * Since: 0.8.5
808  **/
809 gboolean
810 gst_scheduler_register (GstPlugin * plugin, const gchar * name,
811     const gchar * longdesc, GType type)
812 {
813   GstSchedulerFactory *factory;
814
815   g_return_val_if_fail (plugin != NULL, FALSE);
816   g_return_val_if_fail (name != NULL, FALSE);
817   g_return_val_if_fail (longdesc != NULL, FALSE);
818   g_return_val_if_fail (g_type_is_a (type, GST_TYPE_SCHEDULER), FALSE);
819
820   factory = gst_scheduler_factory_find (name);
821   if (factory) {
822     g_return_val_if_fail (factory->type == 0, FALSE);
823     g_free (factory->longdesc);
824     factory->longdesc = g_strdup (longdesc);
825     factory->type = type;
826   } else {
827     factory = gst_scheduler_factory_new (name, longdesc, type);
828     g_return_val_if_fail (factory, FALSE);
829     gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
830   }
831
832   return TRUE;
833 }
834
835 /**
836  * gst_scheduler_factory_new:
837  * @name: name of schedulerfactory to create
838  * @longdesc: long description of schedulerfactory to create
839  * @type: the gtk type of the GstScheduler element of this factory
840  *
841  * Create a new schedulerfactory with the given parameters
842  *
843  * Returns: a new #GstSchedulerFactory.
844  */
845 GstSchedulerFactory *
846 gst_scheduler_factory_new (const gchar * name, const gchar * longdesc,
847     GType type)
848 {
849   GstSchedulerFactory *factory;
850
851   g_return_val_if_fail (name != NULL, NULL);
852
853   factory = gst_scheduler_factory_find (name);
854
855   if (!factory) {
856     factory =
857         GST_SCHEDULER_FACTORY (g_object_new (GST_TYPE_SCHEDULER_FACTORY, NULL));
858     GST_PLUGIN_FEATURE_NAME (factory) = g_strdup (name);
859   } else {
860     g_free (factory->longdesc);
861   }
862
863   factory->longdesc = g_strdup (longdesc);
864   factory->type = type;
865
866   return factory;
867 }
868
869 /**
870  * gst_scheduler_factory_destroy:
871  * @factory: factory to destroy
872  *
873  * Removes the scheduler from the global list.
874  */
875 void
876 gst_scheduler_factory_destroy (GstSchedulerFactory * factory)
877 {
878   g_return_if_fail (factory != NULL);
879
880   /* we don't free the struct bacause someone might  have a handle to it.. */
881 }
882
883 /**
884  * gst_scheduler_factory_find:
885  * @name: name of schedulerfactory to find
886  *
887  * Search for an schedulerfactory of the given name.
888  *
889  * Returns: #GstSchedulerFactory if found, NULL otherwise
890  */
891 GstSchedulerFactory *
892 gst_scheduler_factory_find (const gchar * name)
893 {
894   GstPluginFeature *feature;
895
896   g_return_val_if_fail (name != NULL, NULL);
897
898   GST_DEBUG ("gstscheduler: find \"%s\"", name);
899
900   feature = gst_registry_pool_find_feature (name, GST_TYPE_SCHEDULER_FACTORY);
901
902   if (feature)
903     return GST_SCHEDULER_FACTORY (feature);
904
905   return NULL;
906 }
907
908 /**
909  * gst_scheduler_factory_create:
910  * @factory: the factory used to create the instance
911  * @parent: the parent element of this scheduler
912  *
913  * Create a new #GstScheduler instance from the 
914  * given schedulerfactory with the given parent. @parent will
915  * have its scheduler set to the returned #GstScheduler instance.
916  *
917  * Returns: A new #GstScheduler instance with a reference count of %1.
918  */
919 GstScheduler *
920 gst_scheduler_factory_create (GstSchedulerFactory * factory,
921     GstElement * parent)
922 {
923   GstScheduler *sched = NULL;
924
925   g_return_val_if_fail (factory != NULL, NULL);
926   g_return_val_if_fail (GST_IS_ELEMENT (parent), NULL);
927
928   if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
929     g_return_val_if_fail (factory->type != 0, NULL);
930
931     sched = GST_SCHEDULER (g_object_new (factory->type, NULL));
932     sched->parent = parent;
933
934     GST_ELEMENT_SCHED (parent) = sched;
935
936     /* let's refcount the scheduler */
937     gst_object_ref (GST_OBJECT (sched));
938     gst_object_sink (GST_OBJECT (sched));
939   }
940
941   return sched;
942 }
943
944 /**
945  * gst_scheduler_factory_make:
946  * @name: the name of the factory used to create the instance
947  * @parent: the parent element of this scheduler
948  *
949  * Create a new #GstScheduler instance from the 
950  * schedulerfactory with the given name and parent. @parent will
951  * have its scheduler set to the returned #GstScheduler instance.
952  * If %NULL is passed as @name, the default scheduler name will
953  * be used.
954  *
955  * Returns: A new #GstScheduler instance with a reference count of %1.
956  */
957 GstScheduler *
958 gst_scheduler_factory_make (const gchar * name, GstElement * parent)
959 {
960   GstSchedulerFactory *factory;
961   const gchar *default_name = gst_scheduler_factory_get_default_name ();
962
963   if (name)
964     factory = gst_scheduler_factory_find (name);
965   else {
966     /* FIXME: do better error handling */
967     if (default_name == NULL)
968       g_error ("No default scheduler name - do you have a registry ?");
969     factory = gst_scheduler_factory_find (default_name);
970   }
971
972   if (factory == NULL)
973     return NULL;
974
975   return gst_scheduler_factory_create (factory, parent);
976 }
977
978 /**
979  * gst_scheduler_factory_set_default_name:
980  * @name: the name of the factory used as a default
981  *
982  * Set the default schedulerfactory name.
983  */
984 void
985 gst_scheduler_factory_set_default_name (const gchar * name)
986 {
987   g_free (_default_name);
988
989   _default_name = g_strdup (name);
990 }
991
992 /**
993  * gst_scheduler_factory_get_default_name:
994  *
995  * Get the default schedulerfactory name.
996  *
997  * Returns: the name of the default scheduler.
998  */
999 const gchar *
1000 gst_scheduler_factory_get_default_name (void)
1001 {
1002   return _default_name;
1003 }