Convert %lld and %llu in printf formats to G_G[U]INT64_FORMAT. Fix pointer<->int...
[platform/upstream/gstreamer.git] / libs / gst / control / dparammanager.c
1 /* GStreamer
2  * Copyright (C) 2001 Steve Baker <stevebaker_org@yahoo.co.uk>
3  *
4  * gstdparammanager.c: Dynamic Parameter group functionality
5  *
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.
10  *
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.
15  *
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.
20  */
21
22 #include "dparammanager.h"
23 #include <gst/gstelement.h>
24 #include <gst/gstinfo.h>
25
26 static GHashTable *_element_registry = NULL;
27 static gboolean _gst_dpman_init_done = FALSE;
28
29 enum {
30   NEW_REQUIRED_DPARAM,
31   LAST_SIGNAL
32 };
33
34 static void gst_dpman_class_init (GstDParamManagerClass *klass);
35 static void gst_dpman_init (GstDParamManager *dpman);
36 static void gst_dpman_dispose (GObject *object);
37 static GstDParamWrapper* gst_dpman_new_wrapper(GstDParamManager *dpman, GParamSpec *param_spec, gchar *unit_name, GstDPMUpdateMethod update_method);
38 static GstDParamWrapper* gst_dpman_get_wrapper(GstDParamManager *dpman, gchar *dparam_name);
39 static void gst_dpman_state_change (GstElement *element, gint old_state, gint new_state, GstDParamManager *dpman);
40 static gboolean gst_dpman_preprocess_synchronous(GstDParamManager *dpman, guint frames, gint64 timestamp);
41 static gboolean gst_dpman_preprocess_asynchronous(GstDParamManager *dpman, guint frames, gint64 timestamp);
42 static gboolean gst_dpman_process_asynchronous(GstDParamManager *dpman, guint frame_count);
43 static gboolean gst_dpman_preprocess_noop(GstDParamManager *dpman, guint frames, gint64 timestamp);
44 static gboolean gst_dpman_process_noop(GstDParamManager *dpman, guint frame_count);
45 static void gst_dpman_setup_synchronous(GstDParamManager *dpman);
46 static void gst_dpman_setup_asynchronous(GstDParamManager *dpman);
47 static void gst_dpman_setup_disabled(GstDParamManager *dpman);
48 static void gst_dpman_teardown_synchronous(GstDParamManager *dpman);
49 static void gst_dpman_teardown_asynchronous(GstDParamManager *dpman);
50 static void gst_dpman_teardown_disabled(GstDParamManager *dpman);
51
52 static GObjectClass *parent_class;
53 static guint gst_dpman_signals[LAST_SIGNAL] = { 0 };
54
55 void 
56 _gst_dpman_initialize()
57 {
58         if (_gst_dpman_init_done) return;
59         
60         _gst_dpman_init_done = TRUE;
61         _element_registry = g_hash_table_new(NULL,NULL);
62 }
63
64 GType
65 gst_dpman_get_type (void)
66 {
67         static GType dpman_type = 0;
68
69         if (!dpman_type) {
70                 static const GTypeInfo dpman_info = {
71                         sizeof(GstDParamManagerClass),
72                         NULL,
73                         NULL,
74                         (GClassInitFunc)gst_dpman_class_init,
75                         NULL,
76                         NULL,
77                         sizeof(GstDParamManager),
78                         0,
79                         (GInstanceInitFunc)gst_dpman_init,
80                 };
81                 dpman_type = g_type_register_static(GST_TYPE_OBJECT, "GstDParamManager", &dpman_info, 0);
82         }
83         return dpman_type;
84 }
85
86 static void
87 gst_dpman_class_init (GstDParamManagerClass *klass)
88 {
89         GstObjectClass *gstobject_class;
90         GObjectClass *gobject_class;
91
92         parent_class = g_type_class_peek_parent (klass);
93
94         gstobject_class = (GstObjectClass*) klass;
95         gobject_class = (GObjectClass*) klass;
96         gobject_class->dispose = gst_dpman_dispose;
97
98         klass->modes = g_hash_table_new(g_str_hash,g_str_equal);
99
100         gst_dpman_register_mode (klass, "synchronous", 
101                                gst_dpman_preprocess_synchronous, gst_dpman_process_noop, 
102                                gst_dpman_setup_synchronous, gst_dpman_teardown_synchronous);
103         gst_dpman_register_mode (klass, "asynchronous", 
104                                gst_dpman_preprocess_asynchronous, gst_dpman_process_asynchronous, 
105                                gst_dpman_setup_asynchronous, gst_dpman_teardown_asynchronous);
106         gst_dpman_register_mode (klass, "disabled", 
107                                gst_dpman_preprocess_noop, gst_dpman_process_noop, 
108                                gst_dpman_setup_disabled, gst_dpman_teardown_disabled);
109
110
111         gst_dpman_signals[NEW_REQUIRED_DPARAM] =
112                 g_signal_new ("new_required_dparam", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
113                               G_STRUCT_OFFSET (GstDParamManagerClass, new_required_dparam), NULL, NULL,
114                               gst_marshal_VOID__STRING, G_TYPE_NONE, 1,
115                               G_TYPE_STRING);
116                                               
117 }
118
119 static void
120 gst_dpman_init (GstDParamManager *dpman)
121 {
122         GST_DPMAN_DPARAMS(dpman) = g_hash_table_new(g_str_hash,g_str_equal);
123         GST_DPMAN_DPARAMS_LIST(dpman) = NULL;
124         GST_DPMAN_NAME(dpman) = NULL;
125         GST_DPMAN_PARENT(dpman) = NULL;
126         GST_DPMAN_MODE_NAME(dpman) = NULL;
127         GST_DPMAN_MODE(dpman) = NULL;
128         GST_DPMAN_RATE(dpman) = 0;
129 }
130
131 /**
132  * gst_dpman_new:
133  * @name: name of the GstDParamManager instance
134  * @parent: element which created this instance
135  *
136  * Returns: a new instance of GstDParamManager
137  */
138 GstDParamManager* 
139 gst_dpman_new (gchar *name, GstElement *parent)
140 {
141         GstDParamManager *dpman;
142         
143         g_return_val_if_fail (name != NULL, NULL);
144
145         dpman = g_object_new (gst_dpman_get_type (), NULL);
146         gst_object_set_name (GST_OBJECT (dpman), name);
147         gst_dpman_set_parent(dpman, parent);
148
149         gst_dpman_set_mode(dpman, "disabled");
150
151         return dpman;
152 }
153
154
155 static void
156 gst_dpman_dispose (GObject *object)
157 {
158 /*      GstDParamManager *dpman = GST_DPMAN(object); */
159
160         G_OBJECT_CLASS (parent_class)->dispose (object);
161 }
162
163 /**
164  * gst_dpman_add_required_dparam_callback:
165  * @dpman: GstDParamManager instance
166  * @update_func: callback to update the element with the new value
167  * @update_data: will be included in the call to update_func
168  *
169  * Returns: true if it was successfully added
170  */
171 gboolean 
172 gst_dpman_add_required_dparam_callback (GstDParamManager *dpman, 
173                                         GParamSpec *param_spec,
174                                         gchar *unit_name,
175                                         GstDPMUpdateFunction update_func, 
176                                         gpointer update_data)
177 {
178         GstDParamWrapper* dpwrap;
179
180         g_return_val_if_fail (dpman != NULL, FALSE);
181         g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE);
182         g_return_val_if_fail (update_func != NULL, FALSE);
183
184         dpwrap = gst_dpman_new_wrapper(dpman, param_spec, unit_name, GST_DPMAN_CALLBACK);
185
186         g_return_val_if_fail (dpwrap != NULL, FALSE);
187
188         GST_DEBUG(GST_CAT_PARAMS,"adding required callback dparam '%s'", g_param_spec_get_name(param_spec));
189
190         dpwrap->update_func = update_func;
191         dpwrap->update_data = update_data;
192         
193         g_signal_emit (G_OBJECT (dpman), gst_dpman_signals[NEW_REQUIRED_DPARAM], 0, g_param_spec_get_name(param_spec));
194
195         return TRUE;    
196 }
197
198 /**
199  * gst_dpman_add_required_dparam_direct:
200  * @dpman: GstDParamManager instance
201  * @update_data: pointer to the member to be updated
202  *
203  * Returns: true if it was successfully added
204  */
205 gboolean 
206 gst_dpman_add_required_dparam_direct (GstDParamManager *dpman, 
207                                       GParamSpec *param_spec,
208                                       gchar *unit_name,
209                                       gpointer update_data)
210 {
211         GstDParamWrapper* dpwrap;
212
213         g_return_val_if_fail (dpman != NULL, FALSE);
214         g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE);
215         g_return_val_if_fail (update_data != NULL, FALSE);
216
217         dpwrap = gst_dpman_new_wrapper(dpman, param_spec, unit_name, GST_DPMAN_DIRECT);
218
219         g_return_val_if_fail (dpwrap != NULL, FALSE);
220
221         GST_DEBUG(GST_CAT_PARAMS,"adding required direct dparam '%s'", g_param_spec_get_name(param_spec));
222
223         dpwrap->update_data = update_data;
224
225         g_signal_emit (G_OBJECT (dpman), gst_dpman_signals[NEW_REQUIRED_DPARAM], 0, g_param_spec_get_name(param_spec));
226
227         return TRUE;    
228 }
229
230 /**
231  * gst_dpman_add_required_dparam_array:
232  * @dpman: GstDParamManager instance
233  * @dparam_name: a parameter name unique to this GstDParamManager
234  * @update_data: pointer to where the array will be stored
235  *
236  * Returns: true if it was successfully added
237  */
238 gboolean 
239 gst_dpman_add_required_dparam_array (GstDParamManager *dpman, 
240                                      GParamSpec *param_spec,
241                                      gchar *unit_name,
242                                      gpointer update_data)
243 {
244         GstDParamWrapper* dpwrap;
245
246         g_return_val_if_fail (dpman != NULL, FALSE);
247         g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE);
248         g_return_val_if_fail (update_data != NULL, FALSE);
249
250         dpwrap = gst_dpman_new_wrapper(dpman, param_spec, unit_name, GST_DPMAN_ARRAY);
251
252         g_return_val_if_fail (dpwrap != NULL, FALSE);
253
254         GST_DEBUG(GST_CAT_PARAMS,"adding required array dparam '%s'", g_param_spec_get_name(param_spec));
255
256         dpwrap->update_data = update_data;
257
258         g_signal_emit (G_OBJECT (dpman), gst_dpman_signals[NEW_REQUIRED_DPARAM], 0, g_param_spec_get_name(param_spec));
259
260         return TRUE;    
261 }
262
263 /**
264  * gst_dpman_remove_required_dparam:
265  * @dpman: GstDParamManager instance
266  * @dparam_name: the name of an existing parameter
267  *
268  */
269 void 
270 gst_dpman_remove_required_dparam (GstDParamManager *dpman, gchar *dparam_name)
271 {
272         GstDParamWrapper* dpwrap;
273
274         g_return_if_fail (dpman != NULL);
275         g_return_if_fail (GST_IS_DPMAN (dpman));
276         g_return_if_fail (dparam_name != NULL);
277
278         dpwrap = gst_dpman_get_wrapper(dpman, dparam_name);
279         
280         g_return_if_fail(dpwrap != NULL);
281         g_return_if_fail(dpwrap->dparam == NULL);
282
283         GST_DEBUG(GST_CAT_PARAMS, "removing required dparam: %s", dparam_name);
284         
285         g_hash_table_remove(GST_DPMAN_DPARAMS(dpman), dparam_name);
286         GST_DPMAN_DPARAMS_LIST(dpman) = g_list_remove(GST_DPMAN_DPARAMS_LIST(dpman), dpwrap);
287
288         g_free(dpwrap->value);
289         g_free(dpwrap);
290 }
291
292 /**
293  * gst_dpman_attach_dparam:
294  * @dpman: GstDParamManager instance
295  * @dparam_name: a name previously added with gst_dpman_add_required_dparam
296  * @dparam: GstDParam instance to attach
297  *
298  * Returns: true if it was successfully attached
299  */
300 gboolean 
301 gst_dpman_attach_dparam (GstDParamManager *dpman, gchar *dparam_name, GstDParam *dparam)
302 {
303         GstDParamWrapper* dpwrap;
304
305         g_return_val_if_fail (dpman != NULL, FALSE);
306         g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE);
307         g_return_val_if_fail (dparam_name != NULL, FALSE);
308         g_return_val_if_fail (dparam != NULL, FALSE);
309         g_return_val_if_fail (GST_IS_DPARAM (dparam), FALSE);
310         g_return_val_if_fail (dparam != NULL, FALSE);
311
312         dpwrap = gst_dpman_get_wrapper(dpman, dparam_name);
313
314         g_return_val_if_fail(dpwrap != NULL, FALSE);
315         g_return_val_if_fail(dpwrap->value != NULL, FALSE);
316
317         dpwrap->dparam = dparam;
318         gst_dparam_attach(dparam, dpman, dpwrap->param_spec, dpwrap->unit_name);
319
320         return TRUE;
321 }
322
323 /**
324  * gst_dpman_detach_dparam:
325  * @dpman: GstDParamManager instance
326  * @dparam_name: the name of a parameter with a previously attached GstDParam
327  *
328  */
329 void 
330 gst_dpman_detach_dparam (GstDParamManager *dpman, gchar *dparam_name)
331 {
332         GstDParamWrapper* dpwrap;
333
334         g_return_if_fail (dpman != NULL);
335         g_return_if_fail (GST_IS_DPMAN (dpman));
336         g_return_if_fail (dparam_name != NULL);
337         
338         dpwrap = gst_dpman_get_wrapper(dpman, dparam_name);
339
340         g_return_if_fail(dpwrap);
341         
342         gst_dparam_detach(dpwrap->dparam);
343         dpwrap->dparam = NULL;
344         
345 }
346
347 /**
348  * gst_dpman_get_dparam:
349  * @dpman: GstDParamManager instance
350  * @name: the name of an existing dparam instance
351  *
352  * Returns: the dparam with the given name - or NULL otherwise
353  */
354 GstDParam *
355 gst_dpman_get_dparam (GstDParamManager *dpman, gchar *name)
356 {
357         GstDParamWrapper* dpwrap;
358
359         g_return_val_if_fail (dpman != NULL, NULL);
360         g_return_val_if_fail (GST_IS_DPMAN (dpman), NULL);
361         g_return_val_if_fail (name != NULL, NULL);
362         
363         dpwrap = g_hash_table_lookup(GST_DPMAN_DPARAMS(dpman), name);
364         g_return_val_if_fail (dpwrap != NULL, NULL);
365         
366         return dpwrap->dparam;
367 }
368
369 /**
370  * gst_dpman_get_dparam_type:
371  * @dpman: GstDParamManager instance
372  * @name: the name of dparam
373  *
374  * Returns: the type that this dparam requires/uses
375  */
376 GType
377 gst_dpman_get_dparam_type (GstDParamManager *dpman, gchar *name)
378 {
379         GstDParamWrapper* dpwrap;
380
381         g_return_val_if_fail (dpman != NULL, 0);
382         g_return_val_if_fail (GST_IS_DPMAN (dpman), 0);
383         g_return_val_if_fail (name != NULL, 0);
384         
385         dpwrap = g_hash_table_lookup(GST_DPMAN_DPARAMS(dpman), name);
386         g_return_val_if_fail (dpwrap != NULL, 0);
387         
388         return G_VALUE_TYPE(dpwrap->value);
389 }
390
391 GParamSpec**
392 gst_dpman_list_dparam_specs(GstDParamManager *dpman)
393 {
394         GstDParamWrapper* dpwrap;
395         GList *dwraps;
396         GParamSpec** param_specs;
397         guint x = 0;
398
399         g_return_val_if_fail (dpman != NULL, NULL);
400         g_return_val_if_fail (GST_IS_DPMAN (dpman), NULL);
401         
402         dwraps = GST_DPMAN_DPARAMS_LIST(dpman);
403
404         param_specs = g_new0(GParamSpec*, g_list_length(dwraps) + 1);
405         
406         while (dwraps){
407                 dpwrap = (GstDParamWrapper*)dwraps->data;
408                 param_specs[x++] = dpwrap->param_spec;
409                 dwraps = g_list_next(dwraps);
410         }
411         return param_specs;
412 }
413
414 GParamSpec*
415 gst_dpman_get_param_spec (GstDParamManager *dpman, gchar *dparam_name)
416 {
417         GstDParamWrapper* dpwrap;
418
419         g_return_val_if_fail (dpman != NULL, NULL);
420         g_return_val_if_fail (GST_IS_DPMAN (dpman), NULL);
421         g_return_val_if_fail (dparam_name != NULL, NULL);
422
423         dpwrap = gst_dpman_get_wrapper(dpman, dparam_name);
424         return dpwrap->param_spec;
425 }
426
427 void
428 gst_dpman_set_rate (GstDParamManager *dpman, gint rate)
429 {
430         g_return_if_fail (GST_IS_DPMAN (dpman));
431         GST_DPMAN_RATE(dpman) = rate;
432 }
433
434 /**
435  * gst_dpman_register_mode
436  * @klass: GstDParamManagerClass class instance
437  * @modename: the unique name of the new mode
438  * @preprocessfunc: the function which will be called before each buffer is processed
439  * @processfunc: the function which may be called throughout the processing of a buffer
440  * @setupfunc: the function which initialises the mode when activated
441  * @teardownfunc: the function which frees any resources the mode uses
442  *
443  */
444 void
445 gst_dpman_register_mode (GstDParamManagerClass *klass,
446                          gchar *modename, 
447                          GstDPMModePreProcessFunction preprocessfunc,
448                          GstDPMModeProcessFunction processfunc,
449                          GstDPMModeSetupFunction setupfunc,
450                          GstDPMModeTeardownFunction teardownfunc)
451 {
452         GstDPMMode *mode;
453
454         g_return_if_fail (klass != NULL);
455         g_return_if_fail (modename != NULL);
456         g_return_if_fail (GST_IS_DPMAN_CLASS (klass));
457         
458         mode = g_new0(GstDPMMode,1);
459
460         mode->preprocessfunc = preprocessfunc;
461         mode->processfunc = processfunc;
462         mode->setupfunc = setupfunc;
463         mode->teardownfunc = teardownfunc;
464         
465         g_hash_table_insert(klass->modes, modename, mode);
466         GST_DEBUG(GST_CAT_PARAMS, "mode '%s' registered", modename);
467 }
468
469 /**
470  * gst_dpman_set_mode
471  * @dpman: GstDParamManager instance
472  * @modename: the name of the mode to use
473  *
474  * Returns: TRUE if the mode was set, FALSE otherwise
475  */
476 gboolean
477 gst_dpman_set_mode(GstDParamManager *dpman, gchar *modename)
478 {
479         GstDPMMode *mode=NULL;
480         GstDParamManagerClass *oclass;
481         
482         g_return_val_if_fail (dpman != NULL, FALSE);
483         g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE);
484         g_return_val_if_fail (modename != NULL, FALSE);
485
486         oclass = (GstDParamManagerClass*)(G_OBJECT_GET_CLASS(dpman));
487         
488         mode = g_hash_table_lookup(oclass->modes, modename);
489         g_return_val_if_fail (mode != NULL, FALSE);
490         
491         if (GST_DPMAN_MODE(dpman) == mode) {
492                 GST_DEBUG(GST_CAT_PARAMS, "mode %s already set", modename);
493                 return TRUE;
494         }
495         
496         GST_DEBUG(GST_CAT_PARAMS, "setting mode to %s", modename);
497         if (GST_DPMAN_MODE(dpman) && GST_DPMAN_TEARDOWNFUNC(dpman)){
498                 GST_DPMAN_TEARDOWNFUNC(dpman)(dpman);
499         }
500         
501         GST_DPMAN_MODE(dpman) = mode;
502
503         if (GST_DPMAN_SETUPFUNC(dpman)){
504                 GST_DPMAN_SETUPFUNC(dpman)(dpman);
505         }
506         
507         return TRUE;
508 }
509
510 /**
511  * gst_dpman_set_parent
512  * @dpman: GstDParamManager instance
513  * @parent: the element that this GstDParamManager belongs to
514  *
515  */
516 void
517 gst_dpman_set_parent (GstDParamManager *dpman, GstElement *parent)
518 {
519         g_return_if_fail (dpman != NULL);
520         g_return_if_fail (GST_IS_DPMAN (dpman));
521         g_return_if_fail (parent != NULL);
522         g_return_if_fail (GST_IS_ELEMENT (parent));
523
524         g_hash_table_insert(_element_registry, parent, dpman);
525         gst_object_set_parent (GST_OBJECT (dpman), GST_OBJECT(parent));
526         g_signal_connect(G_OBJECT(parent), "state_change", 
527                          G_CALLBACK (gst_dpman_state_change), dpman);
528 }
529
530 /**
531  * gst_dpman_get_manager
532  * @parent: the element that the desired GstDParamManager belongs to
533  *
534  * Returns: the GstDParamManager which belongs to this element or NULL
535  * if it doesn't exist
536  */
537 GstDParamManager *
538 gst_dpman_get_manager (GstElement *parent)
539 {
540         GstDParamManager *dpman;
541         g_return_val_if_fail (parent != NULL, NULL);
542         g_return_val_if_fail (GST_IS_ELEMENT (parent), NULL);
543         
544         dpman = (GstDParamManager*)g_hash_table_lookup(_element_registry, parent);
545         return dpman;
546 }
547
548 /**
549  * gst_dpman_bypass_dparam:
550  * @dpman: GstDParamManager instance
551  * @dparam_name: the name of dparam
552  *
553  * If a dparam is attached to this dparam_name, it will be detached
554  * and a warning will be issued. This should be called in the _set_property
555  * function of an element if the value it changes is also changed by a dparam.
556  * 
557  */
558 void
559 gst_dpman_bypass_dparam(GstDParamManager *dpman, gchar *dparam_name)
560 {
561         GstDParamWrapper* dpwrap;
562         
563         g_return_if_fail (dpman != NULL);
564         g_return_if_fail (GST_IS_DPMAN (dpman));
565         g_return_if_fail (dparam_name != NULL);
566                 
567         dpwrap = gst_dpman_get_wrapper(dpman, dparam_name);
568         g_return_if_fail (dpwrap != NULL);
569         
570         if (dpwrap->dparam != NULL){
571                 g_warning("Bypassing attached dparam '%s'. It will be detached", dparam_name);
572                 gst_dpman_detach_dparam(dpman, dparam_name);
573         }
574 }
575
576 static GstDParamWrapper* 
577 gst_dpman_get_wrapper(GstDParamManager *dpman, gchar *dparam_name)
578 {
579         g_return_val_if_fail (dpman != NULL, NULL);
580         g_return_val_if_fail (GST_IS_DPMAN (dpman), NULL);
581         g_return_val_if_fail (dparam_name != NULL, NULL);
582         
583         return g_hash_table_lookup(GST_DPMAN_DPARAMS(dpman), dparam_name);
584 }
585
586 static GstDParamWrapper* 
587 gst_dpman_new_wrapper(GstDParamManager *dpman, 
588                       GParamSpec *param_spec, 
589                       gchar *unit_name, 
590                       GstDPMUpdateMethod update_method)
591 {
592         GstDParamWrapper* dpwrap;
593         gchar *dparam_name;
594
595         g_return_val_if_fail (dpman != NULL, NULL);
596         g_return_val_if_fail (GST_IS_DPMAN (dpman), NULL);
597         g_return_val_if_fail (param_spec != NULL, NULL);
598         g_return_val_if_fail (gst_unitconv_unit_exists(unit_name), NULL);
599
600         dparam_name = g_strdup(g_param_spec_get_name(param_spec));
601         g_return_val_if_fail(gst_dpman_get_wrapper(dpman, dparam_name) == NULL, NULL);
602
603         dpwrap = g_new0(GstDParamWrapper,1);
604         dpwrap->update_method = update_method;
605         dpwrap->value = g_new0(GValue,1);
606         g_value_init(dpwrap->value, G_PARAM_SPEC_VALUE_TYPE(param_spec));
607         dpwrap->param_spec = param_spec;
608         dpwrap->unit_name = unit_name;
609         
610         g_hash_table_insert(GST_DPMAN_DPARAMS(dpman), dparam_name, dpwrap);
611         GST_DPMAN_DPARAMS_LIST(dpman) = g_list_append(GST_DPMAN_DPARAMS_LIST(dpman), dpwrap);
612         
613         return dpwrap;  
614 }
615
616
617 static void 
618 gst_dpman_state_change (GstElement *element, gint old_state, gint new_state, GstDParamManager *dpman)
619 {
620         GList *dwraps;
621         GstDParam *dparam;
622         GstDParamWrapper *dpwrap;
623
624         g_return_if_fail (dpman != NULL);
625         g_return_if_fail (GST_IS_DPMAN (dpman));
626         
627         if (new_state == GST_STATE_PLAYING){
628                 GST_DEBUG(GST_CAT_PARAMS, "initialising params");
629
630                         
631                 /* force all params to be updated */
632                 dwraps = GST_DPMAN_DPARAMS_LIST(dpman);
633                 while (dwraps){
634                         dpwrap = (GstDParamWrapper*)dwraps->data;
635                         dparam = dpwrap->dparam;
636                         
637                         if (dparam){
638                                 GST_DPARAM_READY_FOR_UPDATE(dparam) = TRUE;
639                                 GST_DPARAM_NEXT_UPDATE_TIMESTAMP(dparam) = 0LL;
640                         }
641                         /* some dparams treat the first update after the pipeline starts differently */
642                         dpwrap->update_info = GST_DPARAM_UPDATE_FIRST;
643                         dwraps = g_list_next(dwraps);
644                 }
645         }
646 }
647
648 static inline void
649 gst_dpman_inline_direct_update(GValue *value, gpointer data){
650         switch (G_VALUE_TYPE(value)){
651                 case G_TYPE_INT:
652                         *(gint*)data = g_value_get_int(value);
653                         break;
654                 case G_TYPE_INT64:
655                         *(gint64*)data = g_value_get_int64(value);
656                         break;
657                 case G_TYPE_FLOAT:
658                         *(gfloat*)data = g_value_get_float(value);
659                         break;
660                 default:
661                         break;
662         }
663 }
664
665 static gboolean 
666 gst_dpman_preprocess_synchronous(GstDParamManager *dpman, guint frames, gint64 timestamp)
667 {
668         GList *dwraps;
669         GstDParamWrapper *dpwrap;
670
671         g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE);
672
673         /* this basically means don't call GST_DPMAN_PREPROCESS at all */
674         dpman->next_update_frame = frames;
675         dpman->frames_to_process = frames;
676
677         /* now check whether any dparams are ready for an update */
678         dwraps = GST_DPMAN_DPARAMS_LIST(dpman);
679         while (dwraps){
680                 dpwrap = (GstDParamWrapper*)dwraps->data;
681                 
682                 if (dpwrap->dparam && 
683                     GST_DPARAM_READY_FOR_UPDATE(dpwrap->dparam) && 
684                     GST_DPARAM_NEXT_UPDATE_TIMESTAMP(dpwrap->dparam) <= timestamp){
685
686                         switch (dpwrap->update_method) {
687                                 
688                                 /* direct method - set the value directly in the struct of the element */
689                                 case GST_DPMAN_DIRECT:
690                                         GST_DPARAM_DO_UPDATE(dpwrap->dparam, timestamp, dpwrap->value, dpwrap->update_info);
691                                         GST_DEBUG(GST_CAT_PARAMS, "doing direct update");
692
693                                         gst_dpman_inline_direct_update(dpwrap->value, dpwrap->update_data);
694                                         break;
695
696                                 /* callback method - call the element's callback so it can do what it likes */
697                                 case GST_DPMAN_CALLBACK:
698                                         GST_DPARAM_DO_UPDATE(dpwrap->dparam, timestamp, dpwrap->value, dpwrap->update_info);
699                                         GST_DEBUG(GST_CAT_PARAMS, "doing callback update");
700                                         
701                                         GST_DPMAN_CALLBACK_UPDATE(dpwrap, dpwrap->value);
702                                         break;
703
704                                 case GST_DPMAN_ARRAY:
705                                         /* FIXME do array method checking here */
706                                         break;
707                                 default:
708                                         break;
709                         }
710
711                         if (dpwrap->update_info == GST_DPARAM_UPDATE_FIRST){
712                                 /* it is not the first update anymore */
713                                 dpwrap->update_info = GST_DPARAM_UPDATE_NORMAL;
714                         }
715                 }
716                 dwraps = g_list_next(dwraps);
717         }
718
719
720         return FALSE;
721 }
722
723 static gint 
724 gst_dpman_dpwrap_compare (const GstDParamWrapper *a, const GstDParamWrapper *b)
725 {
726         if (a->next_update_frame > b->next_update_frame) return 1;
727         return (a->next_update_frame < b->next_update_frame) ? -1 : 0;
728 }
729
730 static gboolean 
731 gst_dpman_preprocess_asynchronous(GstDParamManager *dpman, guint frames, gint64 timestamp)
732 {
733         GList *dwraps;
734         GstDParamWrapper *dpwrap;
735         gint64 current_time;
736         gboolean updates_pending;
737
738         g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE);
739
740
741         if (GST_DPMAN_RATE(dpman) == 0){
742                 g_warning("The element hasn't given GstDParamManager a frame rate");
743                 return FALSE;
744         }
745         dpman->rate_ratio = (guint)(1000000000LL / (gint64)GST_DPMAN_RATE(dpman));
746
747         dpman->time_buffer_starts = timestamp;
748         dpman->time_buffer_ends = timestamp + ((gint64)frames * (gint64)dpman->rate_ratio);
749         dpman->num_frames = frames;
750
751         updates_pending = FALSE;
752
753         /* now check whether any dparams are ready for an update */
754         dwraps = GST_DPMAN_DPARAMS_LIST(dpman);
755         while (dwraps){
756                 dpwrap = (GstDParamWrapper*)dwraps->data;
757                 
758                 dpwrap->next_update_frame = frames;
759
760                 if (dpwrap->dparam && 
761                     GST_DPARAM_READY_FOR_UPDATE(dpwrap->dparam)){
762
763                         current_time = GST_DPARAM_NEXT_UPDATE_TIMESTAMP(dpwrap->dparam);
764                         if (current_time > dpman->time_buffer_ends){
765                                 /* not due for an update in this buffer */
766                                 dwraps = g_list_next(dwraps);
767                                 continue;
768                         }
769                         if (current_time < timestamp){
770                                 current_time = timestamp;
771                         }
772
773                         if (current_time == timestamp){
774                                 /* we are overdue for an update. lets do it now */
775
776                                 GST_DPARAM_DO_UPDATE(dpwrap->dparam, current_time, dpwrap->value, dpwrap->update_info);
777
778                                 if (dpwrap->update_info == GST_DPARAM_UPDATE_FIRST){
779                                         /* it is not the first update anymore */
780                                         dpwrap->update_info = GST_DPARAM_UPDATE_NORMAL;
781                                 }
782
783                                 switch (dpwrap->update_method) {
784
785                                         /* direct method - set the value directly in the struct of the element */
786                                         case GST_DPMAN_DIRECT:
787                                                 GST_DEBUG(GST_CAT_PARAMS, "doing direct update");
788                                                 gst_dpman_inline_direct_update(dpwrap->value, dpwrap->update_data);
789                                                 break;
790
791                                         /* callback method - call the element's callback so it can do what it likes */
792                                         case GST_DPMAN_CALLBACK:
793                                                 GST_DEBUG(GST_CAT_PARAMS, "doing callback update");
794                                                 GST_DPMAN_CALLBACK_UPDATE(dpwrap, dpwrap->value);
795                                                 break;
796                                         default:
797                                                 break;
798                                 }
799
800                                 current_time = GST_DPARAM_NEXT_UPDATE_TIMESTAMP(dpwrap->dparam);
801
802                                 if (!GST_DPARAM_READY_FOR_UPDATE(dpwrap->dparam) || 
803                                     current_time > dpman->time_buffer_ends){
804                                         /* not due for an update in this buffer */
805                                         dwraps = g_list_next(dwraps);
806                                         continue;
807                                 }
808                         }
809
810                         dpwrap->next_update_frame = (guint)(current_time - timestamp) / dpman->rate_ratio;
811                         updates_pending = TRUE;
812
813                         GST_DEBUG(GST_CAT_PARAMS, "timestamp start: %"
814                                   G_GINT64_FORMAT " end: %"
815                                   G_GINT64_FORMAT " current: %"
816                                   G_GINT64_FORMAT, 
817                                   timestamp, dpman->time_buffer_ends, current_time);
818
819                 }
820                 dwraps = g_list_next(dwraps);
821         }
822         if (updates_pending){
823                 GST_DPMAN_DPARAMS_LIST(dpman) = g_list_sort(GST_DPMAN_DPARAMS_LIST(dpman), (GCompareFunc)gst_dpman_dpwrap_compare); 
824                 dwraps = GST_DPMAN_DPARAMS_LIST(dpman);
825                 dpwrap = (GstDParamWrapper*)dwraps->data;
826
827                 dpman->next_update_frame = dpwrap->next_update_frame;
828                 dpman->frames_to_process = dpman->next_update_frame;
829
830                 GST_DEBUG(GST_CAT_PARAMS, "next update frame %u, frames to process %u", dpman->next_update_frame, dpman->frames_to_process);
831                 return TRUE;
832         }
833         
834         dpman->next_update_frame = frames;
835         dpman->frames_to_process = frames;
836         return FALSE;
837 }
838
839 static gboolean 
840 gst_dpman_process_asynchronous(GstDParamManager *dpman, guint frame_count)
841 {
842         GstDParamWrapper *dpwrap;
843         GList *dwraps;
844         gint64 current_time;
845         gboolean needs_resort = FALSE;
846
847         dwraps = GST_DPMAN_DPARAMS_LIST(dpman);
848         dpwrap = (GstDParamWrapper*)dwraps->data;
849
850         GST_DEBUG(GST_CAT_PARAMS, "in gst_dpman_process_asynchronous");
851
852         if (frame_count >= dpman->num_frames){
853                 g_warning("there is no more buffer to process");
854                 dpman->next_update_frame = dpman->num_frames;
855                 dpman->frames_to_process = 0;
856                 return FALSE;
857         }
858
859         if (frame_count != dpwrap->next_update_frame){
860                 g_warning("frame count %u does not match update frame %u", 
861                           frame_count, dpwrap->next_update_frame);
862         }
863
864         while (dpwrap){
865
866                 current_time = GST_DPARAM_NEXT_UPDATE_TIMESTAMP(dpwrap->dparam);
867                 GST_DPARAM_DO_UPDATE(dpwrap->dparam, current_time, dpwrap->value, dpwrap->update_info);
868                 switch (dpwrap->update_method) {
869
870                         /* direct method - set the value directly in the struct of the element */
871                         case GST_DPMAN_DIRECT:
872                                 GST_DEBUG(GST_CAT_PARAMS, "doing direct update");
873                                 gst_dpman_inline_direct_update(dpwrap->value, dpwrap->update_data);
874                                 break;
875
876                         /* callback method - call the element's callback so it can do what it likes */
877                         case GST_DPMAN_CALLBACK:
878                                 GST_DEBUG(GST_CAT_PARAMS, "doing callback update");
879                                 GST_DPMAN_CALLBACK_UPDATE(dpwrap, dpwrap->value);
880                                 break;
881                         default:
882                                 break;
883                 }
884
885                 dpwrap->next_update_frame = dpman->num_frames;
886                 needs_resort = TRUE;
887
888                 if(GST_DPARAM_READY_FOR_UPDATE(dpwrap->dparam)){
889                         current_time = GST_DPARAM_NEXT_UPDATE_TIMESTAMP(dpwrap->dparam);
890                         if (current_time <= dpman->time_buffer_ends){
891                                 dpwrap->next_update_frame = (guint)(current_time - dpman->time_buffer_starts) / dpman->rate_ratio;
892                         }
893                 }
894
895                 if ((dwraps = g_list_next(dwraps))){
896                         dpwrap = (GstDParamWrapper*)dwraps->data;
897                         if (frame_count == dpwrap->next_update_frame){
898                                 continue;
899                         }
900                 }
901                 dpwrap = NULL;
902         }
903
904         if (needs_resort && g_list_length(GST_DPMAN_DPARAMS_LIST(dpman)) > 1){
905                 GST_DPMAN_DPARAMS_LIST(dpman) = g_list_sort(GST_DPMAN_DPARAMS_LIST(dpman), (GCompareFunc)gst_dpman_dpwrap_compare); 
906         }
907         
908         dwraps = GST_DPMAN_DPARAMS_LIST(dpman);
909         dpwrap = (GstDParamWrapper*)dwraps->data;
910
911         if (dpwrap->next_update_frame == dpman->num_frames){
912                 dpman->next_update_frame = dpman->num_frames;
913                 dpman->frames_to_process = dpman->num_frames - frame_count;
914                 GST_DEBUG(GST_CAT_PARAMS, "no more updates, frames to process %u", dpman->frames_to_process);
915         }
916         else {
917                 dpman->next_update_frame = dpwrap->next_update_frame;
918                 dpman->frames_to_process = dpman->next_update_frame - frame_count;
919                 GST_DEBUG(GST_CAT_PARAMS, "next update frame %u, frames to process %u", dpman->next_update_frame, dpman->frames_to_process);
920         }
921
922         return TRUE;
923 }
924
925 static gboolean 
926 gst_dpman_preprocess_noop(GstDParamManager *dpman, guint frames, gint64 timestamp)
927 {
928         dpman->next_update_frame = frames;
929         dpman->frames_to_process = frames;
930         return FALSE;
931 }
932
933 static gboolean 
934 gst_dpman_process_noop(GstDParamManager *dpman, guint frame_count)
935 {
936         g_warning("gst_dpman_process_noop should never be called - something might be wrong with your processing loop");
937         return FALSE;
938 }
939
940 static void 
941 gst_dpman_setup_synchronous(GstDParamManager *dpman){
942         g_return_if_fail (GST_IS_DPMAN (dpman));
943
944 }
945
946 static void 
947 gst_dpman_setup_asynchronous(GstDParamManager *dpman){
948         g_return_if_fail (GST_IS_DPMAN (dpman));
949
950 }
951
952 static void 
953 gst_dpman_setup_disabled(GstDParamManager *dpman){
954         g_return_if_fail (GST_IS_DPMAN (dpman));
955
956 }
957
958 static void 
959 gst_dpman_teardown_synchronous(GstDParamManager *dpman){
960         g_return_if_fail (GST_IS_DPMAN (dpman));
961
962 }
963
964 static void 
965 gst_dpman_teardown_asynchronous(GstDParamManager *dpman){
966         g_return_if_fail (GST_IS_DPMAN (dpman));
967         
968 }
969
970 static void 
971 gst_dpman_teardown_disabled(GstDParamManager *dpman){
972         g_return_if_fail (GST_IS_DPMAN (dpman));
973
974 }
975