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