2 * Copyright (C) 2001 Steve Baker <stevebaker_org@yahoo.co.uk>
4 * gstdparammanager.c: Dynamic Parameter group functionality
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 #include <gst/control/dparammanager.h>
23 #include <gst/gstelement.h>
24 #include <gst/gstinfo.h>
26 static GHashTable *_element_registry;
28 static void gst_dpman_class_init (GstDParamManagerClass *klass);
29 static void gst_dpman_init (GstDParamManager *dpman);
30 static void gst_dpman_dispose (GObject *object);
31 static GstDParamWrapper* gst_dpman_new_wrapper(GstDParamManager *dpman, GParamSpec *param_spec, gboolean is_log, gboolean is_rate, GstDPMUpdateMethod update_method);
32 static GstDParamWrapper* gst_dpman_get_wrapper(GstDParamManager *dpman, gchar *dparam_name);
33 static void gst_dpman_state_change (GstElement *element, gint old_state, gint new_state, GstDParamManager *dpman);
34 static void gst_dpman_caps_changed (GstPad *pad, GstCaps *caps, GstDParamManager *dpman);
35 static guint gst_dpman_preprocess_synchronous(GstDParamManager *dpman, guint frames, gint64 timestamp);
36 static guint gst_dpman_preprocess_noop(GstDParamManager *dpman, guint frames, gint64 timestamp);
37 static guint gst_dpman_process_noop(GstDParamManager *dpman, guint frame_count);
39 static GObjectClass *parent_class;
42 _gst_dpman_initialize()
47 gst_dpman_get_type (void)
49 static GType dpman_type = 0;
52 static const GTypeInfo dpman_info = {
53 sizeof(GstDParamManagerClass),
56 (GClassInitFunc)gst_dpman_class_init,
59 sizeof(GstDParamManager),
61 (GInstanceInitFunc)gst_dpman_init,
63 dpman_type = g_type_register_static(GST_TYPE_OBJECT, "GstDParamManager", &dpman_info, 0);
69 gst_dpman_class_init (GstDParamManagerClass *klass)
71 GstObjectClass *gstobject_class;
72 GObjectClass *gobject_class;
74 parent_class = g_type_class_peek_parent (klass);
76 gstobject_class = (GstObjectClass*) klass;
77 gobject_class = (GObjectClass*) klass;
78 gobject_class->dispose = gst_dpman_dispose;
80 klass->modes = g_hash_table_new(g_str_hash,g_str_equal);
82 gst_dpman_register_mode (klass, "synchronous",
83 gst_dpman_preprocess_synchronous, gst_dpman_process_noop, NULL, NULL);
84 gst_dpman_register_mode (klass, "asynchronous",
85 gst_dpman_preprocess_noop, gst_dpman_process_noop, NULL, NULL);
86 gst_dpman_register_mode (klass, "disabled",
87 gst_dpman_preprocess_noop, gst_dpman_process_noop, NULL, NULL);
89 _element_registry = g_hash_table_new(NULL,NULL);
93 gst_dpman_init (GstDParamManager *dpman)
95 GST_DPMAN_DPARAMS(dpman) = g_hash_table_new(g_str_hash,g_str_equal);
96 GST_DPMAN_DPARAMS_LIST(dpman) = NULL;
97 GST_DPMAN_NAME(dpman) = NULL;
98 GST_DPMAN_PARENT(dpman) = NULL;
99 GST_DPMAN_MODE_NAME(dpman) = NULL;
100 GST_DPMAN_MODE(dpman) = NULL;
101 GST_DPMAN_MODE_DATA(dpman) = NULL;
102 GST_DPMAN_RATE(dpman) = 0;
107 * @name: name of the GstDParamManager instance
108 * @parent: element which created this instance
110 * Returns: a new instance of GstDParamManager
113 gst_dpman_new (gchar *name, GstElement *parent)
115 GstDParamManager *dpman;
117 g_return_val_if_fail (name != NULL, NULL);
119 dpman = g_object_new (gst_dpman_get_type (), NULL);
120 gst_object_set_name (GST_OBJECT (dpman), name);
121 gst_dpman_set_parent(dpman, parent);
123 gst_dpman_set_mode(dpman, "disabled");
130 gst_dpman_dispose (GObject *object)
132 /* GstDParamManager *dpman = GST_DPMAN(object); */
134 G_OBJECT_CLASS (parent_class)->dispose (object);
138 * gst_dpman_add_required_dparam_callback:
139 * @dpman: GstDParamManager instance
140 * @update_func: callback to update the element with the new value
141 * @update_data: will be included in the call to update_func
143 * Returns: true if it was successfully added
146 gst_dpman_add_required_dparam_callback (GstDParamManager *dpman,
147 GParamSpec *param_spec,
150 GstDPMUpdateFunction update_func,
151 gpointer update_data)
153 GstDParamWrapper* dpwrap;
155 g_return_val_if_fail (dpman != NULL, FALSE);
156 g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE);
157 g_return_val_if_fail (update_func != NULL, FALSE);
159 dpwrap = gst_dpman_new_wrapper(dpman, param_spec, is_log, is_rate, GST_DPMAN_CALLBACK);
161 g_return_val_if_fail (dpwrap != NULL, FALSE);
163 GST_DEBUG(GST_CAT_PARAMS,"adding required callback dparam '%s'", g_param_spec_get_name(param_spec));
165 dpwrap->update_func = update_func;
166 dpwrap->update_data = update_data;
172 * gst_dpman_add_required_dparam_direct:
173 * @dpman: GstDParamManager instance
174 * @update_data: pointer to the member to be updated
176 * Returns: true if it was successfully added
179 gst_dpman_add_required_dparam_direct (GstDParamManager *dpman,
180 GParamSpec *param_spec,
183 gpointer update_data)
185 GstDParamWrapper* dpwrap;
187 g_return_val_if_fail (dpman != NULL, FALSE);
188 g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE);
189 g_return_val_if_fail (update_data != NULL, FALSE);
191 dpwrap = gst_dpman_new_wrapper(dpman, param_spec, is_log, is_rate, GST_DPMAN_DIRECT);
193 g_return_val_if_fail (dpwrap != NULL, FALSE);
195 GST_DEBUG(GST_CAT_PARAMS,"adding required direct dparam '%s'", g_param_spec_get_name(param_spec));
197 dpwrap->update_data = update_data;
203 * gst_dpman_add_required_dparam_array:
204 * @dpman: GstDParamManager instance
205 * @dparam_name: a parameter name unique to this GstDParamManager
206 * @update_data: pointer to where the array will be stored
208 * Returns: true if it was successfully added
211 gst_dpman_add_required_dparam_array (GstDParamManager *dpman,
212 GParamSpec *param_spec,
215 gpointer update_data)
217 GstDParamWrapper* dpwrap;
219 g_return_val_if_fail (dpman != NULL, FALSE);
220 g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE);
221 g_return_val_if_fail (update_data != NULL, FALSE);
223 dpwrap = gst_dpman_new_wrapper(dpman, param_spec, is_log, is_rate, GST_DPMAN_ARRAY);
225 g_return_val_if_fail (dpwrap != NULL, FALSE);
227 GST_DEBUG(GST_CAT_PARAMS,"adding required array dparam '%s'", g_param_spec_get_name(param_spec));
229 dpwrap->update_data = update_data;
235 * gst_dpman_remove_required_dparam:
236 * @dpman: GstDParamManager instance
237 * @dparam_name: the name of an existing parameter
241 gst_dpman_remove_required_dparam (GstDParamManager *dpman, gchar *dparam_name)
243 GstDParamWrapper* dpwrap;
245 g_return_if_fail (dpman != NULL);
246 g_return_if_fail (GST_IS_DPMAN (dpman));
247 g_return_if_fail (dparam_name != NULL);
249 dpwrap = gst_dpman_get_wrapper(dpman, dparam_name);
251 g_return_if_fail(dpwrap != NULL);
252 g_return_if_fail(dpwrap->dparam == NULL);
254 GST_DEBUG(GST_CAT_PARAMS, "removing required dparam: %s", dparam_name);
256 g_hash_table_remove(GST_DPMAN_DPARAMS(dpman), dparam_name);
257 GST_DPMAN_DPARAMS_LIST(dpman) = g_slist_remove(GST_DPMAN_DPARAMS_LIST(dpman), dpwrap);
259 g_free(dpwrap->value);
264 * gst_dpman_attach_dparam:
265 * @dpman: GstDParamManager instance
266 * @dparam_name: a name previously added with gst_dpman_add_required_dparam
267 * @dparam: GstDParam instance to attach
269 * Returns: true if it was successfully attached
272 gst_dpman_attach_dparam (GstDParamManager *dpman, gchar *dparam_name, GstDParam *dparam)
274 GstDParamWrapper* dpwrap;
276 g_return_val_if_fail (dpman != NULL, FALSE);
277 g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE);
278 g_return_val_if_fail (dparam_name != NULL, FALSE);
279 g_return_val_if_fail (dparam != NULL, FALSE);
280 g_return_val_if_fail (GST_IS_DPARAM (dparam), FALSE);
281 g_return_val_if_fail (dparam != NULL, FALSE);
283 dpwrap = gst_dpman_get_wrapper(dpman, dparam_name);
285 g_return_val_if_fail(dpwrap != NULL, FALSE);
286 g_return_val_if_fail(dpwrap->value != NULL, FALSE);
288 dpwrap->dparam = dparam;
289 gst_dparam_attach(dparam, dpman, dpwrap->param_spec, dpwrap->is_log, dpwrap->is_rate);
295 * gst_dpman_detach_dparam:
296 * @dpman: GstDParamManager instance
297 * @dparam_name: the name of a parameter with a previously attached GstDParam
301 gst_dpman_detach_dparam (GstDParamManager *dpman, gchar *dparam_name)
303 GstDParamWrapper* dpwrap;
305 g_return_if_fail (dpman != NULL);
306 g_return_if_fail (GST_IS_DPMAN (dpman));
307 g_return_if_fail (dparam_name != NULL);
309 dpwrap = gst_dpman_get_wrapper(dpman, dparam_name);
311 g_return_if_fail(dpwrap);
313 gst_dparam_detach(dpwrap->dparam);
314 dpwrap->dparam = NULL;
319 * gst_dpman_get_dparam:
320 * @dpman: GstDParamManager instance
321 * @name: the name of an existing dparam instance
323 * Returns: the dparam with the given name - or NULL otherwise
326 gst_dpman_get_dparam (GstDParamManager *dpman, gchar *name)
328 GstDParamWrapper* dpwrap;
330 g_return_val_if_fail (dpman != NULL, NULL);
331 g_return_val_if_fail (GST_IS_DPMAN (dpman), NULL);
332 g_return_val_if_fail (name != NULL, NULL);
334 dpwrap = g_hash_table_lookup(GST_DPMAN_DPARAMS(dpman), name);
335 g_return_val_if_fail (dpwrap != NULL, NULL);
337 return dpwrap->dparam;
341 * gst_dpman_get_dparam_type:
342 * @dpman: GstDParamManager instance
343 * @name: the name of dparam
345 * Returns: the type that this dparam requires/uses
348 gst_dpman_get_dparam_type (GstDParamManager *dpman, gchar *name)
350 GstDParamWrapper* dpwrap;
352 g_return_val_if_fail (dpman != NULL, 0);
353 g_return_val_if_fail (GST_IS_DPMAN (dpman), 0);
354 g_return_val_if_fail (name != NULL, 0);
356 dpwrap = g_hash_table_lookup(GST_DPMAN_DPARAMS(dpman), name);
357 g_return_val_if_fail (dpwrap != NULL, 0);
359 return G_VALUE_TYPE(dpwrap->value);
363 gst_dpman_list_dparam_specs(GstDParamManager *dpman)
365 GstDParamWrapper* dpwrap;
367 GParamSpec** param_specs;
370 g_return_val_if_fail (dpman != NULL, NULL);
371 g_return_val_if_fail (GST_IS_DPMAN (dpman), NULL);
373 dpwraps = GST_DPMAN_DPARAMS_LIST(dpman);
375 param_specs = g_new0(GParamSpec*, g_slist_length(dpwraps) + 1);
378 dpwrap = (GstDParamWrapper*)dpwraps->data;
379 param_specs[x++] = dpwrap->param_spec;
380 dpwraps = g_slist_next(dpwraps);
387 gst_dpman_get_param_spec (GstDParamManager *dpman, gchar *dparam_name)
389 GstDParamWrapper* dpwrap;
391 g_return_val_if_fail (dpman != NULL, NULL);
392 g_return_val_if_fail (GST_IS_DPMAN (dpman), NULL);
393 g_return_val_if_fail (dparam_name != NULL, NULL);
395 dpwrap = gst_dpman_get_wrapper(dpman, dparam_name);
396 return dpwrap->param_spec;
400 * gst_dpman_register_mode
401 * @klass: GstDParamManagerClass class instance
402 * @modename: the unique name of the new mode
403 * @preprocessfunc: the function which will be called before each buffer is processed
404 * @processfunc: the function which may be called throughout the processing of a buffer
405 * @setupfunc: the function which initialises the mode when activated
406 * @teardownfunc: the function which frees any resources the mode uses
410 gst_dpman_register_mode (GstDParamManagerClass *klass,
412 GstDPMModePreProcessFunction preprocessfunc,
413 GstDPMModeProcessFunction processfunc,
414 GstDPMModeSetupFunction setupfunc,
415 GstDPMModeTeardownFunction teardownfunc)
419 g_return_if_fail (klass != NULL);
420 g_return_if_fail (modename != NULL);
421 g_return_if_fail (GST_IS_DPMAN_CLASS (klass));
423 mode = g_new0(GstDPMMode,1);
425 mode->preprocessfunc = preprocessfunc;
426 mode->processfunc = processfunc;
427 mode->setupfunc = setupfunc;
428 mode->teardownfunc = teardownfunc;
430 g_hash_table_insert(klass->modes, modename, mode);
431 GST_DEBUG(GST_CAT_PARAMS, "mode '%s' registered", modename);
436 * @dpman: GstDParamManager instance
437 * @modename: the name of the mode to use
439 * Returns: TRUE if the mode was set, FALSE otherwise
442 gst_dpman_set_mode(GstDParamManager *dpman, gchar *modename)
444 GstDPMMode *mode=NULL;
445 GstDParamManagerClass *oclass;
447 g_return_val_if_fail (dpman != NULL, FALSE);
448 g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE);
449 g_return_val_if_fail (modename != NULL, FALSE);
451 oclass = (GstDParamManagerClass*)(G_OBJECT_GET_CLASS(dpman));
453 mode = g_hash_table_lookup(oclass->modes, modename);
454 g_return_val_if_fail (mode != NULL, FALSE);
456 if (GST_DPMAN_MODE(dpman) == mode) {
457 GST_DEBUG(GST_CAT_PARAMS, "mode %s already set", modename);
461 GST_DEBUG(GST_CAT_PARAMS, "setting mode to %s", modename);
462 if (GST_DPMAN_MODE(dpman) && GST_DPMAN_TEARDOWNFUNC(dpman)){
463 GST_DPMAN_TEARDOWNFUNC(dpman)(dpman);
466 GST_DPMAN_MODE(dpman) = mode;
468 if (GST_DPMAN_SETUPFUNC(dpman)){
469 GST_DPMAN_SETUPFUNC(dpman)(dpman);
476 * gst_dpman_set_parent
477 * @dpman: GstDParamManager instance
478 * @parent: the element that this GstDParamManager belongs to
482 gst_dpman_set_parent (GstDParamManager *dpman, GstElement *parent)
484 g_return_if_fail (dpman != NULL);
485 g_return_if_fail (GST_IS_DPMAN (dpman));
486 g_return_if_fail (parent != NULL);
487 g_return_if_fail (GST_IS_ELEMENT (parent));
489 g_hash_table_insert(_element_registry, parent, dpman);
490 gst_object_set_parent (GST_OBJECT (dpman), GST_OBJECT(parent));
491 g_signal_connect(G_OBJECT(parent), "state_change",
492 G_CALLBACK (gst_dpman_state_change), dpman);
496 * gst_dpman_get_manager
497 * @parent: the element that the desired GstDParamManager belongs to
499 * Returns: the GstDParamManager which belongs to this element or NULL
500 * if it doesn't exist
503 gst_dpman_get_manager (GstElement *parent)
505 GstDParamManager *dpman;
506 g_return_val_if_fail (parent != NULL, NULL);
507 g_return_val_if_fail (GST_IS_ELEMENT (parent), NULL);
509 dpman = (GstDParamManager*)g_hash_table_lookup(_element_registry, parent);
514 * gst_dpman_set_rate_change_pad
515 * @dpman: GstDParamManager instance
516 * @pad: the pad which may have a "rate" caps property
520 gst_dpman_set_rate_change_pad(GstDParamManager *dpman, GstPad *pad)
522 g_return_if_fail (dpman != NULL);
523 g_return_if_fail (GST_IS_DPMAN (dpman));
524 g_return_if_fail (pad != NULL);
525 g_return_if_fail (GST_IS_PAD (pad));
527 g_signal_connect(G_OBJECT(pad), "caps_changed",
528 G_CALLBACK (gst_dpman_caps_changed), dpman);
531 static GstDParamWrapper*
532 gst_dpman_get_wrapper(GstDParamManager *dpman, gchar *dparam_name)
534 g_return_val_if_fail (dpman != NULL, NULL);
535 g_return_val_if_fail (GST_IS_DPMAN (dpman), NULL);
536 g_return_val_if_fail (dparam_name != NULL, NULL);
538 return g_hash_table_lookup(GST_DPMAN_DPARAMS(dpman), dparam_name);
541 static GstDParamWrapper*
542 gst_dpman_new_wrapper(GstDParamManager *dpman,
543 GParamSpec *param_spec,
546 GstDPMUpdateMethod update_method)
548 GstDParamWrapper* dpwrap;
551 g_return_val_if_fail (dpman != NULL, NULL);
552 g_return_val_if_fail (GST_IS_DPMAN (dpman), NULL);
553 g_return_val_if_fail (param_spec != NULL, NULL);
555 dparam_name = g_strdup(g_param_spec_get_name(param_spec));
556 g_return_val_if_fail(gst_dpman_get_wrapper(dpman, dparam_name) == NULL, NULL);
558 dpwrap = g_new0(GstDParamWrapper,1);
559 dpwrap->update_method = update_method;
560 dpwrap->value = g_new0(GValue,1);
561 g_value_init(dpwrap->value, G_PARAM_SPEC_VALUE_TYPE(param_spec));
562 dpwrap->param_spec = param_spec;
563 dpwrap->is_log = is_log;
564 dpwrap->is_rate = is_rate;
566 g_hash_table_insert(GST_DPMAN_DPARAMS(dpman), dparam_name, dpwrap);
567 GST_DPMAN_DPARAMS_LIST(dpman) = g_slist_append(GST_DPMAN_DPARAMS_LIST(dpman), dpwrap);
574 gst_dpman_state_change (GstElement *element, gint old_state, gint new_state, GstDParamManager *dpman)
578 GstDParamWrapper *dpwrap;
580 g_return_if_fail (dpman != NULL);
581 g_return_if_fail (GST_IS_DPMAN (dpman));
583 if (new_state == GST_STATE_PLAYING){
584 GST_DEBUG(GST_CAT_PARAMS, "initialising params");
586 /* force all params to be updated */
587 dwraps = GST_DPMAN_DPARAMS_LIST(dpman);
589 dpwrap = (GstDParamWrapper*)dwraps->data;
590 dparam = dpwrap->dparam;
593 GST_DPARAM_READY_FOR_UPDATE(dparam) = TRUE;
595 g_value_copy(dparam->spec->default_val, dpwrap->value);
598 dwraps = g_slist_next(dwraps);
604 gst_dpman_caps_changed (GstPad *pad, GstCaps *caps, GstDParamManager *dpman)
608 g_return_if_fail (caps != NULL);
609 g_return_if_fail (dpman != NULL);
610 g_return_if_fail (GST_IS_DPMAN (dpman));
612 gst_caps_get_int (caps, "rate", &rate);
613 GST_DPMAN_RATE(dpman) = rate;
615 GST_DEBUG(GST_CAT_PARAMS, "got caps change %d", GST_DPMAN_RATE(dpman));
619 gst_dpman_preprocess_synchronous(GstDParamManager *dpman, guint frames, gint64 timestamp)
623 GstDParamWrapper *dpwrap;
625 g_return_val_if_fail (dpman != NULL, frames);
626 g_return_val_if_fail (GST_IS_DPMAN (dpman), frames);
628 /* now check whether any passive dparams are ready for an update */
629 dwraps = GST_DPMAN_DPARAMS_LIST(dpman);
631 dpwrap = (GstDParamWrapper*)dwraps->data;
632 dparam = dpwrap->dparam;
634 if (dparam && (GST_DPARAM_READY_FOR_UPDATE(dparam) &&
635 (GST_DPARAM_NEXT_UPDATE_TIMESTAMP(dparam) <= timestamp))){
637 switch (dpwrap->update_method) {
639 /* direct method - set the value directly in the struct of the element */
640 case GST_DPMAN_DIRECT:
641 GST_DPARAM_DO_UPDATE(dparam, timestamp, dpwrap->value);
642 GST_DEBUG(GST_CAT_PARAMS, "doing direct update");
643 switch (G_VALUE_TYPE(dpwrap->value)){
645 *(gint*)dpwrap->update_data = g_value_get_int(dpwrap->value);
648 *(gint64*)dpwrap->update_data = g_value_get_int64(dpwrap->value);
651 *(gfloat*)dpwrap->update_data = g_value_get_float(dpwrap->value);
658 /* callback method - call the element's callback so it can do what it likes */
659 case GST_DPMAN_CALLBACK:
660 GST_DPARAM_DO_UPDATE(dparam, timestamp, dpwrap->value);
661 GST_DEBUG(GST_CAT_PARAMS, "doing callback update");
662 GST_DPMAN_DO_UPDATE(dpwrap);
665 /* array method - generate an array of the right size */
666 /* with each value being the same (in synchronous update mode) */
667 case GST_DPMAN_ARRAY:
668 GST_DEBUG(GST_CAT_PARAMS, "doing array update");
669 switch (G_VALUE_TYPE(dpwrap->value)){
684 dwraps = g_slist_next(dwraps);
690 gst_dpman_preprocess_noop(GstDParamManager *dpman, guint frames, gint64 timestamp)
696 gst_dpman_process_noop(GstDParamManager *dpman, guint frame_count)