fix doc build fix autogen
[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 = g_type_register_static (GST_TYPE_OBJECT, "GstScheduler", 
58                     &scheduler_info, G_TYPE_FLAG_ABSTRACT);
59   }
60   return _gst_scheduler_type;
61 }
62
63 static void
64 gst_scheduler_class_init (GstSchedulerClass *klass)
65 {
66   GObjectClass *gobject_class;
67       
68   gobject_class = (GObjectClass*) klass;
69       
70   parent_class = g_type_class_ref (GST_TYPE_OBJECT);
71
72   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_scheduler_dispose);
73 }
74
75 static void
76 gst_scheduler_init (GstScheduler *sched)
77 {
78   sched->clock_providers = NULL;
79   sched->clock_receivers = NULL;
80   sched->schedulers = NULL;
81   sched->state = GST_SCHEDULER_STATE_NONE;
82   sched->parent = NULL;
83   sched->parent_sched = NULL;
84   sched->clock = NULL;
85 }
86
87 static void
88 gst_scheduler_dispose (GObject *object)
89 {
90   GstScheduler *sched = GST_SCHEDULER (object);
91
92   /* thse lists should all be NULL */
93   GST_DEBUG ( "scheduler %p dispose %p %p %p",
94                   object,
95                   sched->clock_providers,
96                   sched->clock_receivers,
97                   sched->schedulers);
98
99   gst_object_replace ((GstObject **)&sched->current_clock, NULL);
100   gst_object_replace ((GstObject **)&sched->clock, NULL);
101
102   G_OBJECT_CLASS (parent_class)->dispose (object);
103 }
104
105 /**
106  * gst_scheduler_setup:
107  * @sched: the scheduler
108  *
109  * Prepare the scheduler.
110  */
111 void
112 gst_scheduler_setup (GstScheduler *sched)
113 {
114   GstSchedulerClass *sclass;
115
116   g_return_if_fail (GST_IS_SCHEDULER (sched));
117
118   sclass = GST_SCHEDULER_GET_CLASS (sched);
119
120   if (sclass->setup)
121     sclass->setup (sched);
122 }
123
124 /**
125  * gst_scheduler_reset:
126  * @sched: a #GstScheduler to reset.
127  *
128  * Reset the schedulers.
129  */
130 void
131 gst_scheduler_reset (GstScheduler *sched)
132 {
133   GstSchedulerClass *sclass;
134
135   g_return_if_fail (GST_IS_SCHEDULER (sched));
136
137   sclass = GST_SCHEDULER_GET_CLASS (sched);
138
139   if (sclass->reset)
140     sclass->reset (sched);
141 }
142
143 /**
144  * gst_scheduler_pad_link:
145  * @sched: the scheduler
146  * @srcpad: the srcpad to link
147  * @sinkpad: the sinkpad to link to
148  *
149  * Links the srcpad to the given sinkpad.
150  */
151 void
152 gst_scheduler_pad_link (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad)
153 {
154   GstSchedulerClass *sclass;
155
156   g_return_if_fail (GST_IS_SCHEDULER (sched));
157   g_return_if_fail (GST_IS_PAD (srcpad));
158   g_return_if_fail (GST_IS_PAD (sinkpad));
159
160   sclass = GST_SCHEDULER_GET_CLASS (sched);
161
162   if (sclass->pad_link)
163     sclass->pad_link (sched, srcpad, sinkpad);
164 }
165
166 /**
167  * gst_scheduler_pad_unlink:
168  * @sched: the scheduler
169  * @srcpad: the srcpad to unlink
170  * @sinkpad: the sinkpad to unlink from
171  *
172  * Unlinks the srcpad from the given sinkpad.
173  */
174 void
175 gst_scheduler_pad_unlink (GstScheduler *sched, GstPad *srcpad, 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   GstSchedulerClass *sclass;
202
203   g_return_val_if_fail (GST_IS_SCHEDULER (sched), NULL);
204   g_return_val_if_fail (padlist != NULL, NULL);
205
206   sclass = GST_SCHEDULER_GET_CLASS (sched);
207
208   if (sclass->pad_select)
209     sclass->pad_select (sched, padlist);
210
211   return NULL;
212 }
213
214 /**
215  * gst_scheduler_add_element:
216  * @sched: the scheduler
217  * @element: the element to add to the scheduler
218  *
219  * Add an element to the scheduler.
220  */
221 void
222 gst_scheduler_add_element (GstScheduler *sched, GstElement *element)
223 {
224   GstSchedulerClass *sclass;
225
226   g_return_if_fail (GST_IS_SCHEDULER (sched));
227   g_return_if_fail (GST_IS_ELEMENT (element));
228
229   /* if it's already in this scheduler, don't bother doing anything */
230   if (GST_ELEMENT_SCHED (element) == sched) {
231     GST_CAT_DEBUG (GST_CAT_SCHEDULING, "element %s already in scheduler %p", 
232                     GST_ELEMENT_NAME (element), sched);
233     return;
234   }
235
236   /* if it's not inside this scheduler, it has to be NULL */
237   g_assert (GST_ELEMENT_SCHED (element) == NULL);
238
239   if (gst_element_provides_clock (element)) {
240     sched->clock_providers = g_list_prepend (sched->clock_providers, element);
241     GST_CAT_DEBUG (GST_CAT_CLOCK, "added clock provider %s", GST_ELEMENT_NAME (element));
242   }
243   if (gst_element_requires_clock (element)) {
244     sched->clock_receivers = g_list_prepend (sched->clock_receivers, element);
245     GST_CAT_DEBUG (GST_CAT_CLOCK, "added clock receiver %s", GST_ELEMENT_NAME (element));
246   }
247
248   gst_element_set_scheduler (element, sched);
249
250   sclass = GST_SCHEDULER_GET_CLASS (sched);
251
252   if (sclass->add_element)
253     sclass->add_element (sched, element);
254 }
255
256 /**
257  * gst_scheduler_remove_element:
258  * @sched: the scheduler
259  * @element: the element to remove
260  *
261  * Remove an element from the scheduler.
262  */
263 void
264 gst_scheduler_remove_element (GstScheduler *sched, GstElement *element)
265 {
266   GstSchedulerClass *sclass;
267
268   g_return_if_fail (GST_IS_SCHEDULER (sched));
269   g_return_if_fail (GST_IS_ELEMENT (element));
270
271   sched->clock_providers = g_list_remove (sched->clock_providers, element);
272   sched->clock_receivers = g_list_remove (sched->clock_receivers, element);
273
274   sclass = GST_SCHEDULER_GET_CLASS (sched);
275
276   if (sclass->remove_element)
277     sclass->remove_element (sched, element);
278
279   gst_element_set_scheduler (element, NULL); 
280 }
281
282 /**
283  * gst_scheduler_state_transition:
284  * @sched: the scheduler
285  * @element: the element with the state transition
286  * @transition: the state transition
287  *
288  * Tell the scheduler that an element changed its state.
289  *
290  * Returns: a GstElementStateReturn indicating success or failure
291  * of the state transition.
292  */
293 GstElementStateReturn
294 gst_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition)
295 {
296   GstSchedulerClass *sclass;
297
298   g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_STATE_FAILURE);
299   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
300
301   if (element == sched->parent && sched->parent_sched == NULL) {
302     switch (transition) {
303       case GST_STATE_READY_TO_PAUSED:
304       {
305         GstClock *clock = gst_scheduler_get_clock (sched);
306         GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler READY to PAUSED clock is %p (%s)", clock, 
307                         (clock ? GST_OBJECT_NAME (clock) : "nil"));
308
309         gst_scheduler_set_clock (sched, clock);
310         break;
311       }
312     }
313   }
314
315   sclass = GST_SCHEDULER_GET_CLASS (sched);
316
317   if (sclass->state_transition)
318     return sclass->state_transition (sched, element, transition);
319
320   return GST_STATE_SUCCESS;
321 }
322
323 /**
324  * gst_scheduler_scheduling_change:
325  * @sched: the scheduler
326  * @element: the element that changed its scheduling strategy
327  *
328  * Tell the scheduler that an element changed its scheduling strategy.
329  * An element could, for example, change its loop function or changes
330  * from a loop based element to a chain based element.
331  */
332 void
333 gst_scheduler_scheduling_change (GstScheduler *sched, GstElement *element)
334 {
335   GstSchedulerClass *sclass;
336
337   g_return_if_fail (GST_IS_SCHEDULER (sched));
338   g_return_if_fail (GST_IS_ELEMENT (element));
339
340   sclass = GST_SCHEDULER_GET_CLASS (sched);
341
342   if (sclass->scheduling_change)
343     sclass->scheduling_change (sched, element);
344 }
345
346 /**
347  * gst_scheduler_add_scheduler:
348  * @sched: a  #GstScheduler to add to
349  * @sched2: the #GstScheduler to add
350  *
351  * Notifies the scheduler that it has to monitor this scheduler.
352  */
353 void
354 gst_scheduler_add_scheduler (GstScheduler *sched, GstScheduler *sched2)
355 {
356   GstSchedulerClass *sclass;
357
358   g_return_if_fail (GST_IS_SCHEDULER (sched));
359   g_return_if_fail (GST_IS_SCHEDULER (sched2));
360   g_return_if_fail (sched2->parent_sched == NULL);
361
362   GST_DEBUG ("gstscheduler: %p add scheduler %p", sched, sched2);
363
364   gst_object_ref (GST_OBJECT (sched2));
365   gst_object_ref (GST_OBJECT (sched));
366
367   sched->schedulers = g_list_prepend (sched->schedulers, sched2);
368   sched2->parent_sched = sched;
369
370   sclass = GST_SCHEDULER_GET_CLASS (sched);
371
372   if (sclass->add_scheduler)
373     sclass->add_scheduler (sched, sched2);
374 }
375
376 /**
377  * gst_scheduler_remove_scheduler:
378  * @sched: the scheduler
379  * @sched2: the scheduler to remove
380  *
381  a Notifies the scheduler that it can stop monitoring this scheduler.
382  */
383 void
384 gst_scheduler_remove_scheduler (GstScheduler *sched, GstScheduler *sched2)
385 {
386   GstSchedulerClass *sclass;
387
388   g_return_if_fail (GST_IS_SCHEDULER (sched));
389   g_return_if_fail (GST_IS_SCHEDULER (sched2));
390   g_return_if_fail (sched2->parent_sched == sched);
391
392   GST_DEBUG ("gstscheduler: %p remove scheduler %p", sched, sched2);
393
394   sclass = GST_SCHEDULER_GET_CLASS (sched);
395
396   if (sclass->remove_scheduler)
397     sclass->remove_scheduler (sched, sched2);
398
399   sched->schedulers = g_list_remove (sched->schedulers, sched2);
400   sched2->parent_sched = NULL;
401
402   gst_object_unref (GST_OBJECT (sched2));
403   gst_object_unref (GST_OBJECT (sched));
404 }
405
406 /**
407  * gst_scheduler_lock_element:
408  * @sched: the scheduler
409  * @element: the element to lock
410  *
411  * Acquire a lock on the given element in the given scheduler.
412  */
413 void
414 gst_scheduler_lock_element (GstScheduler *sched, GstElement *element)
415 {
416   GstSchedulerClass *sclass;
417
418   g_return_if_fail (GST_IS_SCHEDULER (sched));
419   g_return_if_fail (GST_IS_ELEMENT (element));
420
421   sclass = GST_SCHEDULER_GET_CLASS (sched);
422
423   if (sclass->lock_element)
424     sclass->lock_element (sched, element);
425 }
426
427 /**
428  * gst_scheduler_unlock_element:
429  * @sched: the scheduler
430  * @element: the element to unlock
431  *
432  * Release the lock on the given element in the given scheduler.
433  */
434 void
435 gst_scheduler_unlock_element (GstScheduler *sched, GstElement *element)
436 {
437   GstSchedulerClass *sclass;
438
439   g_return_if_fail (GST_IS_SCHEDULER (sched));
440   g_return_if_fail (GST_IS_ELEMENT (element));
441
442   sclass = GST_SCHEDULER_GET_CLASS (sched);
443
444   if (sclass->unlock_element)
445     sclass->unlock_element (sched, element);
446 }
447
448 /**
449  * gst_scheduler_error:
450  * @sched: the scheduler
451  * @element: the element with the error
452  *
453  * Tell the scheduler an element was in error
454  */
455 void
456 gst_scheduler_error (GstScheduler *sched, GstElement *element)
457 {
458   GstSchedulerClass *sclass;
459
460   g_return_if_fail (GST_IS_SCHEDULER (sched));
461   g_return_if_fail (GST_IS_ELEMENT (element));
462
463   sclass = GST_SCHEDULER_GET_CLASS (sched);
464
465   if (sclass->error)
466     sclass->error (sched, element);
467 }
468
469 /**
470  * gst_scheduler_yield:
471  * @sched: the scheduler
472  * @element: the element requesting a yield
473  *
474  * Tell the scheduler to schedule another element.
475  *
476  * Returns: TRUE if the element should save its state, FALSE
477  * if the scheduler can perform this action itself.
478  */
479 gboolean
480 gst_scheduler_yield (GstScheduler *sched, GstElement *element)
481 {
482   GstSchedulerClass *sclass;
483
484   g_return_val_if_fail (GST_IS_SCHEDULER (sched), TRUE);
485   g_return_val_if_fail (GST_IS_ELEMENT (element), TRUE);
486
487   sclass = GST_SCHEDULER_GET_CLASS (sched);
488
489   if (sclass->yield)
490     return sclass->yield (sched, element);
491
492   return TRUE;
493 }
494
495 /**
496  * gst_scheduler_interrupt:
497  * @sched: the scheduler
498  * @element: the element requesting an interrupt
499  *
500  * Tell the scheduler to interrupt execution of this element.
501  *
502  * Returns: TRUE if the element should return NULL from the chain/get
503  * function.
504  */
505 gboolean
506 gst_scheduler_interrupt (GstScheduler *sched, GstElement *element)
507 {
508   GstSchedulerClass *sclass;
509
510   g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
511   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
512
513   sclass = GST_SCHEDULER_GET_CLASS (sched);
514
515   if (sclass->interrupt)
516     return sclass->interrupt (sched, element);
517
518   return FALSE;
519 }
520
521 /**
522  * gst_scheduler_get_clock:
523  * @sched: the scheduler
524  *
525  * Get the current clock used by the scheduler
526  *
527  * Returns: a GstClock
528  */
529 GstClock*
530 gst_scheduler_get_clock (GstScheduler *sched)
531 {
532   GstClock *clock = NULL;
533   
534   /* if we have a fixed clock, use that one */
535   if (GST_FLAG_IS_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK)) {
536     clock = sched->clock;  
537
538     GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)", clock, 
539                         (clock ? GST_OBJECT_NAME (clock) : "nil"));
540   }
541   else {
542     GList *schedulers = sched->schedulers;
543     GList *providers = sched->clock_providers;
544
545     /* try to get a clock from one of the schedulers we manage first */
546     while (schedulers) {
547       GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
548       
549       clock = gst_scheduler_get_clock (scheduler);
550       if (clock)
551         break;
552
553       schedulers = g_list_next (schedulers);
554     }
555     /* still no clock, try to find one in the providers */
556     while (!clock && providers) {
557       clock = gst_element_get_clock (GST_ELEMENT (providers->data));
558
559       providers = g_list_next (providers);
560     }
561     /* still no clock, use a system clock */
562     if (!clock && sched->parent_sched == NULL) {
563       clock = gst_system_clock_obtain ();
564     }
565   }
566   GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, sched, "scheduler selected clock %p (%s)", clock, 
567                       clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
568
569   return clock;
570 }
571
572 /**
573  * gst_scheduler_use_clock:
574  * @sched: the scheduler
575  * @clock: the clock to use
576  *
577  * Force the scheduler to use the given clock. The scheduler will
578  * always use the given clock even if new clock providers are added
579  * to this scheduler.
580  */
581 void
582 gst_scheduler_use_clock (GstScheduler *sched, GstClock *clock)
583 {
584   g_return_if_fail (sched != NULL);
585   g_return_if_fail (GST_IS_SCHEDULER (sched));
586
587   GST_FLAG_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
588
589   gst_object_replace ((GstObject **)&sched->clock, (GstObject *)clock);
590
591   GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)", clock, 
592                 (clock ? GST_OBJECT_NAME (clock) : "nil"));
593 }
594
595 /**
596  * gst_scheduler_set_clock:
597  * @sched: the scheduler
598  * @clock: the clock to set
599  *
600  * Set the clock for the scheduler. The clock will be distributed 
601  * to all the elements managed by the scheduler. 
602  */
603 void
604 gst_scheduler_set_clock (GstScheduler *sched, GstClock *clock)
605 {
606   GList *receivers;
607   GList *schedulers;
608
609   g_return_if_fail (sched != NULL);
610   g_return_if_fail (GST_IS_SCHEDULER (sched));
611
612   receivers = sched->clock_receivers;
613   schedulers = sched->schedulers;
614
615   gst_object_replace ((GstObject **)&sched->current_clock, (GstObject *)clock);
616
617   while (receivers) {
618     GstElement *element = GST_ELEMENT (receivers->data);
619
620     GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler setting clock %p (%s) on element %s", clock, 
621                 (clock ? GST_OBJECT_NAME (clock) : "nil"), GST_ELEMENT_NAME (element));
622     
623     gst_element_set_clock (element, clock);
624     receivers = g_list_next (receivers);
625   }
626   while (schedulers) {
627     GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
628
629     GST_CAT_DEBUG (GST_CAT_CLOCK, "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, 
656                                                          GstClockTimeDiff *jitter);
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 /* static guint gst_scheduler_factory_signals[LAST_SIGNAL] = { 0 }; */
740
741 GType 
742 gst_scheduler_factory_get_type (void) 
743 {
744   static GType schedulerfactory_type = 0;
745
746   if (!schedulerfactory_type) {
747     static const GTypeInfo schedulerfactory_info = {
748       sizeof (GstSchedulerFactoryClass),
749       NULL,
750       NULL,
751       (GClassInitFunc) gst_scheduler_factory_class_init,
752       NULL,
753       NULL,
754       sizeof(GstSchedulerFactory),
755       0,
756       (GInstanceInitFunc) gst_scheduler_factory_init,
757       NULL
758     };
759     schedulerfactory_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE, 
760                                                   "GstSchedulerFactory", &schedulerfactory_info, 0);
761   }
762   return schedulerfactory_type;
763 }
764
765 static void
766 gst_scheduler_factory_class_init (GstSchedulerFactoryClass *klass)
767 {
768   GObjectClass *gobject_class;
769   GstObjectClass *gstobject_class;
770   GstPluginFeatureClass *gstpluginfeature_class;
771
772   gobject_class = (GObjectClass*)klass;
773   gstobject_class = (GstObjectClass*)klass;
774   gstpluginfeature_class = (GstPluginFeatureClass*) klass;
775
776   factory_parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE);
777
778   if (!_default_name) {
779     if (g_getenv ("GST_SCHEDULER")) {
780       _default_name = g_strdup (g_getenv ("GST_SCHEDULER"));
781     } else {
782       _default_name = g_strdup (GST_SCHEDULER_DEFAULT_NAME);
783     }
784   }
785   g_assert (_default_name);
786 }
787
788 static void
789 gst_scheduler_factory_init (GstSchedulerFactory *factory)
790 {
791 }
792         
793
794 /**
795  * gst_scheduler_factory_new:
796  * @name: name of schedulerfactory to create
797  * @longdesc: long description of schedulerfactory to create
798  * @type: the gtk type of the GstScheduler element of this factory
799  *
800  * Create a new schedulerfactory with the given parameters
801  *
802  * Returns: a new #GstSchedulerFactory.
803  */
804 GstSchedulerFactory*
805 gst_scheduler_factory_new (const gchar *name, const gchar *longdesc, GType type)
806 {
807   GstSchedulerFactory *factory;
808
809   g_return_val_if_fail (name != NULL, NULL);
810
811   factory = gst_scheduler_factory_find (name);
812
813   if (!factory) {
814     factory = GST_SCHEDULER_FACTORY (g_object_new (GST_TYPE_SCHEDULER_FACTORY, NULL));
815     GST_PLUGIN_FEATURE_NAME (factory) = g_strdup (name);
816   }
817   else {
818     g_free (factory->longdesc);
819   }
820
821   factory->longdesc = g_strdup (longdesc);
822   factory->type = type;
823
824   return factory;
825 }
826
827 /**
828  * gst_scheduler_factory_destroy:
829  * @factory: factory to destroy
830  *
831  * Removes the scheduler from the global list.
832  */
833 void
834 gst_scheduler_factory_destroy (GstSchedulerFactory *factory)
835 {
836   g_return_if_fail (factory != NULL);
837
838   /* we don't free the struct bacause someone might  have a handle to it.. */
839 }
840
841 /**
842  * gst_scheduler_factory_find:
843  * @name: name of schedulerfactory to find
844  *
845  * Search for an schedulerfactory of the given name.
846  *
847  * Returns: #GstSchedulerFactory if found, NULL otherwise
848  */
849 GstSchedulerFactory*
850 gst_scheduler_factory_find (const gchar *name)
851 {
852   GstPluginFeature *feature;
853
854   g_return_val_if_fail (name != NULL, NULL);
855
856   GST_DEBUG ("gstscheduler: find \"%s\"", name);
857
858   feature = gst_registry_pool_find_feature (name, GST_TYPE_SCHEDULER_FACTORY);
859
860   if (feature)
861     return GST_SCHEDULER_FACTORY (feature);
862
863   return NULL;
864 }
865
866 /**
867  * gst_scheduler_factory_create:
868  * @factory: the factory used to create the instance
869  * @parent: the parent element of this scheduler
870  *
871  * Create a new #GstScheduler instance from the 
872  * given schedulerfactory with the given parent. @parent will
873  * have its scheduler set to the returned #GstScheduler instance.
874  *
875  * Returns: A new #GstScheduler instance with a reference count of %1.
876  */
877 GstScheduler*
878 gst_scheduler_factory_create (GstSchedulerFactory *factory, GstElement *parent)
879 {
880   GstScheduler *sched = NULL;
881
882   g_return_val_if_fail (factory != NULL, NULL);
883   g_return_val_if_fail (GST_IS_ELEMENT (parent), NULL);
884
885   if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
886     g_return_val_if_fail (factory->type != 0, NULL);
887
888     sched = GST_SCHEDULER (g_object_new (factory->type, NULL));
889     sched->parent = parent;
890
891     GST_ELEMENT_SCHED (parent) = sched;
892
893     /* let's refcount the scheduler */
894     gst_object_ref (GST_OBJECT (sched));
895     gst_object_sink (GST_OBJECT (sched));
896   }
897
898   return sched;
899 }
900
901 /**
902  * gst_scheduler_factory_make:
903  * @name: the name of the factory used to create the instance
904  * @parent: the parent element of this scheduler
905  *
906  * Create a new #GstScheduler instance from the 
907  * schedulerfactory with the given name and parent. @parent will
908  * have its scheduler set to the returned #GstScheduler instance.
909  * If %NULL is passed as @name, the default scheduler name will
910  * be used.
911  *
912  * Returns: A new #GstScheduler instance with a reference count of %1.
913  */
914 GstScheduler*
915 gst_scheduler_factory_make (const gchar *name, GstElement *parent)
916 {
917   GstSchedulerFactory *factory;
918   const gchar *default_name = gst_scheduler_factory_get_default_name ();
919
920   if (name)
921     factory = gst_scheduler_factory_find (name);
922   else
923   {
924     /* FIXME: do better error handling */
925     if (default_name == NULL)
926       g_error ("No default scheduler name - do you have a registry ?");
927     factory = gst_scheduler_factory_find (default_name);
928   }
929
930   if (factory == NULL)
931     return NULL;
932
933   return gst_scheduler_factory_create (factory, parent);
934 }
935
936 /**
937  * gst_scheduler_factory_set_default_name:
938  * @name: the name of the factory used as a default
939  *
940  * Set the default schedulerfactory name.
941  */
942 void
943 gst_scheduler_factory_set_default_name (const gchar* name)
944 {
945   g_free (_default_name);
946
947   _default_name = g_strdup (name);
948 }
949
950 /**
951  * gst_scheduler_factory_get_default_name:
952  *
953  * Get the default schedulerfactory name.
954  *
955  * Returns: the name of the default scheduler.
956  */
957 const gchar*
958 gst_scheduler_factory_get_default_name (void)
959 {
960   return _default_name;
961 }