66ec27fca5e2ef015a7d032fd4ba250f72a1eb3e
[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 "gstscheduler.h"
28
29 static void     gst_scheduler_class_init        (GstSchedulerClass *klass);
30 static void     gst_scheduler_init              (GstScheduler *sched);
31
32 static GstObjectClass *parent_class = NULL;
33
34 static gchar *_default_name = NULL;
35
36 GType
37 gst_scheduler_get_type (void)
38 {
39   static GType _gst_scheduler_type = 0;
40
41   if (!_gst_scheduler_type) {
42     static const GTypeInfo scheduler_info = {
43       sizeof (GstSchedulerClass),
44       NULL,
45       NULL,
46       (GClassInitFunc) gst_scheduler_class_init,
47       NULL,
48       NULL,
49       sizeof (GstScheduler),
50       0,
51       (GInstanceInitFunc) gst_scheduler_init,
52       NULL
53     };
54
55     _gst_scheduler_type = g_type_register_static (GST_TYPE_OBJECT, "GstScheduler", 
56                     &scheduler_info, G_TYPE_FLAG_ABSTRACT);
57   }
58   return _gst_scheduler_type;
59 }
60
61 static void
62 gst_scheduler_class_init (GstSchedulerClass *klass)
63 {
64   parent_class = g_type_class_ref (GST_TYPE_OBJECT);
65 }
66
67 static void
68 gst_scheduler_init (GstScheduler *sched)
69 {
70 }
71
72 /**
73  * gst_scheduler_setup:
74  * @sched: the schedulerr
75  *
76  * Prepare the scheduler.
77  */
78 void
79 gst_scheduler_setup (GstScheduler *sched)
80 {
81   g_return_if_fail (GST_IS_SCHEDULER (sched));
82
83   if (CLASS (sched)->setup)
84     CLASS (sched)->setup (sched);
85 }
86
87 /**
88  * gst_scheduler_reset:
89  * @sched: the schedulerr
90  *
91  * Reset the scheduler
92  */
93 void
94 gst_scheduler_reset (GstScheduler *sched)
95 {
96   g_return_if_fail (GST_IS_SCHEDULER (sched));
97
98   if (CLASS (sched)->reset)
99     CLASS (sched)->reset (sched);
100 }
101
102 /**
103  * gst_scheduler_pad_connect:
104  * @sched: the schedulerr
105  * @srcpad: the srcpad to connect
106  * @sinkpad: the sinkpad to connect to
107  *
108  * Connect the srcpad to the given sinkpad.
109  */
110 void
111 gst_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad)
112 {
113   g_return_if_fail (GST_IS_SCHEDULER (sched));
114   g_return_if_fail (GST_IS_PAD (srcpad));
115   g_return_if_fail (GST_IS_PAD (sinkpad));
116
117   if (CLASS (sched)->pad_connect)
118     CLASS (sched)->pad_connect (sched, srcpad, sinkpad);
119 }
120
121 /**
122  * gst_scheduler_pad_disconnect:
123  * @sched: the schedulerr
124  * @srcpad: the srcpad to disconnect
125  * @sinkpad: the sinkpad to disconnect from
126  *
127  * Disconnect the srcpad to the given sinkpad.
128  */
129 void
130 gst_scheduler_pad_disconnect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad)
131 {
132   g_return_if_fail (GST_IS_SCHEDULER (sched));
133   g_return_if_fail (GST_IS_PAD (srcpad));
134   g_return_if_fail (GST_IS_PAD (sinkpad));
135
136   if (CLASS (sched)->pad_disconnect)
137     CLASS (sched)->pad_disconnect (sched, srcpad, sinkpad);
138 }
139
140 /**
141  * gst_scheduler_pad_select:
142  * @sched: the schedulerr
143  * @padlist: the padlist to select on
144  *
145  * register the given padlist for a select operation. 
146  *
147  * Returns: the pad which received a buffer.
148  */
149 GstPad *
150 gst_scheduler_pad_select (GstScheduler *sched, GList *padlist)
151 {
152   g_return_if_fail (GST_IS_SCHEDULER (sched));
153   g_return_if_fail (padlist != NULL);
154
155   if (CLASS (sched)->pad_select)
156     CLASS (sched)->pad_select (sched, padlist);
157 }
158
159 /**
160  * gst_scheduler_add_element:
161  * @sched: the schedulerr
162  * @element: the element to add to the schedulerr
163  *
164  * Add an element to the schedulerr.
165  */
166 void
167 gst_scheduler_add_element (GstScheduler *sched, GstElement *element)
168 {
169   g_return_if_fail (GST_IS_SCHEDULER (sched));
170   g_return_if_fail (GST_IS_ELEMENT (element));
171
172   if (CLASS (sched)->add_element)
173     CLASS (sched)->add_element (sched, element);
174 }
175
176 /**
177  * gst_scheduler_state_transition:
178  * @sched: the schedulerr
179  * @element: the element with the state transition
180  * @transition: the state transition
181  *
182  * Tell the scheduler that an element changed its state.
183  *
184  * Returns: a GstElementStateReturn indicating success or failure
185  * of the state transition.
186  */
187 GstElementStateReturn
188 gst_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition)
189 {
190   g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_STATE_FAILURE);
191   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
192
193   if (CLASS (sched)->state_transition)
194     return CLASS (sched)->state_transition (sched, element, transition);
195
196   return GST_STATE_SUCCESS;
197 }
198
199 /**
200  * gst_scheduler_remove_element:
201  * @sched: the schedulerr
202  * @element: the element to remove
203  *
204  * Remove an element from the schedulerr.
205  */
206 void
207 gst_scheduler_remove_element (GstScheduler *sched, GstElement *element)
208 {
209   g_return_if_fail (GST_IS_SCHEDULER (sched));
210   g_return_if_fail (GST_IS_ELEMENT (element));
211
212   if (CLASS (sched)->remove_element)
213     CLASS (sched)->remove_element (sched, element);
214 }
215
216 /**
217  * gst_scheduler_lock_element:
218  * @sched: the schedulerr
219  * @element: the element to lock
220  *
221  * Acquire a lock on the given element in the given scheduler.
222  */
223 void
224 gst_scheduler_lock_element (GstScheduler *sched, GstElement *element)
225 {
226   g_return_if_fail (GST_IS_SCHEDULER (sched));
227   g_return_if_fail (GST_IS_ELEMENT (element));
228
229   if (CLASS (sched)->lock_element)
230     CLASS (sched)->lock_element (sched, element);
231 }
232
233 /**
234  * gst_scheduler_unlock_element:
235  * @sched: the schedulerr
236  * @element: the element to unlock
237  *
238  * Release the lock on the given element in the given scheduler.
239  */
240 void
241 gst_scheduler_unlock_element (GstScheduler *sched, GstElement *element)
242 {
243   g_return_if_fail (GST_IS_SCHEDULER (sched));
244   g_return_if_fail (GST_IS_ELEMENT (element));
245
246   if (CLASS (sched)->unlock_element)
247     CLASS (sched)->unlock_element (sched, element);
248 }
249
250 /**
251  * gst_scheduler_error:
252  * @sched: the schedulerr
253  * @element: the element with the error
254  *
255  * Tell the scheduler an element was in error
256  */
257 void
258 gst_scheduler_error (GstScheduler *sched, GstElement *element)
259 {
260   g_return_if_fail (GST_IS_SCHEDULER (sched));
261   g_return_if_fail (GST_IS_ELEMENT (element));
262
263   if (CLASS (sched)->error)
264     CLASS (sched)->error (sched, element);
265 }
266
267 /**
268  * gst_scheduler_yield:
269  * @sched: the schedulerr
270  * @element: the element requesting a yield
271  *
272  * Tell the scheduler to schedule another element.
273  */
274 void
275 gst_scheduler_yield (GstScheduler *sched, GstElement *element)
276 {
277   g_return_if_fail (GST_IS_SCHEDULER (sched));
278   g_return_if_fail (GST_IS_ELEMENT (element));
279
280   if (CLASS (sched)->yield)
281     CLASS (sched)->yield (sched, element);
282 }
283
284 /**
285  * gst_scheduler_interrupt:
286  * @sched: the schedulerr
287  * @element: the element requesting an interrupt
288  *
289  * Tell the scheduler to interrupt execution of this element.
290  *
291  * Returns: TRUE if the element should return NULL from the chain/get
292  * function.
293  */
294 gboolean
295 gst_scheduler_interrupt (GstScheduler *sched, GstElement *element)
296 {
297   g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
298   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
299
300   if (CLASS (sched)->interrupt)
301     return CLASS (sched)->interrupt (sched, element);
302
303   return FALSE;
304 }
305
306 /**
307  * gst_scheduler_iterate:
308  * @sched: the schedulerr
309  *
310  * Perform one iteration on the schedulerr.
311  *
312  * Returns: a boolean indicating something usefull has happened.
313  */
314 gboolean
315 gst_scheduler_iterate (GstScheduler *sched)
316 {
317   g_return_if_fail (GST_IS_SCHEDULER (sched));
318
319   if (CLASS (sched)->iterate)
320     CLASS (sched)->iterate (sched);
321 }
322
323
324 /**
325  * gst_scheduler_show:
326  * @sched: the schedulerr
327  *
328  * Dump the state of the schedulerr
329  */
330 void
331 gst_scheduler_show (GstScheduler *sched)
332 {
333   g_return_if_fail (GST_IS_SCHEDULER (sched));
334
335   if (CLASS (sched)->show)
336     CLASS (sched)->show (sched);
337 }
338
339 /*
340  * Factory stuff starts here
341  *
342  */
343
344 static GList* _gst_schedulerfactories;
345
346 static void             gst_schedulerfactory_class_init         (GstSchedulerFactoryClass *klass);
347 static void             gst_schedulerfactory_init               (GstSchedulerFactory *factory);
348
349 #ifndef GST_DISABLE_REGISTRY
350 static xmlNodePtr       gst_schedulerfactory_save_thyself       (GstObject *object, xmlNodePtr parent);
351 static void             gst_schedulerfactory_restore_thyself    (GstObject *object, xmlNodePtr parent);
352 #endif
353
354 static GstPluginFeatureClass *factory_parent_class = NULL;
355 /* static guint gst_schedulerfactory_signals[LAST_SIGNAL] = { 0 }; */
356
357 GType 
358 gst_schedulerfactory_get_type (void) 
359 {
360   static GType schedulerfactory_type = 0;
361
362   if (!schedulerfactory_type) {
363     static const GTypeInfo schedulerfactory_info = {
364       sizeof (GstSchedulerFactoryClass),
365       NULL,
366       NULL,
367       (GClassInitFunc) gst_schedulerfactory_class_init,
368       NULL,
369       NULL,
370       sizeof(GstSchedulerFactory),
371       0,
372       (GInstanceInitFunc) gst_schedulerfactory_init,
373       NULL
374     };
375     schedulerfactory_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE, 
376                                                   "GstSchedulerFactory", &schedulerfactory_info, 0);
377   }
378   return schedulerfactory_type;
379 }
380
381 static void
382 gst_schedulerfactory_class_init (GstSchedulerFactoryClass *klass)
383 {
384   GObjectClass *gobject_class;
385   GstObjectClass *gstobject_class;
386   GstPluginFeatureClass *gstpluginfeature_class;
387
388   gobject_class = (GObjectClass*)klass;
389   gstobject_class = (GstObjectClass*)klass;
390   gstpluginfeature_class = (GstPluginFeatureClass*) klass;
391
392   factory_parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE);
393
394 #ifndef GST_DISABLE_REGISTRY
395   gstobject_class->save_thyself =       GST_DEBUG_FUNCPTR (gst_schedulerfactory_save_thyself);
396   gstobject_class->restore_thyself =    GST_DEBUG_FUNCPTR (gst_schedulerfactory_restore_thyself);
397 #endif
398
399   _gst_schedulerfactories = NULL;
400   _default_name = g_strdup ("basic");
401 }
402
403 static void
404 gst_schedulerfactory_init (GstSchedulerFactory *factory)
405 {
406   _gst_schedulerfactories = g_list_prepend (_gst_schedulerfactories, factory);
407 }
408         
409
410 /**
411  * gst_schedulerfactory_new:
412  * @name: name of schedulerfactory to create
413  * @longdesc: long description of schedulerfactory to create
414  * @type: the gtk type of the GstScheduler element of this factory
415  *
416  * Create a new schedulerfactory with the given parameters
417  *
418  * Returns: a new #GstSchedulerFactory.
419  */
420 GstSchedulerFactory*
421 gst_schedulerfactory_new (const gchar *name, const gchar *longdesc, GType type)
422 {
423   GstSchedulerFactory *factory;
424
425   g_return_val_if_fail(name != NULL, NULL);
426   factory = gst_schedulerfactory_find (name);
427   if (!factory) {
428     factory = GST_SCHEDULERFACTORY (g_object_new (GST_TYPE_SCHEDULERFACTORY, NULL));
429   }
430
431   gst_object_set_name (GST_OBJECT (factory), name);
432   if (factory->longdesc)
433     g_free (factory->longdesc);
434   factory->longdesc = g_strdup (longdesc);
435   factory->type = type;
436
437   return factory;
438 }
439
440 /**
441  * gst_schedulerfactory_destroy:
442  * @factory: factory to destroy
443  *
444  * Removes the scheduler from the global list.
445  */
446 void
447 gst_schedulerfactory_destroy (GstSchedulerFactory *factory)
448 {
449   g_return_if_fail (factory != NULL);
450
451   _gst_schedulerfactories = g_list_remove (_gst_schedulerfactories, factory);
452
453   /* we don't free the struct bacause someone might  have a handle to it.. */
454 }
455
456 /**
457  * gst_schedulerfactory_find:
458  * @name: name of schedulerfactory to find
459  *
460  * Search for an schedulerfactory of the given name.
461  *
462  * Returns: #GstSchedulerFactory if found, NULL otherwise
463  */
464 GstSchedulerFactory*
465 gst_schedulerfactory_find (const gchar *name)
466 {
467   GList *walk;
468   GstSchedulerFactory *factory;
469
470   g_return_val_if_fail(name != NULL, NULL);
471
472   GST_DEBUG (0,"gstscheduler: find \"%s\"\n", name);
473
474   walk = _gst_schedulerfactories;
475   while (walk) {
476     factory = (GstSchedulerFactory *)(walk->data);
477     if (!strcmp (name, GST_OBJECT_NAME (factory)))
478       return factory;
479     walk = g_list_next (walk);
480   }
481
482   return NULL;
483 }
484
485 /**
486  * gst_schedulerfactory_get_list:
487  *
488  * Get the global list of schedulerfactories.
489  *
490  * Returns: GList of type #GstSchedulerFactory
491  */
492 GList*
493 gst_schedulerfactory_get_list (void)
494 {
495   return _gst_schedulerfactories;
496 }
497
498 /**
499  * gst_schedulerfactory_create:
500  * @factory: the factory used to create the instance
501  * @parent: the parent element of this scheduler
502  *
503  * Create a new #GstScheduler instance from the 
504  * given schedulerfactory with the given parent.
505  *
506  * Returns: A new #GstScheduler instance.
507  */
508 GstScheduler*
509 gst_schedulerfactory_create (GstSchedulerFactory *factory, GstElement *parent)
510 {
511   GstScheduler *new = NULL;
512
513   g_return_val_if_fail (factory != NULL, NULL);
514
515   if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
516     g_return_val_if_fail (factory->type != 0, NULL);
517
518     new = GST_SCHEDULER (g_object_new (factory->type, NULL));
519     new->parent = parent;
520   }
521
522   return new;
523 }
524
525 /**
526  * gst_schedulerfactory_make:
527  * @name: the name of the factory used to create the instance
528  * @parent: the parent element of this scheduler
529  *
530  * Create a new #GstScheduler instance from the 
531  * schedulerfactory with the given name and parent.
532  *
533  * Returns: A new #GstScheduler instance.
534  */
535 GstScheduler*
536 gst_schedulerfactory_make (const gchar *name, GstElement *parent)
537 {
538   GstSchedulerFactory *factory;
539
540   g_return_val_if_fail (name != NULL, NULL);
541
542   factory = gst_schedulerfactory_find (name);
543
544   if (factory == NULL)
545     return NULL;
546
547   return gst_schedulerfactory_create (factory, parent);
548 }
549
550 void
551 gst_schedulerfactory_set_default_name (const gchar* name)
552 {
553   if (_default_name)
554     g_free (_default_name);
555
556   _default_name = g_strdup (name);
557 }
558
559 const gchar*
560 gst_schedulerfactory_get_default_name (void)
561 {
562   return _default_name;
563 }
564
565 #ifndef GST_DISABLE_REGISTRY
566 static xmlNodePtr
567 gst_schedulerfactory_save_thyself (GstObject *object, xmlNodePtr parent)
568 {
569   GstSchedulerFactory *factory;
570
571   g_return_val_if_fail (GST_IS_SCHEDULERFACTORY (object), parent);
572
573   factory = GST_SCHEDULERFACTORY (object);
574
575   if (GST_OBJECT_CLASS (factory_parent_class)->save_thyself) {
576     GST_OBJECT_CLASS (factory_parent_class)->save_thyself (object, parent);
577   }
578
579   xmlNewChild (parent, NULL, "longdesc", factory->longdesc);
580
581   return parent;
582 }
583
584 /**
585  * gst_schedulerfactory_load_thyself:
586  * @parent: the parent XML node pointer
587  *
588  * Load an schedulerfactory from the given XML parent node.
589  *
590  * Returns: A new factory based on the XML node.
591  */
592 static void
593 gst_schedulerfactory_restore_thyself (GstObject *object, xmlNodePtr parent)
594 {
595   GstSchedulerFactory *factory = GST_SCHEDULERFACTORY (object);
596   xmlNodePtr children = parent->xmlChildrenNode;
597
598   if (GST_OBJECT_CLASS (factory_parent_class)->restore_thyself) {
599     GST_OBJECT_CLASS (factory_parent_class)->restore_thyself (object, parent);
600   }
601
602   while (children) {
603     if (!strcmp(children->name, "name")) {
604       gst_object_set_name (GST_OBJECT (factory), xmlNodeGetContent (children));
605     }
606     if (!strcmp(children->name, "longdesc")) {
607       factory->longdesc = xmlNodeGetContent (children);
608     }
609     children = children->next;
610   }
611 }
612 #endif /* GST_DISABLE_REGISTRY */