1 | /* GStreamer |
---|
2 | * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> |
---|
3 | * 2000 Wim Taymans <wtay@chello.be> |
---|
4 | * |
---|
5 | * gstelement.c: The base element, all elements derive from this |
---|
6 | * |
---|
7 | * This library is free software; you can redistribute it and/or |
---|
8 | * modify it under the terms of the GNU Library General Public |
---|
9 | * License as published by the Free Software Foundation; either |
---|
10 | * version 2 of the License, or (at your option) any later version. |
---|
11 | * |
---|
12 | * This library is distributed in the hope that it will be useful, |
---|
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
15 | * Library General Public License for more details. |
---|
16 | * |
---|
17 | * You should have received a copy of the GNU Library General Public |
---|
18 | * License along with this library; if not, write to the |
---|
19 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
20 | * Boston, MA 02111-1307, USA. |
---|
21 | */ |
---|
22 | |
---|
23 | #include "gst_private.h" |
---|
24 | #include <glib.h> |
---|
25 | #include <stdarg.h> |
---|
26 | #include <gobject/gvaluecollector.h> |
---|
27 | |
---|
28 | #include "gstelement.h" |
---|
29 | #include "gstbin.h" |
---|
30 | #include "gstmarshal.h" |
---|
31 | #include "gsterror.h" |
---|
32 | #include "gstscheduler.h" |
---|
33 | #include "gstevent.h" |
---|
34 | #include "gstutils.h" |
---|
35 | #include "gstinfo.h" |
---|
36 | #include "gst-i18n-lib.h" |
---|
37 | |
---|
38 | /* Element signals and args */ |
---|
39 | enum |
---|
40 | { |
---|
41 | STATE_CHANGE, |
---|
42 | NEW_PAD, |
---|
43 | PAD_REMOVED, |
---|
44 | ERROR, |
---|
45 | EOS, |
---|
46 | FOUND_TAG, |
---|
47 | NO_MORE_PADS, |
---|
48 | /* add more above */ |
---|
49 | LAST_SIGNAL |
---|
50 | }; |
---|
51 | |
---|
52 | enum |
---|
53 | { |
---|
54 | ARG_0 |
---|
55 | /* FILL ME */ |
---|
56 | }; |
---|
57 | |
---|
58 | extern void __gst_element_details_clear (GstElementDetails * dp); |
---|
59 | extern void __gst_element_details_copy (GstElementDetails * dest, |
---|
60 | const GstElementDetails * src); |
---|
61 | |
---|
62 | static void gst_element_class_init (GstElementClass * klass); |
---|
63 | static void gst_element_init (GstElement * element); |
---|
64 | static void gst_element_base_class_init (gpointer g_class); |
---|
65 | static void gst_element_base_class_finalize (gpointer g_class); |
---|
66 | |
---|
67 | static void gst_element_real_set_property (GObject * object, guint prop_id, |
---|
68 | const GValue * value, GParamSpec * pspec); |
---|
69 | static void gst_element_real_get_property (GObject * object, guint prop_id, |
---|
70 | GValue * value, GParamSpec * pspec); |
---|
71 | |
---|
72 | static void gst_element_dispose (GObject * object); |
---|
73 | |
---|
74 | static GstElementStateReturn gst_element_change_state (GstElement * element); |
---|
75 | static void gst_element_error_func (GstElement * element, GstElement * source, |
---|
76 | GError * error, gchar * debug); |
---|
77 | static void gst_element_found_tag_func (GstElement * element, |
---|
78 | GstElement * source, const GstTagList * tag_list); |
---|
79 | static GstElementStateReturn gst_element_set_state_func (GstElement * element, |
---|
80 | GstElementState state); |
---|
81 | |
---|
82 | #ifndef GST_DISABLE_LOADSAVE |
---|
83 | static xmlNodePtr gst_element_save_thyself (GstObject * object, |
---|
84 | xmlNodePtr parent); |
---|
85 | static void gst_element_restore_thyself (GstObject * parent, xmlNodePtr self); |
---|
86 | #endif |
---|
87 | |
---|
88 | GType _gst_element_type = 0; |
---|
89 | |
---|
90 | static GstObjectClass *parent_class = NULL; |
---|
91 | static guint gst_element_signals[LAST_SIGNAL] = { 0 }; |
---|
92 | |
---|
93 | GType |
---|
94 | gst_element_get_type (void) |
---|
95 | { |
---|
96 | if (!_gst_element_type) { |
---|
97 | static const GTypeInfo element_info = { |
---|
98 | sizeof (GstElementClass), |
---|
99 | gst_element_base_class_init, |
---|
100 | gst_element_base_class_finalize, |
---|
101 | (GClassInitFunc) gst_element_class_init, |
---|
102 | NULL, |
---|
103 | NULL, |
---|
104 | sizeof (GstElement), |
---|
105 | 0, |
---|
106 | (GInstanceInitFunc) gst_element_init, |
---|
107 | NULL |
---|
108 | }; |
---|
109 | |
---|
110 | _gst_element_type = g_type_register_static (GST_TYPE_OBJECT, "GstElement", |
---|
111 | &element_info, G_TYPE_FLAG_ABSTRACT); |
---|
112 | } |
---|
113 | return _gst_element_type; |
---|
114 | } |
---|
115 | |
---|
116 | static void |
---|
117 | gst_element_class_init (GstElementClass * klass) |
---|
118 | { |
---|
119 | GObjectClass *gobject_class; |
---|
120 | GstObjectClass *gstobject_class; |
---|
121 | |
---|
122 | gobject_class = (GObjectClass *) klass; |
---|
123 | gstobject_class = (GstObjectClass *) klass; |
---|
124 | |
---|
125 | parent_class = g_type_class_ref (GST_TYPE_OBJECT); |
---|
126 | |
---|
127 | /** |
---|
128 | * GstElement::state-change: |
---|
129 | * @gstelement: the object which received the signal |
---|
130 | * @int: |
---|
131 | * @int: |
---|
132 | * |
---|
133 | * the #GstElementState of the element has been changed |
---|
134 | */ |
---|
135 | gst_element_signals[STATE_CHANGE] = |
---|
136 | g_signal_new ("state-change", G_TYPE_FROM_CLASS (klass), |
---|
137 | G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstElementClass, state_change), NULL, |
---|
138 | NULL, gst_marshal_VOID__INT_INT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); |
---|
139 | /** |
---|
140 | * GstElement::new-pad: |
---|
141 | * @gstelement: the object which received the signal |
---|
142 | * @object: |
---|
143 | * |
---|
144 | * a new #GstPad has been added to the element |
---|
145 | */ |
---|
146 | gst_element_signals[NEW_PAD] = |
---|
147 | g_signal_new ("new-pad", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, |
---|
148 | G_STRUCT_OFFSET (GstElementClass, new_pad), NULL, NULL, |
---|
149 | gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); |
---|
150 | /** |
---|
151 | * GstElement::pad-removed: |
---|
152 | * @gstelement: the object which received the signal |
---|
153 | * @object: |
---|
154 | * |
---|
155 | * a #GstPad has been removed from the element |
---|
156 | */ |
---|
157 | gst_element_signals[PAD_REMOVED] = |
---|
158 | g_signal_new ("pad-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, |
---|
159 | G_STRUCT_OFFSET (GstElementClass, pad_removed), NULL, NULL, |
---|
160 | gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); |
---|
161 | /** |
---|
162 | * GstElement::error: |
---|
163 | * @gstelement: the object which received the signal |
---|
164 | * @element: |
---|
165 | * @error: |
---|
166 | * @message: |
---|
167 | * |
---|
168 | * a #GstError has occured during data processing |
---|
169 | */ |
---|
170 | gst_element_signals[ERROR] = |
---|
171 | g_signal_new ("error", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, |
---|
172 | G_STRUCT_OFFSET (GstElementClass, error), NULL, NULL, |
---|
173 | gst_marshal_VOID__OBJECT_BOXED_STRING, G_TYPE_NONE, 3, GST_TYPE_ELEMENT, |
---|
174 | GST_TYPE_G_ERROR, G_TYPE_STRING); |
---|
175 | /** |
---|
176 | * GstElement::eos: |
---|
177 | * @gstelement: the object which received the signal |
---|
178 | * |
---|
179 | * the end of the stream has been reached |
---|
180 | */ |
---|
181 | gst_element_signals[EOS] = |
---|
182 | g_signal_new ("eos", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, |
---|
183 | G_STRUCT_OFFSET (GstElementClass, eos), NULL, NULL, |
---|
184 | gst_marshal_VOID__VOID, G_TYPE_NONE, 0); |
---|
185 | /** |
---|
186 | * GstElement::found-tag: |
---|
187 | * @gstelement: the object which received the signal |
---|
188 | * @element: |
---|
189 | * @tags: |
---|
190 | * |
---|
191 | * tags for the incomming stream have been received |
---|
192 | */ |
---|
193 | gst_element_signals[FOUND_TAG] = |
---|
194 | g_signal_new ("found-tag", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, |
---|
195 | G_STRUCT_OFFSET (GstElementClass, found_tag), NULL, NULL, |
---|
196 | gst_marshal_VOID__OBJECT_BOXED, G_TYPE_NONE, 2, GST_TYPE_ELEMENT, |
---|
197 | GST_TYPE_TAG_LIST); |
---|
198 | /** |
---|
199 | * GstElement::no-more-pads: |
---|
200 | * @gstelement: the object which received the signal |
---|
201 | * |
---|
202 | * ? |
---|
203 | */ |
---|
204 | gst_element_signals[NO_MORE_PADS] = |
---|
205 | g_signal_new ("no-more-pads", G_TYPE_FROM_CLASS (klass), |
---|
206 | G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstElementClass, no_more_pads), NULL, |
---|
207 | NULL, gst_marshal_VOID__VOID, G_TYPE_NONE, 0); |
---|
208 | |
---|
209 | gobject_class->set_property = |
---|
210 | GST_DEBUG_FUNCPTR (gst_element_real_set_property); |
---|
211 | gobject_class->get_property = |
---|
212 | GST_DEBUG_FUNCPTR (gst_element_real_get_property); |
---|
213 | |
---|
214 | gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_element_dispose); |
---|
215 | |
---|
216 | #ifndef GST_DISABLE_LOADSAVE |
---|
217 | gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_element_save_thyself); |
---|
218 | gstobject_class->restore_thyself = |
---|
219 | GST_DEBUG_FUNCPTR (gst_element_restore_thyself); |
---|
220 | #endif |
---|
221 | |
---|
222 | klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state); |
---|
223 | klass->error = GST_DEBUG_FUNCPTR (gst_element_error_func); |
---|
224 | klass->found_tag = GST_DEBUG_FUNCPTR (gst_element_found_tag_func); |
---|
225 | klass->numpadtemplates = 0; |
---|
226 | klass->set_state = GST_DEBUG_FUNCPTR (gst_element_set_state_func); |
---|
227 | |
---|
228 | klass->elementfactory = NULL; |
---|
229 | } |
---|
230 | |
---|
231 | static void |
---|
232 | gst_element_base_class_init (gpointer g_class) |
---|
233 | { |
---|
234 | GObjectClass *gobject_class = G_OBJECT_CLASS (g_class); |
---|
235 | GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); |
---|
236 | |
---|
237 | |
---|
238 | gobject_class->set_property = |
---|
239 | GST_DEBUG_FUNCPTR (gst_element_real_set_property); |
---|
240 | gobject_class->get_property = |
---|
241 | GST_DEBUG_FUNCPTR (gst_element_real_get_property); |
---|
242 | |
---|
243 | memset (&element_class->details, 0, sizeof (GstElementDetails)); |
---|
244 | element_class->padtemplates = NULL; |
---|
245 | } |
---|
246 | |
---|
247 | static void |
---|
248 | gst_element_base_class_finalize (gpointer g_class) |
---|
249 | { |
---|
250 | GstElementClass *klass = GST_ELEMENT_CLASS (g_class); |
---|
251 | |
---|
252 | g_list_foreach (klass->padtemplates, (GFunc) gst_object_unref, NULL); |
---|
253 | g_list_free (klass->padtemplates); |
---|
254 | __gst_element_details_clear (&klass->details); |
---|
255 | } |
---|
256 | |
---|
257 | static void |
---|
258 | gst_element_init (GstElement * element) |
---|
259 | { |
---|
260 | element->current_state = GST_STATE_NULL; |
---|
261 | element->pending_state = GST_STATE_VOID_PENDING; |
---|
262 | element->numpads = 0; |
---|
263 | element->numsrcpads = 0; |
---|
264 | element->numsinkpads = 0; |
---|
265 | element->pads = NULL; |
---|
266 | element->loopfunc = NULL; |
---|
267 | element->sched = NULL; |
---|
268 | element->clock = NULL; |
---|
269 | element->sched_private = NULL; |
---|
270 | element->state_mutex = g_mutex_new (); |
---|
271 | element->state_cond = g_cond_new (); |
---|
272 | } |
---|
273 | |
---|
274 | static void |
---|
275 | gst_element_real_set_property (GObject * object, guint prop_id, |
---|
276 | const GValue * value, GParamSpec * pspec) |
---|
277 | { |
---|
278 | GstElementClass *oclass = GST_ELEMENT_GET_CLASS (object); |
---|
279 | |
---|
280 | if (oclass->set_property) |
---|
281 | (oclass->set_property) (object, prop_id, value, pspec); |
---|
282 | } |
---|
283 | |
---|
284 | static void |
---|
285 | gst_element_real_get_property (GObject * object, guint prop_id, GValue * value, |
---|
286 | GParamSpec * pspec) |
---|
287 | { |
---|
288 | GstElementClass *oclass = GST_ELEMENT_GET_CLASS (object); |
---|
289 | |
---|
290 | if (oclass->get_property) |
---|
291 | (oclass->get_property) (object, prop_id, value, pspec); |
---|
292 | } |
---|
293 | |
---|
294 | /** |
---|
295 | * gst_element_default_error: |
---|
296 | * @object: a #GObject that signalled the error. |
---|
297 | * @orig: the #GstObject that initiated the error. |
---|
298 | * @error: the GError. |
---|
299 | * @debug: an additional debug information string, or NULL. |
---|
300 | * |
---|
301 | * A default error signal callback to attach to an element. |
---|
302 | * The user data passed to the g_signal_connect is ignored. |
---|
303 | * |
---|
304 | * The default handler will simply print the error string using g_print. |
---|
305 | */ |
---|
306 | void |
---|
307 | gst_element_default_error (GObject * object, GstObject * source, GError * error, |
---|
308 | gchar * debug) |
---|
309 | { |
---|
310 | gchar *name = gst_object_get_path_string (source); |
---|
311 | |
---|
312 | g_print (_("ERROR: from element %s: %s\n"), name, error->message); |
---|
313 | if (debug) |
---|
314 | g_print (_("Additional debug info:\n%s\n"), debug); |
---|
315 | |
---|
316 | g_free (name); |
---|
317 | } |
---|
318 | |
---|
319 | typedef struct |
---|
320 | { |
---|
321 | const GParamSpec *pspec; |
---|
322 | GValue value; |
---|
323 | } |
---|
324 | prop_value_t; |
---|
325 | |
---|
326 | static void |
---|
327 | element_set_property (GstElement * element, const GParamSpec * pspec, |
---|
328 | const GValue * value) |
---|
329 | { |
---|
330 | prop_value_t *prop_value = g_new0 (prop_value_t, 1); |
---|
331 | |
---|
332 | prop_value->pspec = pspec; |
---|
333 | prop_value->value = *value; |
---|
334 | |
---|
335 | g_async_queue_push (element->prop_value_queue, prop_value); |
---|
336 | } |
---|
337 | |
---|
338 | static void |
---|
339 | element_get_property (GstElement * element, const GParamSpec * pspec, |
---|
340 | GValue * value) |
---|
341 | { |
---|
342 | g_mutex_lock (element->property_mutex); |
---|
343 | g_object_get_property ((GObject *) element, pspec->name, value); |
---|
344 | g_mutex_unlock (element->property_mutex); |
---|
345 | } |
---|
346 | |
---|
347 | static void |
---|
348 | gst_element_threadsafe_properties_pre_run (GstElement * element) |
---|
349 | { |
---|
350 | /* need to ref the object because we don't want to lose the object |
---|
351 | * before the post run function is called */ |
---|
352 | gst_object_ref (GST_OBJECT (element)); |
---|
353 | GST_DEBUG ("locking element %s", GST_OBJECT_NAME (element)); |
---|
354 | g_mutex_lock (element->property_mutex); |
---|
355 | gst_element_set_pending_properties (element); |
---|
356 | } |
---|
357 | |
---|
358 | static void |
---|
359 | gst_element_threadsafe_properties_post_run (GstElement * element) |
---|
360 | { |
---|
361 | GST_DEBUG ("unlocking element %s", GST_OBJECT_NAME (element)); |
---|
362 | g_mutex_unlock (element->property_mutex); |
---|
363 | gst_object_unref (GST_OBJECT (element)); |
---|
364 | } |
---|
365 | |
---|
366 | /** |
---|
367 | * gst_element_enable_threadsafe_properties: |
---|
368 | * @element: a #GstElement to enable threadsafe properties on. |
---|
369 | * |
---|
370 | * Installs an asynchronous queue, a mutex and pre- and post-run functions on |
---|
371 | * this element so that properties on the element can be set in a |
---|
372 | * threadsafe way. |
---|
373 | */ |
---|
374 | void |
---|
375 | gst_element_enable_threadsafe_properties (GstElement * element) |
---|
376 | { |
---|
377 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
378 | |
---|
379 | GST_FLAG_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES); |
---|
380 | element->pre_run_func = gst_element_threadsafe_properties_pre_run; |
---|
381 | element->post_run_func = gst_element_threadsafe_properties_post_run; |
---|
382 | if (!element->prop_value_queue) |
---|
383 | element->prop_value_queue = g_async_queue_new (); |
---|
384 | if (!element->property_mutex) |
---|
385 | element->property_mutex = g_mutex_new (); |
---|
386 | } |
---|
387 | |
---|
388 | /** |
---|
389 | * gst_element_disable_threadsafe_properties: |
---|
390 | * @element: a #GstElement to disable threadsafe properties on. |
---|
391 | * |
---|
392 | * Removes the threadsafe properties, post- and pre-run locks from |
---|
393 | * this element. |
---|
394 | */ |
---|
395 | void |
---|
396 | gst_element_disable_threadsafe_properties (GstElement * element) |
---|
397 | { |
---|
398 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
399 | |
---|
400 | GST_FLAG_UNSET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES); |
---|
401 | |
---|
402 | //element->pre_run_func = NULL; |
---|
403 | //element->post_run_func = NULL; |
---|
404 | /* let's keep around that async queue */ |
---|
405 | } |
---|
406 | |
---|
407 | /** |
---|
408 | * gst_element_set_pending_properties: |
---|
409 | * @element: a #GstElement to set the pending properties on. |
---|
410 | * |
---|
411 | * Sets all pending properties on the threadsafe properties enabled |
---|
412 | * element. |
---|
413 | */ |
---|
414 | void |
---|
415 | gst_element_set_pending_properties (GstElement * element) |
---|
416 | { |
---|
417 | prop_value_t *prop_value; |
---|
418 | |
---|
419 | while ((prop_value = g_async_queue_try_pop (element->prop_value_queue))) { |
---|
420 | g_object_set_property ((GObject *) element, prop_value->pspec->name, |
---|
421 | &prop_value->value); |
---|
422 | g_value_unset (&prop_value->value); |
---|
423 | g_free (prop_value); |
---|
424 | } |
---|
425 | } |
---|
426 | |
---|
427 | /* following 6 functions taken mostly from gobject.c */ |
---|
428 | |
---|
429 | /** |
---|
430 | * gst_element_set: |
---|
431 | * @element: a #GstElement to set properties on. |
---|
432 | * @first_property_name: the first property to set. |
---|
433 | * @...: value of the first property, and more properties to set, ending |
---|
434 | * with NULL. |
---|
435 | * |
---|
436 | * Sets properties on an element. If the element uses threadsafe properties, |
---|
437 | * they will be queued and set on the object when it is scheduled again. |
---|
438 | */ |
---|
439 | void |
---|
440 | gst_element_set (GstElement * element, const gchar * first_property_name, ...) |
---|
441 | { |
---|
442 | va_list var_args; |
---|
443 | |
---|
444 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
445 | |
---|
446 | va_start (var_args, first_property_name); |
---|
447 | gst_element_set_valist (element, first_property_name, var_args); |
---|
448 | va_end (var_args); |
---|
449 | } |
---|
450 | |
---|
451 | /** |
---|
452 | * gst_element_get: |
---|
453 | * @element: a #GstElement to get properties of. |
---|
454 | * @first_property_name: the first property to get. |
---|
455 | * @...: pointer to a variable to store the first property in, as well as |
---|
456 | * more properties to get, ending with NULL. |
---|
457 | * |
---|
458 | * Gets properties from an element. If the element uses threadsafe properties, |
---|
459 | * the element will be locked before getting the given properties. |
---|
460 | */ |
---|
461 | void |
---|
462 | gst_element_get (GstElement * element, const gchar * first_property_name, ...) |
---|
463 | { |
---|
464 | va_list var_args; |
---|
465 | |
---|
466 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
467 | |
---|
468 | va_start (var_args, first_property_name); |
---|
469 | gst_element_get_valist (element, first_property_name, var_args); |
---|
470 | va_end (var_args); |
---|
471 | } |
---|
472 | |
---|
473 | /** |
---|
474 | * gst_element_set_valist: |
---|
475 | * @element: a #GstElement to set properties on. |
---|
476 | * @first_property_name: the first property to set. |
---|
477 | * @var_args: the var_args list of other properties to get. |
---|
478 | * |
---|
479 | * Sets properties on an element. If the element uses threadsafe properties, |
---|
480 | * the property change will be put on the async queue. |
---|
481 | */ |
---|
482 | void |
---|
483 | gst_element_set_valist (GstElement * element, const gchar * first_property_name, |
---|
484 | va_list var_args) |
---|
485 | { |
---|
486 | const gchar *name; |
---|
487 | GObject *object; |
---|
488 | |
---|
489 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
490 | |
---|
491 | object = (GObject *) element; |
---|
492 | |
---|
493 | GST_CAT_DEBUG (GST_CAT_PROPERTIES, |
---|
494 | "setting valist of properties starting with %s on element %s", |
---|
495 | first_property_name, gst_element_get_name (element)); |
---|
496 | |
---|
497 | if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) { |
---|
498 | g_object_set_valist (object, first_property_name, var_args); |
---|
499 | return; |
---|
500 | } |
---|
501 | |
---|
502 | g_object_ref (object); |
---|
503 | |
---|
504 | name = first_property_name; |
---|
505 | |
---|
506 | while (name) { |
---|
507 | GValue value = { 0, }; |
---|
508 | GParamSpec *pspec; |
---|
509 | gchar *error = NULL; |
---|
510 | |
---|
511 | pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), name); |
---|
512 | |
---|
513 | if (!pspec) { |
---|
514 | g_warning ("%s: object class `%s' has no property named `%s'", |
---|
515 | G_STRLOC, G_OBJECT_TYPE_NAME (object), name); |
---|
516 | break; |
---|
517 | } |
---|
518 | if (!(pspec->flags & G_PARAM_WRITABLE)) { |
---|
519 | g_warning ("%s: property `%s' of object class `%s' is not writable", |
---|
520 | G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (object)); |
---|
521 | break; |
---|
522 | } |
---|
523 | |
---|
524 | g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); |
---|
525 | |
---|
526 | G_VALUE_COLLECT (&value, var_args, 0, &error); |
---|
527 | if (error) { |
---|
528 | g_warning ("%s: %s", G_STRLOC, error); |
---|
529 | g_free (error); |
---|
530 | |
---|
531 | /* we purposely leak the value here, it might not be |
---|
532 | * in a sane state if an error condition occoured |
---|
533 | */ |
---|
534 | break; |
---|
535 | } |
---|
536 | |
---|
537 | element_set_property (element, pspec, &value); |
---|
538 | g_value_unset (&value); |
---|
539 | |
---|
540 | name = va_arg (var_args, gchar *); |
---|
541 | } |
---|
542 | |
---|
543 | g_object_unref (object); |
---|
544 | } |
---|
545 | |
---|
546 | /** |
---|
547 | * gst_element_get_valist: |
---|
548 | * @element: a #GstElement to get properties of. |
---|
549 | * @first_property_name: the first property to get. |
---|
550 | * @var_args: the var_args list of other properties to get. |
---|
551 | * |
---|
552 | * Gets properties from an element. If the element uses threadsafe properties, |
---|
553 | * the element will be locked before getting the given properties. |
---|
554 | */ |
---|
555 | void |
---|
556 | gst_element_get_valist (GstElement * element, const gchar * first_property_name, |
---|
557 | va_list var_args) |
---|
558 | { |
---|
559 | const gchar *name; |
---|
560 | GObject *object; |
---|
561 | |
---|
562 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
563 | |
---|
564 | object = (GObject *) element; |
---|
565 | |
---|
566 | if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) { |
---|
567 | g_object_get_valist (object, first_property_name, var_args); |
---|
568 | return; |
---|
569 | } |
---|
570 | |
---|
571 | g_object_ref (object); |
---|
572 | |
---|
573 | name = first_property_name; |
---|
574 | |
---|
575 | while (name) { |
---|
576 | GValue value = { 0, }; |
---|
577 | GParamSpec *pspec; |
---|
578 | gchar *error; |
---|
579 | |
---|
580 | pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), name); |
---|
581 | |
---|
582 | if (!pspec) { |
---|
583 | g_warning ("%s: object class `%s' has no property named `%s'", |
---|
584 | G_STRLOC, G_OBJECT_TYPE_NAME (object), name); |
---|
585 | break; |
---|
586 | } |
---|
587 | if (!(pspec->flags & G_PARAM_READABLE)) { |
---|
588 | g_warning ("%s: property `%s' of object class `%s' is not readable", |
---|
589 | G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (object)); |
---|
590 | break; |
---|
591 | } |
---|
592 | |
---|
593 | g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); |
---|
594 | |
---|
595 | element_get_property (element, pspec, &value); |
---|
596 | |
---|
597 | G_VALUE_LCOPY (&value, var_args, 0, &error); |
---|
598 | if (error) { |
---|
599 | g_warning ("%s: %s", G_STRLOC, error); |
---|
600 | g_free (error); |
---|
601 | g_value_unset (&value); |
---|
602 | break; |
---|
603 | } |
---|
604 | |
---|
605 | g_value_unset (&value); |
---|
606 | |
---|
607 | name = va_arg (var_args, gchar *); |
---|
608 | } |
---|
609 | |
---|
610 | g_object_unref (object); |
---|
611 | } |
---|
612 | |
---|
613 | /** |
---|
614 | * gst_element_set_property: |
---|
615 | * @element: a #GstElement to set properties on. |
---|
616 | * @property_name: the first property to get. |
---|
617 | * @value: the #GValue that holds the value to set. |
---|
618 | * |
---|
619 | * Sets a property on an element. If the element uses threadsafe properties, |
---|
620 | * the property will be put on the async queue. |
---|
621 | */ |
---|
622 | void |
---|
623 | gst_element_set_property (GstElement * element, const gchar * property_name, |
---|
624 | const GValue * value) |
---|
625 | { |
---|
626 | GParamSpec *pspec; |
---|
627 | GObject *object; |
---|
628 | |
---|
629 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
630 | g_return_if_fail (property_name != NULL); |
---|
631 | g_return_if_fail (G_IS_VALUE (value)); |
---|
632 | |
---|
633 | object = (GObject *) element; |
---|
634 | |
---|
635 | GST_CAT_DEBUG (GST_CAT_PROPERTIES, "setting property %s on element %s", |
---|
636 | property_name, gst_element_get_name (element)); |
---|
637 | if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) { |
---|
638 | g_object_set_property (object, property_name, value); |
---|
639 | return; |
---|
640 | } |
---|
641 | |
---|
642 | g_object_ref (object); |
---|
643 | |
---|
644 | pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), |
---|
645 | property_name); |
---|
646 | |
---|
647 | if (!pspec) |
---|
648 | g_warning ("%s: object class `%s' has no property named `%s'", |
---|
649 | G_STRLOC, G_OBJECT_TYPE_NAME (object), property_name); |
---|
650 | else |
---|
651 | element_set_property (element, pspec, value); |
---|
652 | |
---|
653 | g_object_unref (object); |
---|
654 | } |
---|
655 | |
---|
656 | /** |
---|
657 | * gst_element_get_property: |
---|
658 | * @element: a #GstElement to get properties of. |
---|
659 | * @property_name: the first property to get. |
---|
660 | * @value: the #GValue to store the property value in. |
---|
661 | * |
---|
662 | * Gets a property from an element. If the element uses threadsafe properties, |
---|
663 | * the element will be locked before getting the given property. |
---|
664 | */ |
---|
665 | void |
---|
666 | gst_element_get_property (GstElement * element, const gchar * property_name, |
---|
667 | GValue * value) |
---|
668 | { |
---|
669 | GParamSpec *pspec; |
---|
670 | GObject *object; |
---|
671 | |
---|
672 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
673 | g_return_if_fail (property_name != NULL); |
---|
674 | g_return_if_fail (G_IS_VALUE (value)); |
---|
675 | |
---|
676 | object = (GObject *) element; |
---|
677 | |
---|
678 | if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) { |
---|
679 | g_object_get_property (object, property_name, value); |
---|
680 | return; |
---|
681 | } |
---|
682 | |
---|
683 | g_object_ref (object); |
---|
684 | |
---|
685 | pspec = |
---|
686 | g_object_class_find_property (G_OBJECT_GET_CLASS (object), property_name); |
---|
687 | |
---|
688 | if (!pspec) |
---|
689 | g_warning ("%s: object class `%s' has no property named `%s'", |
---|
690 | G_STRLOC, G_OBJECT_TYPE_NAME (object), property_name); |
---|
691 | else { |
---|
692 | GValue *prop_value, tmp_value = { 0, }; |
---|
693 | |
---|
694 | /* auto-conversion of the callers value type |
---|
695 | */ |
---|
696 | if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec)) { |
---|
697 | g_value_reset (value); |
---|
698 | prop_value = value; |
---|
699 | } else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), |
---|
700 | G_VALUE_TYPE (value))) { |
---|
701 | g_warning |
---|
702 | ("can't retrieve property `%s' of type `%s' as value of type `%s'", |
---|
703 | pspec->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)), |
---|
704 | G_VALUE_TYPE_NAME (value)); |
---|
705 | g_object_unref (object); |
---|
706 | return; |
---|
707 | } else { |
---|
708 | g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); |
---|
709 | prop_value = &tmp_value; |
---|
710 | } |
---|
711 | element_get_property (element, pspec, prop_value); |
---|
712 | if (prop_value != value) { |
---|
713 | g_value_transform (prop_value, value); |
---|
714 | g_value_unset (&tmp_value); |
---|
715 | } |
---|
716 | } |
---|
717 | |
---|
718 | g_object_unref (object); |
---|
719 | } |
---|
720 | |
---|
721 | static GstPad * |
---|
722 | gst_element_request_pad (GstElement * element, GstPadTemplate * templ, |
---|
723 | const gchar * name) |
---|
724 | { |
---|
725 | GstPad *newpad = NULL; |
---|
726 | GstElementClass *oclass; |
---|
727 | |
---|
728 | oclass = GST_ELEMENT_GET_CLASS (element); |
---|
729 | |
---|
730 | if (oclass->request_new_pad) |
---|
731 | newpad = (oclass->request_new_pad) (element, templ, name); |
---|
732 | |
---|
733 | return newpad; |
---|
734 | } |
---|
735 | |
---|
736 | /** |
---|
737 | * gst_element_release_request_pad: |
---|
738 | * @element: a #GstElement to release the request pad of. |
---|
739 | * @pad: the #GstPad to release. |
---|
740 | * |
---|
741 | * Makes the element free the previously requested pad as obtained |
---|
742 | * with gst_element_get_request_pad(). |
---|
743 | */ |
---|
744 | void |
---|
745 | gst_element_release_request_pad (GstElement * element, GstPad * pad) |
---|
746 | { |
---|
747 | GstElementClass *oclass; |
---|
748 | |
---|
749 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
750 | g_return_if_fail (GST_IS_PAD (pad)); |
---|
751 | |
---|
752 | oclass = GST_ELEMENT_GET_CLASS (element); |
---|
753 | |
---|
754 | if (oclass->release_pad) |
---|
755 | (oclass->release_pad) (element, pad); |
---|
756 | else |
---|
757 | gst_element_remove_pad (element, pad); |
---|
758 | } |
---|
759 | |
---|
760 | /** |
---|
761 | * gst_element_requires_clock: |
---|
762 | * @element: a #GstElement to query |
---|
763 | * |
---|
764 | * Query if the element requiresd a clock |
---|
765 | * |
---|
766 | * Returns: TRUE if the element requires a clock |
---|
767 | */ |
---|
768 | gboolean |
---|
769 | gst_element_requires_clock (GstElement * element) |
---|
770 | { |
---|
771 | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
---|
772 | |
---|
773 | return (GST_ELEMENT_GET_CLASS (element)->set_clock != NULL); |
---|
774 | } |
---|
775 | |
---|
776 | /** |
---|
777 | * gst_element_provides_clock: |
---|
778 | * @element: a #GstElement to query |
---|
779 | * |
---|
780 | * Query if the element provides a clock |
---|
781 | * |
---|
782 | * Returns: TRUE if the element provides a clock |
---|
783 | */ |
---|
784 | gboolean |
---|
785 | gst_element_provides_clock (GstElement * element) |
---|
786 | { |
---|
787 | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
---|
788 | |
---|
789 | return (GST_ELEMENT_GET_CLASS (element)->get_clock != NULL); |
---|
790 | } |
---|
791 | |
---|
792 | /** |
---|
793 | * gst_element_set_clock: |
---|
794 | * @element: a #GstElement to set the clock for. |
---|
795 | * @clock: the #GstClock to set for the element. |
---|
796 | * |
---|
797 | * Sets the clock for the element. |
---|
798 | */ |
---|
799 | void |
---|
800 | gst_element_set_clock (GstElement * element, GstClock * clock) |
---|
801 | { |
---|
802 | GstElementClass *oclass; |
---|
803 | |
---|
804 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
805 | |
---|
806 | oclass = GST_ELEMENT_GET_CLASS (element); |
---|
807 | |
---|
808 | if (oclass->set_clock) |
---|
809 | oclass->set_clock (element, clock); |
---|
810 | |
---|
811 | gst_object_replace ((GstObject **) & element->clock, (GstObject *) clock); |
---|
812 | } |
---|
813 | |
---|
814 | /** |
---|
815 | * gst_element_get_clock: |
---|
816 | * @element: a #GstElement to get the clock of. |
---|
817 | * |
---|
818 | * Gets the clock of the element. |
---|
819 | * |
---|
820 | * Returns: the #GstClock of the element. |
---|
821 | */ |
---|
822 | GstClock * |
---|
823 | gst_element_get_clock (GstElement * element) |
---|
824 | { |
---|
825 | GstElementClass *oclass; |
---|
826 | |
---|
827 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
828 | |
---|
829 | oclass = GST_ELEMENT_GET_CLASS (element); |
---|
830 | |
---|
831 | if (oclass->get_clock) |
---|
832 | return oclass->get_clock (element); |
---|
833 | |
---|
834 | return NULL; |
---|
835 | } |
---|
836 | |
---|
837 | /** |
---|
838 | * gst_element_clock_wait: |
---|
839 | * @element: a #GstElement. |
---|
840 | * @id: the #GstClock to use. |
---|
841 | * @jitter: the difference between requested time and actual time. |
---|
842 | * |
---|
843 | * Waits for a specific time on the clock. |
---|
844 | * |
---|
845 | * Returns: the #GstClockReturn result of the wait operation. |
---|
846 | */ |
---|
847 | GstClockReturn |
---|
848 | gst_element_clock_wait (GstElement * element, GstClockID id, |
---|
849 | GstClockTimeDiff * jitter) |
---|
850 | { |
---|
851 | GstClockReturn res; |
---|
852 | |
---|
853 | g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_ERROR); |
---|
854 | |
---|
855 | if (GST_ELEMENT_SCHED (element)) { |
---|
856 | GST_CAT_DEBUG (GST_CAT_CLOCK, "waiting on scheduler clock with id %d"); |
---|
857 | res = |
---|
858 | gst_scheduler_clock_wait (GST_ELEMENT_SCHED (element), element, id, |
---|
859 | jitter); |
---|
860 | } else { |
---|
861 | GST_CAT_DEBUG (GST_CAT_CLOCK, "no scheduler, returning GST_CLOCK_TIMEOUT"); |
---|
862 | res = GST_CLOCK_TIMEOUT; |
---|
863 | } |
---|
864 | |
---|
865 | return res; |
---|
866 | } |
---|
867 | |
---|
868 | #undef GST_CAT_DEFAULT |
---|
869 | #define GST_CAT_DEFAULT GST_CAT_CLOCK |
---|
870 | /** |
---|
871 | * gst_element_get_time: |
---|
872 | * @element: element to query |
---|
873 | * |
---|
874 | * Query the element's time. FIXME: The element must use |
---|
875 | * |
---|
876 | * Returns: the current stream time in #GST_STATE_PLAYING, |
---|
877 | * the element base time in #GST_STATE_PAUSED, |
---|
878 | * or #GST_CLOCK_TIME_NONE otherwise. |
---|
879 | */ |
---|
880 | /* FIXME: this should always return time on the same scale. Now it returns |
---|
881 | * the (absolute) base_time in PAUSED and the (current running) time in |
---|
882 | * PLAYING. |
---|
883 | * Solution: have a get_base_time and make the element subtract if it needs |
---|
884 | * to. In PAUSED return the same as PLAYING, ie. the current timestamp where |
---|
885 | * the element is at according to the provided clock. |
---|
886 | */ |
---|
887 | GstClockTime |
---|
888 | gst_element_get_time (GstElement * element) |
---|
889 | { |
---|
890 | g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_TIME_NONE); |
---|
891 | |
---|
892 | if (element->clock == NULL) { |
---|
893 | GST_WARNING_OBJECT (element, "element queries time but has no clock"); |
---|
894 | return GST_CLOCK_TIME_NONE; |
---|
895 | } |
---|
896 | switch (element->current_state) { |
---|
897 | case GST_STATE_NULL: |
---|
898 | case GST_STATE_READY: |
---|
899 | return GST_CLOCK_TIME_NONE; |
---|
900 | case GST_STATE_PAUSED: |
---|
901 | return element->base_time; |
---|
902 | case GST_STATE_PLAYING: |
---|
903 | return gst_clock_get_time (element->clock) - element->base_time; |
---|
904 | default: |
---|
905 | g_assert_not_reached (); |
---|
906 | return GST_CLOCK_TIME_NONE; |
---|
907 | } |
---|
908 | } |
---|
909 | |
---|
910 | /** |
---|
911 | * gst_element_wait: |
---|
912 | * @element: element that should wait |
---|
913 | * @timestamp: what timestamp to wait on |
---|
914 | * |
---|
915 | * Waits until the given relative time stamp for the element has arrived. |
---|
916 | * When this function returns successfully, the relative time point specified |
---|
917 | * in the timestamp has passed for this element. |
---|
918 | * <note>This function can only be called on elements in |
---|
919 | * #GST_STATE_PLAYING</note> |
---|
920 | * |
---|
921 | * Returns: TRUE on success. |
---|
922 | */ |
---|
923 | gboolean |
---|
924 | gst_element_wait (GstElement * element, GstClockTime timestamp) |
---|
925 | { |
---|
926 | GstClockID id; |
---|
927 | GstClockReturn ret; |
---|
928 | GstClockTime time; |
---|
929 | |
---|
930 | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
---|
931 | g_return_val_if_fail (GST_IS_CLOCK (element->clock), FALSE); |
---|
932 | g_return_val_if_fail (element->current_state == GST_STATE_PLAYING, FALSE); |
---|
933 | g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE); |
---|
934 | |
---|
935 | /* shortcut when we're already late... */ |
---|
936 | time = gst_element_get_time (element); |
---|
937 | GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, element, "element time %" GST_TIME_FORMAT, |
---|
938 | GST_TIME_ARGS (time)); |
---|
939 | if (time >= timestamp) { |
---|
940 | GST_CAT_INFO_OBJECT (GST_CAT_CLOCK, element, |
---|
941 | "called gst_element_wait (% " GST_TIME_FORMAT ") and was late (%" |
---|
942 | GST_TIME_FORMAT, GST_TIME_ARGS (timestamp), |
---|
943 | GST_TIME_ARGS (gst_element_get_time (element))); |
---|
944 | return TRUE; |
---|
945 | } |
---|
946 | |
---|
947 | id = gst_clock_new_single_shot_id (element->clock, |
---|
948 | element->base_time + timestamp); |
---|
949 | ret = gst_element_clock_wait (element, id, NULL); |
---|
950 | gst_clock_id_free (id); |
---|
951 | |
---|
952 | return ret == GST_CLOCK_STOPPED; |
---|
953 | } |
---|
954 | |
---|
955 | /** |
---|
956 | * gst_element_set_time: |
---|
957 | * @element: element to set time on |
---|
958 | * @time: time to set |
---|
959 | * |
---|
960 | * Sets the current time of the element. This function can be used when handling |
---|
961 | * discont events. You can only call this function on an element with a clock in |
---|
962 | * #GST_STATE_PAUSED or #GST_STATE_PLAYING. You might want to have a look at |
---|
963 | * gst_element_adjust_time(), if you want to adjust by a difference as that is |
---|
964 | * more accurate. |
---|
965 | */ |
---|
966 | void |
---|
967 | gst_element_set_time (GstElement * element, GstClockTime time) |
---|
968 | { |
---|
969 | gst_element_set_time_delay (element, time, 0); |
---|
970 | } |
---|
971 | |
---|
972 | /** |
---|
973 | * gst_element_set_time_delay: |
---|
974 | * @element: element to set time on |
---|
975 | * @time: time to set |
---|
976 | * @delay: a delay to discount from the given time |
---|
977 | * |
---|
978 | * Sets the current time of the element to time - delay. This function can be |
---|
979 | * used when handling discont events in elements writing to an external buffer, |
---|
980 | * i. e., an audio sink that writes to a sound card that buffers the sound |
---|
981 | * before playing it. The delay should be the current buffering delay. |
---|
982 | * |
---|
983 | * You can only call this function on an element with a clock in |
---|
984 | * #GST_STATE_PAUSED or #GST_STATE_PLAYING. You might want to have a look at |
---|
985 | * gst_element_adjust_time(), if you want to adjust by a difference as that is |
---|
986 | * more accurate. |
---|
987 | */ |
---|
988 | void |
---|
989 | gst_element_set_time_delay (GstElement * element, GstClockTime time, |
---|
990 | GstClockTime delay) |
---|
991 | { |
---|
992 | GstClockTime event_time; |
---|
993 | |
---|
994 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
995 | g_return_if_fail (GST_IS_CLOCK (element->clock)); |
---|
996 | g_return_if_fail (element->current_state >= GST_STATE_PAUSED); |
---|
997 | g_return_if_fail (time >= delay); |
---|
998 | |
---|
999 | switch (element->current_state) { |
---|
1000 | case GST_STATE_PAUSED: |
---|
1001 | element->base_time = time - delay; |
---|
1002 | break; |
---|
1003 | case GST_STATE_PLAYING: |
---|
1004 | event_time = gst_clock_get_event_time_delay (element->clock, delay); |
---|
1005 | GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, element, |
---|
1006 | "clock time %" GST_TIME_FORMAT ": setting element time to %" |
---|
1007 | GST_TIME_FORMAT, GST_TIME_ARGS (event_time), GST_TIME_ARGS (time)); |
---|
1008 | element->base_time = event_time - time; |
---|
1009 | break; |
---|
1010 | default: |
---|
1011 | g_assert_not_reached (); |
---|
1012 | break; |
---|
1013 | } |
---|
1014 | } |
---|
1015 | |
---|
1016 | /** |
---|
1017 | * gst_element_adjust_time: |
---|
1018 | * @element: element to adjust time on |
---|
1019 | * @diff: difference to adjust |
---|
1020 | * |
---|
1021 | * Adjusts the current time of the element by the specified difference. This |
---|
1022 | * function can be used when handling discont events. You can only call this |
---|
1023 | * function on an element with a clock in #GST_STATE_PAUSED or |
---|
1024 | * #GST_STATE_PLAYING. It is more accurate than gst_element_set_time(). |
---|
1025 | */ |
---|
1026 | void |
---|
1027 | gst_element_adjust_time (GstElement * element, GstClockTimeDiff diff) |
---|
1028 | { |
---|
1029 | GstClockTime time; |
---|
1030 | |
---|
1031 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
1032 | g_return_if_fail (GST_IS_CLOCK (element->clock)); |
---|
1033 | g_return_if_fail (element->current_state >= GST_STATE_PAUSED); |
---|
1034 | |
---|
1035 | switch (element->current_state) { |
---|
1036 | case GST_STATE_PAUSED: |
---|
1037 | if (diff < 0 && element->base_time < abs (diff)) { |
---|
1038 | g_warning ("attempted to set the current time of element %s below 0", |
---|
1039 | GST_OBJECT_NAME (element)); |
---|
1040 | element->base_time = 0; |
---|
1041 | } else { |
---|
1042 | element->base_time += diff; |
---|
1043 | } |
---|
1044 | break; |
---|
1045 | case GST_STATE_PLAYING: |
---|
1046 | time = gst_clock_get_time (element->clock); |
---|
1047 | if (time < element->base_time - diff) { |
---|
1048 | g_warning ("attempted to set the current time of element %s below 0", |
---|
1049 | GST_OBJECT_NAME (element)); |
---|
1050 | element->base_time = time; |
---|
1051 | } else { |
---|
1052 | element->base_time -= diff; |
---|
1053 | } |
---|
1054 | break; |
---|
1055 | default: |
---|
1056 | g_assert_not_reached (); |
---|
1057 | break; |
---|
1058 | } |
---|
1059 | } |
---|
1060 | |
---|
1061 | #undef GST_CAT_DEFAULT |
---|
1062 | |
---|
1063 | #ifndef GST_DISABLE_INDEX |
---|
1064 | /** |
---|
1065 | * gst_element_is_indexable: |
---|
1066 | * @element: a #GstElement. |
---|
1067 | * |
---|
1068 | * Queries if the element can be indexed. |
---|
1069 | * |
---|
1070 | * Returns: TRUE if the element can be indexed. |
---|
1071 | */ |
---|
1072 | gboolean |
---|
1073 | gst_element_is_indexable (GstElement * element) |
---|
1074 | { |
---|
1075 | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
---|
1076 | |
---|
1077 | return (GST_ELEMENT_GET_CLASS (element)->set_index != NULL); |
---|
1078 | } |
---|
1079 | |
---|
1080 | /** |
---|
1081 | * gst_element_set_index: |
---|
1082 | * @element: a #GstElement. |
---|
1083 | * @index: a #GstIndex. |
---|
1084 | * |
---|
1085 | * Set the specified GstIndex on the element. |
---|
1086 | */ |
---|
1087 | void |
---|
1088 | gst_element_set_index (GstElement * element, GstIndex * index) |
---|
1089 | { |
---|
1090 | GstElementClass *oclass; |
---|
1091 | |
---|
1092 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
1093 | g_return_if_fail (GST_IS_INDEX (index)); |
---|
1094 | |
---|
1095 | oclass = GST_ELEMENT_GET_CLASS (element); |
---|
1096 | |
---|
1097 | if (oclass->set_index) |
---|
1098 | oclass->set_index (element, index); |
---|
1099 | } |
---|
1100 | |
---|
1101 | /** |
---|
1102 | * gst_element_get_index: |
---|
1103 | * @element: a #GstElement. |
---|
1104 | * |
---|
1105 | * Gets the index from the element. |
---|
1106 | * |
---|
1107 | * Returns: a #GstIndex or NULL when no index was set on the |
---|
1108 | * element. |
---|
1109 | */ |
---|
1110 | GstIndex * |
---|
1111 | gst_element_get_index (GstElement * element) |
---|
1112 | { |
---|
1113 | GstElementClass *oclass; |
---|
1114 | |
---|
1115 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
1116 | |
---|
1117 | oclass = GST_ELEMENT_GET_CLASS (element); |
---|
1118 | |
---|
1119 | if (oclass->get_index) |
---|
1120 | return oclass->get_index (element); |
---|
1121 | |
---|
1122 | return NULL; |
---|
1123 | } |
---|
1124 | #endif |
---|
1125 | |
---|
1126 | /** |
---|
1127 | * gst_element_release_locks: |
---|
1128 | * @element: a #GstElement to release all locks on. |
---|
1129 | * |
---|
1130 | * Instruct the element to release all the locks it is holding, such as |
---|
1131 | * blocking reads, waiting for the clock, ... |
---|
1132 | * |
---|
1133 | * Returns: TRUE if the locks could be released. |
---|
1134 | */ |
---|
1135 | gboolean |
---|
1136 | gst_element_release_locks (GstElement * element) |
---|
1137 | { |
---|
1138 | GstElementClass *oclass; |
---|
1139 | |
---|
1140 | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
---|
1141 | |
---|
1142 | oclass = GST_ELEMENT_GET_CLASS (element); |
---|
1143 | |
---|
1144 | if (oclass->release_locks) |
---|
1145 | return oclass->release_locks (element); |
---|
1146 | |
---|
1147 | return TRUE; |
---|
1148 | } |
---|
1149 | |
---|
1150 | /** |
---|
1151 | * gst_element_add_pad: |
---|
1152 | * @element: a #GstElement to add the pad to. |
---|
1153 | * @pad: the #GstPad to add to the element. |
---|
1154 | * |
---|
1155 | * Adds a pad (link point) to @element. @pad's parent will be set to @element; |
---|
1156 | * see gst_object_set_parent() for refcounting information. |
---|
1157 | * |
---|
1158 | * Pads are automatically activated when the element is in state PLAYING. |
---|
1159 | */ |
---|
1160 | void |
---|
1161 | gst_element_add_pad (GstElement * element, GstPad * pad) |
---|
1162 | { |
---|
1163 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
1164 | g_return_if_fail (GST_IS_PAD (pad)); |
---|
1165 | |
---|
1166 | /* first check to make sure the pad hasn't already been added to another |
---|
1167 | * element */ |
---|
1168 | g_return_if_fail (GST_PAD_PARENT (pad) == NULL); |
---|
1169 | |
---|
1170 | /* then check to see if there's already a pad by that name here */ |
---|
1171 | g_return_if_fail (gst_object_check_uniqueness (element->pads, |
---|
1172 | GST_PAD_NAME (pad)) == TRUE); |
---|
1173 | |
---|
1174 | GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element, "adding pad '%s'", |
---|
1175 | GST_STR_NULL (GST_OBJECT_NAME (pad))); |
---|
1176 | |
---|
1177 | /* set the pad's parent */ |
---|
1178 | gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element)); |
---|
1179 | |
---|
1180 | /* add it to the list */ |
---|
1181 | element->pads = g_list_append (element->pads, pad); |
---|
1182 | element->numpads++; |
---|
1183 | |
---|
1184 | switch (gst_pad_get_direction (pad)) { |
---|
1185 | case GST_PAD_SRC: |
---|
1186 | element->numsrcpads++; |
---|
1187 | break; |
---|
1188 | case GST_PAD_SINK: |
---|
1189 | element->numsinkpads++; |
---|
1190 | break; |
---|
1191 | default: |
---|
1192 | /* can happen for ghost pads */ |
---|
1193 | break; |
---|
1194 | } |
---|
1195 | |
---|
1196 | /* activate element when we are playing */ |
---|
1197 | if (GST_STATE (element) == GST_STATE_PLAYING) |
---|
1198 | gst_pad_set_active (pad, TRUE); |
---|
1199 | |
---|
1200 | /* emit the NEW_PAD signal */ |
---|
1201 | g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, pad); |
---|
1202 | } |
---|
1203 | |
---|
1204 | /** |
---|
1205 | * gst_element_add_ghost_pad: |
---|
1206 | * @element: a #GstElement to add the ghost pad to. |
---|
1207 | * @pad: the #GstPad from which the new ghost pad will be created. |
---|
1208 | * @name: the name of the new ghost pad, or NULL to assign a unique name |
---|
1209 | * automatically. |
---|
1210 | * |
---|
1211 | * Creates a ghost pad from @pad, and adds it to @element via |
---|
1212 | * gst_element_add_pad(). |
---|
1213 | * |
---|
1214 | * Returns: the added ghost #GstPad, or NULL on error. |
---|
1215 | */ |
---|
1216 | GstPad * |
---|
1217 | gst_element_add_ghost_pad (GstElement * element, GstPad * pad, |
---|
1218 | const gchar * name) |
---|
1219 | { |
---|
1220 | GstPad *ghostpad; |
---|
1221 | |
---|
1222 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
1223 | g_return_val_if_fail (GST_IS_PAD (pad), NULL); |
---|
1224 | |
---|
1225 | /* then check to see if there's already a pad by that name here */ |
---|
1226 | g_return_val_if_fail (gst_object_check_uniqueness (element->pads, |
---|
1227 | name) == TRUE, NULL); |
---|
1228 | |
---|
1229 | ghostpad = gst_ghost_pad_new (name, pad); |
---|
1230 | |
---|
1231 | gst_element_add_pad (element, ghostpad); |
---|
1232 | |
---|
1233 | return ghostpad; |
---|
1234 | } |
---|
1235 | |
---|
1236 | /** |
---|
1237 | * gst_element_remove_pad: |
---|
1238 | * @element: a #GstElement to remove pad from. |
---|
1239 | * @pad: the #GstPad to remove from the element. |
---|
1240 | * |
---|
1241 | * Removes @pad from @element. @pad will be destroyed if it has not been |
---|
1242 | * referenced elsewhere. |
---|
1243 | */ |
---|
1244 | void |
---|
1245 | gst_element_remove_pad (GstElement * element, GstPad * pad) |
---|
1246 | { |
---|
1247 | g_return_if_fail (element != NULL); |
---|
1248 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
1249 | g_return_if_fail (pad != NULL); |
---|
1250 | g_return_if_fail (GST_IS_PAD (pad)); |
---|
1251 | |
---|
1252 | g_return_if_fail (GST_PAD_PARENT (pad) == element); |
---|
1253 | |
---|
1254 | if (GST_IS_REAL_PAD (pad)) { |
---|
1255 | /* unlink if necessary */ |
---|
1256 | if (GST_RPAD_PEER (pad) != NULL) { |
---|
1257 | gst_pad_unlink (pad, GST_PAD (GST_RPAD_PEER (pad))); |
---|
1258 | } |
---|
1259 | gst_caps_replace (&GST_RPAD_EXPLICIT_CAPS (pad), NULL); |
---|
1260 | } else if (GST_IS_GHOST_PAD (pad)) { |
---|
1261 | g_object_set (pad, "real-pad", NULL, NULL); |
---|
1262 | } |
---|
1263 | |
---|
1264 | /* remove it from the list */ |
---|
1265 | element->pads = g_list_remove (element->pads, pad); |
---|
1266 | element->numpads--; |
---|
1267 | switch (gst_pad_get_direction (pad)) { |
---|
1268 | case GST_PAD_SRC: |
---|
1269 | element->numsrcpads--; |
---|
1270 | break; |
---|
1271 | case GST_PAD_SINK: |
---|
1272 | element->numsinkpads--; |
---|
1273 | break; |
---|
1274 | default: |
---|
1275 | /* can happen for ghost pads */ |
---|
1276 | break; |
---|
1277 | } |
---|
1278 | |
---|
1279 | g_signal_emit (G_OBJECT (element), gst_element_signals[PAD_REMOVED], 0, pad); |
---|
1280 | |
---|
1281 | gst_object_unparent (GST_OBJECT (pad)); |
---|
1282 | } |
---|
1283 | |
---|
1284 | /** |
---|
1285 | * gst_element_remove_ghost_pad: |
---|
1286 | * @element: a #GstElement to remove the ghost pad from. |
---|
1287 | * @pad: ghost #GstPad to remove. |
---|
1288 | * |
---|
1289 | * Removes a ghost pad from an element. Deprecated, use gst_element_remove_pad() |
---|
1290 | * instead. |
---|
1291 | */ |
---|
1292 | void |
---|
1293 | gst_element_remove_ghost_pad (GstElement * element, GstPad * pad) |
---|
1294 | { |
---|
1295 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
1296 | g_return_if_fail (GST_IS_GHOST_PAD (pad)); |
---|
1297 | |
---|
1298 | g_warning ("gst_element_remove_ghost_pad is deprecated.\n" |
---|
1299 | "Use gst_element_remove_pad instead."); |
---|
1300 | |
---|
1301 | gst_element_remove_pad (element, pad); |
---|
1302 | } |
---|
1303 | |
---|
1304 | /** |
---|
1305 | * gst_element_no_more_pads: |
---|
1306 | * @element: a #GstElement |
---|
1307 | * |
---|
1308 | * Use this function to signal that the element does not expect any more pads |
---|
1309 | * to show up in the current pipeline. This function should be called whenever |
---|
1310 | * pads have been added by the element itself. Elements with GST_PAD_SOMETIMES |
---|
1311 | * pad templates use this in combination with autopluggers to figure out that |
---|
1312 | * the element is done initializing its pads. |
---|
1313 | */ |
---|
1314 | void |
---|
1315 | gst_element_no_more_pads (GstElement * element) |
---|
1316 | { |
---|
1317 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
1318 | |
---|
1319 | g_signal_emit (element, gst_element_signals[NO_MORE_PADS], 0); |
---|
1320 | } |
---|
1321 | |
---|
1322 | /** |
---|
1323 | * gst_element_get_pad: |
---|
1324 | * @element: a #GstElement. |
---|
1325 | * @name: the name of the pad to retrieve. |
---|
1326 | * |
---|
1327 | * Retrieves a pad from @element by name. Tries gst_element_get_static_pad() |
---|
1328 | * first, then gst_element_get_request_pad(). |
---|
1329 | * |
---|
1330 | * Returns: the #GstPad if found, otherwise %NULL. |
---|
1331 | */ |
---|
1332 | GstPad * |
---|
1333 | gst_element_get_pad (GstElement * element, const gchar * name) |
---|
1334 | { |
---|
1335 | GstPad *pad; |
---|
1336 | |
---|
1337 | g_return_val_if_fail (element != NULL, NULL); |
---|
1338 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
1339 | g_return_val_if_fail (name != NULL, NULL); |
---|
1340 | |
---|
1341 | pad = gst_element_get_static_pad (element, name); |
---|
1342 | if (!pad) |
---|
1343 | pad = gst_element_get_request_pad (element, name); |
---|
1344 | |
---|
1345 | return pad; |
---|
1346 | } |
---|
1347 | |
---|
1348 | /** |
---|
1349 | * gst_element_get_static_pad: |
---|
1350 | * @element: a #GstElement to find a static pad of. |
---|
1351 | * @name: the name of the static #GstPad to retrieve. |
---|
1352 | * |
---|
1353 | * Retrieves a pad from @element by name. This version only retrieves |
---|
1354 | * already-existing (i.e. 'static') pads. |
---|
1355 | * |
---|
1356 | * Returns: the requested #GstPad if found, otherwise NULL. |
---|
1357 | */ |
---|
1358 | GstPad * |
---|
1359 | gst_element_get_static_pad (GstElement * element, const gchar * name) |
---|
1360 | { |
---|
1361 | GList *walk; |
---|
1362 | |
---|
1363 | g_return_val_if_fail (element != NULL, NULL); |
---|
1364 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
1365 | g_return_val_if_fail (name != NULL, NULL); |
---|
1366 | |
---|
1367 | walk = element->pads; |
---|
1368 | while (walk) { |
---|
1369 | GstPad *pad; |
---|
1370 | |
---|
1371 | pad = GST_PAD (walk->data); |
---|
1372 | if (strcmp (GST_PAD_NAME (pad), name) == 0) { |
---|
1373 | GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "found pad %s:%s", |
---|
1374 | GST_DEBUG_PAD_NAME (pad)); |
---|
1375 | return pad; |
---|
1376 | } |
---|
1377 | walk = g_list_next (walk); |
---|
1378 | } |
---|
1379 | |
---|
1380 | GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "no such pad '%s' in element \"%s\"", |
---|
1381 | name, GST_OBJECT_NAME (element)); |
---|
1382 | return NULL; |
---|
1383 | } |
---|
1384 | |
---|
1385 | /** |
---|
1386 | * gst_element_get_request_pad: |
---|
1387 | * @element: a #GstElement to find a request pad of. |
---|
1388 | * @name: the name of the request #GstPad to retrieve. |
---|
1389 | * |
---|
1390 | * Retrieves a pad from the element by name. This version only retrieves |
---|
1391 | * request pads. |
---|
1392 | * |
---|
1393 | * Returns: requested #GstPad if found, otherwise NULL. |
---|
1394 | */ |
---|
1395 | GstPad * |
---|
1396 | gst_element_get_request_pad (GstElement * element, const gchar * name) |
---|
1397 | { |
---|
1398 | GstPadTemplate *templ = NULL; |
---|
1399 | GstPad *pad; |
---|
1400 | const gchar *req_name = NULL; |
---|
1401 | gboolean templ_found = FALSE; |
---|
1402 | GList *list; |
---|
1403 | gint n; |
---|
1404 | const gchar *data; |
---|
1405 | gchar *str, *endptr = NULL; |
---|
1406 | |
---|
1407 | g_return_val_if_fail (element != NULL, NULL); |
---|
1408 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
1409 | g_return_val_if_fail (name != NULL, NULL); |
---|
1410 | |
---|
1411 | if (strstr (name, "%")) { |
---|
1412 | templ = gst_element_get_pad_template (element, name); |
---|
1413 | req_name = NULL; |
---|
1414 | if (templ) |
---|
1415 | templ_found = TRUE; |
---|
1416 | } else { |
---|
1417 | list = gst_element_get_pad_template_list (element); |
---|
1418 | while (!templ_found && list) { |
---|
1419 | templ = (GstPadTemplate *) list->data; |
---|
1420 | if (templ->presence == GST_PAD_REQUEST) { |
---|
1421 | /* Because of sanity checks in gst_pad_template_new(), we know that %s |
---|
1422 | and %d, occurring at the end of the name_template, are the only |
---|
1423 | possibilities. */ |
---|
1424 | GST_CAT_DEBUG (GST_CAT_PADS, "comparing %s to %s", name, |
---|
1425 | templ->name_template); |
---|
1426 | if ((str = strchr (templ->name_template, '%')) |
---|
1427 | && strncmp (templ->name_template, name, |
---|
1428 | str - templ->name_template) == 0 |
---|
1429 | && strlen (name) > str - templ->name_template) { |
---|
1430 | data = name + (str - templ->name_template); |
---|
1431 | if (*(str + 1) == 'd') { |
---|
1432 | /* it's an int */ |
---|
1433 | n = (gint) strtol (data, &endptr, 10); |
---|
1434 | if (endptr && *endptr == '\0') { |
---|
1435 | templ_found = TRUE; |
---|
1436 | req_name = name; |
---|
1437 | break; |
---|
1438 | } |
---|
1439 | } else { |
---|
1440 | /* it's a string */ |
---|
1441 | templ_found = TRUE; |
---|
1442 | req_name = name; |
---|
1443 | break; |
---|
1444 | } |
---|
1445 | } |
---|
1446 | } |
---|
1447 | list = list->next; |
---|
1448 | } |
---|
1449 | } |
---|
1450 | |
---|
1451 | if (!templ_found) |
---|
1452 | return NULL; |
---|
1453 | |
---|
1454 | pad = gst_element_request_pad (element, templ, req_name); |
---|
1455 | |
---|
1456 | return pad; |
---|
1457 | } |
---|
1458 | |
---|
1459 | /** |
---|
1460 | * gst_element_get_pad_list: |
---|
1461 | * @element: a #GstElement to get pads of. |
---|
1462 | * |
---|
1463 | * Retrieves a list of @element's pads. The list must not be modified by the |
---|
1464 | * calling code. |
---|
1465 | * |
---|
1466 | * Returns: the #GList of pads. |
---|
1467 | */ |
---|
1468 | const GList * |
---|
1469 | gst_element_get_pad_list (GstElement * element) |
---|
1470 | { |
---|
1471 | g_return_val_if_fail (element != NULL, NULL); |
---|
1472 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
1473 | |
---|
1474 | /* return the list of pads */ |
---|
1475 | return element->pads; |
---|
1476 | } |
---|
1477 | |
---|
1478 | /** |
---|
1479 | * gst_element_class_add_pad_template: |
---|
1480 | * @klass: the #GstElementClass to add the pad template to. |
---|
1481 | * @templ: a #GstPadTemplate to add to the element class. |
---|
1482 | * |
---|
1483 | * Adds a padtemplate to an element class. This is mainly used in the _base_init |
---|
1484 | * functions of classes. |
---|
1485 | */ |
---|
1486 | void |
---|
1487 | gst_element_class_add_pad_template (GstElementClass * klass, |
---|
1488 | GstPadTemplate * templ) |
---|
1489 | { |
---|
1490 | g_return_if_fail (GST_IS_ELEMENT_CLASS (klass)); |
---|
1491 | g_return_if_fail (GST_IS_PAD_TEMPLATE (templ)); |
---|
1492 | |
---|
1493 | /* avoid registering pad templates with the same name */ |
---|
1494 | g_return_if_fail (gst_element_class_get_pad_template (klass, |
---|
1495 | templ->name_template) == NULL); |
---|
1496 | |
---|
1497 | klass->padtemplates = g_list_append (klass->padtemplates, |
---|
1498 | gst_object_ref (GST_OBJECT (templ))); |
---|
1499 | klass->numpadtemplates++; |
---|
1500 | } |
---|
1501 | |
---|
1502 | /** |
---|
1503 | * gst_element_class_set_details: |
---|
1504 | * @klass: class to set details for |
---|
1505 | * @details: details to set |
---|
1506 | * |
---|
1507 | * Sets the detailed information for a #GstElementClass. |
---|
1508 | * <note>This function is for use in _base_init functions only.</note> |
---|
1509 | */ |
---|
1510 | void |
---|
1511 | gst_element_class_set_details (GstElementClass * klass, |
---|
1512 | const GstElementDetails * details) |
---|
1513 | { |
---|
1514 | g_return_if_fail (GST_IS_ELEMENT_CLASS (klass)); |
---|
1515 | g_return_if_fail (GST_IS_ELEMENT_DETAILS (details)); |
---|
1516 | |
---|
1517 | __gst_element_details_copy (&klass->details, details); |
---|
1518 | } |
---|
1519 | |
---|
1520 | /** |
---|
1521 | * gst_element_class_get_pad_template_list: |
---|
1522 | * @element_class: a #GstElementClass to get pad templates of. |
---|
1523 | * |
---|
1524 | * Retrieves a list of the pad templates associated with @element_class. The |
---|
1525 | * list must not be modified by the calling code. |
---|
1526 | * <note>If you use this function in the #GInstanceInitFunc of an object class |
---|
1527 | * that has subclasses, make sure to pass the g_class parameter of the |
---|
1528 | * #GInstanceInitFunc here.</note> |
---|
1529 | * |
---|
1530 | * Returns: the #GList of padtemplates. |
---|
1531 | */ |
---|
1532 | GList * |
---|
1533 | gst_element_class_get_pad_template_list (GstElementClass * element_class) |
---|
1534 | { |
---|
1535 | g_return_val_if_fail (element_class != NULL, NULL); |
---|
1536 | g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL); |
---|
1537 | |
---|
1538 | return element_class->padtemplates; |
---|
1539 | } |
---|
1540 | |
---|
1541 | /** |
---|
1542 | * gst_element_class_get_pad_template: |
---|
1543 | * @element_class: a #GstElementClass to get the pad template of. |
---|
1544 | * @name: the name of the #GstPadTemplate to get. |
---|
1545 | * |
---|
1546 | * Retrieves a padtemplate from @element_class with the given name. |
---|
1547 | * <note>If you use this function in the #GInstanceInitFunc of an object class |
---|
1548 | * that has subclasses, make sure to pass the g_class parameter of the |
---|
1549 | * #GInstanceInitFunc here.</note> |
---|
1550 | * |
---|
1551 | * Returns: the #GstPadTemplate with the given name, or NULL if none was found. |
---|
1552 | * No unreferencing is necessary. |
---|
1553 | */ |
---|
1554 | GstPadTemplate * |
---|
1555 | gst_element_class_get_pad_template (GstElementClass * element_class, |
---|
1556 | const gchar * name) |
---|
1557 | { |
---|
1558 | GList *padlist; |
---|
1559 | |
---|
1560 | g_return_val_if_fail (element_class != NULL, NULL); |
---|
1561 | g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL); |
---|
1562 | g_return_val_if_fail (name != NULL, NULL); |
---|
1563 | |
---|
1564 | padlist = gst_element_class_get_pad_template_list (element_class); |
---|
1565 | |
---|
1566 | while (padlist) { |
---|
1567 | GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data; |
---|
1568 | |
---|
1569 | if (strcmp (padtempl->name_template, name) == 0) |
---|
1570 | return padtempl; |
---|
1571 | |
---|
1572 | padlist = g_list_next (padlist); |
---|
1573 | } |
---|
1574 | |
---|
1575 | return NULL; |
---|
1576 | } |
---|
1577 | |
---|
1578 | /** |
---|
1579 | * gst_element_get_pad_template_list: |
---|
1580 | * @element: a #GstElement to get pad templates of. |
---|
1581 | * |
---|
1582 | * Retrieves a list of the pad templates associated with the element. |
---|
1583 | * (FIXME: Should be deprecated in favor of |
---|
1584 | * gst_element_class_get_pad_template_list). |
---|
1585 | * |
---|
1586 | * Returns: the #GList of padtemplates. |
---|
1587 | */ |
---|
1588 | GList * |
---|
1589 | gst_element_get_pad_template_list (GstElement * element) |
---|
1590 | { |
---|
1591 | g_return_val_if_fail (element != NULL, NULL); |
---|
1592 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
1593 | |
---|
1594 | return GST_ELEMENT_GET_CLASS (element)->padtemplates; |
---|
1595 | } |
---|
1596 | |
---|
1597 | /** |
---|
1598 | * gst_element_get_pad_template: |
---|
1599 | * @element: a #GstElement to get the pad template of. |
---|
1600 | * @name: the name of the #GstPadTemplate to get. |
---|
1601 | * |
---|
1602 | * Retrieves a padtemplate from this element with the |
---|
1603 | * given name. |
---|
1604 | * (FIXME: Should be deprecated in favor of gst_element_class_get_pad_template). |
---|
1605 | * |
---|
1606 | * Returns: the #GstPadTemplate with the given name, or NULL if none was found. |
---|
1607 | * No unreferencing is necessary. |
---|
1608 | */ |
---|
1609 | GstPadTemplate * |
---|
1610 | gst_element_get_pad_template (GstElement * element, const gchar * name) |
---|
1611 | { |
---|
1612 | g_return_val_if_fail (element != NULL, NULL); |
---|
1613 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
1614 | g_return_val_if_fail (name != NULL, NULL); |
---|
1615 | |
---|
1616 | return gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (element), |
---|
1617 | name); |
---|
1618 | } |
---|
1619 | |
---|
1620 | /** |
---|
1621 | * gst_element_get_compatible_pad_template: |
---|
1622 | * @element: a #GstElement to get a compatible pad template for. |
---|
1623 | * @compattempl: the #GstPadTemplate to find a compatible template for. |
---|
1624 | * |
---|
1625 | * Retrieves a pad template from @element that is compatible with @compattempl. |
---|
1626 | * Pads from compatible templates can be linked together. |
---|
1627 | * |
---|
1628 | * Returns: a compatible #GstPadTemplate, or NULL if none was found. No |
---|
1629 | * unreferencing is necessary. |
---|
1630 | */ |
---|
1631 | GstPadTemplate * |
---|
1632 | gst_element_get_compatible_pad_template (GstElement * element, |
---|
1633 | GstPadTemplate * compattempl) |
---|
1634 | { |
---|
1635 | GstPadTemplate *newtempl = NULL; |
---|
1636 | GList *padlist; |
---|
1637 | |
---|
1638 | g_return_val_if_fail (element != NULL, NULL); |
---|
1639 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
1640 | g_return_val_if_fail (compattempl != NULL, NULL); |
---|
1641 | |
---|
1642 | padlist = gst_element_get_pad_template_list (element); |
---|
1643 | |
---|
1644 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, |
---|
1645 | "Looking for a suitable pad template in %s out of %d templates...", |
---|
1646 | GST_ELEMENT_NAME (element), g_list_length (padlist)); |
---|
1647 | |
---|
1648 | while (padlist) { |
---|
1649 | GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data; |
---|
1650 | GstCaps *intersection; |
---|
1651 | |
---|
1652 | /* Ignore name |
---|
1653 | * Ignore presence |
---|
1654 | * Check direction (must be opposite) |
---|
1655 | * Check caps |
---|
1656 | */ |
---|
1657 | GST_CAT_LOG (GST_CAT_CAPS, |
---|
1658 | "checking pad template %s", padtempl->name_template); |
---|
1659 | if (padtempl->direction != compattempl->direction) { |
---|
1660 | gboolean is_empty; |
---|
1661 | |
---|
1662 | GST_CAT_DEBUG (GST_CAT_CAPS, |
---|
1663 | "compatible direction: found %s pad template \"%s\"", |
---|
1664 | padtempl->direction == GST_PAD_SRC ? "src" : "sink", |
---|
1665 | padtempl->name_template); |
---|
1666 | |
---|
1667 | intersection = gst_caps_intersect (GST_PAD_TEMPLATE_CAPS (compattempl), |
---|
1668 | GST_PAD_TEMPLATE_CAPS (padtempl)); |
---|
1669 | |
---|
1670 | is_empty = gst_caps_is_empty (intersection); |
---|
1671 | |
---|
1672 | GST_CAT_DEBUG (GST_CAT_CAPS, "caps are %scompatible", |
---|
1673 | is_empty ? "not " : ""); |
---|
1674 | |
---|
1675 | if (!is_empty) |
---|
1676 | newtempl = padtempl; |
---|
1677 | gst_caps_free (intersection); |
---|
1678 | if (newtempl) |
---|
1679 | break; |
---|
1680 | } |
---|
1681 | |
---|
1682 | padlist = g_list_next (padlist); |
---|
1683 | } |
---|
1684 | if (newtempl) |
---|
1685 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, |
---|
1686 | "Returning new pad template %p", newtempl); |
---|
1687 | else |
---|
1688 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "No compatible pad template found"); |
---|
1689 | |
---|
1690 | return newtempl; |
---|
1691 | } |
---|
1692 | |
---|
1693 | /** |
---|
1694 | * gst_element_get_pad_from_template: |
---|
1695 | * @element: a #GstElement. |
---|
1696 | * @templ: a #GstPadTemplate belonging to @element. |
---|
1697 | * |
---|
1698 | * Gets a pad from @element described by @templ. If the presence of @templ is |
---|
1699 | * #GST_PAD_REQUEST, requests a new pad. Can return %NULL for #GST_PAD_SOMETIMES |
---|
1700 | * templates. |
---|
1701 | * |
---|
1702 | * Returns: the #GstPad, or NULL if one could not be found or created. |
---|
1703 | */ |
---|
1704 | static GstPad * |
---|
1705 | gst_element_get_pad_from_template (GstElement * element, GstPadTemplate * templ) |
---|
1706 | { |
---|
1707 | GstPad *ret = NULL; |
---|
1708 | GstPadPresence presence; |
---|
1709 | |
---|
1710 | /* If this function is ever exported, we need check the validity of `element' |
---|
1711 | * and `templ', and to make sure the template actually belongs to the |
---|
1712 | * element. */ |
---|
1713 | |
---|
1714 | presence = GST_PAD_TEMPLATE_PRESENCE (templ); |
---|
1715 | |
---|
1716 | switch (presence) { |
---|
1717 | case GST_PAD_ALWAYS: |
---|
1718 | case GST_PAD_SOMETIMES: |
---|
1719 | ret = gst_element_get_static_pad (element, templ->name_template); |
---|
1720 | if (!ret && presence == GST_PAD_ALWAYS) |
---|
1721 | g_warning |
---|
1722 | ("Element %s has an ALWAYS template %s, but no pad of the same name", |
---|
1723 | GST_OBJECT_NAME (element), templ->name_template); |
---|
1724 | break; |
---|
1725 | |
---|
1726 | case GST_PAD_REQUEST: |
---|
1727 | ret = gst_element_request_pad (element, templ, NULL); |
---|
1728 | break; |
---|
1729 | } |
---|
1730 | |
---|
1731 | return ret; |
---|
1732 | } |
---|
1733 | |
---|
1734 | /** |
---|
1735 | * gst_element_request_compatible_pad: |
---|
1736 | * @element: a #GstElement. |
---|
1737 | * @templ: the #GstPadTemplate to which the new pad should be able to link. |
---|
1738 | * |
---|
1739 | * Requests a pad from @element. The returned pad should be unlinked and |
---|
1740 | * compatible with @templ. Might return an existing pad, or request a new one. |
---|
1741 | * |
---|
1742 | * Returns: a #GstPad, or %NULL if one could not be found or created. |
---|
1743 | */ |
---|
1744 | GstPad * |
---|
1745 | gst_element_request_compatible_pad (GstElement * element, |
---|
1746 | GstPadTemplate * templ) |
---|
1747 | { |
---|
1748 | GstPadTemplate *templ_new; |
---|
1749 | GstPad *pad = NULL; |
---|
1750 | |
---|
1751 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
1752 | g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL); |
---|
1753 | |
---|
1754 | /* FIXME: should really loop through the templates, testing each for |
---|
1755 | compatibility and pad availability. */ |
---|
1756 | templ_new = gst_element_get_compatible_pad_template (element, templ); |
---|
1757 | if (templ_new) |
---|
1758 | pad = gst_element_get_pad_from_template (element, templ_new); |
---|
1759 | |
---|
1760 | /* This can happen for non-request pads. No need to unref. */ |
---|
1761 | if (pad && GST_PAD_PEER (pad)) |
---|
1762 | pad = NULL; |
---|
1763 | |
---|
1764 | return pad; |
---|
1765 | } |
---|
1766 | |
---|
1767 | /** |
---|
1768 | * gst_element_get_compatible_pad_filtered: |
---|
1769 | * @element: a #GstElement in which the pad should be found. |
---|
1770 | * @pad: the #GstPad to find a compatible one for. |
---|
1771 | * @filtercaps: the #GstCaps to use as a filter. |
---|
1772 | * |
---|
1773 | * Looks for an unlinked pad to which the given pad can link. It is not |
---|
1774 | * guaranteed that linking the pads will work, though it should work in most |
---|
1775 | * cases. |
---|
1776 | * |
---|
1777 | * Returns: the #GstPad to which a link can be made, or %NULL if one cannot be |
---|
1778 | * found. |
---|
1779 | */ |
---|
1780 | GstPad * |
---|
1781 | gst_element_get_compatible_pad_filtered (GstElement * element, GstPad * pad, |
---|
1782 | const GstCaps * filtercaps) |
---|
1783 | { |
---|
1784 | const GList *pads; |
---|
1785 | GstPadTemplate *templ; |
---|
1786 | GstCaps *templcaps; |
---|
1787 | GstPad *foundpad = NULL; |
---|
1788 | |
---|
1789 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
1790 | g_return_val_if_fail (GST_IS_PAD (pad), NULL); |
---|
1791 | |
---|
1792 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, |
---|
1793 | "finding pad in %s compatible with %s:%s and filter %" GST_PTR_FORMAT, |
---|
1794 | GST_ELEMENT_NAME (element), GST_DEBUG_PAD_NAME (pad), filtercaps); |
---|
1795 | |
---|
1796 | /* let's use the real pad */ |
---|
1797 | pad = (GstPad *) GST_PAD_REALIZE (pad); |
---|
1798 | g_return_val_if_fail (pad != NULL, NULL); |
---|
1799 | g_return_val_if_fail (GST_RPAD_PEER (pad) == NULL, NULL); |
---|
1800 | |
---|
1801 | /* try to get an existing unlinked pad */ |
---|
1802 | pads = gst_element_get_pad_list (element); |
---|
1803 | while (pads) { |
---|
1804 | GstPad *current = GST_PAD (pads->data); |
---|
1805 | |
---|
1806 | GST_CAT_LOG (GST_CAT_ELEMENT_PADS, "examing pad %s:%s", |
---|
1807 | GST_DEBUG_PAD_NAME (current)); |
---|
1808 | if (GST_PAD_PEER (current) == NULL && |
---|
1809 | gst_pad_can_link_filtered (pad, current, filtercaps)) { |
---|
1810 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, |
---|
1811 | "found existing unlinked pad %s:%s", GST_DEBUG_PAD_NAME (current)); |
---|
1812 | return current; |
---|
1813 | } |
---|
1814 | pads = g_list_next (pads); |
---|
1815 | } |
---|
1816 | |
---|
1817 | /* try to create a new one */ |
---|
1818 | /* requesting is a little crazy, we need a template. Let's create one */ |
---|
1819 | templcaps = gst_pad_get_caps (pad); |
---|
1820 | if (filtercaps != NULL) { |
---|
1821 | GstCaps *temp; |
---|
1822 | |
---|
1823 | temp = gst_caps_intersect (filtercaps, templcaps); |
---|
1824 | gst_caps_free (templcaps); |
---|
1825 | templcaps = temp; |
---|
1826 | } |
---|
1827 | |
---|
1828 | templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad), |
---|
1829 | GST_PAD_DIRECTION (pad), GST_PAD_ALWAYS, templcaps); |
---|
1830 | foundpad = gst_element_request_compatible_pad (element, templ); |
---|
1831 | gst_object_unref (GST_OBJECT (templ)); |
---|
1832 | |
---|
1833 | if (foundpad) { |
---|
1834 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, |
---|
1835 | "found existing request pad %s:%s", GST_DEBUG_PAD_NAME (foundpad)); |
---|
1836 | return foundpad; |
---|
1837 | } |
---|
1838 | |
---|
1839 | GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element, |
---|
1840 | "Could not find a compatible pad to link to %s:%s", |
---|
1841 | GST_DEBUG_PAD_NAME (pad)); |
---|
1842 | return NULL; |
---|
1843 | } |
---|
1844 | |
---|
1845 | /** |
---|
1846 | * gst_element_get_compatible_pad: |
---|
1847 | * @element: a #GstElement in which the pad should be found. |
---|
1848 | * @pad: the #GstPad to find a compatible one for. |
---|
1849 | * |
---|
1850 | * Looks for an unlinked pad to which the given pad can link to. |
---|
1851 | * It is not guaranteed that linking the pads will work, though |
---|
1852 | * it should work in most cases. |
---|
1853 | * |
---|
1854 | * Returns: the #GstPad to which a link can be made, or %NULL if one |
---|
1855 | * could not be found. |
---|
1856 | */ |
---|
1857 | GstPad * |
---|
1858 | gst_element_get_compatible_pad (GstElement * element, GstPad * pad) |
---|
1859 | { |
---|
1860 | return gst_element_get_compatible_pad_filtered (element, pad, NULL); |
---|
1861 | } |
---|
1862 | |
---|
1863 | /** |
---|
1864 | * gst_element_link_pads_filtered: |
---|
1865 | * @src: a #GstElement containing the source pad. |
---|
1866 | * @srcpadname: the name of the #GstPad in source element or NULL for any pad. |
---|
1867 | * @dest: the #GstElement containing the destination pad. |
---|
1868 | * @destpadname: the name of the #GstPad in destination element or NULL for any pad. |
---|
1869 | * @filtercaps: the #GstCaps to use as a filter. |
---|
1870 | * |
---|
1871 | * Links the two named pads of the source and destination elements. |
---|
1872 | * Side effect is that if one of the pads has no parent, it becomes a |
---|
1873 | * child of the parent of the other element. If they have different |
---|
1874 | * parents, the link fails. |
---|
1875 | * |
---|
1876 | * Returns: TRUE if the pads could be linked, FALSE otherwise. |
---|
1877 | */ |
---|
1878 | gboolean |
---|
1879 | gst_element_link_pads_filtered (GstElement * src, const gchar * srcpadname, |
---|
1880 | GstElement * dest, const gchar * destpadname, const GstCaps * filtercaps) |
---|
1881 | { |
---|
1882 | const GList *srcpads, *destpads, *srctempls, *desttempls, *l; |
---|
1883 | GstPad *srcpad, *destpad; |
---|
1884 | GstPadTemplate *srctempl, *desttempl; |
---|
1885 | |
---|
1886 | /* checks */ |
---|
1887 | g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE); |
---|
1888 | g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE); |
---|
1889 | |
---|
1890 | GST_CAT_INFO (GST_CAT_ELEMENT_PADS, |
---|
1891 | "trying to link element %s:%s to element %s:%s", GST_ELEMENT_NAME (src), |
---|
1892 | srcpadname ? srcpadname : "(any)", GST_ELEMENT_NAME (dest), |
---|
1893 | destpadname ? destpadname : "(any)"); |
---|
1894 | |
---|
1895 | /* now get the pads we're trying to link and a list of all remaining pads */ |
---|
1896 | if (srcpadname) { |
---|
1897 | srcpad = gst_element_get_pad (src, srcpadname); |
---|
1898 | if (!srcpad) { |
---|
1899 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s", |
---|
1900 | GST_ELEMENT_NAME (src), srcpadname); |
---|
1901 | return FALSE; |
---|
1902 | } else { |
---|
1903 | if (!(GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC)) { |
---|
1904 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no src pad", |
---|
1905 | GST_DEBUG_PAD_NAME (srcpad)); |
---|
1906 | return FALSE; |
---|
1907 | } |
---|
1908 | if (GST_PAD_PEER (srcpad) != NULL) { |
---|
1909 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked", |
---|
1910 | GST_DEBUG_PAD_NAME (srcpad)); |
---|
1911 | return FALSE; |
---|
1912 | } |
---|
1913 | } |
---|
1914 | srcpads = NULL; |
---|
1915 | } else { |
---|
1916 | srcpads = gst_element_get_pad_list (src); |
---|
1917 | srcpad = srcpads ? (GstPad *) GST_PAD_REALIZE (srcpads->data) : NULL; |
---|
1918 | } |
---|
1919 | if (destpadname) { |
---|
1920 | destpad = gst_element_get_pad (dest, destpadname); |
---|
1921 | if (!destpad) { |
---|
1922 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s", |
---|
1923 | GST_ELEMENT_NAME (dest), destpadname); |
---|
1924 | return FALSE; |
---|
1925 | } else { |
---|
1926 | if (!(GST_PAD_DIRECTION (destpad) == GST_PAD_SINK)) { |
---|
1927 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no sink pad", |
---|
1928 | GST_DEBUG_PAD_NAME (destpad)); |
---|
1929 | return FALSE; |
---|
1930 | } |
---|
1931 | if (GST_PAD_PEER (destpad) != NULL) { |
---|
1932 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked", |
---|
1933 | GST_DEBUG_PAD_NAME (destpad)); |
---|
1934 | return FALSE; |
---|
1935 | } |
---|
1936 | } |
---|
1937 | destpads = NULL; |
---|
1938 | } else { |
---|
1939 | destpads = gst_element_get_pad_list (dest); |
---|
1940 | destpad = destpads ? (GstPad *) GST_PAD_REALIZE (destpads->data) : NULL; |
---|
1941 | } |
---|
1942 | |
---|
1943 | if (srcpadname && destpadname) { |
---|
1944 | /* two explicitly specified pads */ |
---|
1945 | return gst_pad_link_filtered (srcpad, destpad, filtercaps); |
---|
1946 | } |
---|
1947 | if (srcpad) { |
---|
1948 | /* loop through the allowed pads in the source, trying to find a |
---|
1949 | * compatible destination pad */ |
---|
1950 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, |
---|
1951 | "looping through allowed src and dest pads"); |
---|
1952 | do { |
---|
1953 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying src pad %s:%s", |
---|
1954 | GST_DEBUG_PAD_NAME (srcpad)); |
---|
1955 | if ((GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC) && |
---|
1956 | (GST_PAD_PEER (srcpad) == NULL)) { |
---|
1957 | GstPad *temp = destpadname ? destpad : |
---|
1958 | gst_element_get_compatible_pad_filtered (dest, srcpad, |
---|
1959 | filtercaps); |
---|
1960 | |
---|
1961 | if (temp && gst_pad_link_filtered (srcpad, temp, filtercaps)) { |
---|
1962 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s", |
---|
1963 | GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (temp)); |
---|
1964 | return TRUE; |
---|
1965 | } |
---|
1966 | } |
---|
1967 | /* find a better way for this mess */ |
---|
1968 | if (srcpads) { |
---|
1969 | srcpads = g_list_next (srcpads); |
---|
1970 | if (srcpads) |
---|
1971 | srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data); |
---|
1972 | } |
---|
1973 | } while (srcpads); |
---|
1974 | } |
---|
1975 | if (srcpadname) { |
---|
1976 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s:%s to %s", |
---|
1977 | GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (dest)); |
---|
1978 | return FALSE; |
---|
1979 | } |
---|
1980 | if (destpad) { |
---|
1981 | /* loop through the existing pads in the destination */ |
---|
1982 | do { |
---|
1983 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying dest pad %s:%s", |
---|
1984 | GST_DEBUG_PAD_NAME (destpad)); |
---|
1985 | if ((GST_PAD_DIRECTION (destpad) == GST_PAD_SINK) && |
---|
1986 | (GST_PAD_PEER (destpad) == NULL)) { |
---|
1987 | GstPad *temp = gst_element_get_compatible_pad_filtered (src, destpad, |
---|
1988 | filtercaps); |
---|
1989 | |
---|
1990 | if (temp && gst_pad_link_filtered (temp, destpad, filtercaps)) { |
---|
1991 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s", |
---|
1992 | GST_DEBUG_PAD_NAME (temp), GST_DEBUG_PAD_NAME (destpad)); |
---|
1993 | return TRUE; |
---|
1994 | } |
---|
1995 | } |
---|
1996 | if (destpads) { |
---|
1997 | destpads = g_list_next (destpads); |
---|
1998 | if (destpads) |
---|
1999 | destpad = (GstPad *) GST_PAD_REALIZE (destpads->data); |
---|
2000 | } |
---|
2001 | } while (destpads); |
---|
2002 | } |
---|
2003 | if (destpadname) { |
---|
2004 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s:%s", |
---|
2005 | GST_ELEMENT_NAME (src), GST_DEBUG_PAD_NAME (destpad)); |
---|
2006 | return FALSE; |
---|
2007 | } |
---|
2008 | |
---|
2009 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, |
---|
2010 | "we might have request pads on both sides, checking..."); |
---|
2011 | srctempls = gst_element_get_pad_template_list (src); |
---|
2012 | desttempls = gst_element_get_pad_template_list (dest); |
---|
2013 | |
---|
2014 | if (srctempls && desttempls) { |
---|
2015 | while (srctempls) { |
---|
2016 | srctempl = (GstPadTemplate *) srctempls->data; |
---|
2017 | if (srctempl->presence == GST_PAD_REQUEST) { |
---|
2018 | for (l = desttempls; l; l = l->next) { |
---|
2019 | desttempl = (GstPadTemplate *) l->data; |
---|
2020 | if (desttempl->presence == GST_PAD_REQUEST && |
---|
2021 | desttempl->direction != srctempl->direction) { |
---|
2022 | if (gst_caps_is_always_compatible (gst_pad_template_get_caps |
---|
2023 | (srctempl), gst_pad_template_get_caps (desttempl))) { |
---|
2024 | srcpad = |
---|
2025 | gst_element_get_request_pad (src, srctempl->name_template); |
---|
2026 | destpad = |
---|
2027 | gst_element_get_request_pad (dest, desttempl->name_template); |
---|
2028 | if (gst_pad_link_filtered (srcpad, destpad, filtercaps)) { |
---|
2029 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, |
---|
2030 | "linked pad %s:%s to pad %s:%s", |
---|
2031 | GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad)); |
---|
2032 | return TRUE; |
---|
2033 | } |
---|
2034 | /* it failed, so we release the request pads */ |
---|
2035 | gst_element_release_request_pad (src, srcpad); |
---|
2036 | gst_element_release_request_pad (dest, destpad); |
---|
2037 | } |
---|
2038 | } |
---|
2039 | } |
---|
2040 | } |
---|
2041 | srctempls = srctempls->next; |
---|
2042 | } |
---|
2043 | } |
---|
2044 | |
---|
2045 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s", |
---|
2046 | GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest)); |
---|
2047 | return FALSE; |
---|
2048 | } |
---|
2049 | |
---|
2050 | /** |
---|
2051 | * gst_element_link_filtered: |
---|
2052 | * @src: a #GstElement containing the source pad. |
---|
2053 | * @dest: the #GstElement containing the destination pad. |
---|
2054 | * @filtercaps: the #GstCaps to use as a filter. |
---|
2055 | * |
---|
2056 | * Links @src to @dest, filtered by @filtercaps. The link must be from source to |
---|
2057 | * destination; the other direction will not be tried. The function looks for |
---|
2058 | * existing pads that aren't linked yet. It will request new pads if necessary. |
---|
2059 | * If multiple links are possible, only one is established. |
---|
2060 | * |
---|
2061 | * Returns: TRUE if the elements could be linked, FALSE otherwise. |
---|
2062 | */ |
---|
2063 | gboolean |
---|
2064 | gst_element_link_filtered (GstElement * src, GstElement * dest, |
---|
2065 | const GstCaps * filtercaps) |
---|
2066 | { |
---|
2067 | return gst_element_link_pads_filtered (src, NULL, dest, NULL, filtercaps); |
---|
2068 | } |
---|
2069 | |
---|
2070 | /** |
---|
2071 | * gst_element_link_many: |
---|
2072 | * @element_1: the first #GstElement in the link chain. |
---|
2073 | * @element_2: the second #GstElement in the link chain. |
---|
2074 | * @...: the NULL-terminated list of elements to link in order. |
---|
2075 | * |
---|
2076 | * Chain together a series of elements. Uses gst_element_link(). |
---|
2077 | * |
---|
2078 | * Returns: TRUE on success, FALSE otherwise. |
---|
2079 | */ |
---|
2080 | gboolean |
---|
2081 | gst_element_link_many (GstElement * element_1, GstElement * element_2, ...) |
---|
2082 | { |
---|
2083 | va_list args; |
---|
2084 | |
---|
2085 | g_return_val_if_fail (GST_IS_ELEMENT (element_1), FALSE); |
---|
2086 | g_return_val_if_fail (GST_IS_ELEMENT (element_2), FALSE); |
---|
2087 | |
---|
2088 | va_start (args, element_2); |
---|
2089 | |
---|
2090 | while (element_2) { |
---|
2091 | if (!gst_element_link (element_1, element_2)) |
---|
2092 | return FALSE; |
---|
2093 | |
---|
2094 | element_1 = element_2; |
---|
2095 | element_2 = va_arg (args, GstElement *); |
---|
2096 | } |
---|
2097 | |
---|
2098 | va_end (args); |
---|
2099 | |
---|
2100 | return TRUE; |
---|
2101 | } |
---|
2102 | |
---|
2103 | /** |
---|
2104 | * gst_element_link: |
---|
2105 | * @src: a #GstElement containing the source pad. |
---|
2106 | * @dest: the #GstElement containing the destination pad. |
---|
2107 | * |
---|
2108 | * Links @src to @dest with no filter caps. See gst_element_link_filtered() for |
---|
2109 | * more information. |
---|
2110 | * |
---|
2111 | * Returns: TRUE if the elements could be linked, FALSE otherwise. |
---|
2112 | */ |
---|
2113 | gboolean |
---|
2114 | gst_element_link (GstElement * src, GstElement * dest) |
---|
2115 | { |
---|
2116 | return gst_element_link_pads_filtered (src, NULL, dest, NULL, NULL); |
---|
2117 | } |
---|
2118 | |
---|
2119 | /** |
---|
2120 | * gst_element_link_pads: |
---|
2121 | * @src: a #GstElement containing the source pad. |
---|
2122 | * @srcpadname: the name of the #GstPad in the source element. |
---|
2123 | * @dest: the #GstElement containing the destination pad. |
---|
2124 | * @destpadname: the name of the #GstPad in destination element. |
---|
2125 | * |
---|
2126 | * Links the two named pads of the source and destination elements. |
---|
2127 | * Side effect is that if one of the pads has no parent, it becomes a |
---|
2128 | * child of the parent of the other element. If they have different |
---|
2129 | * parents, the link fails. |
---|
2130 | * |
---|
2131 | * Returns: TRUE if the pads could be linked, FALSE otherwise. |
---|
2132 | */ |
---|
2133 | gboolean |
---|
2134 | gst_element_link_pads (GstElement * src, const gchar * srcpadname, |
---|
2135 | GstElement * dest, const gchar * destpadname) |
---|
2136 | { |
---|
2137 | return gst_element_link_pads_filtered (src, srcpadname, dest, destpadname, |
---|
2138 | NULL); |
---|
2139 | } |
---|
2140 | |
---|
2141 | /** |
---|
2142 | * gst_element_unlink_pads: |
---|
2143 | * @src: a #GstElement containing the source pad. |
---|
2144 | * @srcpadname: the name of the #GstPad in source element. |
---|
2145 | * @dest: a #GstElement containing the destination pad. |
---|
2146 | * @destpadname: the name of the #GstPad in destination element. |
---|
2147 | * |
---|
2148 | * Unlinks the two named pads of the source and destination elements. |
---|
2149 | */ |
---|
2150 | void |
---|
2151 | gst_element_unlink_pads (GstElement * src, const gchar * srcpadname, |
---|
2152 | GstElement * dest, const gchar * destpadname) |
---|
2153 | { |
---|
2154 | GstPad *srcpad, *destpad; |
---|
2155 | |
---|
2156 | g_return_if_fail (src != NULL); |
---|
2157 | g_return_if_fail (GST_IS_ELEMENT (src)); |
---|
2158 | g_return_if_fail (srcpadname != NULL); |
---|
2159 | g_return_if_fail (dest != NULL); |
---|
2160 | g_return_if_fail (GST_IS_ELEMENT (dest)); |
---|
2161 | g_return_if_fail (destpadname != NULL); |
---|
2162 | |
---|
2163 | /* obtain the pads requested */ |
---|
2164 | srcpad = gst_element_get_pad (src, srcpadname); |
---|
2165 | if (srcpad == NULL) { |
---|
2166 | GST_WARNING_OBJECT (src, "source element has no pad \"%s\"", srcpadname); |
---|
2167 | return; |
---|
2168 | } |
---|
2169 | destpad = gst_element_get_pad (dest, destpadname); |
---|
2170 | if (srcpad == NULL) { |
---|
2171 | GST_WARNING_OBJECT (dest, "destination element has no pad \"%s\"", |
---|
2172 | destpadname); |
---|
2173 | return; |
---|
2174 | } |
---|
2175 | |
---|
2176 | /* we're satisified they can be unlinked, let's do it */ |
---|
2177 | gst_pad_unlink (srcpad, destpad); |
---|
2178 | } |
---|
2179 | |
---|
2180 | /** |
---|
2181 | * gst_element_unlink_many: |
---|
2182 | * @element_1: the first #GstElement in the link chain. |
---|
2183 | * @element_2: the second #GstElement in the link chain. |
---|
2184 | * @...: the NULL-terminated list of elements to unlink in order. |
---|
2185 | * |
---|
2186 | * Unlinks a series of elements. Uses gst_element_unlink(). |
---|
2187 | */ |
---|
2188 | void |
---|
2189 | gst_element_unlink_many (GstElement * element_1, GstElement * element_2, ...) |
---|
2190 | { |
---|
2191 | va_list args; |
---|
2192 | |
---|
2193 | g_return_if_fail (element_1 != NULL && element_2 != NULL); |
---|
2194 | g_return_if_fail (GST_IS_ELEMENT (element_1) && GST_IS_ELEMENT (element_2)); |
---|
2195 | |
---|
2196 | va_start (args, element_2); |
---|
2197 | |
---|
2198 | while (element_2) { |
---|
2199 | gst_element_unlink (element_1, element_2); |
---|
2200 | |
---|
2201 | element_1 = element_2; |
---|
2202 | element_2 = va_arg (args, GstElement *); |
---|
2203 | } |
---|
2204 | |
---|
2205 | va_end (args); |
---|
2206 | } |
---|
2207 | |
---|
2208 | /** |
---|
2209 | * gst_element_unlink: |
---|
2210 | * @src: the source #GstElement to unlink. |
---|
2211 | * @dest: the sink #GstElement to unlink. |
---|
2212 | * |
---|
2213 | * Unlinks all source pads of the source element with all sink pads |
---|
2214 | * of the sink element to which they are linked. |
---|
2215 | */ |
---|
2216 | void |
---|
2217 | gst_element_unlink (GstElement * src, GstElement * dest) |
---|
2218 | { |
---|
2219 | const GList *srcpads; |
---|
2220 | GstPad *pad; |
---|
2221 | |
---|
2222 | g_return_if_fail (GST_IS_ELEMENT (src)); |
---|
2223 | g_return_if_fail (GST_IS_ELEMENT (dest)); |
---|
2224 | |
---|
2225 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unlinking \"%s\" and \"%s\"", |
---|
2226 | GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest)); |
---|
2227 | |
---|
2228 | srcpads = gst_element_get_pad_list (src); |
---|
2229 | |
---|
2230 | while (srcpads) { |
---|
2231 | pad = GST_PAD (srcpads->data); |
---|
2232 | |
---|
2233 | /* we only care about real src pads */ |
---|
2234 | if (GST_IS_REAL_PAD (pad) && GST_PAD_IS_SRC (pad)) { |
---|
2235 | GstPad *peerpad = GST_PAD_PEER (pad); |
---|
2236 | |
---|
2237 | /* see if the pad is connected and is really a pad |
---|
2238 | * of dest */ |
---|
2239 | if (peerpad && (GST_OBJECT_PARENT (peerpad) == (GstObject *) dest)) { |
---|
2240 | gst_pad_unlink (pad, peerpad); |
---|
2241 | } |
---|
2242 | } |
---|
2243 | |
---|
2244 | srcpads = g_list_next (srcpads); |
---|
2245 | } |
---|
2246 | } |
---|
2247 | |
---|
2248 | static void |
---|
2249 | gst_element_error_func (GstElement * element, GstElement * source, |
---|
2250 | GError * error, gchar * debug) |
---|
2251 | { |
---|
2252 | GstObject *parent = GST_OBJECT_PARENT (element); |
---|
2253 | |
---|
2254 | /* tell the parent */ |
---|
2255 | if (parent) { |
---|
2256 | gst_object_ref (GST_OBJECT (element)); |
---|
2257 | gst_object_ref (parent); |
---|
2258 | GST_CAT_DEBUG (GST_CAT_ERROR_SYSTEM, |
---|
2259 | "forwarding error \"%s\" from %s to %s", error->message, |
---|
2260 | GST_ELEMENT_NAME (element), GST_OBJECT_NAME (parent)); |
---|
2261 | |
---|
2262 | g_signal_emit (G_OBJECT (parent), |
---|
2263 | gst_element_signals[ERROR], 0, source, error, debug); |
---|
2264 | GST_CAT_DEBUG (GST_CAT_ERROR_SYSTEM, "forwarded error \"%s\" from %s to %s", |
---|
2265 | error->message, GST_ELEMENT_NAME (element), GST_OBJECT_NAME (parent)); |
---|
2266 | gst_object_unref (GST_OBJECT (element)); |
---|
2267 | gst_object_unref (GST_OBJECT (parent)); |
---|
2268 | } |
---|
2269 | } |
---|
2270 | |
---|
2271 | static GstPad * |
---|
2272 | gst_element_get_random_pad (GstElement * element, GstPadDirection dir) |
---|
2273 | { |
---|
2274 | GList *pads = element->pads; |
---|
2275 | |
---|
2276 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "getting a random pad"); |
---|
2277 | while (pads) { |
---|
2278 | GstPad *pad = GST_PAD (pads->data); |
---|
2279 | |
---|
2280 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "checking pad %s:%s", |
---|
2281 | GST_DEBUG_PAD_NAME (pad)); |
---|
2282 | |
---|
2283 | if (GST_PAD_DIRECTION (pad) == dir) { |
---|
2284 | if (GST_PAD_IS_LINKED (pad)) { |
---|
2285 | return pad; |
---|
2286 | } else { |
---|
2287 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is not linked", |
---|
2288 | GST_DEBUG_PAD_NAME (pad)); |
---|
2289 | } |
---|
2290 | } else { |
---|
2291 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is in wrong direction", |
---|
2292 | GST_DEBUG_PAD_NAME (pad)); |
---|
2293 | } |
---|
2294 | |
---|
2295 | pads = g_list_next (pads); |
---|
2296 | } |
---|
2297 | return NULL; |
---|
2298 | } |
---|
2299 | |
---|
2300 | /** |
---|
2301 | * gst_element_get_event_masks: |
---|
2302 | * @element: a #GstElement to query |
---|
2303 | * |
---|
2304 | * Get an array of event masks from the element. |
---|
2305 | * If the element doesn't implement an event masks function, |
---|
2306 | * the query will be forwarded to a random linked sink pad. |
---|
2307 | * |
---|
2308 | * Returns: An array of #GstEventMask elements. |
---|
2309 | */ |
---|
2310 | const GstEventMask * |
---|
2311 | gst_element_get_event_masks (GstElement * element) |
---|
2312 | { |
---|
2313 | GstElementClass *oclass; |
---|
2314 | |
---|
2315 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
2316 | |
---|
2317 | oclass = GST_ELEMENT_GET_CLASS (element); |
---|
2318 | |
---|
2319 | if (oclass->get_event_masks) |
---|
2320 | return oclass->get_event_masks (element); |
---|
2321 | else { |
---|
2322 | GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK); |
---|
2323 | |
---|
2324 | if (pad) |
---|
2325 | return gst_pad_get_event_masks (GST_PAD_PEER (pad)); |
---|
2326 | } |
---|
2327 | |
---|
2328 | return NULL; |
---|
2329 | } |
---|
2330 | |
---|
2331 | /** |
---|
2332 | * gst_element_send_event: |
---|
2333 | * @element: a #GstElement to send the event to. |
---|
2334 | * @event: the #GstEvent to send to the element. |
---|
2335 | * |
---|
2336 | * Sends an event to an element. If the element doesn't |
---|
2337 | * implement an event handler, the event will be forwarded |
---|
2338 | * to a random sink pad. |
---|
2339 | * |
---|
2340 | * Returns: TRUE if the event was handled. |
---|
2341 | */ |
---|
2342 | gboolean |
---|
2343 | gst_element_send_event (GstElement * element, GstEvent * event) |
---|
2344 | { |
---|
2345 | GstElementClass *oclass; |
---|
2346 | |
---|
2347 | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
---|
2348 | g_return_val_if_fail (event != NULL, FALSE); |
---|
2349 | |
---|
2350 | oclass = GST_ELEMENT_GET_CLASS (element); |
---|
2351 | |
---|
2352 | if (oclass->send_event) |
---|
2353 | return oclass->send_event (element, event); |
---|
2354 | else { |
---|
2355 | GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK); |
---|
2356 | |
---|
2357 | if (pad) { |
---|
2358 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "sending event to random pad %s:%s", |
---|
2359 | GST_DEBUG_PAD_NAME (pad)); |
---|
2360 | return gst_pad_send_event (GST_PAD_PEER (pad), event); |
---|
2361 | } |
---|
2362 | } |
---|
2363 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "can't send event on element %s", |
---|
2364 | GST_ELEMENT_NAME (element)); |
---|
2365 | return FALSE; |
---|
2366 | } |
---|
2367 | |
---|
2368 | /** |
---|
2369 | * gst_element_seek: |
---|
2370 | * @element: a #GstElement to send the event to. |
---|
2371 | * @seek_type: the method to use for seeking. |
---|
2372 | * @offset: the offset to seek to. |
---|
2373 | * |
---|
2374 | * Sends a seek event to an element. |
---|
2375 | * |
---|
2376 | * Returns: TRUE if the event was handled. |
---|
2377 | */ |
---|
2378 | gboolean |
---|
2379 | gst_element_seek (GstElement * element, GstSeekType seek_type, guint64 offset) |
---|
2380 | { |
---|
2381 | GstEvent *event = gst_event_new_seek (seek_type, offset); |
---|
2382 | |
---|
2383 | return gst_element_send_event (element, event); |
---|
2384 | } |
---|
2385 | |
---|
2386 | /** |
---|
2387 | * gst_element_get_query_types: |
---|
2388 | * @element: a #GstElement to query |
---|
2389 | * |
---|
2390 | * Get an array of query types from the element. |
---|
2391 | * If the element doesn't implement a query types function, |
---|
2392 | * the query will be forwarded to a random sink pad. |
---|
2393 | * |
---|
2394 | * Returns: An array of #GstQueryType elements. |
---|
2395 | */ |
---|
2396 | const GstQueryType * |
---|
2397 | gst_element_get_query_types (GstElement * element) |
---|
2398 | { |
---|
2399 | GstElementClass *oclass; |
---|
2400 | |
---|
2401 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
2402 | |
---|
2403 | oclass = GST_ELEMENT_GET_CLASS (element); |
---|
2404 | |
---|
2405 | if (oclass->get_query_types) |
---|
2406 | return oclass->get_query_types (element); |
---|
2407 | else { |
---|
2408 | GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK); |
---|
2409 | |
---|
2410 | if (pad) |
---|
2411 | return gst_pad_get_query_types (GST_PAD_PEER (pad)); |
---|
2412 | } |
---|
2413 | |
---|
2414 | return NULL; |
---|
2415 | } |
---|
2416 | |
---|
2417 | /** |
---|
2418 | * gst_element_query: |
---|
2419 | * @element: a #GstElement to perform the query on. |
---|
2420 | * @type: the #GstQueryType. |
---|
2421 | * @format: the #GstFormat pointer to hold the format of the result. |
---|
2422 | * @value: the pointer to the value of the result. |
---|
2423 | * |
---|
2424 | * Performs a query on the given element. If the format is set |
---|
2425 | * to GST_FORMAT_DEFAULT and this function returns TRUE, the |
---|
2426 | * format pointer will hold the default format. |
---|
2427 | * For element that don't implement a query handler, this function |
---|
2428 | * forwards the query to a random usable sinkpad of this element. |
---|
2429 | * |
---|
2430 | * Returns: TRUE if the query could be performed. |
---|
2431 | */ |
---|
2432 | gboolean |
---|
2433 | gst_element_query (GstElement * element, GstQueryType type, |
---|
2434 | GstFormat * format, gint64 * value) |
---|
2435 | { |
---|
2436 | GstElementClass *oclass; |
---|
2437 | |
---|
2438 | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
---|
2439 | g_return_val_if_fail (format != NULL, FALSE); |
---|
2440 | g_return_val_if_fail (value != NULL, FALSE); |
---|
2441 | |
---|
2442 | oclass = GST_ELEMENT_GET_CLASS (element); |
---|
2443 | |
---|
2444 | if (oclass->query) |
---|
2445 | return oclass->query (element, type, format, value); |
---|
2446 | else { |
---|
2447 | GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SRC); |
---|
2448 | |
---|
2449 | if (pad) |
---|
2450 | return gst_pad_query (pad, type, format, value); |
---|
2451 | pad = gst_element_get_random_pad (element, GST_PAD_SINK); |
---|
2452 | if (pad) |
---|
2453 | return gst_pad_query (GST_PAD_PEER (pad), type, format, value); |
---|
2454 | } |
---|
2455 | |
---|
2456 | return FALSE; |
---|
2457 | } |
---|
2458 | |
---|
2459 | /** |
---|
2460 | * gst_element_get_formats: |
---|
2461 | * @element: a #GstElement to query |
---|
2462 | * |
---|
2463 | * Get an array of formats from the element. |
---|
2464 | * If the element doesn't implement a formats function, |
---|
2465 | * the query will be forwarded to a random sink pad. |
---|
2466 | * |
---|
2467 | * Returns: An array of #GstFormat elements. |
---|
2468 | */ |
---|
2469 | const GstFormat * |
---|
2470 | gst_element_get_formats (GstElement * element) |
---|
2471 | { |
---|
2472 | GstElementClass *oclass; |
---|
2473 | |
---|
2474 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
2475 | |
---|
2476 | oclass = GST_ELEMENT_GET_CLASS (element); |
---|
2477 | |
---|
2478 | if (oclass->get_formats) |
---|
2479 | return oclass->get_formats (element); |
---|
2480 | else { |
---|
2481 | GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK); |
---|
2482 | |
---|
2483 | if (pad) |
---|
2484 | return gst_pad_get_formats (GST_PAD_PEER (pad)); |
---|
2485 | } |
---|
2486 | |
---|
2487 | return NULL; |
---|
2488 | } |
---|
2489 | |
---|
2490 | /** |
---|
2491 | * gst_element_convert: |
---|
2492 | * @element: a #GstElement to invoke the converter on. |
---|
2493 | * @src_format: the source #GstFormat. |
---|
2494 | * @src_value: the source value. |
---|
2495 | * @dest_format: a pointer to the destination #GstFormat. |
---|
2496 | * @dest_value: a pointer to the destination value. |
---|
2497 | * |
---|
2498 | * Invokes a conversion on the element. |
---|
2499 | * If the element doesn't implement a convert function, |
---|
2500 | * the query will be forwarded to a random sink pad. |
---|
2501 | * |
---|
2502 | * Returns: TRUE if the conversion could be performed. |
---|
2503 | */ |
---|
2504 | gboolean |
---|
2505 | gst_element_convert (GstElement * element, |
---|
2506 | GstFormat src_format, gint64 src_value, |
---|
2507 | GstFormat * dest_format, gint64 * dest_value) |
---|
2508 | { |
---|
2509 | GstElementClass *oclass; |
---|
2510 | |
---|
2511 | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
---|
2512 | g_return_val_if_fail (dest_format != NULL, FALSE); |
---|
2513 | g_return_val_if_fail (dest_value != NULL, FALSE); |
---|
2514 | |
---|
2515 | if (src_format == *dest_format) { |
---|
2516 | *dest_value = src_value; |
---|
2517 | return TRUE; |
---|
2518 | } |
---|
2519 | |
---|
2520 | oclass = GST_ELEMENT_GET_CLASS (element); |
---|
2521 | |
---|
2522 | if (oclass->convert) |
---|
2523 | return oclass->convert (element, |
---|
2524 | src_format, src_value, dest_format, dest_value); |
---|
2525 | else { |
---|
2526 | GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK); |
---|
2527 | |
---|
2528 | if (pad) |
---|
2529 | return gst_pad_convert (GST_PAD_PEER (pad), |
---|
2530 | src_format, src_value, dest_format, dest_value); |
---|
2531 | } |
---|
2532 | |
---|
2533 | return FALSE; |
---|
2534 | } |
---|
2535 | |
---|
2536 | /** |
---|
2537 | * _gst_element_error_printf: |
---|
2538 | * @format: the printf-like format to use, or NULL |
---|
2539 | * |
---|
2540 | * This function is only used internally by the #gst_element_error macro. |
---|
2541 | * |
---|
2542 | * Returns: a newly allocated string, or NULL if the format was NULL or "" |
---|
2543 | */ |
---|
2544 | gchar * |
---|
2545 | _gst_element_error_printf (const gchar * format, ...) |
---|
2546 | { |
---|
2547 | va_list args; |
---|
2548 | gchar *buffer; |
---|
2549 | |
---|
2550 | if (format == NULL) |
---|
2551 | return NULL; |
---|
2552 | if (format[0] == 0) |
---|
2553 | return NULL; |
---|
2554 | |
---|
2555 | va_start (args, format); |
---|
2556 | buffer = g_strdup_vprintf (format, args); |
---|
2557 | va_end (args); |
---|
2558 | return buffer; |
---|
2559 | } |
---|
2560 | |
---|
2561 | /** |
---|
2562 | * gst_element_error_full: |
---|
2563 | * @element: a #GstElement with the error. |
---|
2564 | * @domain: the GStreamer error domain this error belongs to. |
---|
2565 | * @code: the error code belonging to the domain |
---|
2566 | * @message: an allocated message to be used as a replacement for the default |
---|
2567 | * message connected to code, or NULL |
---|
2568 | * @debug: an allocated debug message to be used as a replacement for the |
---|
2569 | * default debugging information, or NULL |
---|
2570 | * @file: the source code file where the error was generated |
---|
2571 | * @function: the source code function where the error was generated |
---|
2572 | * @line: the source code line where the error was generated |
---|
2573 | * |
---|
2574 | * Signals an error condition on an element. |
---|
2575 | * This function is used internally by elements. |
---|
2576 | * It results in the "error" signal. |
---|
2577 | */ |
---|
2578 | void gst_element_error_full |
---|
2579 | (GstElement * element, GQuark domain, gint code, gchar * message, |
---|
2580 | gchar * debug, const gchar * file, const gchar * function, gint line) |
---|
2581 | { |
---|
2582 | GError *error = NULL; |
---|
2583 | gchar *name; |
---|
2584 | gchar *sent_message; |
---|
2585 | gchar *sent_debug; |
---|
2586 | |
---|
2587 | /* checks */ |
---|
2588 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
2589 | |
---|
2590 | /* check if we send the given message or the default error message */ |
---|
2591 | if ((message == NULL) || (message[0] == 0)) { |
---|
2592 | /* we got this message from g_strdup_printf (""); */ |
---|
2593 | g_free (message); |
---|
2594 | sent_message = gst_error_get_message (domain, code); |
---|
2595 | } else |
---|
2596 | sent_message = message; |
---|
2597 | |
---|
2598 | if ((debug == NULL) || (debug[0] == 0)) { |
---|
2599 | /* we got this debug from g_strdup_printf (""); */ |
---|
2600 | g_free (debug); |
---|
2601 | debug = NULL; |
---|
2602 | } |
---|
2603 | |
---|
2604 | /* create error message */ |
---|
2605 | GST_CAT_INFO (GST_CAT_ERROR_SYSTEM, "signaling error in %s: %s", |
---|
2606 | GST_ELEMENT_NAME (element), sent_message); |
---|
2607 | error = g_error_new_literal (domain, code, sent_message); |
---|
2608 | |
---|
2609 | /* if the element was already in error, stop now */ |
---|
2610 | if (GST_FLAG_IS_SET (element, GST_ELEMENT_IN_ERROR)) { |
---|
2611 | GST_CAT_INFO (GST_CAT_ERROR_SYSTEM, "recursive ERROR detected in %s", |
---|
2612 | GST_ELEMENT_NAME (element)); |
---|
2613 | g_free (sent_message); |
---|
2614 | if (debug) |
---|
2615 | g_free (debug); |
---|
2616 | return; |
---|
2617 | } |
---|
2618 | |
---|
2619 | GST_FLAG_SET (element, GST_ELEMENT_IN_ERROR); |
---|
2620 | |
---|
2621 | /* emit the signal, make sure the element stays available */ |
---|
2622 | gst_object_ref (GST_OBJECT (element)); |
---|
2623 | name = gst_object_get_path_string (GST_OBJECT (element)); |
---|
2624 | if (debug) |
---|
2625 | sent_debug = g_strdup_printf ("%s(%d): %s: %s:\n%s", |
---|
2626 | file, line, function, name, debug ? debug : ""); |
---|
2627 | else |
---|
2628 | sent_debug = NULL; |
---|
2629 | g_free (debug); |
---|
2630 | g_free (name); |
---|
2631 | g_signal_emit (G_OBJECT (element), gst_element_signals[ERROR], 0, element, |
---|
2632 | error, sent_debug); |
---|
2633 | GST_CAT_INFO (GST_CAT_ERROR_SYSTEM, "signalled error in %s: %s", |
---|
2634 | GST_ELEMENT_NAME (element), sent_message); |
---|
2635 | |
---|
2636 | /* tell the scheduler */ |
---|
2637 | if (element->sched) { |
---|
2638 | gst_scheduler_error (element->sched, element); |
---|
2639 | } |
---|
2640 | |
---|
2641 | if (GST_STATE (element) == GST_STATE_PLAYING) { |
---|
2642 | GstElementStateReturn ret; |
---|
2643 | |
---|
2644 | ret = gst_element_set_state (element, GST_STATE_PAUSED); |
---|
2645 | if (ret != GST_STATE_SUCCESS) { |
---|
2646 | g_warning ("could not PAUSE element \"%s\" after error, help!", |
---|
2647 | GST_ELEMENT_NAME (element)); |
---|
2648 | } |
---|
2649 | } |
---|
2650 | |
---|
2651 | GST_FLAG_UNSET (element, GST_ELEMENT_IN_ERROR); |
---|
2652 | |
---|
2653 | /* cleanup */ |
---|
2654 | gst_object_unref (GST_OBJECT (element)); |
---|
2655 | g_free (sent_message); |
---|
2656 | g_free (sent_debug); |
---|
2657 | g_error_free (error); |
---|
2658 | } |
---|
2659 | |
---|
2660 | /** |
---|
2661 | * gst_element_is_locked_state: |
---|
2662 | * @element: a #GstElement. |
---|
2663 | * |
---|
2664 | * Checks if the state of an element is locked. |
---|
2665 | * If the state of an element is locked, state changes of the parent don't |
---|
2666 | * affect the element. |
---|
2667 | * This way you can leave currently unused elements inside bins. Just lock their |
---|
2668 | * state before changing the state from #GST_STATE_NULL. |
---|
2669 | * |
---|
2670 | * Returns: TRUE, if the element's state is locked. |
---|
2671 | */ |
---|
2672 | gboolean |
---|
2673 | gst_element_is_locked_state (GstElement * element) |
---|
2674 | { |
---|
2675 | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
---|
2676 | |
---|
2677 | return GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE) ? TRUE : FALSE; |
---|
2678 | } |
---|
2679 | |
---|
2680 | /** |
---|
2681 | * gst_element_set_locked_state: |
---|
2682 | * @element: a #GstElement |
---|
2683 | * @locked_state: TRUE to lock the element's state |
---|
2684 | * |
---|
2685 | * Locks the state of an element, so state changes of the parent don't affect |
---|
2686 | * this element anymore. |
---|
2687 | */ |
---|
2688 | void |
---|
2689 | gst_element_set_locked_state (GstElement * element, gboolean locked_state) |
---|
2690 | { |
---|
2691 | gboolean old; |
---|
2692 | |
---|
2693 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
2694 | |
---|
2695 | old = GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE); |
---|
2696 | |
---|
2697 | if (old == locked_state) |
---|
2698 | return; |
---|
2699 | |
---|
2700 | if (locked_state) { |
---|
2701 | GST_CAT_DEBUG (GST_CAT_STATES, "locking state of element %s", |
---|
2702 | GST_ELEMENT_NAME (element)); |
---|
2703 | GST_FLAG_SET (element, GST_ELEMENT_LOCKED_STATE); |
---|
2704 | } else { |
---|
2705 | GST_CAT_DEBUG (GST_CAT_STATES, "unlocking state of element %s", |
---|
2706 | GST_ELEMENT_NAME (element)); |
---|
2707 | GST_FLAG_UNSET (element, GST_ELEMENT_LOCKED_STATE); |
---|
2708 | } |
---|
2709 | } |
---|
2710 | |
---|
2711 | /** |
---|
2712 | * gst_element_sync_state_with_parent: |
---|
2713 | * @element: a #GstElement. |
---|
2714 | * |
---|
2715 | * Tries to change the state of the element to the same as its parent. |
---|
2716 | * If this function returns FALSE, the state of element is undefined. |
---|
2717 | * |
---|
2718 | * Returns: TRUE, if the element's state could be synced to the parent's state. |
---|
2719 | */ |
---|
2720 | gboolean |
---|
2721 | gst_element_sync_state_with_parent (GstElement * element) |
---|
2722 | { |
---|
2723 | GstElement *parent; |
---|
2724 | |
---|
2725 | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
---|
2726 | parent = GST_ELEMENT (GST_ELEMENT_PARENT (element)); |
---|
2727 | g_return_val_if_fail (GST_IS_BIN (parent), FALSE); |
---|
2728 | |
---|
2729 | GST_CAT_DEBUG (GST_CAT_STATES, "syncing state of element %s (%s) to %s (%s)", |
---|
2730 | GST_ELEMENT_NAME (element), |
---|
2731 | gst_element_state_get_name (GST_STATE (element)), |
---|
2732 | GST_ELEMENT_NAME (parent), |
---|
2733 | gst_element_state_get_name (GST_STATE (parent))); |
---|
2734 | if (gst_element_set_state (element, GST_STATE (parent)) == GST_STATE_FAILURE) { |
---|
2735 | return FALSE; |
---|
2736 | } |
---|
2737 | return TRUE; |
---|
2738 | } |
---|
2739 | |
---|
2740 | /** |
---|
2741 | * gst_element_get_state: |
---|
2742 | * @element: a #GstElement to get the state of. |
---|
2743 | * |
---|
2744 | * Gets the state of the element. |
---|
2745 | * |
---|
2746 | * Returns: the #GstElementState of the element. |
---|
2747 | */ |
---|
2748 | GstElementState |
---|
2749 | gst_element_get_state (GstElement * element) |
---|
2750 | { |
---|
2751 | g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_VOID_PENDING); |
---|
2752 | |
---|
2753 | return GST_STATE (element); |
---|
2754 | } |
---|
2755 | |
---|
2756 | /** |
---|
2757 | * gst_element_wait_state_change: |
---|
2758 | * @element: a #GstElement to wait for a state change on. |
---|
2759 | * |
---|
2760 | * Waits and blocks until the element changed its state. |
---|
2761 | */ |
---|
2762 | void |
---|
2763 | gst_element_wait_state_change (GstElement * element) |
---|
2764 | { |
---|
2765 | g_mutex_lock (element->state_mutex); |
---|
2766 | g_cond_wait (element->state_cond, element->state_mutex); |
---|
2767 | g_mutex_unlock (element->state_mutex); |
---|
2768 | } |
---|
2769 | |
---|
2770 | /** |
---|
2771 | * gst_element_set_state: |
---|
2772 | * @element: a #GstElement to change state of. |
---|
2773 | * @state: the element's new #GstElementState. |
---|
2774 | * |
---|
2775 | * Sets the state of the element. This function will try to set the |
---|
2776 | * requested state by going through all the intermediary states and calling |
---|
2777 | * the class's state change function for each. |
---|
2778 | * |
---|
2779 | * Returns: TRUE if the state was successfully set. |
---|
2780 | * (using #GstElementStateReturn). |
---|
2781 | */ |
---|
2782 | GstElementStateReturn |
---|
2783 | gst_element_set_state (GstElement * element, GstElementState state) |
---|
2784 | { |
---|
2785 | GstElementClass *klass = GST_ELEMENT_GET_CLASS (element); |
---|
2786 | GstElementStateReturn ret; |
---|
2787 | |
---|
2788 | g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE); |
---|
2789 | GST_DEBUG_OBJECT (element, "setting state to %s", |
---|
2790 | gst_element_state_get_name (state)); |
---|
2791 | klass = GST_ELEMENT_GET_CLASS (element); |
---|
2792 | g_return_val_if_fail (klass->set_state, GST_STATE_FAILURE); |
---|
2793 | |
---|
2794 | /* a set_state function is mandatory */ |
---|
2795 | gst_object_ref (GST_OBJECT (element)); |
---|
2796 | ret = klass->set_state (element, state); |
---|
2797 | gst_object_unref (GST_OBJECT (element)); |
---|
2798 | |
---|
2799 | return ret; |
---|
2800 | } |
---|
2801 | |
---|
2802 | static GstElementStateReturn |
---|
2803 | gst_element_set_state_func (GstElement * element, GstElementState state) |
---|
2804 | { |
---|
2805 | GstElementClass *oclass; |
---|
2806 | GstElementState curpending; |
---|
2807 | GstElementStateReturn return_val = GST_STATE_SUCCESS; |
---|
2808 | |
---|
2809 | oclass = GST_ELEMENT_GET_CLASS (element); |
---|
2810 | |
---|
2811 | /* start with the current state */ |
---|
2812 | curpending = GST_STATE (element); |
---|
2813 | |
---|
2814 | if (state == curpending) { |
---|
2815 | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
---|
2816 | "element is already in requested state %s, returning", |
---|
2817 | gst_element_state_get_name (state)); |
---|
2818 | return GST_STATE_SUCCESS; |
---|
2819 | } |
---|
2820 | |
---|
2821 | /* reentrancy issues with signals in change_state) */ |
---|
2822 | gst_object_ref (GST_OBJECT (element)); |
---|
2823 | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "setting state from %s to %s", |
---|
2824 | gst_element_state_get_name (curpending), |
---|
2825 | gst_element_state_get_name (state)); |
---|
2826 | |
---|
2827 | /* loop until the final requested state is set */ |
---|
2828 | |
---|
2829 | while (GST_STATE (element) != state |
---|
2830 | && GST_STATE (element) != GST_STATE_VOID_PENDING) { |
---|
2831 | /* move the curpending state in the correct direction */ |
---|
2832 | if (curpending < state) |
---|
2833 | curpending <<= 1; |
---|
2834 | else |
---|
2835 | curpending >>= 1; |
---|
2836 | |
---|
2837 | /* set the pending state variable */ |
---|
2838 | GST_STATE_PENDING (element) = curpending; |
---|
2839 | |
---|
2840 | if (curpending != state) { |
---|
2841 | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
---|
2842 | "intermediate: setting state from %s to %s", |
---|
2843 | gst_element_state_get_name (GST_STATE (element)), |
---|
2844 | gst_element_state_get_name (curpending)); |
---|
2845 | } else { |
---|
2846 | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
---|
2847 | "start: setting current state %s again", |
---|
2848 | gst_element_state_get_name (GST_STATE (element))); |
---|
2849 | } |
---|
2850 | |
---|
2851 | /* call the state change function so it can set the state */ |
---|
2852 | if (oclass->change_state) |
---|
2853 | return_val = (oclass->change_state) (element); |
---|
2854 | |
---|
2855 | switch (return_val) { |
---|
2856 | case GST_STATE_FAILURE: |
---|
2857 | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
---|
2858 | "have failed change_state return"); |
---|
2859 | goto exit; |
---|
2860 | case GST_STATE_ASYNC: |
---|
2861 | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
---|
2862 | "element will change state async"); |
---|
2863 | goto exit; |
---|
2864 | case GST_STATE_SUCCESS: |
---|
2865 | /* Last thing we do is verify that a successful state change really |
---|
2866 | * did change the state... */ |
---|
2867 | /* if it did not, this is an error - fix the element that does this */ |
---|
2868 | if (GST_STATE (element) != curpending) { |
---|
2869 | g_warning ("element %s claimed state-change success," |
---|
2870 | "but state didn't change to %s. State is %s (%s pending), " |
---|
2871 | "fix the element", |
---|
2872 | GST_ELEMENT_NAME (element), |
---|
2873 | gst_element_state_get_name (curpending), |
---|
2874 | gst_element_state_get_name (GST_STATE (element)), |
---|
2875 | gst_element_state_get_name (GST_STATE_PENDING (element))); |
---|
2876 | return_val = GST_STATE_FAILURE; |
---|
2877 | goto exit; |
---|
2878 | } |
---|
2879 | break; |
---|
2880 | default: |
---|
2881 | /* somebody added a GST_STATE_ and forgot to do stuff here ! */ |
---|
2882 | g_assert_not_reached (); |
---|
2883 | } |
---|
2884 | } |
---|
2885 | |
---|
2886 | exit: |
---|
2887 | gst_object_unref (GST_OBJECT (element)); |
---|
2888 | |
---|
2889 | return return_val; |
---|
2890 | } |
---|
2891 | |
---|
2892 | static gboolean |
---|
2893 | gst_element_negotiate_pads (GstElement * element) |
---|
2894 | { |
---|
2895 | GList *pads; |
---|
2896 | |
---|
2897 | GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element, "negotiating pads"); |
---|
2898 | |
---|
2899 | for (pads = GST_ELEMENT_PADS (element); pads; pads = g_list_next (pads)) { |
---|
2900 | GstPad *pad = GST_PAD (pads->data); |
---|
2901 | |
---|
2902 | if (!GST_IS_REAL_PAD (pad)) |
---|
2903 | continue; |
---|
2904 | |
---|
2905 | /* if we have a link on this pad and it doesn't have caps |
---|
2906 | * allready, try to negotiate */ |
---|
2907 | if (!gst_pad_is_negotiated (pad)) { |
---|
2908 | GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element, |
---|
2909 | "perform negotiate for %s:%s", GST_DEBUG_PAD_NAME (pad)); |
---|
2910 | if (gst_pad_renegotiate (pad) == GST_PAD_LINK_REFUSED) |
---|
2911 | return FALSE; |
---|
2912 | } |
---|
2913 | } |
---|
2914 | |
---|
2915 | return TRUE; |
---|
2916 | } |
---|
2917 | |
---|
2918 | static void |
---|
2919 | gst_element_clear_pad_caps (GstElement * element) |
---|
2920 | { |
---|
2921 | GList *pads = GST_ELEMENT_PADS (element); |
---|
2922 | |
---|
2923 | GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element, "clearing pad caps"); |
---|
2924 | |
---|
2925 | while (pads) { |
---|
2926 | GstPad *pad = GST_PAD (pads->data); |
---|
2927 | |
---|
2928 | gst_pad_unnegotiate (pad); |
---|
2929 | if (GST_IS_REAL_PAD (pad)) { |
---|
2930 | gst_caps_replace (&GST_RPAD_EXPLICIT_CAPS (pad), NULL); |
---|
2931 | } |
---|
2932 | |
---|
2933 | pads = g_list_next (pads); |
---|
2934 | } |
---|
2935 | } |
---|
2936 | |
---|
2937 | static void |
---|
2938 | gst_element_pads_activate (GstElement * element, gboolean active) |
---|
2939 | { |
---|
2940 | GList *pads = element->pads; |
---|
2941 | |
---|
2942 | while (pads) { |
---|
2943 | GstPad *pad = GST_PAD (pads->data); |
---|
2944 | |
---|
2945 | pads = g_list_next (pads); |
---|
2946 | |
---|
2947 | if (!GST_IS_REAL_PAD (pad)) |
---|
2948 | continue; |
---|
2949 | |
---|
2950 | gst_pad_set_active (pad, active); |
---|
2951 | } |
---|
2952 | } |
---|
2953 | |
---|
2954 | static GstElementStateReturn |
---|
2955 | gst_element_change_state (GstElement * element) |
---|
2956 | { |
---|
2957 | GstElementState old_state, old_pending; |
---|
2958 | GstObject *parent; |
---|
2959 | gint old_transition; |
---|
2960 | |
---|
2961 | g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE); |
---|
2962 | |
---|
2963 | old_state = GST_STATE (element); |
---|
2964 | old_pending = GST_STATE_PENDING (element); |
---|
2965 | old_transition = GST_STATE_TRANSITION (element); |
---|
2966 | |
---|
2967 | /* if the element already is in the given state, we just return success */ |
---|
2968 | if (old_pending == GST_STATE_VOID_PENDING || |
---|
2969 | old_state == GST_STATE_PENDING (element)) { |
---|
2970 | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
---|
2971 | "element is already in the %s state", |
---|
2972 | gst_element_state_get_name (old_state)); |
---|
2973 | return GST_STATE_SUCCESS; |
---|
2974 | } |
---|
2975 | |
---|
2976 | /* we need to ref the object because of reentrancy issues with the signal |
---|
2977 | * handlers (including those in pads and gst_bin_child_state_change */ |
---|
2978 | gst_object_ref (GST_OBJECT (element)); |
---|
2979 | GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, |
---|
2980 | "default handler tries setting state from %s to %s (%04x)", |
---|
2981 | gst_element_state_get_name (old_state), |
---|
2982 | gst_element_state_get_name (old_pending), old_transition); |
---|
2983 | |
---|
2984 | /* we set the state change early for the negotiation functions */ |
---|
2985 | GST_STATE (element) = old_pending; |
---|
2986 | GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING; |
---|
2987 | |
---|
2988 | switch (old_transition) { |
---|
2989 | case GST_STATE_PLAYING_TO_PAUSED: |
---|
2990 | if (element->clock) { |
---|
2991 | GstClockTimeDiff time = gst_clock_get_event_time (element->clock); |
---|
2992 | |
---|
2993 | g_assert (time >= element->base_time); |
---|
2994 | element->base_time = time - element->base_time; |
---|
2995 | GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, element, "setting base time to %" |
---|
2996 | G_GINT64_FORMAT, element->base_time); |
---|
2997 | } |
---|
2998 | gst_element_pads_activate (element, FALSE); |
---|
2999 | break; |
---|
3000 | case GST_STATE_PAUSED_TO_PLAYING: |
---|
3001 | gst_element_pads_activate (element, TRUE); |
---|
3002 | if (element->clock) { |
---|
3003 | GstClockTime time = gst_clock_get_event_time (element->clock); |
---|
3004 | |
---|
3005 | element->base_time = time - element->base_time; |
---|
3006 | GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, element, "setting base time to %" |
---|
3007 | GST_TIME_FORMAT, GST_TIME_ARGS (element->base_time)); |
---|
3008 | } |
---|
3009 | break; |
---|
3010 | /* if we are going to paused, we try to negotiate the pads */ |
---|
3011 | case GST_STATE_READY_TO_PAUSED: |
---|
3012 | g_assert (element->base_time == 0); |
---|
3013 | if (!gst_element_negotiate_pads (element)) { |
---|
3014 | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
---|
3015 | "failed state change, could not negotiate pads"); |
---|
3016 | goto failure; |
---|
3017 | } |
---|
3018 | break; |
---|
3019 | /* going to the READY state clears all pad caps */ |
---|
3020 | /* FIXME: Why doesn't this happen on READY => NULL? -- Company */ |
---|
3021 | case GST_STATE_PAUSED_TO_READY: |
---|
3022 | element->base_time = 0; |
---|
3023 | gst_element_clear_pad_caps (element); |
---|
3024 | break; |
---|
3025 | case GST_STATE_NULL_TO_READY: |
---|
3026 | case GST_STATE_READY_TO_NULL: |
---|
3027 | break; |
---|
3028 | default: |
---|
3029 | /* this will catch real but unhandled state changes; |
---|
3030 | * can only be caused by: |
---|
3031 | * - a new state was added |
---|
3032 | * - somehow the element was asked to jump across an intermediate state |
---|
3033 | */ |
---|
3034 | g_warning ("Unhandled state change from %s to %s", |
---|
3035 | gst_element_state_get_name (old_state), |
---|
3036 | gst_element_state_get_name (old_pending)); |
---|
3037 | break; |
---|
3038 | } |
---|
3039 | |
---|
3040 | parent = GST_ELEMENT_PARENT (element); |
---|
3041 | |
---|
3042 | GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, |
---|
3043 | "signaling state change from %s to %s", |
---|
3044 | gst_element_state_get_name (old_state), |
---|
3045 | gst_element_state_get_name (GST_STATE (element))); |
---|
3046 | |
---|
3047 | /* tell the scheduler if we have one */ |
---|
3048 | if (element->sched) { |
---|
3049 | if (gst_scheduler_state_transition (element->sched, element, |
---|
3050 | old_transition) != GST_STATE_SUCCESS) { |
---|
3051 | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
---|
3052 | "scheduler could not change state"); |
---|
3053 | goto failure; |
---|
3054 | } |
---|
3055 | } |
---|
3056 | |
---|
3057 | /* tell our parent about the state change */ |
---|
3058 | if (parent && GST_IS_BIN (parent)) { |
---|
3059 | gst_bin_child_state_change (GST_BIN (parent), old_state, |
---|
3060 | GST_STATE (element), element); |
---|
3061 | } |
---|
3062 | /* at this point the state of the element could have changed again */ |
---|
3063 | |
---|
3064 | g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE], |
---|
3065 | 0, old_state, GST_STATE (element)); |
---|
3066 | |
---|
3067 | /* signal the state change in case somebody is waiting for us */ |
---|
3068 | g_cond_signal (element->state_cond); |
---|
3069 | |
---|
3070 | gst_object_unref (GST_OBJECT (element)); |
---|
3071 | return GST_STATE_SUCCESS; |
---|
3072 | |
---|
3073 | failure: |
---|
3074 | /* undo the state change */ |
---|
3075 | GST_STATE (element) = old_state; |
---|
3076 | GST_STATE_PENDING (element) = old_pending; |
---|
3077 | gst_object_unref (GST_OBJECT (element)); |
---|
3078 | |
---|
3079 | return GST_STATE_FAILURE; |
---|
3080 | } |
---|
3081 | |
---|
3082 | /** |
---|
3083 | * gst_element_get_factory: |
---|
3084 | * @element: a #GstElement to request the element factory of. |
---|
3085 | * |
---|
3086 | * Retrieves the factory that was used to create this element. |
---|
3087 | * |
---|
3088 | * Returns: the #GstElementFactory used for creating this element. |
---|
3089 | */ |
---|
3090 | GstElementFactory * |
---|
3091 | gst_element_get_factory (GstElement * element) |
---|
3092 | { |
---|
3093 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
3094 | |
---|
3095 | return GST_ELEMENT_GET_CLASS (element)->elementfactory; |
---|
3096 | } |
---|
3097 | |
---|
3098 | static void |
---|
3099 | gst_element_dispose (GObject * object) |
---|
3100 | { |
---|
3101 | GstElement *element = GST_ELEMENT (object); |
---|
3102 | |
---|
3103 | GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "dispose"); |
---|
3104 | |
---|
3105 | gst_element_set_state (element, GST_STATE_NULL); |
---|
3106 | |
---|
3107 | /* first we break all our links with the ouside */ |
---|
3108 | while (element->pads) { |
---|
3109 | gst_element_remove_pad (element, GST_PAD (element->pads->data)); |
---|
3110 | } |
---|
3111 | |
---|
3112 | element->numsrcpads = 0; |
---|
3113 | element->numsinkpads = 0; |
---|
3114 | element->numpads = 0; |
---|
3115 | if (element->state_mutex) |
---|
3116 | g_mutex_free (element->state_mutex); |
---|
3117 | element->state_mutex = NULL; |
---|
3118 | if (element->state_cond) |
---|
3119 | g_cond_free (element->state_cond); |
---|
3120 | element->state_cond = NULL; |
---|
3121 | |
---|
3122 | if (element->prop_value_queue) |
---|
3123 | g_async_queue_unref (element->prop_value_queue); |
---|
3124 | element->prop_value_queue = NULL; |
---|
3125 | if (element->property_mutex) |
---|
3126 | g_mutex_free (element->property_mutex); |
---|
3127 | element->property_mutex = NULL; |
---|
3128 | |
---|
3129 | gst_object_replace ((GstObject **) & element->sched, NULL); |
---|
3130 | gst_object_replace ((GstObject **) & element->clock, NULL); |
---|
3131 | |
---|
3132 | G_OBJECT_CLASS (parent_class)->dispose (object); |
---|
3133 | } |
---|
3134 | |
---|
3135 | #ifndef GST_DISABLE_LOADSAVE |
---|
3136 | /** |
---|
3137 | * gst_element_save_thyself: |
---|
3138 | * @element: a #GstElement to save. |
---|
3139 | * @parent: the xml parent node. |
---|
3140 | * |
---|
3141 | * Saves the element as part of the given XML structure. |
---|
3142 | * |
---|
3143 | * Returns: the new #xmlNodePtr. |
---|
3144 | */ |
---|
3145 | static xmlNodePtr |
---|
3146 | gst_element_save_thyself (GstObject * object, xmlNodePtr parent) |
---|
3147 | { |
---|
3148 | GList *pads; |
---|
3149 | GstElementClass *oclass; |
---|
3150 | GParamSpec **specs, *spec; |
---|
3151 | gint nspecs, i; |
---|
3152 | GValue value = { 0, }; |
---|
3153 | GstElement *element; |
---|
3154 | |
---|
3155 | g_return_val_if_fail (GST_IS_ELEMENT (object), parent); |
---|
3156 | |
---|
3157 | element = GST_ELEMENT (object); |
---|
3158 | |
---|
3159 | oclass = GST_ELEMENT_GET_CLASS (element); |
---|
3160 | |
---|
3161 | xmlNewChild (parent, NULL, "name", GST_ELEMENT_NAME (element)); |
---|
3162 | |
---|
3163 | if (oclass->elementfactory != NULL) { |
---|
3164 | GstElementFactory *factory = (GstElementFactory *) oclass->elementfactory; |
---|
3165 | |
---|
3166 | xmlNewChild (parent, NULL, "type", GST_PLUGIN_FEATURE (factory)->name); |
---|
3167 | } |
---|
3168 | |
---|
3169 | /* FIXME: what is this? */ |
---|
3170 | /* if (element->manager) */ |
---|
3171 | /* xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager)); */ |
---|
3172 | |
---|
3173 | /* params */ |
---|
3174 | specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &nspecs); |
---|
3175 | |
---|
3176 | for (i = 0; i < nspecs; i++) { |
---|
3177 | spec = specs[i]; |
---|
3178 | if (spec->flags & G_PARAM_READABLE) { |
---|
3179 | xmlNodePtr param; |
---|
3180 | char *contents; |
---|
3181 | |
---|
3182 | g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (spec)); |
---|
3183 | |
---|
3184 | g_object_get_property (G_OBJECT (element), spec->name, &value); |
---|
3185 | param = xmlNewChild (parent, NULL, "param", NULL); |
---|
3186 | xmlNewChild (param, NULL, "name", spec->name); |
---|
3187 | |
---|
3188 | if (G_IS_PARAM_SPEC_STRING (spec)) |
---|
3189 | contents = g_value_dup_string (&value); |
---|
3190 | else if (G_IS_PARAM_SPEC_ENUM (spec)) |
---|
3191 | contents = g_strdup_printf ("%d", g_value_get_enum (&value)); |
---|
3192 | else if (G_IS_PARAM_SPEC_INT64 (spec)) |
---|
3193 | contents = g_strdup_printf ("%" G_GINT64_FORMAT, |
---|
3194 | g_value_get_int64 (&value)); |
---|
3195 | else |
---|
3196 | contents = g_strdup_value_contents (&value); |
---|
3197 | |
---|
3198 | xmlNewChild (param, NULL, "value", contents); |
---|
3199 | g_free (contents); |
---|
3200 | |
---|
3201 | g_value_unset (&value); |
---|
3202 | } |
---|
3203 | } |
---|
3204 | |
---|
3205 | pads = GST_ELEMENT_PADS (element); |
---|
3206 | |
---|
3207 | while (pads) { |
---|
3208 | GstPad *pad = GST_PAD (pads->data); |
---|
3209 | |
---|
3210 | /* figure out if it's a direct pad or a ghostpad */ |
---|
3211 | if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) { |
---|
3212 | xmlNodePtr padtag = xmlNewChild (parent, NULL, "pad", NULL); |
---|
3213 | |
---|
3214 | gst_object_save_thyself (GST_OBJECT (pad), padtag); |
---|
3215 | } |
---|
3216 | pads = g_list_next (pads); |
---|
3217 | } |
---|
3218 | |
---|
3219 | return parent; |
---|
3220 | } |
---|
3221 | |
---|
3222 | static void |
---|
3223 | gst_element_restore_thyself (GstObject * object, xmlNodePtr self) |
---|
3224 | { |
---|
3225 | xmlNodePtr children; |
---|
3226 | GstElement *element; |
---|
3227 | gchar *name = NULL; |
---|
3228 | gchar *value = NULL; |
---|
3229 | |
---|
3230 | element = GST_ELEMENT (object); |
---|
3231 | g_return_if_fail (element != NULL); |
---|
3232 | |
---|
3233 | /* parameters */ |
---|
3234 | children = self->xmlChildrenNode; |
---|
3235 | while (children) { |
---|
3236 | if (!strcmp (children->name, "param")) { |
---|
3237 | xmlNodePtr child = children->xmlChildrenNode; |
---|
3238 | |
---|
3239 | while (child) { |
---|
3240 | if (!strcmp (child->name, "name")) { |
---|
3241 | name = xmlNodeGetContent (child); |
---|
3242 | } else if (!strcmp (child->name, "value")) { |
---|
3243 | value = xmlNodeGetContent (child); |
---|
3244 | } |
---|
3245 | child = child->next; |
---|
3246 | } |
---|
3247 | /* FIXME: can this just be g_object_set ? */ |
---|
3248 | gst_util_set_object_arg (G_OBJECT (element), name, value); |
---|
3249 | /* g_object_set (G_OBJECT (element), name, value, NULL); */ |
---|
3250 | g_free (name); |
---|
3251 | g_free (value); |
---|
3252 | } |
---|
3253 | children = children->next; |
---|
3254 | } |
---|
3255 | |
---|
3256 | /* pads */ |
---|
3257 | children = self->xmlChildrenNode; |
---|
3258 | while (children) { |
---|
3259 | if (!strcmp (children->name, "pad")) { |
---|
3260 | gst_pad_load_and_link (children, GST_OBJECT (element)); |
---|
3261 | } |
---|
3262 | children = children->next; |
---|
3263 | } |
---|
3264 | |
---|
3265 | if (GST_OBJECT_CLASS (parent_class)->restore_thyself) |
---|
3266 | (GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self); |
---|
3267 | } |
---|
3268 | #endif /* GST_DISABLE_LOADSAVE */ |
---|
3269 | |
---|
3270 | /** |
---|
3271 | * gst_element_yield: |
---|
3272 | * @element: a #GstElement to yield. |
---|
3273 | * |
---|
3274 | * Requests a yield operation for the element. The scheduler will typically |
---|
3275 | * give control to another element. |
---|
3276 | */ |
---|
3277 | void |
---|
3278 | gst_element_yield (GstElement * element) |
---|
3279 | { |
---|
3280 | if (GST_ELEMENT_SCHED (element)) { |
---|
3281 | gst_scheduler_yield (GST_ELEMENT_SCHED (element), element); |
---|
3282 | } |
---|
3283 | } |
---|
3284 | |
---|
3285 | /** |
---|
3286 | * gst_element_interrupt: |
---|
3287 | * @element: a #GstElement to interrupt. |
---|
3288 | * |
---|
3289 | * Requests the scheduler of this element to interrupt the execution of |
---|
3290 | * this element and scheduler another one. |
---|
3291 | * |
---|
3292 | * Returns: TRUE if the element should exit its chain/loop/get |
---|
3293 | * function ASAP, depending on the scheduler implementation. |
---|
3294 | */ |
---|
3295 | gboolean |
---|
3296 | gst_element_interrupt (GstElement * element) |
---|
3297 | { |
---|
3298 | if (GST_ELEMENT_SCHED (element)) { |
---|
3299 | return gst_scheduler_interrupt (GST_ELEMENT_SCHED (element), element); |
---|
3300 | } else |
---|
3301 | return TRUE; |
---|
3302 | } |
---|
3303 | |
---|
3304 | /** |
---|
3305 | * gst_element_set_scheduler: |
---|
3306 | * @element: a #GstElement to set the scheduler of. |
---|
3307 | * @sched: the #GstScheduler to set. |
---|
3308 | * |
---|
3309 | * Sets the scheduler of the element. For internal use only, unless you're |
---|
3310 | * writing a new bin subclass. |
---|
3311 | */ |
---|
3312 | void |
---|
3313 | gst_element_set_scheduler (GstElement * element, GstScheduler * sched) |
---|
3314 | { |
---|
3315 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
3316 | |
---|
3317 | GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element, "setting scheduler to %p", |
---|
3318 | sched); |
---|
3319 | |
---|
3320 | gst_object_replace ((GstObject **) & GST_ELEMENT_SCHED (element), |
---|
3321 | GST_OBJECT (sched)); |
---|
3322 | } |
---|
3323 | |
---|
3324 | /** |
---|
3325 | * gst_element_get_scheduler: |
---|
3326 | * @element: a #GstElement to get the scheduler of. |
---|
3327 | * |
---|
3328 | * Returns the scheduler of the element. |
---|
3329 | * |
---|
3330 | * Returns: the element's #GstScheduler. |
---|
3331 | */ |
---|
3332 | GstScheduler * |
---|
3333 | gst_element_get_scheduler (GstElement * element) |
---|
3334 | { |
---|
3335 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
---|
3336 | |
---|
3337 | return GST_ELEMENT_SCHED (element); |
---|
3338 | } |
---|
3339 | |
---|
3340 | /** |
---|
3341 | * gst_element_set_loop_function: |
---|
3342 | * @element: a #GstElement to set the loop function of. |
---|
3343 | * @loop: Pointer to #GstElementLoopFunction. |
---|
3344 | * |
---|
3345 | * This sets the loop function for the element. The function pointed to |
---|
3346 | * can deviate from the GstElementLoopFunction definition in type of |
---|
3347 | * pointer only. |
---|
3348 | * |
---|
3349 | * NOTE: in order for this to take effect, the current loop function *must* |
---|
3350 | * exit. Assuming the loop function itself is the only one who will cause |
---|
3351 | * a new loopfunc to be assigned, this should be no problem. |
---|
3352 | */ |
---|
3353 | void |
---|
3354 | gst_element_set_loop_function (GstElement * element, |
---|
3355 | GstElementLoopFunction loop) |
---|
3356 | { |
---|
3357 | gboolean need_notify = FALSE; |
---|
3358 | |
---|
3359 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
3360 | |
---|
3361 | /* if the element changed from loop based to chain/get based |
---|
3362 | * or vice versa, we need to inform the scheduler about that */ |
---|
3363 | if ((element->loopfunc == NULL && loop != NULL) || |
---|
3364 | (element->loopfunc != NULL && loop == NULL)) { |
---|
3365 | need_notify = TRUE; |
---|
3366 | } |
---|
3367 | |
---|
3368 | /* set the loop function */ |
---|
3369 | element->loopfunc = loop; |
---|
3370 | |
---|
3371 | if (need_notify) { |
---|
3372 | /* set the NEW_LOOPFUNC flag so everyone knows to go try again */ |
---|
3373 | GST_FLAG_SET (element, GST_ELEMENT_NEW_LOOPFUNC); |
---|
3374 | |
---|
3375 | if (GST_ELEMENT_SCHED (element)) { |
---|
3376 | gst_scheduler_scheduling_change (GST_ELEMENT_SCHED (element), element); |
---|
3377 | } |
---|
3378 | } |
---|
3379 | } |
---|
3380 | static inline void |
---|
3381 | gst_element_emit_found_tag (GstElement * element, GstElement * source, |
---|
3382 | const GstTagList * tag_list) |
---|
3383 | { |
---|
3384 | gst_object_ref (GST_OBJECT (element)); |
---|
3385 | g_signal_emit (element, gst_element_signals[FOUND_TAG], 0, source, tag_list); |
---|
3386 | gst_object_unref (GST_OBJECT (element)); |
---|
3387 | } |
---|
3388 | static void |
---|
3389 | gst_element_found_tag_func (GstElement * element, GstElement * source, |
---|
3390 | const GstTagList * tag_list) |
---|
3391 | { |
---|
3392 | /* tell the parent */ |
---|
3393 | if (GST_OBJECT_PARENT (element)) { |
---|
3394 | GST_CAT_LOG_OBJECT (GST_CAT_EVENT, element, "forwarding tag event to %s", |
---|
3395 | GST_OBJECT_NAME (GST_OBJECT_PARENT (element))); |
---|
3396 | gst_element_emit_found_tag (GST_ELEMENT (GST_OBJECT_PARENT (element)), |
---|
3397 | source, tag_list); |
---|
3398 | } |
---|
3399 | } |
---|
3400 | |
---|
3401 | /** |
---|
3402 | * gst_element_found_tags: |
---|
3403 | * @element: the element that found the tags |
---|
3404 | * @tag_list: the found tags |
---|
3405 | * |
---|
3406 | * This function emits the found_tags signal. This is a recursive signal, so |
---|
3407 | * every parent will emit that signal, too, before this function returns. |
---|
3408 | * Only emit this signal, when you extracted these tags out of the data stream, |
---|
3409 | * not when you handle an event. |
---|
3410 | */ |
---|
3411 | void |
---|
3412 | gst_element_found_tags (GstElement * element, const GstTagList * tag_list) |
---|
3413 | { |
---|
3414 | gst_element_emit_found_tag (element, element, tag_list); |
---|
3415 | } |
---|
3416 | |
---|
3417 | /** |
---|
3418 | * gst_element_found_tags_for_pad: |
---|
3419 | * @element: element that found the tag |
---|
3420 | * @pad: src pad the tags correspond to |
---|
3421 | * @timestamp: time the tags were found |
---|
3422 | * @list: the taglist |
---|
3423 | * |
---|
3424 | * This is a convenience routine for tag finding. Most of the time you only |
---|
3425 | * want to push the found tags down one pad, in that case this function is for |
---|
3426 | * you. It takes ownership of the taglist, emits the found-tag signal and |
---|
3427 | * pushes a tag event down the pad. |
---|
3428 | * <note>This function may not be used in a #GstPadGetFunction, because it calls |
---|
3429 | * gst_pad_push(). In those functions, call gst_element_found_tags(), create a |
---|
3430 | * tag event with gst_event_new_tag() and return that from your |
---|
3431 | * #GstPadGetFunction.</note> |
---|
3432 | */ |
---|
3433 | void |
---|
3434 | gst_element_found_tags_for_pad (GstElement * element, GstPad * pad, |
---|
3435 | GstClockTime timestamp, GstTagList * list) |
---|
3436 | { |
---|
3437 | GstEvent *tag_event; |
---|
3438 | |
---|
3439 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
3440 | g_return_if_fail (GST_IS_REAL_PAD (pad)); |
---|
3441 | g_return_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SRC); |
---|
3442 | g_return_if_fail (element == GST_PAD_PARENT (pad)); |
---|
3443 | g_return_if_fail (list != NULL); |
---|
3444 | |
---|
3445 | tag_event = gst_event_new_tag (list); |
---|
3446 | GST_EVENT_TIMESTAMP (tag_event) = timestamp; |
---|
3447 | gst_element_found_tags (element, gst_event_tag_get_list (tag_event)); |
---|
3448 | if (GST_PAD_IS_USABLE (pad)) { |
---|
3449 | gst_pad_push (pad, GST_DATA (tag_event)); |
---|
3450 | } else { |
---|
3451 | gst_data_unref (GST_DATA (tag_event)); |
---|
3452 | } |
---|
3453 | } |
---|
3454 | |
---|
3455 | static inline void |
---|
3456 | gst_element_set_eos_recursive (GstElement * element) |
---|
3457 | { |
---|
3458 | /* this function is only called, when we were in PLAYING before. So every |
---|
3459 | parent that's PAUSED was PLAYING before. That means it has reached EOS. */ |
---|
3460 | GstElement *parent; |
---|
3461 | |
---|
3462 | GST_CAT_DEBUG (GST_CAT_EVENT, "setting recursive EOS on %s", |
---|
3463 | GST_OBJECT_NAME (element)); |
---|
3464 | g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0); |
---|
3465 | |
---|
3466 | if (!GST_OBJECT_PARENT (element)) |
---|
3467 | return; |
---|
3468 | |
---|
3469 | parent = GST_ELEMENT (GST_OBJECT_PARENT (element)); |
---|
3470 | if (GST_STATE (parent) == GST_STATE_PAUSED) |
---|
3471 | gst_element_set_eos_recursive (parent); |
---|
3472 | } |
---|
3473 | |
---|
3474 | /** |
---|
3475 | * gst_element_set_eos: |
---|
3476 | * @element: a #GstElement to set to the EOS state. |
---|
3477 | * |
---|
3478 | * Perform the actions needed to bring the element in the EOS state. |
---|
3479 | */ |
---|
3480 | void |
---|
3481 | gst_element_set_eos (GstElement * element) |
---|
3482 | { |
---|
3483 | g_return_if_fail (GST_IS_ELEMENT (element)); |
---|
3484 | |
---|
3485 | GST_CAT_DEBUG (GST_CAT_EVENT, "setting EOS on element %s", |
---|
3486 | GST_OBJECT_NAME (element)); |
---|
3487 | |
---|
3488 | if (GST_STATE (element) == GST_STATE_PLAYING) { |
---|
3489 | gst_element_set_state (element, GST_STATE_PAUSED); |
---|
3490 | gst_element_set_eos_recursive (element); |
---|
3491 | } else { |
---|
3492 | g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0); |
---|
3493 | } |
---|
3494 | } |
---|
3495 | |
---|
3496 | |
---|
3497 | /** |
---|
3498 | * gst_element_state_get_name: |
---|
3499 | * @state: a #GstElementState to get the name of. |
---|
3500 | * |
---|
3501 | * Gets a string representing the given state. |
---|
3502 | * |
---|
3503 | * Returns: a string with the name of the state. |
---|
3504 | */ |
---|
3505 | const gchar * |
---|
3506 | gst_element_state_get_name (GstElementState state) |
---|
3507 | { |
---|
3508 | switch (state) { |
---|
3509 | #ifdef GST_DEBUG_COLOR |
---|
3510 | case GST_STATE_VOID_PENDING: |
---|
3511 | return "NONE_PENDING"; |
---|
3512 | break; |
---|
3513 | case GST_STATE_NULL: |
---|
3514 | return "\033[01;34mNULL\033[00m"; |
---|
3515 | break; |
---|
3516 | case GST_STATE_READY: |
---|
3517 | return "\033[01;31mREADY\033[00m"; |
---|
3518 | break; |
---|
3519 | case GST_STATE_PLAYING: |
---|
3520 | return "\033[01;32mPLAYING\033[00m"; |
---|
3521 | break; |
---|
3522 | case GST_STATE_PAUSED: |
---|
3523 | return "\033[01;33mPAUSED\033[00m"; |
---|
3524 | break; |
---|
3525 | default: |
---|
3526 | /* This is a memory leak */ |
---|
3527 | return g_strdup_printf ("\033[01;35;41mUNKNOWN!\033[00m(%d)", state); |
---|
3528 | #else |
---|
3529 | case GST_STATE_VOID_PENDING: |
---|
3530 | return "NONE_PENDING"; |
---|
3531 | break; |
---|
3532 | case GST_STATE_NULL: |
---|
3533 | return "NULL"; |
---|
3534 | break; |
---|
3535 | case GST_STATE_READY: |
---|
3536 | return "READY"; |
---|
3537 | break; |
---|
3538 | case GST_STATE_PLAYING: |
---|
3539 | return "PLAYING"; |
---|
3540 | break; |
---|
3541 | case GST_STATE_PAUSED: |
---|
3542 | return "PAUSED"; |
---|
3543 | break; |
---|
3544 | default: |
---|
3545 | return "UNKNOWN!"; |
---|
3546 | #endif |
---|
3547 | } |
---|
3548 | return ""; |
---|
3549 | } |
---|
3550 | |
---|
3551 | static void |
---|
3552 | gst_element_populate_std_props (GObjectClass * klass, const gchar * prop_name, |
---|
3553 | guint arg_id, GParamFlags flags) |
---|
3554 | { |
---|
3555 | GQuark prop_id = g_quark_from_string (prop_name); |
---|
3556 | GParamSpec *pspec; |
---|
3557 | |
---|
3558 | static GQuark fd_id = 0; |
---|
3559 | static GQuark blocksize_id; |
---|
3560 | static GQuark bytesperread_id; |
---|
3561 | static GQuark dump_id; |
---|
3562 | static GQuark filesize_id; |
---|
3563 | static GQuark mmapsize_id; |
---|
3564 | static GQuark location_id; |
---|
3565 | static GQuark offset_id; |
---|
3566 | static GQuark silent_id; |
---|
3567 | static GQuark touch_id; |
---|
3568 | |
---|
3569 | if (!fd_id) { |
---|
3570 | fd_id = g_quark_from_static_string ("fd"); |
---|
3571 | blocksize_id = g_quark_from_static_string ("blocksize"); |
---|
3572 | bytesperread_id = g_quark_from_static_string ("bytesperread"); |
---|
3573 | dump_id = g_quark_from_static_string ("dump"); |
---|
3574 | filesize_id = g_quark_from_static_string ("filesize"); |
---|
3575 | mmapsize_id = g_quark_from_static_string ("mmapsize"); |
---|
3576 | location_id = g_quark_from_static_string ("location"); |
---|
3577 | offset_id = g_quark_from_static_string ("offset"); |
---|
3578 | silent_id = g_quark_from_static_string ("silent"); |
---|
3579 | touch_id = g_quark_from_static_string ("touch"); |
---|
3580 | } |
---|
3581 | |
---|
3582 | if (prop_id == fd_id) { |
---|
3583 | pspec = g_param_spec_int ("fd", "File-descriptor", |
---|
3584 | "File-descriptor for the file being read", 0, G_MAXINT, 0, flags); |
---|
3585 | } else if (prop_id == blocksize_id) { |
---|
3586 | pspec = g_param_spec_ulong ("blocksize", "Block Size", |
---|
3587 | "Block size to read per buffer", 0, G_MAXULONG, 4096, flags); |
---|
3588 | |
---|
3589 | } else if (prop_id == bytesperread_id) { |
---|
3590 | pspec = g_param_spec_int ("bytesperread", "Bytes per read", |
---|
3591 | "Number of bytes to read per buffer", G_MININT, G_MAXINT, 0, flags); |
---|
3592 | |
---|
3593 | } else if (prop_id == dump_id) { |
---|
3594 | pspec = g_param_spec_boolean ("dump", "Dump", |
---|
3595 | "Dump bytes to stdout", FALSE, flags); |
---|
3596 | |
---|
3597 | } else if (prop_id == filesize_id) { |
---|
3598 | pspec = g_param_spec_int64 ("filesize", "File Size", |
---|
3599 | "Size of the file being read", 0, G_MAXINT64, 0, flags); |
---|
3600 | |
---|
3601 | } else if (prop_id == mmapsize_id) { |
---|
3602 | pspec = g_param_spec_ulong ("mmapsize", "mmap() Block Size", |
---|
3603 | "Size in bytes of mmap()d regions", 0, G_MAXULONG, 4 * 1048576, flags); |
---|
3604 | |
---|
3605 | } else if (prop_id == location_id) { |
---|
3606 | pspec = g_param_spec_string ("location", "File Location", |
---|
3607 | "Location of the file to read", NULL, flags); |
---|
3608 | |
---|
3609 | } else if (prop_id == offset_id) { |
---|
3610 | pspec = g_param_spec_int64 ("offset", "File Offset", |
---|
3611 | "Byte offset of current read pointer", 0, G_MAXINT64, 0, flags); |
---|
3612 | |
---|
3613 | } else if (prop_id == silent_id) { |
---|
3614 | pspec = g_param_spec_boolean ("silent", "Silent", "Don't produce events", |
---|
3615 | FALSE, flags); |
---|
3616 | |
---|
3617 | } else if (prop_id == touch_id) { |
---|
3618 | pspec = g_param_spec_boolean ("touch", "Touch read data", |
---|
3619 | "Touch data to force disk read before " "push ()", TRUE, flags); |
---|
3620 | } else { |
---|
3621 | g_warning ("Unknown - 'standard' property '%s' id %d from klass %s", |
---|
3622 | prop_name, arg_id, g_type_name (G_OBJECT_CLASS_TYPE (klass))); |
---|
3623 | pspec = NULL; |
---|
3624 | } |
---|
3625 | |
---|
3626 | if (pspec) { |
---|
3627 | g_object_class_install_property (klass, arg_id, pspec); |
---|
3628 | } |
---|
3629 | } |
---|
3630 | |
---|
3631 | /** |
---|
3632 | * gst_element_class_install_std_props: |
---|
3633 | * @klass: the #GstElementClass to add the properties to. |
---|
3634 | * @first_name: the name of the first property. |
---|
3635 | * in a NULL terminated |
---|
3636 | * @...: the id and flags of the first property, followed by |
---|
3637 | * further 'name', 'id', 'flags' triplets and terminated by NULL. |
---|
3638 | * |
---|
3639 | * Adds a list of standardized properties with types to the @klass. |
---|
3640 | * the id is for the property switch in your get_prop method, and |
---|
3641 | * the flags determine readability / writeability. |
---|
3642 | **/ |
---|
3643 | void |
---|
3644 | gst_element_class_install_std_props (GstElementClass * klass, |
---|
3645 | const gchar * first_name, ...) |
---|
3646 | { |
---|
3647 | const char *name; |
---|
3648 | |
---|
3649 | va_list args; |
---|
3650 | |
---|
3651 | g_return_if_fail (GST_IS_ELEMENT_CLASS (klass)); |
---|
3652 | |
---|
3653 | va_start (args, first_name); |
---|
3654 | |
---|
3655 | name = first_name; |
---|
3656 | |
---|
3657 | while (name) { |
---|
3658 | int arg_id = va_arg (args, int); |
---|
3659 | int flags = va_arg (args, int); |
---|
3660 | |
---|
3661 | gst_element_populate_std_props ((GObjectClass *) klass, name, arg_id, |
---|
3662 | flags); |
---|
3663 | |
---|
3664 | name = va_arg (args, char *); |
---|
3665 | } |
---|
3666 | |
---|
3667 | va_end (args); |
---|
3668 | } |
---|
3669 | |
---|
3670 | /** |
---|
3671 | * gst_element_get_managing_bin: |
---|
3672 | * @element: a #GstElement to get the managing bin of. |
---|
3673 | * |
---|
3674 | * Gets the managing bin (a pipeline or a thread, for example) of an element. |
---|
3675 | * |
---|
3676 | * Returns: the #GstBin, or NULL on failure. |
---|
3677 | **/ |
---|
3678 | GstBin * |
---|
3679 | gst_element_get_managing_bin (GstElement * element) |
---|
3680 | { |
---|
3681 | GstBin *bin; |
---|
3682 | |
---|
3683 | g_return_val_if_fail (element != NULL, NULL); |
---|
3684 | |
---|
3685 | bin = GST_BIN (gst_object_get_parent (GST_OBJECT (element))); |
---|
3686 | |
---|
3687 | while (bin && !GST_FLAG_IS_SET (GST_OBJECT (bin), GST_BIN_FLAG_MANAGER)) |
---|
3688 | bin = GST_BIN (gst_object_get_parent (GST_OBJECT (bin))); |
---|
3689 | |
---|
3690 | return bin; |
---|
3691 | } |
---|