77590c8d3b1953ea97157d2fb1a01c85d1a5765b
[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 "gstlog.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 (0, "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_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_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_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
307         if (clock)
308           gst_clock_reset (clock);
309
310         GST_DEBUG (GST_CAT_CLOCK, "scheduler READY to PAUSED clock is %p (%s)", clock, 
311                         (clock ? GST_OBJECT_NAME (clock) : "nil"));
312
313         gst_object_replace ((GstObject **)&sched->current_clock, (GstObject *)clock);
314         break;
315       }
316       case GST_STATE_PAUSED_TO_PLAYING:
317       {
318         GstClock *clock = gst_scheduler_get_clock (sched);
319
320         GST_DEBUG (GST_CAT_CLOCK, "scheduler PAUSED to PLAYING clock is %p (%s)", clock, 
321                         (clock ? GST_OBJECT_NAME (clock) : "nil"));
322
323         gst_scheduler_set_clock (sched, clock);
324         if (clock) {
325           GST_DEBUG (GST_CAT_CLOCK, "enabling clock %p (%s)", clock, 
326                         GST_OBJECT_NAME (clock));
327           gst_clock_set_active (clock, TRUE);
328         }
329         break;
330       }
331       case GST_STATE_PLAYING_TO_PAUSED:
332         if (sched->current_clock) {
333           GST_DEBUG (GST_CAT_CLOCK, "disabling clock %p (%s)", sched->current_clock, 
334                         GST_OBJECT_NAME (sched->current_clock));
335           gst_clock_set_active (sched->current_clock, FALSE);
336         }
337         break;
338     }
339   }
340
341   sclass = GST_SCHEDULER_GET_CLASS (sched);
342
343   if (sclass->state_transition)
344     return sclass->state_transition (sched, element, transition);
345
346   return GST_STATE_SUCCESS;
347 }
348
349 /**
350  * gst_scheduler_scheduling_change:
351  * @sched: the scheduler
352  * @element: the element that changed its scheduling strategy
353  *
354  * Tell the scheduler that an element changed its scheduling strategy.
355  * An element could, for example, change its loop function or changes
356  * from a loop based element to a chain based element.
357  */
358 void
359 gst_scheduler_scheduling_change (GstScheduler *sched, GstElement *element)
360 {
361   GstSchedulerClass *sclass;
362
363   g_return_if_fail (GST_IS_SCHEDULER (sched));
364   g_return_if_fail (GST_IS_ELEMENT (element));
365
366   sclass = GST_SCHEDULER_GET_CLASS (sched);
367
368   if (sclass->scheduling_change)
369     sclass->scheduling_change (sched, element);
370 }
371
372 /**
373  * gst_scheduler_add_scheduler:
374  * @sched: a  #GstScheduler to add to
375  * @sched2: the #GstScheduler to add
376  *
377  * Notifies the scheduler that it has to monitor this scheduler.
378  */
379 void
380 gst_scheduler_add_scheduler (GstScheduler *sched, GstScheduler *sched2)
381 {
382   GstSchedulerClass *sclass;
383
384   g_return_if_fail (GST_IS_SCHEDULER (sched));
385   g_return_if_fail (GST_IS_SCHEDULER (sched2));
386   g_return_if_fail (sched2->parent_sched == NULL);
387
388   GST_DEBUG (0,"gstscheduler: %p add scheduler %p", sched, sched2);
389
390   gst_object_ref (GST_OBJECT (sched2));
391   gst_object_ref (GST_OBJECT (sched));
392
393   sched->schedulers = g_list_prepend (sched->schedulers, sched2);
394   sched2->parent_sched = sched;
395
396   sclass = GST_SCHEDULER_GET_CLASS (sched);
397
398   if (sclass->add_scheduler)
399     sclass->add_scheduler (sched, sched2);
400 }
401
402 /**
403  * gst_scheduler_remove_scheduler:
404  * @sched: the scheduler
405  * @sched2: the scheduler to remove
406  *
407  a Notifies the scheduler that it can stop monitoring this scheduler.
408  */
409 void
410 gst_scheduler_remove_scheduler (GstScheduler *sched, GstScheduler *sched2)
411 {
412   GstSchedulerClass *sclass;
413
414   g_return_if_fail (GST_IS_SCHEDULER (sched));
415   g_return_if_fail (GST_IS_SCHEDULER (sched2));
416   g_return_if_fail (sched2->parent_sched == sched);
417
418   GST_DEBUG (0,"gstscheduler: %p remove scheduler %p", sched, sched2);
419
420   sclass = GST_SCHEDULER_GET_CLASS (sched);
421
422   if (sclass->remove_scheduler)
423     sclass->remove_scheduler (sched, sched2);
424
425   sched->schedulers = g_list_remove (sched->schedulers, sched2);
426   sched2->parent_sched = NULL;
427
428   gst_object_unref (GST_OBJECT (sched2));
429   gst_object_unref (GST_OBJECT (sched));
430 }
431
432 /**
433  * gst_scheduler_lock_element:
434  * @sched: the scheduler
435  * @element: the element to lock
436  *
437  * Acquire a lock on the given element in the given scheduler.
438  */
439 void
440 gst_scheduler_lock_element (GstScheduler *sched, GstElement *element)
441 {
442   GstSchedulerClass *sclass;
443
444   g_return_if_fail (GST_IS_SCHEDULER (sched));
445   g_return_if_fail (GST_IS_ELEMENT (element));
446
447   sclass = GST_SCHEDULER_GET_CLASS (sched);
448
449   if (sclass->lock_element)
450     sclass->lock_element (sched, element);
451 }
452
453 /**
454  * gst_scheduler_unlock_element:
455  * @sched: the scheduler
456  * @element: the element to unlock
457  *
458  * Release the lock on the given element in the given scheduler.
459  */
460 void
461 gst_scheduler_unlock_element (GstScheduler *sched, GstElement *element)
462 {
463   GstSchedulerClass *sclass;
464
465   g_return_if_fail (GST_IS_SCHEDULER (sched));
466   g_return_if_fail (GST_IS_ELEMENT (element));
467
468   sclass = GST_SCHEDULER_GET_CLASS (sched);
469
470   if (sclass->unlock_element)
471     sclass->unlock_element (sched, element);
472 }
473
474 /**
475  * gst_scheduler_error:
476  * @sched: the scheduler
477  * @element: the element with the error
478  *
479  * Tell the scheduler an element was in error
480  */
481 void
482 gst_scheduler_error (GstScheduler *sched, GstElement *element)
483 {
484   GstSchedulerClass *sclass;
485
486   g_return_if_fail (GST_IS_SCHEDULER (sched));
487   g_return_if_fail (GST_IS_ELEMENT (element));
488
489   sclass = GST_SCHEDULER_GET_CLASS (sched);
490
491   if (sclass->error)
492     sclass->error (sched, element);
493 }
494
495 /**
496  * gst_scheduler_yield:
497  * @sched: the scheduler
498  * @element: the element requesting a yield
499  *
500  * Tell the scheduler to schedule another element.
501  *
502  * Returns: TRUE if the element should save its state, FALSE
503  * if the scheduler can perform this action itself.
504  */
505 gboolean
506 gst_scheduler_yield (GstScheduler *sched, GstElement *element)
507 {
508   GstSchedulerClass *sclass;
509
510   g_return_val_if_fail (GST_IS_SCHEDULER (sched), TRUE);
511   g_return_val_if_fail (GST_IS_ELEMENT (element), TRUE);
512
513   sclass = GST_SCHEDULER_GET_CLASS (sched);
514
515   if (sclass->yield)
516     return sclass->yield (sched, element);
517
518   return TRUE;
519 }
520
521 /**
522  * gst_scheduler_interrupt:
523  * @sched: the scheduler
524  * @element: the element requesting an interrupt
525  *
526  * Tell the scheduler to interrupt execution of this element.
527  *
528  * Returns: TRUE if the element should return NULL from the chain/get
529  * function.
530  */
531 gboolean
532 gst_scheduler_interrupt (GstScheduler *sched, GstElement *element)
533 {
534   GstSchedulerClass *sclass;
535
536   g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
537   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
538
539   sclass = GST_SCHEDULER_GET_CLASS (sched);
540
541   if (sclass->interrupt)
542     return sclass->interrupt (sched, element);
543
544   return FALSE;
545 }
546
547 /**
548  * gst_scheduler_get_clock:
549  * @sched: the scheduler
550  *
551  * Get the current clock used by the scheduler
552  *
553  * Returns: a GstClock
554  */
555 GstClock*
556 gst_scheduler_get_clock (GstScheduler *sched)
557 {
558   GstClock *clock = NULL;
559   
560   /* if we have a fixed clock, use that one */
561   if (GST_FLAG_IS_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK)) {
562     clock = sched->clock;  
563
564     GST_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)", clock, 
565                         (clock ? GST_OBJECT_NAME (clock) : "nil"));
566   }
567   else {
568     GList *schedulers = sched->schedulers;
569     GList *providers = sched->clock_providers;
570
571     /* try to get a clock from one of the schedulers we manage first */
572     while (schedulers) {
573       GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
574       
575       clock = gst_scheduler_get_clock (scheduler);
576       if (clock)
577         break;
578
579       schedulers = g_list_next (schedulers);
580     }
581     /* still no clock, try to find one in the providers */
582     while (!clock && providers) {
583       clock = gst_element_get_clock (GST_ELEMENT (providers->data));
584
585       providers = g_list_next (providers);
586     }
587     /* still no clock, use a system clock */
588     if (!clock && sched->parent_sched == NULL) {
589       clock = gst_system_clock_obtain ();
590     }
591   }
592   GST_DEBUG (GST_CAT_CLOCK, "scheduler selected clock %p (%s)", clock, 
593                 (clock ? GST_OBJECT_NAME (clock) : "nil"));
594
595   return clock;
596 }
597
598 /**
599  * gst_scheduler_use_clock:
600  * @sched: the scheduler
601  * @clock: the clock to use
602  *
603  * Force the scheduler to use the given clock. The scheduler will
604  * always use the given clock even if new clock providers are added
605  * to this scheduler.
606  */
607 void
608 gst_scheduler_use_clock (GstScheduler *sched, GstClock *clock)
609 {
610   g_return_if_fail (sched != NULL);
611   g_return_if_fail (GST_IS_SCHEDULER (sched));
612
613   GST_FLAG_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
614
615   gst_object_replace ((GstObject **)&sched->clock, (GstObject *)clock);
616
617   GST_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)", clock, 
618                 (clock ? GST_OBJECT_NAME (clock) : "nil"));
619 }
620
621 /**
622  * gst_scheduler_set_clock:
623  * @sched: the scheduler
624  * @clock: the clock to set
625  *
626  * Set the clock for the scheduler. The clock will be distributed 
627  * to all the elements managed by the scheduler. 
628  */
629 void
630 gst_scheduler_set_clock (GstScheduler *sched, GstClock *clock)
631 {
632   GList *receivers;
633   GList *schedulers;
634
635   g_return_if_fail (sched != NULL);
636   g_return_if_fail (GST_IS_SCHEDULER (sched));
637
638   receivers = sched->clock_receivers;
639   schedulers = sched->schedulers;
640
641   gst_object_replace ((GstObject **)&sched->current_clock, (GstObject *)clock);
642
643   while (receivers) {
644     GstElement *element = GST_ELEMENT (receivers->data);
645
646     GST_DEBUG (GST_CAT_CLOCK, "scheduler setting clock %p (%s) on element %s", clock, 
647                 (clock ? GST_OBJECT_NAME (clock) : "nil"), GST_ELEMENT_NAME (element));
648     
649     gst_element_set_clock (element, clock);
650     receivers = g_list_next (receivers);
651   }
652   while (schedulers) {
653     GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
654
655     GST_DEBUG (GST_CAT_CLOCK, "scheduler setting clock %p (%s) on scheduler %p", clock, 
656                 (clock ? GST_OBJECT_NAME (clock) : "nil"), scheduler);
657     gst_scheduler_set_clock (scheduler, clock);
658     schedulers = g_list_next (schedulers);
659   }
660 }
661
662 /**
663  * gst_scheduler_auto_clock:
664  * @sched: the scheduler
665  *
666  * Let the scheduler select a clock automatically.
667  */
668 void
669 gst_scheduler_auto_clock (GstScheduler *sched)
670 {
671   g_return_if_fail (sched != NULL);
672   g_return_if_fail (GST_IS_SCHEDULER (sched));
673
674   GST_FLAG_UNSET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
675
676   gst_object_replace ((GstObject **)&sched->clock, NULL);
677
678   GST_DEBUG (GST_CAT_CLOCK, "scheduler using automatic clock");
679 }
680
681 /**
682  * gst_scheduler_clock_wait:
683  * @sched: the scheduler
684  * @element: the element that wants to wait
685  * @id: the clockid to use
686  * @jitter: the time difference between requested time and actual time
687  *
688  * Wait till the clock reaches a specific time. The ClockID can
689  * be obtained from #gst_clock_new_single_shot_id. 
690  *
691  * Returns: the status of the operation
692  */
693 GstClockReturn
694 gst_scheduler_clock_wait (GstScheduler *sched, GstElement *element, 
695                           GstClockID id, GstClockTimeDiff *jitter)
696 {
697   GstSchedulerClass *sclass;
698
699   g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_CLOCK_ERROR);
700   g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
701
702   sclass = GST_SCHEDULER_GET_CLASS (sched);
703
704   if (sclass->clock_wait)
705     return sclass->clock_wait (sched, element, id, jitter);
706   else 
707     return gst_clock_id_wait (id, jitter);
708 }
709
710 /**
711  * gst_scheduler_iterate:
712  * @sched: the scheduler
713  *
714  * Perform one iteration on the scheduler.
715  *
716  * Returns: a boolean indicating something usefull has happened.
717  */
718 gboolean
719 gst_scheduler_iterate (GstScheduler *sched)
720 {
721   GstSchedulerClass *sclass;
722   gboolean res = FALSE;
723
724   g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
725
726   sclass = GST_SCHEDULER_GET_CLASS (sched);
727
728   if (sclass->iterate) {
729     res = sclass->iterate (sched);
730   }
731
732   return res;
733 }
734
735
736 /**
737  * gst_scheduler_show:
738  * @sched: the scheduler
739  *
740  * Dump the state of the scheduler
741  */
742 void
743 gst_scheduler_show (GstScheduler *sched)
744 {
745   GstSchedulerClass *sclass;
746
747   g_return_if_fail (GST_IS_SCHEDULER (sched));
748
749   sclass = GST_SCHEDULER_GET_CLASS (sched);
750
751   if (sclass->show)
752     sclass->show (sched);
753 }
754
755 /*
756  * Factory stuff starts here
757  *
758  */
759 static void             gst_scheduler_factory_class_init                (GstSchedulerFactoryClass *klass);
760 static void             gst_scheduler_factory_init              (GstSchedulerFactory *factory);
761
762 static GstPluginFeatureClass *factory_parent_class = NULL;
763 /* static guint gst_scheduler_factory_signals[LAST_SIGNAL] = { 0 }; */
764
765 GType 
766 gst_scheduler_factory_get_type (void) 
767 {
768   static GType schedulerfactory_type = 0;
769
770   if (!schedulerfactory_type) {
771     static const GTypeInfo schedulerfactory_info = {
772       sizeof (GstSchedulerFactoryClass),
773       NULL,
774       NULL,
775       (GClassInitFunc) gst_scheduler_factory_class_init,
776       NULL,
777       NULL,
778       sizeof(GstSchedulerFactory),
779       0,
780       (GInstanceInitFunc) gst_scheduler_factory_init,
781       NULL
782     };
783     schedulerfactory_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE, 
784                                                   "GstSchedulerFactory", &schedulerfactory_info, 0);
785   }
786   return schedulerfactory_type;
787 }
788
789 static void
790 gst_scheduler_factory_class_init (GstSchedulerFactoryClass *klass)
791 {
792   GObjectClass *gobject_class;
793   GstObjectClass *gstobject_class;
794   GstPluginFeatureClass *gstpluginfeature_class;
795
796   gobject_class = (GObjectClass*)klass;
797   gstobject_class = (GstObjectClass*)klass;
798   gstpluginfeature_class = (GstPluginFeatureClass*) klass;
799
800   factory_parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE);
801
802   if (!_default_name)
803     _default_name = g_strdup (GST_SCHEDULER_DEFAULT_NAME);
804 }
805
806 static void
807 gst_scheduler_factory_init (GstSchedulerFactory *factory)
808 {
809 }
810         
811
812 /**
813  * gst_scheduler_factory_new:
814  * @name: name of schedulerfactory to create
815  * @longdesc: long description of schedulerfactory to create
816  * @type: the gtk type of the GstScheduler element of this factory
817  *
818  * Create a new schedulerfactory with the given parameters
819  *
820  * Returns: a new #GstSchedulerFactory.
821  */
822 GstSchedulerFactory*
823 gst_scheduler_factory_new (const gchar *name, const gchar *longdesc, GType type)
824 {
825   GstSchedulerFactory *factory;
826
827   g_return_val_if_fail (name != NULL, NULL);
828
829   factory = gst_scheduler_factory_find (name);
830
831   if (!factory) {
832     factory = GST_SCHEDULER_FACTORY (g_object_new (GST_TYPE_SCHEDULER_FACTORY, NULL));
833     GST_PLUGIN_FEATURE_NAME (factory) = g_strdup (name);
834   }
835   else {
836     g_free (factory->longdesc);
837   }
838
839   factory->longdesc = g_strdup (longdesc);
840   factory->type = type;
841
842   return factory;
843 }
844
845 /**
846  * gst_scheduler_factory_destroy:
847  * @factory: factory to destroy
848  *
849  * Removes the scheduler from the global list.
850  */
851 void
852 gst_scheduler_factory_destroy (GstSchedulerFactory *factory)
853 {
854   g_return_if_fail (factory != NULL);
855
856   /* we don't free the struct bacause someone might  have a handle to it.. */
857 }
858
859 /**
860  * gst_scheduler_factory_find:
861  * @name: name of schedulerfactory to find
862  *
863  * Search for an schedulerfactory of the given name.
864  *
865  * Returns: #GstSchedulerFactory if found, NULL otherwise
866  */
867 GstSchedulerFactory*
868 gst_scheduler_factory_find (const gchar *name)
869 {
870   GstPluginFeature *feature;
871
872   g_return_val_if_fail (name != NULL, NULL);
873
874   GST_DEBUG (0,"gstscheduler: find \"%s\"", name);
875
876   feature = gst_registry_pool_find_feature (name, GST_TYPE_SCHEDULER_FACTORY);
877
878   if (feature)
879     return GST_SCHEDULER_FACTORY (feature);
880
881   return NULL;
882 }
883
884 /**
885  * gst_scheduler_factory_create:
886  * @factory: the factory used to create the instance
887  * @parent: the parent element of this scheduler
888  *
889  * Create a new #GstScheduler instance from the 
890  * given schedulerfactory with the given parent. @parent will
891  * have its scheduler set to the returned #GstScheduler instance.
892  *
893  * Returns: A new #GstScheduler instance with a reference count of %1.
894  */
895 GstScheduler*
896 gst_scheduler_factory_create (GstSchedulerFactory *factory, GstElement *parent)
897 {
898   GstScheduler *sched = NULL;
899
900   g_return_val_if_fail (factory != NULL, NULL);
901   g_return_val_if_fail (GST_IS_ELEMENT (parent), NULL);
902
903   if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
904     g_return_val_if_fail (factory->type != 0, NULL);
905
906     sched = GST_SCHEDULER (g_object_new (factory->type, NULL));
907     sched->parent = parent;
908
909     GST_ELEMENT_SCHED (parent) = sched;
910
911     /* let's refcount the scheduler */
912     gst_object_ref (GST_OBJECT (sched));
913     gst_object_sink (GST_OBJECT (sched));
914   }
915
916   return sched;
917 }
918
919 /**
920  * gst_scheduler_factory_make:
921  * @name: the name of the factory used to create the instance
922  * @parent: the parent element of this scheduler
923  *
924  * Create a new #GstScheduler instance from the 
925  * schedulerfactory with the given name and parent. @parent will
926  * have its scheduler set to the returned #GstScheduler instance.
927  * If %NULL is passed as @name, the default scheduler name will
928  * be used.
929  *
930  * Returns: A new #GstScheduler instance with a reference count of %1.
931  */
932 GstScheduler*
933 gst_scheduler_factory_make (const gchar *name, GstElement *parent)
934 {
935   GstSchedulerFactory *factory;
936   const gchar *default_name = gst_scheduler_factory_get_default_name ();
937
938   if (name)
939     factory = gst_scheduler_factory_find (name);
940   else
941   {
942     /* FIXME: do better error handling */
943     if (default_name == NULL)
944       g_error ("No default scheduler name - do you have a registry ?");
945     factory = gst_scheduler_factory_find (default_name);
946   }
947
948   if (factory == NULL)
949     return NULL;
950
951   return gst_scheduler_factory_create (factory, parent);
952 }
953
954 /**
955  * gst_scheduler_factory_set_default_name:
956  * @name: the name of the factory used as a default
957  *
958  * Set the default schedulerfactory name.
959  */
960 void
961 gst_scheduler_factory_set_default_name (const gchar* name)
962 {
963   g_free (_default_name);
964
965   _default_name = g_strdup (name);
966 }
967
968 /**
969  * gst_scheduler_factory_get_default_name:
970  *
971  * Get the default schedulerfactory name.
972  *
973  * Returns: the name of the default scheduler.
974  */
975 const gchar*
976 gst_scheduler_factory_get_default_name (void)
977 {
978   return _default_name;
979 }