|
1 /* GStreamer |
|
2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> |
|
3 * 2004 Wim Taymans <wim@fluendo.com> |
|
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 /** |
|
24 * SECTION:gstelement |
|
25 * @short_description: Abstract base class for all pipeline elements |
|
26 * @see_also: #GstElementFactory, #GstPad |
|
27 * |
|
28 * GstElement is the abstract base class needed to construct an element that |
|
29 * can be used in a GStreamer pipeline. Please refer to the plugin writers |
|
30 * guide for more information on creating #GstElement subclasses. |
|
31 * |
|
32 * The name of a #GstElement can be get with gst_element_get_name() and set with |
|
33 * gst_element_set_name(). For speed, GST_ELEMENT_NAME() can be used in the |
|
34 * core when using the appropriate locking. Do not use this in plug-ins or |
|
35 * applications in order to retain ABI compatibility. |
|
36 * |
|
37 * All elements have pads (of the type #GstPad). These pads link to pads on |
|
38 * other elements. #GstBuffer flow between these linked pads. |
|
39 * A #GstElement has a #GList of #GstPad structures for all their input (or sink) |
|
40 * and output (or source) pads. |
|
41 * Core and plug-in writers can add and remove pads with gst_element_add_pad() |
|
42 * and gst_element_remove_pad(). |
|
43 * |
|
44 * A pad of an element can be retrieved by name with gst_element_get_pad(). |
|
45 * An iterator of all pads can be retrieved with gst_element_iterate_pads(). |
|
46 * |
|
47 * Elements can be linked through their pads. |
|
48 * If the link is straightforward, use the gst_element_link() |
|
49 * convenience function to link two elements, or gst_element_link_many() |
|
50 * for more elements in a row. |
|
51 * Use gst_element_link_filtered() to link two elements constrained by |
|
52 * a specified set of #GstCaps. |
|
53 * For finer control, use gst_element_link_pads() and |
|
54 * gst_element_link_pads_filtered() to specify the pads to link on |
|
55 * each element by name. |
|
56 * |
|
57 * Each element has a state (see #GstState). You can get and set the state |
|
58 * of an element with gst_element_get_state() and gst_element_set_state(). |
|
59 * To get a string representation of a #GstState, use |
|
60 * gst_element_state_get_name(). |
|
61 * |
|
62 * You can get and set a #GstClock on an element using gst_element_get_clock() |
|
63 * and gst_element_set_clock(). |
|
64 * Some elements can provide a clock for the pipeline if |
|
65 * gst_element_provides_clock() returns %TRUE. With the |
|
66 * gst_element_provide_clock() method one can retrieve the clock provided by |
|
67 * such an element. |
|
68 * Not all elements require a clock to operate correctly. If |
|
69 * gst_element_requires_clock() returns %TRUE, a clock should be set on the |
|
70 * element with gst_element_set_clock(). |
|
71 * |
|
72 * Note that clock slection and distribution is normally handled by the |
|
73 * toplevel #GstPipeline so the clock functions are only to be used in very |
|
74 * specific situations. |
|
75 * |
|
76 * Last reviewed on 2006-03-12 (0.10.5) |
|
77 */ |
|
78 |
|
79 #include "gst_private.h" |
|
80 #include <glib.h> |
|
81 #include <stdarg.h> |
|
82 #include <gobject/gvaluecollector.h> |
|
83 |
|
84 #include "gstelement.h" |
|
85 #include "gstenumtypes.h" |
|
86 #include "gstbus.h" |
|
87 #include "gstmarshal.h" |
|
88 #include "gsterror.h" |
|
89 #include "gstevent.h" |
|
90 #include "gstutils.h" |
|
91 #include "gstinfo.h" |
|
92 #include "gst-i18n-lib.h" |
|
93 |
|
94 #ifdef __SYMBIAN32__ |
|
95 #include <glib_global.h> |
|
96 #endif |
|
97 |
|
98 /* Element signals and args */ |
|
99 enum |
|
100 { |
|
101 PAD_ADDED, |
|
102 PAD_REMOVED, |
|
103 NO_MORE_PADS, |
|
104 /* add more above */ |
|
105 LAST_SIGNAL |
|
106 }; |
|
107 |
|
108 enum |
|
109 { |
|
110 ARG_0 |
|
111 /* FILL ME */ |
|
112 }; |
|
113 |
|
114 extern void __gst_element_details_clear (GstElementDetails * dp); |
|
115 extern void __gst_element_details_copy (GstElementDetails * dest, |
|
116 const GstElementDetails * src); |
|
117 |
|
118 static void gst_element_class_init (GstElementClass * klass); |
|
119 static void gst_element_init (GstElement * element); |
|
120 static void gst_element_base_class_init (gpointer g_class); |
|
121 static void gst_element_base_class_finalize (gpointer g_class); |
|
122 |
|
123 static void gst_element_dispose (GObject * object); |
|
124 static void gst_element_finalize (GObject * object); |
|
125 |
|
126 static GstStateChangeReturn gst_element_change_state_func (GstElement * element, |
|
127 GstStateChange transition); |
|
128 static GstStateChangeReturn gst_element_get_state_func (GstElement * element, |
|
129 GstState * state, GstState * pending, GstClockTime timeout); |
|
130 static GstStateChangeReturn gst_element_set_state_func (GstElement * element, |
|
131 GstState state); |
|
132 static void gst_element_set_bus_func (GstElement * element, GstBus * bus); |
|
133 |
|
134 static gboolean gst_element_default_send_event (GstElement * element, |
|
135 GstEvent * event); |
|
136 static gboolean gst_element_default_query (GstElement * element, |
|
137 GstQuery * query); |
|
138 |
|
139 static GstPadTemplate |
|
140 * gst_element_class_get_request_pad_template (GstElementClass * |
|
141 element_class, const gchar * name); |
|
142 |
|
143 #ifndef GST_DISABLE_LOADSAVE |
|
144 static xmlNodePtr gst_element_save_thyself (GstObject * object, |
|
145 xmlNodePtr parent); |
|
146 static void gst_element_restore_thyself (GstObject * parent, xmlNodePtr self); |
|
147 #endif |
|
148 |
|
149 static GstObjectClass *parent_class = NULL; |
|
150 static guint gst_element_signals[LAST_SIGNAL] = { 0 }; |
|
151 #ifdef __SYMBIAN32__ |
|
152 EXPORT_C |
|
153 #endif |
|
154 |
|
155 |
|
156 GType |
|
157 gst_element_get_type (void) |
|
158 { |
|
159 static GType gst_element_type = 0; |
|
160 |
|
161 if (G_UNLIKELY (gst_element_type == 0)) { |
|
162 static const GTypeInfo element_info = { |
|
163 sizeof (GstElementClass), |
|
164 gst_element_base_class_init, |
|
165 gst_element_base_class_finalize, |
|
166 (GClassInitFunc) gst_element_class_init, |
|
167 NULL, |
|
168 NULL, |
|
169 sizeof (GstElement), |
|
170 0, |
|
171 (GInstanceInitFunc) gst_element_init, |
|
172 NULL |
|
173 }; |
|
174 |
|
175 gst_element_type = g_type_register_static (GST_TYPE_OBJECT, "GstElement", |
|
176 &element_info, G_TYPE_FLAG_ABSTRACT); |
|
177 } |
|
178 return gst_element_type; |
|
179 } |
|
180 |
|
181 static void |
|
182 gst_element_class_init (GstElementClass * klass) |
|
183 { |
|
184 GObjectClass *gobject_class; |
|
185 GstObjectClass *gstobject_class; |
|
186 |
|
187 gobject_class = (GObjectClass *) klass; |
|
188 gstobject_class = (GstObjectClass *) klass; |
|
189 |
|
190 parent_class = g_type_class_peek_parent (klass); |
|
191 |
|
192 /** |
|
193 * GstElement::pad-added: |
|
194 * @gstelement: the object which received the signal |
|
195 * @new_pad: the pad that has been added |
|
196 * |
|
197 * a new #GstPad has been added to the element. |
|
198 */ |
|
199 gst_element_signals[PAD_ADDED] = |
|
200 g_signal_new ("pad-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, |
|
201 G_STRUCT_OFFSET (GstElementClass, pad_added), NULL, NULL, |
|
202 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_PAD); |
|
203 /** |
|
204 * GstElement::pad-removed: |
|
205 * @gstelement: the object which received the signal |
|
206 * @old_pad: the pad that has been removed |
|
207 * |
|
208 * a #GstPad has been removed from the element |
|
209 */ |
|
210 gst_element_signals[PAD_REMOVED] = |
|
211 g_signal_new ("pad-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, |
|
212 G_STRUCT_OFFSET (GstElementClass, pad_removed), NULL, NULL, |
|
213 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_PAD); |
|
214 /** |
|
215 * GstElement::no-more-pads: |
|
216 * @gstelement: the object which received the signal |
|
217 * |
|
218 * This signals that the element will not generate more dynamic pads. |
|
219 */ |
|
220 gst_element_signals[NO_MORE_PADS] = |
|
221 g_signal_new ("no-more-pads", G_TYPE_FROM_CLASS (klass), |
|
222 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstElementClass, no_more_pads), NULL, |
|
223 NULL, gst_marshal_VOID__VOID, G_TYPE_NONE, 0); |
|
224 |
|
225 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_element_dispose); |
|
226 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_element_finalize); |
|
227 |
|
228 #ifndef GST_DISABLE_LOADSAVE |
|
229 gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_element_save_thyself); |
|
230 gstobject_class->restore_thyself = |
|
231 GST_DEBUG_FUNCPTR (gst_element_restore_thyself); |
|
232 #endif |
|
233 |
|
234 klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state_func); |
|
235 klass->set_state = GST_DEBUG_FUNCPTR (gst_element_set_state_func); |
|
236 klass->get_state = GST_DEBUG_FUNCPTR (gst_element_get_state_func); |
|
237 klass->set_bus = GST_DEBUG_FUNCPTR (gst_element_set_bus_func); |
|
238 klass->query = GST_DEBUG_FUNCPTR (gst_element_default_query); |
|
239 klass->send_event = GST_DEBUG_FUNCPTR (gst_element_default_send_event); |
|
240 klass->numpadtemplates = 0; |
|
241 |
|
242 klass->elementfactory = NULL; |
|
243 } |
|
244 |
|
245 static void |
|
246 gst_element_base_class_init (gpointer g_class) |
|
247 { |
|
248 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); |
|
249 |
|
250 /* FIXME 0.11: Copy the element details and instead of clearing the |
|
251 * pad template list copy the list and increase the refcount of |
|
252 * the pad templates by one. |
|
253 * |
|
254 * This will make it possible to add pad templates and set element |
|
255 * details in the class_init functions and is the real GObject way |
|
256 * of doing things. |
|
257 * See http://bugzilla.gnome.org/show_bug.cgi?id=491501 |
|
258 */ |
|
259 memset (&element_class->details, 0, sizeof (GstElementDetails)); |
|
260 element_class->padtemplates = NULL; |
|
261 } |
|
262 |
|
263 static void |
|
264 gst_element_base_class_finalize (gpointer g_class) |
|
265 { |
|
266 GstElementClass *klass = GST_ELEMENT_CLASS (g_class); |
|
267 |
|
268 g_list_foreach (klass->padtemplates, (GFunc) gst_object_unref, NULL); |
|
269 g_list_free (klass->padtemplates); |
|
270 __gst_element_details_clear (&klass->details); |
|
271 } |
|
272 |
|
273 static void |
|
274 gst_element_init (GstElement * element) |
|
275 { |
|
276 GST_STATE (element) = GST_STATE_NULL; |
|
277 GST_STATE_TARGET (element) = GST_STATE_NULL; |
|
278 GST_STATE_NEXT (element) = GST_STATE_VOID_PENDING; |
|
279 GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING; |
|
280 GST_STATE_RETURN (element) = GST_STATE_CHANGE_SUCCESS; |
|
281 |
|
282 element->state_lock = g_new0 (GStaticRecMutex, 1); |
|
283 g_static_rec_mutex_init (element->state_lock); |
|
284 element->state_cond = g_cond_new (); |
|
285 } |
|
286 |
|
287 /** |
|
288 * gst_element_default_error: |
|
289 * @object: a #GObject that signalled the error. |
|
290 * @orig: the #GstObject that initiated the error. |
|
291 * @error: the GError. |
|
292 * @debug: an additional debug information string, or %NULL. |
|
293 * |
|
294 * A default error signal callback to attach to an element. |
|
295 * The user data passed to the g_signal_connect is ignored. |
|
296 * |
|
297 * The default handler will simply print the error string using g_print. |
|
298 * |
|
299 * MT safe. |
|
300 */ |
|
301 #ifdef __SYMBIAN32__ |
|
302 EXPORT_C |
|
303 #endif |
|
304 |
|
305 void |
|
306 gst_element_default_error (GObject * object, GstObject * source, GError * error, |
|
307 gchar * debug) |
|
308 { |
|
309 gchar *name = gst_object_get_path_string (source); |
|
310 |
|
311 g_print (_("ERROR: from element %s: %s\n"), name, error->message); |
|
312 if (debug) |
|
313 g_print (_("Additional debug info:\n%s\n"), debug); |
|
314 |
|
315 g_free (name); |
|
316 } |
|
317 |
|
318 /** |
|
319 * gst_element_release_request_pad: |
|
320 * @element: a #GstElement to release the request pad of. |
|
321 * @pad: the #GstPad to release. |
|
322 * |
|
323 * Makes the element free the previously requested pad as obtained |
|
324 * with gst_element_get_request_pad(). |
|
325 * |
|
326 * MT safe. |
|
327 */ |
|
328 #ifdef __SYMBIAN32__ |
|
329 EXPORT_C |
|
330 #endif |
|
331 |
|
332 void |
|
333 gst_element_release_request_pad (GstElement * element, GstPad * pad) |
|
334 { |
|
335 GstElementClass *oclass; |
|
336 |
|
337 g_return_if_fail (GST_IS_ELEMENT (element)); |
|
338 g_return_if_fail (GST_IS_PAD (pad)); |
|
339 |
|
340 oclass = GST_ELEMENT_GET_CLASS (element); |
|
341 |
|
342 /* if the element implements a custom release function we call that, else we |
|
343 * simply remove the pad from the element */ |
|
344 if (oclass->release_pad) |
|
345 (oclass->release_pad) (element, pad); |
|
346 else |
|
347 gst_element_remove_pad (element, pad); |
|
348 } |
|
349 |
|
350 /** |
|
351 * gst_element_requires_clock: |
|
352 * @element: a #GstElement to query |
|
353 * |
|
354 * Query if the element requires a clock. |
|
355 * |
|
356 * Returns: %TRUE if the element requires a clock |
|
357 * |
|
358 * MT safe. |
|
359 */ |
|
360 #ifdef __SYMBIAN32__ |
|
361 EXPORT_C |
|
362 #endif |
|
363 |
|
364 gboolean |
|
365 gst_element_requires_clock (GstElement * element) |
|
366 { |
|
367 gboolean result; |
|
368 |
|
369 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
|
370 |
|
371 result = (GST_ELEMENT_GET_CLASS (element)->set_clock != NULL); |
|
372 |
|
373 return result; |
|
374 } |
|
375 |
|
376 /** |
|
377 * gst_element_provides_clock: |
|
378 * @element: a #GstElement to query |
|
379 * |
|
380 * Query if the element provides a clock. A #GstClock provided by an |
|
381 * element can be used as the global #GstClock for the pipeline. |
|
382 * An element that can provide a clock is only required to do so in the PAUSED |
|
383 * state, this means when it is fully negotiated and has allocated the resources |
|
384 * to operate the clock. |
|
385 * |
|
386 * Returns: %TRUE if the element provides a clock |
|
387 * |
|
388 * MT safe. |
|
389 */ |
|
390 #ifdef __SYMBIAN32__ |
|
391 EXPORT_C |
|
392 #endif |
|
393 |
|
394 gboolean |
|
395 gst_element_provides_clock (GstElement * element) |
|
396 { |
|
397 gboolean result; |
|
398 |
|
399 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
|
400 |
|
401 result = (GST_ELEMENT_GET_CLASS (element)->provide_clock != NULL); |
|
402 |
|
403 return result; |
|
404 } |
|
405 |
|
406 /** |
|
407 * gst_element_provide_clock: |
|
408 * @element: a #GstElement to query |
|
409 * |
|
410 * Get the clock provided by the given element. |
|
411 * <note>An element is only required to provide a clock in the PAUSED |
|
412 * state. Some elements can provide a clock in other states.</note> |
|
413 * |
|
414 * Returns: the GstClock provided by the element or %NULL |
|
415 * if no clock could be provided. Unref after usage. |
|
416 * |
|
417 * MT safe. |
|
418 */ |
|
419 #ifdef __SYMBIAN32__ |
|
420 EXPORT_C |
|
421 #endif |
|
422 |
|
423 GstClock * |
|
424 gst_element_provide_clock (GstElement * element) |
|
425 { |
|
426 GstClock *result = NULL; |
|
427 GstElementClass *oclass; |
|
428 |
|
429 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
|
430 |
|
431 oclass = GST_ELEMENT_GET_CLASS (element); |
|
432 |
|
433 if (oclass->provide_clock) |
|
434 result = oclass->provide_clock (element); |
|
435 |
|
436 return result; |
|
437 } |
|
438 |
|
439 /** |
|
440 * gst_element_set_clock: |
|
441 * @element: a #GstElement to set the clock for. |
|
442 * @clock: the #GstClock to set for the element. |
|
443 * |
|
444 * Sets the clock for the element. This function increases the |
|
445 * refcount on the clock. Any previously set clock on the object |
|
446 * is unreffed. |
|
447 * |
|
448 * Returns: %TRUE if the element accepted the clock. An element can refuse a |
|
449 * clock when it, for example, is not able to slave its internal clock to the |
|
450 * @clock or when it requires a specific clock to operate. |
|
451 * |
|
452 * MT safe. |
|
453 */ |
|
454 #ifdef __SYMBIAN32__ |
|
455 EXPORT_C |
|
456 #endif |
|
457 |
|
458 gboolean |
|
459 gst_element_set_clock (GstElement * element, GstClock * clock) |
|
460 { |
|
461 GstElementClass *oclass; |
|
462 gboolean res = TRUE; |
|
463 GstClock **clock_p; |
|
464 |
|
465 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
|
466 |
|
467 oclass = GST_ELEMENT_GET_CLASS (element); |
|
468 |
|
469 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, element, "setting clock %p", clock); |
|
470 |
|
471 if (oclass->set_clock) |
|
472 res = oclass->set_clock (element, clock); |
|
473 |
|
474 if (res) { |
|
475 /* only update the clock pointer if the element accepted the clock */ |
|
476 GST_OBJECT_LOCK (element); |
|
477 clock_p = &element->clock; |
|
478 gst_object_replace ((GstObject **) clock_p, (GstObject *) clock); |
|
479 GST_OBJECT_UNLOCK (element); |
|
480 } |
|
481 return res; |
|
482 } |
|
483 |
|
484 /** |
|
485 * gst_element_get_clock: |
|
486 * @element: a #GstElement to get the clock of. |
|
487 * |
|
488 * Gets the currently configured clock of the element. This is the clock as was |
|
489 * last set with gst_element_set_clock(). |
|
490 * |
|
491 * Returns: the #GstClock of the element. unref after usage. |
|
492 * |
|
493 * MT safe. |
|
494 */ |
|
495 #ifdef __SYMBIAN32__ |
|
496 EXPORT_C |
|
497 #endif |
|
498 |
|
499 GstClock * |
|
500 gst_element_get_clock (GstElement * element) |
|
501 { |
|
502 GstClock *result; |
|
503 |
|
504 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
|
505 |
|
506 GST_OBJECT_LOCK (element); |
|
507 if ((result = element->clock)) |
|
508 gst_object_ref (result); |
|
509 GST_OBJECT_UNLOCK (element); |
|
510 |
|
511 return result; |
|
512 } |
|
513 |
|
514 /** |
|
515 * gst_element_set_base_time: |
|
516 * @element: a #GstElement. |
|
517 * @time: the base time to set. |
|
518 * |
|
519 * Set the base time of an element. See gst_element_get_base_time(). |
|
520 * |
|
521 * MT safe. |
|
522 */ |
|
523 #ifdef __SYMBIAN32__ |
|
524 EXPORT_C |
|
525 #endif |
|
526 |
|
527 void |
|
528 gst_element_set_base_time (GstElement * element, GstClockTime time) |
|
529 { |
|
530 GstClockTime old; |
|
531 |
|
532 g_return_if_fail (GST_IS_ELEMENT (element)); |
|
533 |
|
534 GST_OBJECT_LOCK (element); |
|
535 old = element->base_time; |
|
536 element->base_time = time; |
|
537 GST_OBJECT_UNLOCK (element); |
|
538 |
|
539 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, element, |
|
540 "set base_time=%" GST_TIME_FORMAT ", old %" GST_TIME_FORMAT, |
|
541 GST_TIME_ARGS (time), GST_TIME_ARGS (old)); |
|
542 } |
|
543 |
|
544 /** |
|
545 * gst_element_get_base_time: |
|
546 * @element: a #GstElement. |
|
547 * |
|
548 * Returns the base time of the element. The base time is the |
|
549 * absolute time of the clock when this element was last put to |
|
550 * PLAYING. Subtracting the base time from the clock time gives |
|
551 * the stream time of the element. |
|
552 * |
|
553 * Returns: the base time of the element. |
|
554 * |
|
555 * MT safe. |
|
556 */ |
|
557 #ifdef __SYMBIAN32__ |
|
558 EXPORT_C |
|
559 #endif |
|
560 |
|
561 GstClockTime |
|
562 gst_element_get_base_time (GstElement * element) |
|
563 { |
|
564 GstClockTime result; |
|
565 |
|
566 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_TIME_NONE); |
|
567 |
|
568 GST_OBJECT_LOCK (element); |
|
569 result = element->base_time; |
|
570 GST_OBJECT_UNLOCK (element); |
|
571 |
|
572 return result; |
|
573 } |
|
574 |
|
575 #ifndef GST_DISABLE_INDEX |
|
576 /** |
|
577 * gst_element_is_indexable: |
|
578 * @element: a #GstElement. |
|
579 * |
|
580 * Queries if the element can be indexed. |
|
581 * |
|
582 * Returns: TRUE if the element can be indexed. |
|
583 * |
|
584 * MT safe. |
|
585 */ |
|
586 #ifdef __SYMBIAN32__ |
|
587 EXPORT_C |
|
588 #endif |
|
589 |
|
590 gboolean |
|
591 gst_element_is_indexable (GstElement * element) |
|
592 { |
|
593 gboolean result; |
|
594 |
|
595 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
|
596 |
|
597 result = (GST_ELEMENT_GET_CLASS (element)->set_index != NULL); |
|
598 |
|
599 return result; |
|
600 } |
|
601 |
|
602 /** |
|
603 * gst_element_set_index: |
|
604 * @element: a #GstElement. |
|
605 * @index: a #GstIndex. |
|
606 * |
|
607 * Set @index on the element. The refcount of the index |
|
608 * will be increased, any previously set index is unreffed. |
|
609 * |
|
610 * MT safe. |
|
611 */ |
|
612 #ifdef __SYMBIAN32__ |
|
613 EXPORT_C |
|
614 #endif |
|
615 |
|
616 void |
|
617 gst_element_set_index (GstElement * element, GstIndex * index) |
|
618 { |
|
619 GstElementClass *oclass; |
|
620 |
|
621 g_return_if_fail (GST_IS_ELEMENT (element)); |
|
622 g_return_if_fail (GST_IS_INDEX (index)); |
|
623 |
|
624 oclass = GST_ELEMENT_GET_CLASS (element); |
|
625 |
|
626 if (oclass->set_index) |
|
627 oclass->set_index (element, index); |
|
628 } |
|
629 |
|
630 /** |
|
631 * gst_element_get_index: |
|
632 * @element: a #GstElement. |
|
633 * |
|
634 * Gets the index from the element. |
|
635 * |
|
636 * Returns: a #GstIndex or %NULL when no index was set on the |
|
637 * element. unref after usage. |
|
638 * |
|
639 * MT safe. |
|
640 */ |
|
641 #ifdef __SYMBIAN32__ |
|
642 EXPORT_C |
|
643 #endif |
|
644 |
|
645 GstIndex * |
|
646 gst_element_get_index (GstElement * element) |
|
647 { |
|
648 GstElementClass *oclass; |
|
649 GstIndex *result = NULL; |
|
650 |
|
651 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
|
652 |
|
653 oclass = GST_ELEMENT_GET_CLASS (element); |
|
654 |
|
655 if (oclass->get_index) |
|
656 result = oclass->get_index (element); |
|
657 |
|
658 return result; |
|
659 } |
|
660 #endif |
|
661 |
|
662 /** |
|
663 * gst_element_add_pad: |
|
664 * @element: a #GstElement to add the pad to. |
|
665 * @pad: the #GstPad to add to the element. |
|
666 * |
|
667 * Adds a pad (link point) to @element. @pad's parent will be set to @element; |
|
668 #ifdef __SYMBIAN32__ |
|
669 EXPORT_C |
|
670 #endif |
|
671 |
|
672 * see gst_object_set_parent() for refcounting information. |
|
673 * |
|
674 * Pads are not automatically activated so elements should perform the needed |
|
675 * steps to activate the pad in case this pad is added in the PAUSED or PLAYING |
|
676 * state. See gst_pad_set_active() for more information about activating pads. |
|
677 * |
|
678 * The pad and the element should be unlocked when calling this function. |
|
679 * |
|
680 * This function will emit the #GstElement::pad-added signal on the element. |
|
681 * |
|
682 * Returns: %TRUE if the pad could be added. This function can fail when |
|
683 * a pad with the same name already existed or the pad already had another |
|
684 * parent. |
|
685 * |
|
686 * MT safe. |
|
687 */ |
|
688 #ifdef __SYMBIAN32__ |
|
689 EXPORT_C |
|
690 #endif |
|
691 |
|
692 gboolean |
|
693 gst_element_add_pad (GstElement * element, GstPad * pad) |
|
694 { |
|
695 gchar *pad_name; |
|
696 gboolean flushing; |
|
697 |
|
698 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
|
699 g_return_val_if_fail (GST_IS_PAD (pad), FALSE); |
|
700 |
|
701 /* locking pad to look at the name */ |
|
702 GST_OBJECT_LOCK (pad); |
|
703 pad_name = g_strdup (GST_PAD_NAME (pad)); |
|
704 GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element, "adding pad '%s'", |
|
705 GST_STR_NULL (pad_name)); |
|
706 flushing = GST_PAD_IS_FLUSHING (pad); |
|
707 GST_OBJECT_UNLOCK (pad); |
|
708 |
|
709 /* then check to see if there's already a pad by that name here */ |
|
710 GST_OBJECT_LOCK (element); |
|
711 if (G_UNLIKELY (!gst_object_check_uniqueness (element->pads, pad_name))) |
|
712 goto name_exists; |
|
713 |
|
714 /* try to set the pad's parent */ |
|
715 if (G_UNLIKELY (!gst_object_set_parent (GST_OBJECT_CAST (pad), |
|
716 GST_OBJECT_CAST (element)))) |
|
717 goto had_parent; |
|
718 |
|
719 /* check for flushing pads */ |
|
720 if (flushing && (GST_STATE (element) > GST_STATE_READY || |
|
721 GST_STATE_NEXT (element) == GST_STATE_PAUSED)) { |
|
722 g_warning ("adding flushing pad '%s' to running element '%s'", |
|
723 GST_STR_NULL (pad_name), GST_ELEMENT_NAME (element)); |
|
724 /* unset flushing */ |
|
725 GST_OBJECT_LOCK (pad); |
|
726 GST_PAD_UNSET_FLUSHING (pad); |
|
727 GST_OBJECT_UNLOCK (pad); |
|
728 } |
|
729 |
|
730 g_free (pad_name); |
|
731 |
|
732 /* add it to the list */ |
|
733 switch (gst_pad_get_direction (pad)) { |
|
734 case GST_PAD_SRC: |
|
735 element->srcpads = g_list_prepend (element->srcpads, pad); |
|
736 element->numsrcpads++; |
|
737 break; |
|
738 case GST_PAD_SINK: |
|
739 element->sinkpads = g_list_prepend (element->sinkpads, pad); |
|
740 element->numsinkpads++; |
|
741 break; |
|
742 default: |
|
743 goto no_direction; |
|
744 } |
|
745 element->pads = g_list_prepend (element->pads, pad); |
|
746 element->numpads++; |
|
747 element->pads_cookie++; |
|
748 GST_OBJECT_UNLOCK (element); |
|
749 |
|
750 /* emit the PAD_ADDED signal */ |
|
751 g_signal_emit (element, gst_element_signals[PAD_ADDED], 0, pad); |
|
752 |
|
753 return TRUE; |
|
754 |
|
755 /* ERROR cases */ |
|
756 name_exists: |
|
757 { |
|
758 g_critical ("Padname %s is not unique in element %s, not adding", |
|
759 pad_name, GST_ELEMENT_NAME (element)); |
|
760 GST_OBJECT_UNLOCK (element); |
|
761 g_free (pad_name); |
|
762 return FALSE; |
|
763 } |
|
764 had_parent: |
|
765 { |
|
766 g_critical |
|
767 ("Pad %s already has parent when trying to add to element %s", |
|
768 pad_name, GST_ELEMENT_NAME (element)); |
|
769 GST_OBJECT_UNLOCK (element); |
|
770 g_free (pad_name); |
|
771 return FALSE; |
|
772 } |
|
773 no_direction: |
|
774 { |
|
775 GST_OBJECT_LOCK (pad); |
|
776 g_critical |
|
777 ("Trying to add pad %s to element %s, but it has no direction", |
|
778 GST_OBJECT_NAME (pad), GST_ELEMENT_NAME (element)); |
|
779 GST_OBJECT_UNLOCK (pad); |
|
780 GST_OBJECT_UNLOCK (element); |
|
781 return FALSE; |
|
782 } |
|
783 } |
|
784 |
|
785 /** |
|
786 * gst_element_remove_pad: |
|
787 * @element: a #GstElement to remove pad from. |
|
788 * @pad: the #GstPad to remove from the element. |
|
789 * |
|
790 * Removes @pad from @element. @pad will be destroyed if it has not been |
|
791 * referenced elsewhere using gst_object_unparent(). |
|
792 * |
|
793 * This function is used by plugin developers and should not be used |
|
794 * by applications. Pads that were dynamically requested from elements |
|
795 * with gst_element_get_request_pad() should be released with the |
|
796 * gst_element_release_request_pad() function instead. |
|
797 * |
|
798 * Pads are not automatically deactivated so elements should perform the needed |
|
799 * steps to deactivate the pad in case this pad is removed in the PAUSED or |
|
800 * PLAYING state. See gst_pad_set_active() for more information about |
|
801 * deactivating pads. |
|
802 * |
|
803 * The pad and the element should be unlocked when calling this function. |
|
804 * |
|
805 * This function will emit the #GstElement::pad-removed signal on the element. |
|
806 * |
|
807 * Returns: %TRUE if the pad could be removed. Can return %FALSE if the |
|
808 * pad does not belong to the provided element. |
|
809 * |
|
810 * MT safe. |
|
811 */ |
|
812 #ifdef __SYMBIAN32__ |
|
813 EXPORT_C |
|
814 #endif |
|
815 |
|
816 gboolean |
|
817 gst_element_remove_pad (GstElement * element, GstPad * pad) |
|
818 { |
|
819 GstPad *peer; |
|
820 |
|
821 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
|
822 g_return_val_if_fail (GST_IS_PAD (pad), FALSE); |
|
823 |
|
824 /* locking pad to look at the name and parent */ |
|
825 GST_OBJECT_LOCK (pad); |
|
826 GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element, "removing pad '%s'", |
|
827 GST_STR_NULL (GST_PAD_NAME (pad))); |
|
828 |
|
829 if (G_UNLIKELY (GST_PAD_PARENT (pad) != element)) |
|
830 goto not_our_pad; |
|
831 GST_OBJECT_UNLOCK (pad); |
|
832 |
|
833 /* unlink */ |
|
834 if ((peer = gst_pad_get_peer (pad))) { |
|
835 /* window for MT unsafeness, someone else could unlink here |
|
836 * and then we call unlink with wrong pads. The unlink |
|
837 * function would catch this and safely return failed. */ |
|
838 if (GST_PAD_IS_SRC (pad)) |
|
839 gst_pad_unlink (pad, peer); |
|
840 else |
|
841 gst_pad_unlink (peer, pad); |
|
842 |
|
843 gst_object_unref (peer); |
|
844 } |
|
845 |
|
846 GST_OBJECT_LOCK (element); |
|
847 /* remove it from the list */ |
|
848 switch (gst_pad_get_direction (pad)) { |
|
849 case GST_PAD_SRC: |
|
850 element->srcpads = g_list_remove (element->srcpads, pad); |
|
851 element->numsrcpads--; |
|
852 break; |
|
853 case GST_PAD_SINK: |
|
854 element->sinkpads = g_list_remove (element->sinkpads, pad); |
|
855 element->numsinkpads--; |
|
856 break; |
|
857 default: |
|
858 g_critical ("Removing pad without direction???"); |
|
859 break; |
|
860 } |
|
861 element->pads = g_list_remove (element->pads, pad); |
|
862 element->numpads--; |
|
863 element->pads_cookie++; |
|
864 GST_OBJECT_UNLOCK (element); |
|
865 |
|
866 /* emit the PAD_REMOVED signal before unparenting and losing the last ref. */ |
|
867 g_signal_emit (element, gst_element_signals[PAD_REMOVED], 0, pad); |
|
868 |
|
869 gst_object_unparent (GST_OBJECT_CAST (pad)); |
|
870 |
|
871 return TRUE; |
|
872 |
|
873 /* ERRORS */ |
|
874 not_our_pad: |
|
875 { |
|
876 /* FIXME, locking order? */ |
|
877 GST_OBJECT_LOCK (element); |
|
878 g_critical ("Padname %s:%s does not belong to element %s when removing", |
|
879 GST_DEBUG_PAD_NAME (pad), GST_ELEMENT_NAME (element)); |
|
880 GST_OBJECT_UNLOCK (element); |
|
881 GST_OBJECT_UNLOCK (pad); |
|
882 return FALSE; |
|
883 } |
|
884 } |
|
885 |
|
886 /** |
|
887 * gst_element_no_more_pads: |
|
888 * @element: a #GstElement |
|
889 * |
|
890 * Use this function to signal that the element does not expect any more pads |
|
891 * to show up in the current pipeline. This function should be called whenever |
|
892 * pads have been added by the element itself. Elements with #GST_PAD_SOMETIMES |
|
893 * pad templates use this in combination with autopluggers to figure out that |
|
894 * the element is done initializing its pads. |
|
895 * |
|
896 * This function emits the #GstElement::no-more-pads signal. |
|
897 * |
|
898 * MT safe. |
|
899 */ |
|
900 #ifdef __SYMBIAN32__ |
|
901 EXPORT_C |
|
902 #endif |
|
903 |
|
904 void |
|
905 gst_element_no_more_pads (GstElement * element) |
|
906 { |
|
907 g_return_if_fail (GST_IS_ELEMENT (element)); |
|
908 |
|
909 g_signal_emit (element, gst_element_signals[NO_MORE_PADS], 0); |
|
910 } |
|
911 |
|
912 static gint |
|
913 pad_compare_name (GstPad * pad1, const gchar * name) |
|
914 { |
|
915 gint result; |
|
916 |
|
917 GST_OBJECT_LOCK (pad1); |
|
918 result = strcmp (GST_PAD_NAME (pad1), name); |
|
919 GST_OBJECT_UNLOCK (pad1); |
|
920 |
|
921 return result; |
|
922 } |
|
923 |
|
924 /** |
|
925 * gst_element_get_static_pad: |
|
926 * @element: a #GstElement to find a static pad of. |
|
927 * @name: the name of the static #GstPad to retrieve. |
|
928 * |
|
929 * Retrieves a pad from @element by name. This version only retrieves |
|
930 * already-existing (i.e. 'static') pads. |
|
931 * |
|
932 * Returns: the requested #GstPad if found, otherwise %NULL. unref after |
|
933 * usage. |
|
934 * |
|
935 * MT safe. |
|
936 */ |
|
937 #ifdef __SYMBIAN32__ |
|
938 EXPORT_C |
|
939 #endif |
|
940 |
|
941 GstPad * |
|
942 gst_element_get_static_pad (GstElement * element, const gchar * name) |
|
943 { |
|
944 GList *find; |
|
945 GstPad *result = NULL; |
|
946 |
|
947 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
|
948 g_return_val_if_fail (name != NULL, NULL); |
|
949 |
|
950 GST_OBJECT_LOCK (element); |
|
951 find = |
|
952 g_list_find_custom (element->pads, name, (GCompareFunc) pad_compare_name); |
|
953 if (find) { |
|
954 result = GST_PAD_CAST (find->data); |
|
955 gst_object_ref (result); |
|
956 } |
|
957 |
|
958 if (result == NULL) { |
|
959 GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "no such pad '%s' in element \"%s\"", |
|
960 name, GST_ELEMENT_NAME (element)); |
|
961 } else { |
|
962 GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "found pad %s:%s", |
|
963 GST_ELEMENT_NAME (element), name); |
|
964 } |
|
965 GST_OBJECT_UNLOCK (element); |
|
966 |
|
967 return result; |
|
968 } |
|
969 |
|
970 static GstPad * |
|
971 gst_element_request_pad (GstElement * element, GstPadTemplate * templ, |
|
972 const gchar * name) |
|
973 { |
|
974 GstPad *newpad = NULL; |
|
975 GstElementClass *oclass; |
|
976 |
|
977 oclass = GST_ELEMENT_GET_CLASS (element); |
|
978 |
|
979 if (oclass->request_new_pad) |
|
980 newpad = (oclass->request_new_pad) (element, templ, name); |
|
981 |
|
982 if (newpad) |
|
983 gst_object_ref (newpad); |
|
984 |
|
985 return newpad; |
|
986 } |
|
987 |
|
988 /** |
|
989 * gst_element_get_request_pad: |
|
990 * @element: a #GstElement to find a request pad of. |
|
991 * @name: the name of the request #GstPad to retrieve. |
|
992 * |
|
993 * Retrieves a pad from the element by name. This version only retrieves |
|
994 * request pads. The pad should be released with |
|
995 * gst_element_release_request_pad(). |
|
996 * |
|
997 * Returns: requested #GstPad if found, otherwise %NULL. Release after usage. |
|
998 */ |
|
999 #ifdef __SYMBIAN32__ |
|
1000 EXPORT_C |
|
1001 #endif |
|
1002 |
|
1003 GstPad * |
|
1004 gst_element_get_request_pad (GstElement * element, const gchar * name) |
|
1005 { |
|
1006 GstPadTemplate *templ = NULL; |
|
1007 GstPad *pad; |
|
1008 const gchar *req_name = NULL; |
|
1009 gboolean templ_found = FALSE; |
|
1010 GList *list; |
|
1011 gint n; |
|
1012 const gchar *data; |
|
1013 gchar *str, *endptr = NULL; |
|
1014 GstElementClass *class; |
|
1015 |
|
1016 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
|
1017 g_return_val_if_fail (name != NULL, NULL); |
|
1018 |
|
1019 class = GST_ELEMENT_GET_CLASS (element); |
|
1020 |
|
1021 /* if the name contains a %, we assume it's the complete template name. Get |
|
1022 * the template and try to get a pad */ |
|
1023 if (strstr (name, "%")) { |
|
1024 templ = gst_element_class_get_request_pad_template (class, name); |
|
1025 req_name = NULL; |
|
1026 if (templ) |
|
1027 templ_found = TRUE; |
|
1028 } else { |
|
1029 /* there is no % in the name, try to find a matching template */ |
|
1030 list = gst_element_class_get_pad_template_list (class); |
|
1031 while (!templ_found && list) { |
|
1032 templ = (GstPadTemplate *) list->data; |
|
1033 if (templ->presence == GST_PAD_REQUEST) { |
|
1034 GST_CAT_DEBUG (GST_CAT_PADS, "comparing %s to %s", name, |
|
1035 templ->name_template); |
|
1036 /* see if we find an exact match */ |
|
1037 if (strcmp (name, templ->name_template) == 0) { |
|
1038 templ_found = TRUE; |
|
1039 req_name = name; |
|
1040 break; |
|
1041 } |
|
1042 /* Because of sanity checks in gst_pad_template_new(), we know that %s |
|
1043 and %d, occurring at the end of the name_template, are the only |
|
1044 possibilities. */ |
|
1045 else if ((str = strchr (templ->name_template, '%')) |
|
1046 && strncmp (templ->name_template, name, |
|
1047 str - templ->name_template) == 0 |
|
1048 && strlen (name) > str - templ->name_template) { |
|
1049 data = name + (str - templ->name_template); |
|
1050 if (*(str + 1) == 'd') { |
|
1051 /* it's an int */ |
|
1052 n = (gint) strtol (data, &endptr, 10); |
|
1053 if (endptr && *endptr == '\0') { |
|
1054 templ_found = TRUE; |
|
1055 req_name = name; |
|
1056 break; |
|
1057 } |
|
1058 } else { |
|
1059 /* it's a string */ |
|
1060 templ_found = TRUE; |
|
1061 req_name = name; |
|
1062 break; |
|
1063 } |
|
1064 } |
|
1065 } |
|
1066 list = list->next; |
|
1067 } |
|
1068 } |
|
1069 |
|
1070 if (!templ_found) |
|
1071 return NULL; |
|
1072 |
|
1073 pad = gst_element_request_pad (element, templ, req_name); |
|
1074 |
|
1075 return pad; |
|
1076 } |
|
1077 |
|
1078 /** |
|
1079 * gst_element_get_pad: |
|
1080 * @element: a #GstElement. |
|
1081 * @name: the name of the pad to retrieve. |
|
1082 * |
|
1083 * Retrieves a pad from @element by name. Tries gst_element_get_static_pad() |
|
1084 * first, then gst_element_get_request_pad(). |
|
1085 * |
|
1086 * <note>Usage of this function is not recommended as it is unclear if the reference |
|
1087 * to the result pad should be released with gst_object_unref() in case of a static pad |
|
1088 * or gst_element_release_request_pad() in case of a request pad.</note> |
|
1089 * |
|
1090 * Returns: the #GstPad if found, otherwise %NULL. Unref or Release after usage, |
|
1091 * depending on the type of the pad. |
|
1092 */ |
|
1093 #ifdef __SYMBIAN32__ |
|
1094 EXPORT_C |
|
1095 #endif |
|
1096 |
|
1097 GstPad * |
|
1098 gst_element_get_pad (GstElement * element, const gchar * name) |
|
1099 { |
|
1100 GstPad *pad; |
|
1101 |
|
1102 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
|
1103 g_return_val_if_fail (name != NULL, NULL); |
|
1104 |
|
1105 pad = gst_element_get_static_pad (element, name); |
|
1106 if (!pad) |
|
1107 pad = gst_element_get_request_pad (element, name); |
|
1108 |
|
1109 return pad; |
|
1110 } |
|
1111 |
|
1112 static GstIteratorItem |
|
1113 iterate_pad (GstIterator * it, GstPad * pad) |
|
1114 { |
|
1115 gst_object_ref (pad); |
|
1116 return GST_ITERATOR_ITEM_PASS; |
|
1117 } |
|
1118 |
|
1119 static GstIterator * |
|
1120 gst_element_iterate_pad_list (GstElement * element, GList ** padlist) |
|
1121 { |
|
1122 GstIterator *result; |
|
1123 |
|
1124 GST_OBJECT_LOCK (element); |
|
1125 gst_object_ref (element); |
|
1126 result = gst_iterator_new_list (GST_TYPE_PAD, |
|
1127 GST_OBJECT_GET_LOCK (element), |
|
1128 &element->pads_cookie, |
|
1129 padlist, |
|
1130 element, |
|
1131 (GstIteratorItemFunction) iterate_pad, |
|
1132 (GstIteratorDisposeFunction) gst_object_unref); |
|
1133 GST_OBJECT_UNLOCK (element); |
|
1134 |
|
1135 return result; |
|
1136 } |
|
1137 |
|
1138 /** |
|
1139 * gst_element_iterate_pads: |
|
1140 * @element: a #GstElement to iterate pads of. |
|
1141 * |
|
1142 * Retrieves an iterattor of @element's pads. The iterator should |
|
1143 * be freed after usage. |
|
1144 * |
|
1145 * Returns: the #GstIterator of #GstPad. Unref each pad after use. |
|
1146 * |
|
1147 * MT safe. |
|
1148 */ |
|
1149 #ifdef __SYMBIAN32__ |
|
1150 EXPORT_C |
|
1151 #endif |
|
1152 |
|
1153 GstIterator * |
|
1154 gst_element_iterate_pads (GstElement * element) |
|
1155 { |
|
1156 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
|
1157 |
|
1158 return gst_element_iterate_pad_list (element, &element->pads); |
|
1159 } |
|
1160 |
|
1161 /** |
|
1162 * gst_element_iterate_src_pads: |
|
1163 * @element: a #GstElement. |
|
1164 * |
|
1165 * Retrieves an iterator of @element's source pads. |
|
1166 * |
|
1167 * Returns: the #GstIterator of #GstPad. Unref each pad after use. |
|
1168 * |
|
1169 * MT safe. |
|
1170 */ |
|
1171 #ifdef __SYMBIAN32__ |
|
1172 EXPORT_C |
|
1173 #endif |
|
1174 |
|
1175 GstIterator * |
|
1176 gst_element_iterate_src_pads (GstElement * element) |
|
1177 { |
|
1178 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
|
1179 |
|
1180 return gst_element_iterate_pad_list (element, &element->srcpads); |
|
1181 } |
|
1182 |
|
1183 /** |
|
1184 * gst_element_iterate_sink_pads: |
|
1185 * @element: a #GstElement. |
|
1186 * |
|
1187 * Retrieves an iterator of @element's sink pads. |
|
1188 * |
|
1189 * Returns: the #GstIterator of #GstPad. Unref each pad after use. |
|
1190 * |
|
1191 * MT safe. |
|
1192 */ |
|
1193 #ifdef __SYMBIAN32__ |
|
1194 EXPORT_C |
|
1195 #endif |
|
1196 |
|
1197 GstIterator * |
|
1198 gst_element_iterate_sink_pads (GstElement * element) |
|
1199 { |
|
1200 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
|
1201 |
|
1202 return gst_element_iterate_pad_list (element, &element->sinkpads); |
|
1203 } |
|
1204 |
|
1205 /** |
|
1206 * gst_element_class_add_pad_template: |
|
1207 * @klass: the #GstElementClass to add the pad template to. |
|
1208 * @templ: a #GstPadTemplate to add to the element class. |
|
1209 * |
|
1210 * Adds a padtemplate to an element class. This is mainly used in the _base_init |
|
1211 * functions of classes. |
|
1212 */ |
|
1213 #ifdef __SYMBIAN32__ |
|
1214 EXPORT_C |
|
1215 #endif |
|
1216 |
|
1217 void |
|
1218 gst_element_class_add_pad_template (GstElementClass * klass, |
|
1219 GstPadTemplate * templ) |
|
1220 { |
|
1221 g_return_if_fail (GST_IS_ELEMENT_CLASS (klass)); |
|
1222 g_return_if_fail (GST_IS_PAD_TEMPLATE (templ)); |
|
1223 |
|
1224 /* FIXME 0.11: allow replacing the pad templates by |
|
1225 * calling this with the same name as an already existing pad |
|
1226 * template. For this we _must_ _not_ ref the added pad template |
|
1227 * a second time and _must_ document that this function takes |
|
1228 * ownership of the pad template. Otherwise we will leak pad templates |
|
1229 * or the caller unref's the pad template and it disappears */ |
|
1230 /* avoid registering pad templates with the same name */ |
|
1231 g_return_if_fail (gst_element_class_get_pad_template (klass, |
|
1232 templ->name_template) == NULL); |
|
1233 |
|
1234 klass->padtemplates = g_list_append (klass->padtemplates, |
|
1235 gst_object_ref (templ)); |
|
1236 klass->numpadtemplates++; |
|
1237 } |
|
1238 |
|
1239 /** |
|
1240 * gst_element_class_set_details: |
|
1241 * @klass: class to set details for |
|
1242 * @details: details to set |
|
1243 * |
|
1244 * Sets the detailed information for a #GstElementClass. |
|
1245 * <note>This function is for use in _base_init functions only.</note> |
|
1246 * |
|
1247 * The @details are copied. |
|
1248 */ |
|
1249 #ifdef __SYMBIAN32__ |
|
1250 EXPORT_C |
|
1251 #endif |
|
1252 |
|
1253 void |
|
1254 gst_element_class_set_details (GstElementClass * klass, |
|
1255 const GstElementDetails * details) |
|
1256 { |
|
1257 g_return_if_fail (GST_IS_ELEMENT_CLASS (klass)); |
|
1258 g_return_if_fail (GST_IS_ELEMENT_DETAILS (details)); |
|
1259 |
|
1260 __gst_element_details_copy (&klass->details, details); |
|
1261 } |
|
1262 |
|
1263 /** |
|
1264 * gst_element_class_set_details_simple: |
|
1265 * @klass: class to set details for |
|
1266 * @longname: The long English name of the element. E.g. "File Sink" |
|
1267 * @classification: String describing the type of element, as an unordered list |
|
1268 * separated with slashes ('/'). See draft-klass.txt of the design docs |
|
1269 * for more details and common types. E.g: "Sink/File" |
|
1270 * @description: Sentence describing the purpose of the element. |
|
1271 * E.g: "Write stream to a file" |
|
1272 * @author: Name and contact details of the author(s). Use \n to separate |
|
1273 * multiple author details. E.g: "Joe Bloggs <joe.blogs at foo.com>" |
|
1274 * |
|
1275 * Sets the detailed information for a #GstElementClass. Simpler version of |
|
1276 * gst_element_class_set_details() that generates less linker overhead. |
|
1277 * <note>This function is for use in _base_init functions only.</note> |
|
1278 * |
|
1279 * The detail parameter strings are copied into the #GstElementDetails for |
|
1280 * the element class. |
|
1281 * |
|
1282 * Since: 0.10.14 |
|
1283 */ |
|
1284 #ifdef __SYMBIAN32__ |
|
1285 EXPORT_C |
|
1286 #endif |
|
1287 |
|
1288 void |
|
1289 gst_element_class_set_details_simple (GstElementClass * klass, |
|
1290 const gchar * longname, const gchar * classification, |
|
1291 const gchar * description, const gchar * author) |
|
1292 { |
|
1293 #ifdef __SYMBIAN32__ // VASU |
|
1294 const GstElementDetails details; |
|
1295 ((GstElementDetails*)&details)->longname = (gchar *) longname; |
|
1296 ((GstElementDetails*)&details)->klass = (gchar *) classification; |
|
1297 ((GstElementDetails*)&details)->description = (gchar *) description; |
|
1298 ((GstElementDetails*)&details)->author = (gchar *) author; |
|
1299 ((GstElementDetails*)&details)->_gst_reserved[0] = NULL; |
|
1300 #else |
|
1301 const GstElementDetails details = |
|
1302 GST_ELEMENT_DETAILS ((gchar *) longname, (gchar *) classification, |
|
1303 (gchar *) description, (gchar *) author); |
|
1304 #endif // __SYMBIAN32__ |
|
1305 |
|
1306 g_return_if_fail (GST_IS_ELEMENT_CLASS (klass)); |
|
1307 |
|
1308 __gst_element_details_copy (&klass->details, &details); |
|
1309 } |
|
1310 |
|
1311 /** |
|
1312 * gst_element_class_get_pad_template_list: |
|
1313 * @element_class: a #GstElementClass to get pad templates of. |
|
1314 * |
|
1315 * Retrieves a list of the pad templates associated with @element_class. The |
|
1316 * list must not be modified by the calling code. |
|
1317 * <note>If you use this function in the #GInstanceInitFunc of an object class |
|
1318 * that has subclasses, make sure to pass the g_class parameter of the |
|
1319 * #GInstanceInitFunc here.</note> |
|
1320 * |
|
1321 * Returns: the #GList of padtemplates. |
|
1322 */ |
|
1323 #ifdef __SYMBIAN32__ |
|
1324 EXPORT_C |
|
1325 #endif |
|
1326 |
|
1327 GList * |
|
1328 gst_element_class_get_pad_template_list (GstElementClass * element_class) |
|
1329 { |
|
1330 g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL); |
|
1331 |
|
1332 return element_class->padtemplates; |
|
1333 } |
|
1334 |
|
1335 /** |
|
1336 * gst_element_class_get_pad_template: |
|
1337 * @element_class: a #GstElementClass to get the pad template of. |
|
1338 * @name: the name of the #GstPadTemplate to get. |
|
1339 * |
|
1340 * Retrieves a padtemplate from @element_class with the given name. |
|
1341 * <note>If you use this function in the #GInstanceInitFunc of an object class |
|
1342 * that has subclasses, make sure to pass the g_class parameter of the |
|
1343 * #GInstanceInitFunc here.</note> |
|
1344 * |
|
1345 * Returns: the #GstPadTemplate with the given name, or %NULL if none was found. |
|
1346 * No unreferencing is necessary. |
|
1347 */ |
|
1348 #ifdef __SYMBIAN32__ |
|
1349 EXPORT_C |
|
1350 #endif |
|
1351 |
|
1352 GstPadTemplate * |
|
1353 gst_element_class_get_pad_template (GstElementClass * element_class, |
|
1354 const gchar * name) |
|
1355 { |
|
1356 GList *padlist; |
|
1357 |
|
1358 g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL); |
|
1359 g_return_val_if_fail (name != NULL, NULL); |
|
1360 |
|
1361 padlist = gst_element_class_get_pad_template_list (element_class); |
|
1362 |
|
1363 while (padlist) { |
|
1364 GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data; |
|
1365 |
|
1366 if (strcmp (padtempl->name_template, name) == 0) |
|
1367 return padtempl; |
|
1368 |
|
1369 padlist = g_list_next (padlist); |
|
1370 } |
|
1371 |
|
1372 return NULL; |
|
1373 } |
|
1374 |
|
1375 static GstPadTemplate * |
|
1376 gst_element_class_get_request_pad_template (GstElementClass * element_class, |
|
1377 const gchar * name) |
|
1378 { |
|
1379 GstPadTemplate *tmpl; |
|
1380 |
|
1381 tmpl = gst_element_class_get_pad_template (element_class, name); |
|
1382 if (tmpl != NULL && tmpl->presence == GST_PAD_REQUEST) |
|
1383 return tmpl; |
|
1384 |
|
1385 return NULL; |
|
1386 } |
|
1387 |
|
1388 /* get a random pad on element of the given direction. |
|
1389 * The pad is random in a sense that it is the first pad that is (optionaly) linked. |
|
1390 */ |
|
1391 static GstPad * |
|
1392 gst_element_get_random_pad (GstElement * element, gboolean need_linked, |
|
1393 GstPadDirection dir) |
|
1394 { |
|
1395 GstPad *result = NULL; |
|
1396 GList *pads; |
|
1397 |
|
1398 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "getting a random pad"); |
|
1399 |
|
1400 switch (dir) { |
|
1401 case GST_PAD_SRC: |
|
1402 GST_OBJECT_LOCK (element); |
|
1403 pads = element->srcpads; |
|
1404 break; |
|
1405 case GST_PAD_SINK: |
|
1406 GST_OBJECT_LOCK (element); |
|
1407 pads = element->sinkpads; |
|
1408 break; |
|
1409 default: |
|
1410 goto wrong_direction; |
|
1411 } |
|
1412 for (; pads; pads = g_list_next (pads)) { |
|
1413 GstPad *pad = GST_PAD_CAST (pads->data); |
|
1414 |
|
1415 GST_OBJECT_LOCK (pad); |
|
1416 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "checking pad %s:%s", |
|
1417 GST_DEBUG_PAD_NAME (pad)); |
|
1418 |
|
1419 if (need_linked && !GST_PAD_IS_LINKED (pad)) { |
|
1420 /* if we require a linked pad, and it is not linked, continue the |
|
1421 * search */ |
|
1422 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is not linked", |
|
1423 GST_DEBUG_PAD_NAME (pad)); |
|
1424 GST_OBJECT_UNLOCK (pad); |
|
1425 continue; |
|
1426 } else { |
|
1427 /* found a pad, stop search */ |
|
1428 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "found pad %s:%s", |
|
1429 GST_DEBUG_PAD_NAME (pad)); |
|
1430 GST_OBJECT_UNLOCK (pad); |
|
1431 result = pad; |
|
1432 break; |
|
1433 } |
|
1434 } |
|
1435 if (result) |
|
1436 gst_object_ref (result); |
|
1437 |
|
1438 GST_OBJECT_UNLOCK (element); |
|
1439 |
|
1440 return result; |
|
1441 |
|
1442 /* ERROR handling */ |
|
1443 wrong_direction: |
|
1444 { |
|
1445 g_warning ("unknown pad direction %d", dir); |
|
1446 return NULL; |
|
1447 } |
|
1448 } |
|
1449 |
|
1450 static gboolean |
|
1451 gst_element_default_send_event (GstElement * element, GstEvent * event) |
|
1452 { |
|
1453 gboolean result = FALSE; |
|
1454 GstPad *pad; |
|
1455 |
|
1456 pad = GST_EVENT_IS_DOWNSTREAM (event) ? |
|
1457 gst_element_get_random_pad (element, TRUE, GST_PAD_SRC) : |
|
1458 gst_element_get_random_pad (element, TRUE, GST_PAD_SINK); |
|
1459 |
|
1460 if (pad) { |
|
1461 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, |
|
1462 "pushing %s event to random %s pad %s:%s", |
|
1463 GST_EVENT_TYPE_NAME (event), |
|
1464 (GST_PAD_DIRECTION (pad) == GST_PAD_SRC ? "src" : "sink"), |
|
1465 GST_DEBUG_PAD_NAME (pad)); |
|
1466 |
|
1467 result = gst_pad_push_event (pad, event); |
|
1468 gst_object_unref (pad); |
|
1469 } else { |
|
1470 GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "can't send %s event on element %s", |
|
1471 GST_EVENT_TYPE_NAME (event), GST_ELEMENT_NAME (element)); |
|
1472 } |
|
1473 return result; |
|
1474 } |
|
1475 |
|
1476 /** |
|
1477 * gst_element_send_event: |
|
1478 * @element: a #GstElement to send the event to. |
|
1479 * @event: the #GstEvent to send to the element. |
|
1480 * |
|
1481 * Sends an event to an element. If the element doesn't implement an |
|
1482 * event handler, the event will be pushed on a random linked sink pad for |
|
1483 * upstream events or a random linked source pad for downstream events. |
|
1484 * |
|
1485 * This function takes owership of the provided event so you should |
|
1486 * gst_event_ref() it if you want to reuse the event after this call. |
|
1487 * |
|
1488 * Returns: %TRUE if the event was handled. |
|
1489 * |
|
1490 * MT safe. |
|
1491 */ |
|
1492 #ifdef __SYMBIAN32__ |
|
1493 EXPORT_C |
|
1494 #endif |
|
1495 |
|
1496 gboolean |
|
1497 gst_element_send_event (GstElement * element, GstEvent * event) |
|
1498 { |
|
1499 GstElementClass *oclass; |
|
1500 gboolean result = FALSE; |
|
1501 |
|
1502 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
|
1503 g_return_val_if_fail (event != NULL, FALSE); |
|
1504 |
|
1505 oclass = GST_ELEMENT_GET_CLASS (element); |
|
1506 |
|
1507 GST_STATE_LOCK (element); |
|
1508 if (oclass->send_event) { |
|
1509 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "send %s event on element %s", |
|
1510 GST_EVENT_TYPE_NAME (event), GST_ELEMENT_NAME (element)); |
|
1511 result = oclass->send_event (element, event); |
|
1512 } else { |
|
1513 result = gst_element_default_send_event (element, event); |
|
1514 } |
|
1515 GST_STATE_UNLOCK (element); |
|
1516 |
|
1517 return result; |
|
1518 } |
|
1519 |
|
1520 /** |
|
1521 * gst_element_seek: |
|
1522 * @element: a #GstElement to send the event to. |
|
1523 * @rate: The new playback rate |
|
1524 * @format: The format of the seek values |
|
1525 * @flags: The optional seek flags. |
|
1526 * @cur_type: The type and flags for the new current position |
|
1527 * @cur: The value of the new current position |
|
1528 * @stop_type: The type and flags for the new stop position |
|
1529 * @stop: The value of the new stop position |
|
1530 * |
|
1531 * Sends a seek event to an element. See gst_event_new_seek() for the details of |
|
1532 * the parameters. The seek event is sent to the element using |
|
1533 * gst_element_send_event(). |
|
1534 * |
|
1535 * Returns: %TRUE if the event was handled. |
|
1536 * |
|
1537 * MT safe. |
|
1538 */ |
|
1539 #ifdef __SYMBIAN32__ |
|
1540 EXPORT_C |
|
1541 #endif |
|
1542 |
|
1543 gboolean |
|
1544 gst_element_seek (GstElement * element, gdouble rate, GstFormat format, |
|
1545 GstSeekFlags flags, GstSeekType cur_type, gint64 cur, |
|
1546 GstSeekType stop_type, gint64 stop) |
|
1547 { |
|
1548 GstEvent *event; |
|
1549 gboolean result; |
|
1550 |
|
1551 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
|
1552 |
|
1553 event = |
|
1554 gst_event_new_seek (rate, format, flags, cur_type, cur, stop_type, stop); |
|
1555 result = gst_element_send_event (element, event); |
|
1556 |
|
1557 return result; |
|
1558 } |
|
1559 |
|
1560 /** |
|
1561 * gst_element_get_query_types: |
|
1562 * @element: a #GstElement to query |
|
1563 * |
|
1564 * Get an array of query types from the element. |
|
1565 * If the element doesn't implement a query types function, |
|
1566 * the query will be forwarded to the peer of a random linked sink pad. |
|
1567 * |
|
1568 * Returns: An array of #GstQueryType elements that should not |
|
1569 * be freed or modified. |
|
1570 * |
|
1571 * MT safe. |
|
1572 */ |
|
1573 #ifdef __SYMBIAN32__ |
|
1574 EXPORT_C |
|
1575 #endif |
|
1576 |
|
1577 const GstQueryType * |
|
1578 gst_element_get_query_types (GstElement * element) |
|
1579 { |
|
1580 GstElementClass *oclass; |
|
1581 const GstQueryType *result = NULL; |
|
1582 |
|
1583 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
|
1584 |
|
1585 oclass = GST_ELEMENT_GET_CLASS (element); |
|
1586 |
|
1587 if (oclass->get_query_types) { |
|
1588 result = oclass->get_query_types (element); |
|
1589 } else { |
|
1590 GstPad *pad = gst_element_get_random_pad (element, TRUE, GST_PAD_SINK); |
|
1591 |
|
1592 if (pad) { |
|
1593 GstPad *peer = gst_pad_get_peer (pad); |
|
1594 |
|
1595 if (peer) { |
|
1596 result = gst_pad_get_query_types (peer); |
|
1597 |
|
1598 gst_object_unref (peer); |
|
1599 } |
|
1600 gst_object_unref (pad); |
|
1601 } |
|
1602 } |
|
1603 return result; |
|
1604 } |
|
1605 |
|
1606 static gboolean |
|
1607 gst_element_default_query (GstElement * element, GstQuery * query) |
|
1608 { |
|
1609 gboolean result = FALSE; |
|
1610 GstPad *pad; |
|
1611 |
|
1612 pad = gst_element_get_random_pad (element, FALSE, GST_PAD_SRC); |
|
1613 if (pad) { |
|
1614 result = gst_pad_query (pad, query); |
|
1615 |
|
1616 gst_object_unref (pad); |
|
1617 } else { |
|
1618 pad = gst_element_get_random_pad (element, TRUE, GST_PAD_SINK); |
|
1619 if (pad) { |
|
1620 GstPad *peer = gst_pad_get_peer (pad); |
|
1621 |
|
1622 if (peer) { |
|
1623 result = gst_pad_query (peer, query); |
|
1624 |
|
1625 gst_object_unref (peer); |
|
1626 } |
|
1627 gst_object_unref (pad); |
|
1628 } |
|
1629 } |
|
1630 return result; |
|
1631 } |
|
1632 |
|
1633 /** |
|
1634 * gst_element_query: |
|
1635 * @element: a #GstElement to perform the query on. |
|
1636 * @query: the #GstQuery. |
|
1637 * |
|
1638 * Performs a query on the given element. |
|
1639 * |
|
1640 * For elements that don't implement a query handler, this function |
|
1641 * forwards the query to a random srcpad or to the peer of a |
|
1642 * random linked sinkpad of this element. |
|
1643 * |
|
1644 * Returns: TRUE if the query could be performed. |
|
1645 * |
|
1646 * MT safe. |
|
1647 */ |
|
1648 #ifdef __SYMBIAN32__ |
|
1649 EXPORT_C |
|
1650 #endif |
|
1651 |
|
1652 gboolean |
|
1653 gst_element_query (GstElement * element, GstQuery * query) |
|
1654 { |
|
1655 GstElementClass *oclass; |
|
1656 gboolean result = FALSE; |
|
1657 |
|
1658 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
|
1659 g_return_val_if_fail (query != NULL, FALSE); |
|
1660 |
|
1661 oclass = GST_ELEMENT_GET_CLASS (element); |
|
1662 |
|
1663 if (oclass->query) { |
|
1664 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "send query on element %s", |
|
1665 GST_ELEMENT_NAME (element)); |
|
1666 result = oclass->query (element, query); |
|
1667 } else { |
|
1668 result = gst_element_default_query (element, query); |
|
1669 } |
|
1670 return result; |
|
1671 } |
|
1672 |
|
1673 /** |
|
1674 * gst_element_post_message: |
|
1675 * @element: a #GstElement posting the message |
|
1676 * @message: a #GstMessage to post |
|
1677 * |
|
1678 * Post a message on the element's #GstBus. This function takes ownership of the |
|
1679 * message; if you want to access the message after this call, you should add an |
|
1680 * additional reference before calling. |
|
1681 * |
|
1682 * Returns: %TRUE if the message was successfully posted. The function returns |
|
1683 * %FALSE if the element did not have a bus. |
|
1684 * |
|
1685 * MT safe. |
|
1686 */ |
|
1687 #ifdef __SYMBIAN32__ |
|
1688 EXPORT_C |
|
1689 #endif |
|
1690 |
|
1691 gboolean |
|
1692 gst_element_post_message (GstElement * element, GstMessage * message) |
|
1693 { |
|
1694 GstBus *bus; |
|
1695 gboolean result = FALSE; |
|
1696 |
|
1697 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
|
1698 g_return_val_if_fail (message != NULL, FALSE); |
|
1699 |
|
1700 GST_OBJECT_LOCK (element); |
|
1701 bus = element->bus; |
|
1702 |
|
1703 if (G_UNLIKELY (bus == NULL)) |
|
1704 goto no_bus; |
|
1705 |
|
1706 gst_object_ref (bus); |
|
1707 GST_OBJECT_UNLOCK (element); |
|
1708 |
|
1709 /* we release the element lock when posting the message so that any |
|
1710 * (synchronous) message handlers can operate on the element */ |
|
1711 result = gst_bus_post (bus, message); |
|
1712 gst_object_unref (bus); |
|
1713 |
|
1714 return result; |
|
1715 |
|
1716 /* ERRORS */ |
|
1717 no_bus: |
|
1718 { |
|
1719 GST_CAT_DEBUG_OBJECT (GST_CAT_MESSAGE, element, |
|
1720 "not posting message %p: no bus", message); |
|
1721 GST_OBJECT_UNLOCK (element); |
|
1722 gst_message_unref (message); |
|
1723 return FALSE; |
|
1724 } |
|
1725 } |
|
1726 |
|
1727 /** |
|
1728 * _gst_element_error_printf: |
|
1729 * @format: the printf-like format to use, or %NULL |
|
1730 * |
|
1731 * This function is only used internally by the gst_element_error() macro. |
|
1732 * |
|
1733 * Returns: a newly allocated string, or %NULL if the format was %NULL or "" |
|
1734 * |
|
1735 * MT safe. |
|
1736 */ |
|
1737 #ifdef __SYMBIAN32__ |
|
1738 EXPORT_C |
|
1739 #endif |
|
1740 |
|
1741 gchar * |
|
1742 _gst_element_error_printf (const gchar * format, ...) |
|
1743 { |
|
1744 va_list args; |
|
1745 gchar *buffer; |
|
1746 |
|
1747 if (format == NULL) |
|
1748 return NULL; |
|
1749 if (format[0] == 0) |
|
1750 return NULL; |
|
1751 |
|
1752 va_start (args, format); |
|
1753 buffer = g_strdup_vprintf (format, args); |
|
1754 va_end (args); |
|
1755 return buffer; |
|
1756 } |
|
1757 |
|
1758 /** |
|
1759 * gst_element_message_full: |
|
1760 * @element: a #GstElement to send message from |
|
1761 * @type: the #GstMessageType |
|
1762 * @domain: the GStreamer GError domain this message belongs to |
|
1763 * @code: the GError code belonging to the domain |
|
1764 * @text: an allocated text string to be used as a replacement for the |
|
1765 * default message connected to code, or %NULL |
|
1766 * @debug: an allocated debug message to be used as a replacement for the |
|
1767 * default debugging information, or %NULL |
|
1768 * @file: the source code file where the error was generated |
|
1769 * @function: the source code function where the error was generated |
|
1770 * @line: the source code line where the error was generated |
|
1771 * |
|
1772 * Post an error, warning or info message on the bus from inside an element. |
|
1773 * |
|
1774 * @type must be of #GST_MESSAGE_ERROR, #GST_MESSAGE_WARNING or |
|
1775 * #GST_MESSAGE_INFO. |
|
1776 * |
|
1777 * MT safe. |
|
1778 */ |
|
1779 #ifdef __SYMBIAN32__ |
|
1780 EXPORT_C |
|
1781 #endif |
|
1782 |
|
1783 void gst_element_message_full |
|
1784 (GstElement * element, GstMessageType type, |
|
1785 GQuark domain, gint code, gchar * text, |
|
1786 gchar * debug, const gchar * file, const gchar * function, gint line) |
|
1787 { |
|
1788 GError *gerror = NULL; |
|
1789 gchar *name; |
|
1790 gchar *sent_text; |
|
1791 gchar *sent_debug; |
|
1792 gboolean has_debug = TRUE; |
|
1793 GstMessage *message = NULL; |
|
1794 |
|
1795 /* checks */ |
|
1796 GST_DEBUG_OBJECT (element, "start"); |
|
1797 g_return_if_fail (GST_IS_ELEMENT (element)); |
|
1798 g_return_if_fail ((type == GST_MESSAGE_ERROR) || |
|
1799 (type == GST_MESSAGE_WARNING) || (type == GST_MESSAGE_INFO)); |
|
1800 |
|
1801 /* check if we send the given text or the default error text */ |
|
1802 if ((text == NULL) || (text[0] == 0)) { |
|
1803 /* text could have come from g_strdup_printf (""); */ |
|
1804 g_free (text); |
|
1805 sent_text = gst_error_get_message (domain, code); |
|
1806 } else |
|
1807 sent_text = text; |
|
1808 |
|
1809 /* construct a sent_debug with extra information from source */ |
|
1810 if ((debug == NULL) || (debug[0] == 0)) { |
|
1811 /* debug could have come from g_strdup_printf (""); */ |
|
1812 has_debug = FALSE; |
|
1813 } |
|
1814 |
|
1815 name = gst_object_get_path_string (GST_OBJECT_CAST (element)); |
|
1816 if (has_debug) |
|
1817 sent_debug = g_strdup_printf ("%s(%d): %s (): %s:\n%s", |
|
1818 file, line, function, name, debug); |
|
1819 else |
|
1820 sent_debug = g_strdup_printf ("%s(%d): %s (): %s", |
|
1821 file, line, function, name); |
|
1822 g_free (name); |
|
1823 g_free (debug); |
|
1824 |
|
1825 /* create gerror and post message */ |
|
1826 GST_CAT_INFO_OBJECT (GST_CAT_ERROR_SYSTEM, element, "posting message: %s", |
|
1827 sent_text); |
|
1828 gerror = g_error_new_literal (domain, code, sent_text); |
|
1829 |
|
1830 switch (type) { |
|
1831 case GST_MESSAGE_ERROR: |
|
1832 message = |
|
1833 gst_message_new_error (GST_OBJECT_CAST (element), gerror, sent_debug); |
|
1834 break; |
|
1835 case GST_MESSAGE_WARNING: |
|
1836 message = gst_message_new_warning (GST_OBJECT_CAST (element), gerror, |
|
1837 sent_debug); |
|
1838 break; |
|
1839 case GST_MESSAGE_INFO: |
|
1840 message = gst_message_new_info (GST_OBJECT_CAST (element), gerror, |
|
1841 sent_debug); |
|
1842 break; |
|
1843 default: |
|
1844 g_assert_not_reached (); |
|
1845 break; |
|
1846 } |
|
1847 gst_element_post_message (element, message); |
|
1848 |
|
1849 GST_CAT_INFO_OBJECT (GST_CAT_ERROR_SYSTEM, element, "posted %s message: %s", |
|
1850 (type == GST_MESSAGE_ERROR ? "error" : "warning"), sent_text); |
|
1851 |
|
1852 /* cleanup */ |
|
1853 g_error_free (gerror); |
|
1854 g_free (sent_debug); |
|
1855 g_free (sent_text); |
|
1856 } |
|
1857 |
|
1858 /** |
|
1859 * gst_element_is_locked_state: |
|
1860 * @element: a #GstElement. |
|
1861 * |
|
1862 * Checks if the state of an element is locked. |
|
1863 * If the state of an element is locked, state changes of the parent don't |
|
1864 * affect the element. |
|
1865 * This way you can leave currently unused elements inside bins. Just lock their |
|
1866 * state before changing the state from #GST_STATE_NULL. |
|
1867 * |
|
1868 * MT safe. |
|
1869 * |
|
1870 * Returns: TRUE, if the element's state is locked. |
|
1871 */ |
|
1872 #ifdef __SYMBIAN32__ |
|
1873 EXPORT_C |
|
1874 #endif |
|
1875 |
|
1876 gboolean |
|
1877 gst_element_is_locked_state (GstElement * element) |
|
1878 { |
|
1879 gboolean result; |
|
1880 |
|
1881 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
|
1882 |
|
1883 GST_OBJECT_LOCK (element); |
|
1884 result = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE); |
|
1885 GST_OBJECT_UNLOCK (element); |
|
1886 |
|
1887 return result; |
|
1888 } |
|
1889 |
|
1890 /** |
|
1891 * gst_element_set_locked_state: |
|
1892 * @element: a #GstElement |
|
1893 * @locked_state: TRUE to lock the element's state |
|
1894 * |
|
1895 * Locks the state of an element, so state changes of the parent don't affect |
|
1896 * this element anymore. |
|
1897 * |
|
1898 * MT safe. |
|
1899 * |
|
1900 * Returns: TRUE if the state was changed, FALSE if bad parameters were given |
|
1901 * or the elements state-locking needed no change. |
|
1902 */ |
|
1903 #ifdef __SYMBIAN32__ |
|
1904 EXPORT_C |
|
1905 #endif |
|
1906 |
|
1907 gboolean |
|
1908 gst_element_set_locked_state (GstElement * element, gboolean locked_state) |
|
1909 { |
|
1910 gboolean old; |
|
1911 |
|
1912 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
|
1913 |
|
1914 GST_OBJECT_LOCK (element); |
|
1915 old = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE); |
|
1916 |
|
1917 if (G_UNLIKELY (old == locked_state)) |
|
1918 goto was_ok; |
|
1919 |
|
1920 if (locked_state) { |
|
1921 GST_CAT_DEBUG (GST_CAT_STATES, "locking state of element %s", |
|
1922 GST_ELEMENT_NAME (element)); |
|
1923 GST_OBJECT_FLAG_SET (element, GST_ELEMENT_LOCKED_STATE); |
|
1924 } else { |
|
1925 GST_CAT_DEBUG (GST_CAT_STATES, "unlocking state of element %s", |
|
1926 GST_ELEMENT_NAME (element)); |
|
1927 GST_OBJECT_FLAG_UNSET (element, GST_ELEMENT_LOCKED_STATE); |
|
1928 } |
|
1929 GST_OBJECT_UNLOCK (element); |
|
1930 |
|
1931 return TRUE; |
|
1932 |
|
1933 was_ok: |
|
1934 { |
|
1935 GST_CAT_DEBUG (GST_CAT_STATES, "elements %s was in locked state %d", |
|
1936 GST_ELEMENT_NAME (element), old); |
|
1937 GST_OBJECT_UNLOCK (element); |
|
1938 |
|
1939 return FALSE; |
|
1940 } |
|
1941 } |
|
1942 |
|
1943 /** |
|
1944 * gst_element_sync_state_with_parent: |
|
1945 * @element: a #GstElement. |
|
1946 * |
|
1947 * Tries to change the state of the element to the same as its parent. |
|
1948 * If this function returns FALSE, the state of element is undefined. |
|
1949 * |
|
1950 * Returns: TRUE, if the element's state could be synced to the parent's state. |
|
1951 * |
|
1952 * MT safe. |
|
1953 */ |
|
1954 #ifdef __SYMBIAN32__ |
|
1955 EXPORT_C |
|
1956 #endif |
|
1957 |
|
1958 gboolean |
|
1959 gst_element_sync_state_with_parent (GstElement * element) |
|
1960 { |
|
1961 GstElement *parent; |
|
1962 GstState target; |
|
1963 GstStateChangeReturn ret; |
|
1964 |
|
1965 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
|
1966 |
|
1967 if ((parent = GST_ELEMENT_CAST (gst_element_get_parent (element)))) { |
|
1968 GstState parent_current, parent_pending; |
|
1969 |
|
1970 GST_OBJECT_LOCK (parent); |
|
1971 parent_current = GST_STATE (parent); |
|
1972 parent_pending = GST_STATE_PENDING (parent); |
|
1973 GST_OBJECT_UNLOCK (parent); |
|
1974 |
|
1975 /* set to pending if there is one, else we set it to the current state of |
|
1976 * the parent */ |
|
1977 if (parent_pending != GST_STATE_VOID_PENDING) |
|
1978 target = parent_pending; |
|
1979 else |
|
1980 target = parent_current; |
|
1981 |
|
1982 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
|
1983 "syncing state (%s) to parent %s %s (%s, %s)", |
|
1984 gst_element_state_get_name (GST_STATE (element)), |
|
1985 GST_ELEMENT_NAME (parent), gst_element_state_get_name (target), |
|
1986 gst_element_state_get_name (parent_current), |
|
1987 gst_element_state_get_name (parent_pending)); |
|
1988 |
|
1989 ret = gst_element_set_state (element, target); |
|
1990 if (ret == GST_STATE_CHANGE_FAILURE) |
|
1991 goto failed; |
|
1992 |
|
1993 gst_object_unref (parent); |
|
1994 |
|
1995 return TRUE; |
|
1996 } else { |
|
1997 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "element has no parent"); |
|
1998 } |
|
1999 return FALSE; |
|
2000 |
|
2001 /* ERROR */ |
|
2002 failed: |
|
2003 { |
|
2004 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
|
2005 "syncing state failed (%s)", |
|
2006 gst_element_state_change_return_get_name (ret)); |
|
2007 return FALSE; |
|
2008 } |
|
2009 } |
|
2010 |
|
2011 /* MT safe */ |
|
2012 static GstStateChangeReturn |
|
2013 gst_element_get_state_func (GstElement * element, |
|
2014 GstState * state, GstState * pending, GstClockTime timeout) |
|
2015 { |
|
2016 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE; |
|
2017 GstState old_pending; |
|
2018 |
|
2019 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "getting state, timeout %" |
|
2020 GST_TIME_FORMAT, GST_TIME_ARGS (timeout)); |
|
2021 |
|
2022 GST_OBJECT_LOCK (element); |
|
2023 ret = GST_STATE_RETURN (element); |
|
2024 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "RETURN is %s", |
|
2025 gst_element_state_change_return_get_name (ret)); |
|
2026 |
|
2027 /* we got an error, report immediatly */ |
|
2028 if (ret == GST_STATE_CHANGE_FAILURE) |
|
2029 goto done; |
|
2030 |
|
2031 /* we got no_preroll, report immediatly */ |
|
2032 if (ret == GST_STATE_CHANGE_NO_PREROLL) |
|
2033 goto done; |
|
2034 |
|
2035 /* no need to wait async if we are not async */ |
|
2036 if (ret != GST_STATE_CHANGE_ASYNC) |
|
2037 goto done; |
|
2038 |
|
2039 old_pending = GST_STATE_PENDING (element); |
|
2040 if (old_pending != GST_STATE_VOID_PENDING) { |
|
2041 GTimeVal *timeval, abstimeout; |
|
2042 guint32 cookie; |
|
2043 |
|
2044 if (timeout != GST_CLOCK_TIME_NONE) { |
|
2045 glong add = timeout / 1000; |
|
2046 |
|
2047 if (add == 0) |
|
2048 goto done; |
|
2049 |
|
2050 /* make timeout absolute */ |
|
2051 g_get_current_time (&abstimeout); |
|
2052 g_time_val_add (&abstimeout, add); |
|
2053 timeval = &abstimeout; |
|
2054 } else { |
|
2055 timeval = NULL; |
|
2056 } |
|
2057 /* get cookie to dected state change during waiting */ |
|
2058 cookie = element->state_cookie; |
|
2059 |
|
2060 GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
|
2061 "waiting for element to commit state"); |
|
2062 |
|
2063 /* we have a pending state change, wait for it to complete */ |
|
2064 if (!GST_STATE_TIMED_WAIT (element, timeval)) { |
|
2065 GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "timed out"); |
|
2066 /* timeout triggered */ |
|
2067 ret = GST_STATE_CHANGE_ASYNC; |
|
2068 } else { |
|
2069 if (cookie != element->state_cookie) |
|
2070 goto interrupted; |
|
2071 |
|
2072 /* could be success or failure */ |
|
2073 if (old_pending == GST_STATE (element)) { |
|
2074 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "got success"); |
|
2075 ret = GST_STATE_CHANGE_SUCCESS; |
|
2076 } else { |
|
2077 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "got failure"); |
|
2078 ret = GST_STATE_CHANGE_FAILURE; |
|
2079 } |
|
2080 } |
|
2081 /* if nothing is pending anymore we can return SUCCESS */ |
|
2082 if (GST_STATE_PENDING (element) == GST_STATE_VOID_PENDING) { |
|
2083 GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, "nothing pending"); |
|
2084 ret = GST_STATE_CHANGE_SUCCESS; |
|
2085 } |
|
2086 } |
|
2087 |
|
2088 done: |
|
2089 if (state) |
|
2090 *state = GST_STATE (element); |
|
2091 if (pending) |
|
2092 *pending = GST_STATE_PENDING (element); |
|
2093 |
|
2094 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
|
2095 "state current: %s, pending: %s, result: %s", |
|
2096 gst_element_state_get_name (GST_STATE (element)), |
|
2097 gst_element_state_get_name (GST_STATE_PENDING (element)), |
|
2098 gst_element_state_change_return_get_name (ret)); |
|
2099 GST_OBJECT_UNLOCK (element); |
|
2100 |
|
2101 return ret; |
|
2102 |
|
2103 interrupted: |
|
2104 { |
|
2105 if (state) |
|
2106 *state = GST_STATE_VOID_PENDING; |
|
2107 if (pending) |
|
2108 *pending = GST_STATE_VOID_PENDING; |
|
2109 |
|
2110 GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "interruped"); |
|
2111 |
|
2112 GST_OBJECT_UNLOCK (element); |
|
2113 |
|
2114 return GST_STATE_CHANGE_FAILURE; |
|
2115 } |
|
2116 } |
|
2117 |
|
2118 /** |
|
2119 * gst_element_get_state: |
|
2120 * @element: a #GstElement to get the state of. |
|
2121 * @state: a pointer to #GstState to hold the state. Can be %NULL. |
|
2122 * @pending: a pointer to #GstState to hold the pending state. |
|
2123 * Can be %NULL. |
|
2124 * @timeout: a #GstClockTime to specify the timeout for an async |
|
2125 * state change or %GST_CLOCK_TIME_NONE for infinite timeout. |
|
2126 * |
|
2127 * Gets the state of the element. |
|
2128 * |
|
2129 * For elements that performed an ASYNC state change, as reported by |
|
2130 * gst_element_set_state(), this function will block up to the |
|
2131 * specified timeout value for the state change to complete. |
|
2132 * If the element completes the state change or goes into |
|
2133 * an error, this function returns immediately with a return value of |
|
2134 * %GST_STATE_CHANGE_SUCCESS or %GST_STATE_CHANGE_FAILURE respectively. |
|
2135 * |
|
2136 * For elements that did not return %GST_STATE_CHANGE_ASYNC, this function |
|
2137 * returns the current and pending state immediately. |
|
2138 * |
|
2139 * This function returns %GST_STATE_CHANGE_NO_PREROLL if the element |
|
2140 * successfully changed its state but is not able to provide data yet. |
|
2141 * This mostly happens for live sources that only produce data in the PLAYING |
|
2142 * state. While the state change return is equivalent to |
|
2143 * %GST_STATE_CHANGE_SUCCESS, it is returned to the application to signal that |
|
2144 * some sink elements might not be able to complete their state change because |
|
2145 * an element is not producing data to complete the preroll. When setting the |
|
2146 * element to playing, the preroll will complete and playback will start. |
|
2147 * |
|
2148 * Returns: %GST_STATE_CHANGE_SUCCESS if the element has no more pending state |
|
2149 * and the last state change succeeded, %GST_STATE_CHANGE_ASYNC if the |
|
2150 * element is still performing a state change or |
|
2151 * %GST_STATE_CHANGE_FAILURE if the last state change failed. |
|
2152 * |
|
2153 * MT safe. |
|
2154 */ |
|
2155 #ifdef __SYMBIAN32__ |
|
2156 EXPORT_C |
|
2157 #endif |
|
2158 |
|
2159 GstStateChangeReturn |
|
2160 gst_element_get_state (GstElement * element, |
|
2161 GstState * state, GstState * pending, GstClockTime timeout) |
|
2162 { |
|
2163 GstElementClass *oclass; |
|
2164 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; |
|
2165 |
|
2166 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE); |
|
2167 |
|
2168 oclass = GST_ELEMENT_GET_CLASS (element); |
|
2169 |
|
2170 if (oclass->get_state) |
|
2171 result = (oclass->get_state) (element, state, pending, timeout); |
|
2172 |
|
2173 return result; |
|
2174 } |
|
2175 |
|
2176 /** |
|
2177 * gst_element_abort_state: |
|
2178 * @element: a #GstElement to abort the state of. |
|
2179 * |
|
2180 * Abort the state change of the element. This function is used |
|
2181 * by elements that do asynchronous state changes and find out |
|
2182 * something is wrong. |
|
2183 * |
|
2184 * This function should be called with the STATE_LOCK held. |
|
2185 * |
|
2186 * MT safe. |
|
2187 */ |
|
2188 #ifdef __SYMBIAN32__ |
|
2189 EXPORT_C |
|
2190 #endif |
|
2191 |
|
2192 void |
|
2193 gst_element_abort_state (GstElement * element) |
|
2194 { |
|
2195 GstState pending; |
|
2196 |
|
2197 #ifndef GST_DISABLE_GST_DEBUG |
|
2198 GstState old_state; |
|
2199 #endif |
|
2200 |
|
2201 g_return_if_fail (GST_IS_ELEMENT (element)); |
|
2202 |
|
2203 GST_OBJECT_LOCK (element); |
|
2204 pending = GST_STATE_PENDING (element); |
|
2205 |
|
2206 if (pending == GST_STATE_VOID_PENDING || |
|
2207 GST_STATE_RETURN (element) == GST_STATE_CHANGE_FAILURE) |
|
2208 goto nothing_aborted; |
|
2209 |
|
2210 #ifndef GST_DISABLE_GST_DEBUG |
|
2211 old_state = GST_STATE (element); |
|
2212 |
|
2213 GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
|
2214 "aborting state from %s to %s", gst_element_state_get_name (old_state), |
|
2215 gst_element_state_get_name (pending)); |
|
2216 #endif |
|
2217 |
|
2218 /* flag error */ |
|
2219 GST_STATE_RETURN (element) = GST_STATE_CHANGE_FAILURE; |
|
2220 |
|
2221 GST_STATE_BROADCAST (element); |
|
2222 GST_OBJECT_UNLOCK (element); |
|
2223 |
|
2224 return; |
|
2225 |
|
2226 nothing_aborted: |
|
2227 { |
|
2228 GST_OBJECT_UNLOCK (element); |
|
2229 return; |
|
2230 } |
|
2231 } |
|
2232 |
|
2233 /** |
|
2234 * gst_element_continue_state: |
|
2235 * @element: a #GstElement to continue the state change of. |
|
2236 * @ret: The previous state return value |
|
2237 * |
|
2238 * Commit the state change of the element and proceed to the next |
|
2239 * pending state if any. This function is used |
|
2240 * by elements that do asynchronous state changes. |
|
2241 * The core will normally call this method automatically when an |
|
2242 * element returned %GST_STATE_CHANGE_SUCCESS from the state change function. |
|
2243 * |
|
2244 * If after calling this method the element still has not reached |
|
2245 * the pending state, the next state change is performed. |
|
2246 * |
|
2247 * This method is used internally and should normally not be called by plugins |
|
2248 * or applications. |
|
2249 * |
|
2250 * Returns: The result of the commit state change. |
|
2251 * |
|
2252 * MT safe. |
|
2253 */ |
|
2254 #ifdef __SYMBIAN32__ |
|
2255 EXPORT_C |
|
2256 #endif |
|
2257 |
|
2258 GstStateChangeReturn |
|
2259 gst_element_continue_state (GstElement * element, GstStateChangeReturn ret) |
|
2260 { |
|
2261 GstStateChangeReturn old_ret; |
|
2262 GstState old_state, old_next; |
|
2263 GstState current, next, pending; |
|
2264 GstMessage *message; |
|
2265 GstStateChange transition; |
|
2266 |
|
2267 GST_OBJECT_LOCK (element); |
|
2268 old_ret = GST_STATE_RETURN (element); |
|
2269 GST_STATE_RETURN (element) = ret; |
|
2270 pending = GST_STATE_PENDING (element); |
|
2271 |
|
2272 /* check if there is something to commit */ |
|
2273 if (pending == GST_STATE_VOID_PENDING) |
|
2274 goto nothing_pending; |
|
2275 |
|
2276 old_state = GST_STATE (element); |
|
2277 /* this is the state we should go to next */ |
|
2278 old_next = GST_STATE_NEXT (element); |
|
2279 /* update current state */ |
|
2280 current = GST_STATE (element) = old_next; |
|
2281 |
|
2282 /* see if we reached the final state */ |
|
2283 if (pending == current) |
|
2284 goto complete; |
|
2285 |
|
2286 next = GST_STATE_GET_NEXT (current, pending); |
|
2287 transition = (GstStateChange) GST_STATE_TRANSITION (current, next); |
|
2288 |
|
2289 GST_STATE_NEXT (element) = next; |
|
2290 /* mark busy */ |
|
2291 GST_STATE_RETURN (element) = GST_STATE_CHANGE_ASYNC; |
|
2292 GST_OBJECT_UNLOCK (element); |
|
2293 |
|
2294 GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
|
2295 "committing state from %s to %s, pending %s", |
|
2296 gst_element_state_get_name (old_state), |
|
2297 gst_element_state_get_name (old_next), |
|
2298 gst_element_state_get_name (pending)); |
|
2299 |
|
2300 message = gst_message_new_state_changed (GST_OBJECT_CAST (element), |
|
2301 old_state, old_next, pending); |
|
2302 gst_element_post_message (element, message); |
|
2303 |
|
2304 GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
|
2305 "continue state change %s to %s, final %s", |
|
2306 gst_element_state_get_name (current), |
|
2307 gst_element_state_get_name (next), gst_element_state_get_name (pending)); |
|
2308 |
|
2309 ret = gst_element_change_state (element, transition); |
|
2310 |
|
2311 return ret; |
|
2312 |
|
2313 nothing_pending: |
|
2314 { |
|
2315 GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "nothing pending"); |
|
2316 GST_OBJECT_UNLOCK (element); |
|
2317 return ret; |
|
2318 } |
|
2319 complete: |
|
2320 { |
|
2321 GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING; |
|
2322 GST_STATE_NEXT (element) = GST_STATE_VOID_PENDING; |
|
2323 |
|
2324 GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
|
2325 "completed state change to %s", gst_element_state_get_name (pending)); |
|
2326 GST_OBJECT_UNLOCK (element); |
|
2327 |
|
2328 /* don't post silly messages with the same state. This can happen |
|
2329 * when an element state is changed to what it already was. For bins |
|
2330 * this can be the result of a lost state, which we check with the |
|
2331 * previous return value. |
|
2332 * We do signal the cond though as a _get_state() might be blocking |
|
2333 * on it. */ |
|
2334 if (old_state != old_next || old_ret == GST_STATE_CHANGE_ASYNC) { |
|
2335 GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
|
2336 "posting state-changed %s to %s", |
|
2337 gst_element_state_get_name (old_state), |
|
2338 gst_element_state_get_name (old_next)); |
|
2339 message = |
|
2340 gst_message_new_state_changed (GST_OBJECT_CAST (element), old_state, |
|
2341 old_next, GST_STATE_VOID_PENDING); |
|
2342 gst_element_post_message (element, message); |
|
2343 } |
|
2344 |
|
2345 GST_STATE_BROADCAST (element); |
|
2346 |
|
2347 return ret; |
|
2348 } |
|
2349 } |
|
2350 |
|
2351 /** |
|
2352 * gst_element_lost_state: |
|
2353 * @element: a #GstElement the state is lost of |
|
2354 * |
|
2355 * Brings the element to the lost state. The current state of the |
|
2356 * element is copied to the pending state so that any call to |
|
2357 * gst_element_get_state() will return %GST_STATE_CHANGE_ASYNC. |
|
2358 * |
|
2359 * An ASYNC_START message is posted with an indication to distribute a new |
|
2360 * base_time to the element. |
|
2361 * If the element was PLAYING, it will go to PAUSED. The element |
|
2362 * will be restored to its PLAYING state by the parent pipeline when it |
|
2363 * prerolls again. |
|
2364 * |
|
2365 * This is mostly used for elements that lost their preroll buffer |
|
2366 * in the %GST_STATE_PAUSED or %GST_STATE_PLAYING state after a flush, |
|
2367 * they will go to their pending state again when a new preroll buffer is |
|
2368 * queued. This function can only be called when the element is currently |
|
2369 * not in error or an async state change. |
|
2370 * |
|
2371 * This function is used internally and should normally not be called from |
|
2372 * plugins or applications. |
|
2373 * |
|
2374 * MT safe. |
|
2375 */ |
|
2376 #ifdef __SYMBIAN32__ |
|
2377 EXPORT_C |
|
2378 #endif |
|
2379 |
|
2380 void |
|
2381 gst_element_lost_state (GstElement * element) |
|
2382 { |
|
2383 GstState old_state, new_state; |
|
2384 GstMessage *message; |
|
2385 |
|
2386 g_return_if_fail (GST_IS_ELEMENT (element)); |
|
2387 |
|
2388 GST_OBJECT_LOCK (element); |
|
2389 if (GST_STATE_PENDING (element) != GST_STATE_VOID_PENDING || |
|
2390 GST_STATE_RETURN (element) == GST_STATE_CHANGE_FAILURE) |
|
2391 goto nothing_lost; |
|
2392 |
|
2393 old_state = GST_STATE (element); |
|
2394 |
|
2395 /* when we were PLAYING, the new state is PAUSED. We will also not |
|
2396 * automatically go to PLAYING but let the parent bin(s) set us to PLAYING |
|
2397 * when we preroll. */ |
|
2398 if (old_state > GST_STATE_PAUSED) |
|
2399 new_state = GST_STATE_PAUSED; |
|
2400 else |
|
2401 new_state = old_state; |
|
2402 |
|
2403 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
|
2404 "lost state of %s to %s", gst_element_state_get_name (old_state), |
|
2405 gst_element_state_get_name (new_state)); |
|
2406 |
|
2407 GST_STATE (element) = new_state; |
|
2408 GST_STATE_NEXT (element) = new_state; |
|
2409 GST_STATE_PENDING (element) = new_state; |
|
2410 GST_STATE_RETURN (element) = GST_STATE_CHANGE_ASYNC; |
|
2411 GST_OBJECT_UNLOCK (element); |
|
2412 |
|
2413 message = gst_message_new_state_changed (GST_OBJECT_CAST (element), |
|
2414 new_state, new_state, new_state); |
|
2415 gst_element_post_message (element, message); |
|
2416 |
|
2417 message = gst_message_new_async_start (GST_OBJECT_CAST (element), TRUE); |
|
2418 gst_element_post_message (element, message); |
|
2419 |
|
2420 return; |
|
2421 |
|
2422 nothing_lost: |
|
2423 { |
|
2424 GST_OBJECT_UNLOCK (element); |
|
2425 return; |
|
2426 } |
|
2427 } |
|
2428 |
|
2429 /** |
|
2430 * gst_element_set_state: |
|
2431 * @element: a #GstElement to change state of. |
|
2432 * @state: the element's new #GstState. |
|
2433 * |
|
2434 * Sets the state of the element. This function will try to set the |
|
2435 * requested state by going through all the intermediary states and calling |
|
2436 * the class's state change function for each. |
|
2437 * |
|
2438 * This function can return #GST_STATE_CHANGE_ASYNC, in which case the |
|
2439 * element will perform the remainder of the state change asynchronously in |
|
2440 * another thread. |
|
2441 * An application can use gst_element_get_state() to wait for the completion |
|
2442 * of the state change or it can wait for a state change message on the bus. |
|
2443 * |
|
2444 * Returns: Result of the state change using #GstStateChangeReturn. |
|
2445 * |
|
2446 * MT safe. |
|
2447 */ |
|
2448 #ifdef __SYMBIAN32__ |
|
2449 EXPORT_C |
|
2450 #endif |
|
2451 |
|
2452 GstStateChangeReturn |
|
2453 gst_element_set_state (GstElement * element, GstState state) |
|
2454 { |
|
2455 GstElementClass *oclass; |
|
2456 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; |
|
2457 |
|
2458 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE); |
|
2459 |
|
2460 oclass = GST_ELEMENT_GET_CLASS (element); |
|
2461 |
|
2462 if (oclass->set_state) |
|
2463 result = (oclass->set_state) (element, state); |
|
2464 |
|
2465 return result; |
|
2466 } |
|
2467 |
|
2468 /* |
|
2469 * default set state function, calculates the next state based |
|
2470 * on current state and calls the change_state function |
|
2471 */ |
|
2472 static GstStateChangeReturn |
|
2473 gst_element_set_state_func (GstElement * element, GstState state) |
|
2474 { |
|
2475 GstState current, next, old_pending; |
|
2476 GstStateChangeReturn ret; |
|
2477 GstStateChange transition; |
|
2478 GstStateChangeReturn old_ret; |
|
2479 |
|
2480 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE); |
|
2481 |
|
2482 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "set_state to %s", |
|
2483 gst_element_state_get_name (state)); |
|
2484 |
|
2485 /* state lock is taken to protect the set_state() and get_state() |
|
2486 * procedures, it does not lock any variables. */ |
|
2487 GST_STATE_LOCK (element); |
|
2488 |
|
2489 /* now calculate how to get to the new state */ |
|
2490 GST_OBJECT_LOCK (element); |
|
2491 old_ret = GST_STATE_RETURN (element); |
|
2492 /* previous state change returned an error, remove all pending |
|
2493 * and next states */ |
|
2494 if (old_ret == GST_STATE_CHANGE_FAILURE) { |
|
2495 GST_STATE_NEXT (element) = GST_STATE_VOID_PENDING; |
|
2496 GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING; |
|
2497 GST_STATE_RETURN (element) = GST_STATE_CHANGE_SUCCESS; |
|
2498 } |
|
2499 |
|
2500 current = GST_STATE (element); |
|
2501 next = GST_STATE_NEXT (element); |
|
2502 old_pending = GST_STATE_PENDING (element); |
|
2503 |
|
2504 /* this is the (new) state we should go to. TARGET is the last state we set on |
|
2505 * the element. */ |
|
2506 if (state != GST_STATE_TARGET (element)) { |
|
2507 GST_STATE_TARGET (element) = state; |
|
2508 /* increment state cookie so that we can track each state change. We only do |
|
2509 * this if this is actually a new state change. */ |
|
2510 element->state_cookie++; |
|
2511 } |
|
2512 GST_STATE_PENDING (element) = state; |
|
2513 |
|
2514 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
|
2515 "current %s, old_pending %s, next %s, old return %s", |
|
2516 gst_element_state_get_name (current), |
|
2517 gst_element_state_get_name (old_pending), |
|
2518 gst_element_state_get_name (next), |
|
2519 gst_element_state_change_return_get_name (old_ret)); |
|
2520 |
|
2521 /* if the element was busy doing a state change, we just update the |
|
2522 * target state, it'll get to it async then. */ |
|
2523 if (old_pending != GST_STATE_VOID_PENDING) { |
|
2524 /* upwards state change will happen ASYNC */ |
|
2525 if (old_pending <= state) |
|
2526 goto was_busy; |
|
2527 /* element is going to this state already */ |
|
2528 else if (next == state) |
|
2529 goto was_busy; |
|
2530 /* element was performing an ASYNC upward state change and |
|
2531 * we request to go downward again. Start from the next pending |
|
2532 * state then. */ |
|
2533 else if (next > state |
|
2534 && GST_STATE_RETURN (element) == GST_STATE_CHANGE_ASYNC) { |
|
2535 current = next; |
|
2536 } |
|
2537 } |
|
2538 next = GST_STATE_GET_NEXT (current, state); |
|
2539 /* now we store the next state */ |
|
2540 GST_STATE_NEXT (element) = next; |
|
2541 /* mark busy, we need to check that there is actually a state change |
|
2542 * to be done else we could accidentally override SUCCESS/NO_PREROLL and |
|
2543 * the default element change_state function has no way to know what the |
|
2544 * old value was... could consider this a FIXME...*/ |
|
2545 if (current != next) |
|
2546 GST_STATE_RETURN (element) = GST_STATE_CHANGE_ASYNC; |
|
2547 |
|
2548 transition = (GstStateChange) GST_STATE_TRANSITION (current, next); |
|
2549 |
|
2550 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
|
2551 "%s: setting state from %s to %s", |
|
2552 (next != state ? "intermediate" : "final"), |
|
2553 gst_element_state_get_name (current), gst_element_state_get_name (next)); |
|
2554 |
|
2555 /* now signal any waiters, they will error since the cookie was incremented */ |
|
2556 GST_STATE_BROADCAST (element); |
|
2557 |
|
2558 GST_OBJECT_UNLOCK (element); |
|
2559 |
|
2560 ret = gst_element_change_state (element, transition); |
|
2561 |
|
2562 GST_STATE_UNLOCK (element); |
|
2563 |
|
2564 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "returned %s", |
|
2565 gst_element_state_change_return_get_name (ret)); |
|
2566 |
|
2567 return ret; |
|
2568 |
|
2569 was_busy: |
|
2570 { |
|
2571 GST_STATE_RETURN (element) = GST_STATE_CHANGE_ASYNC; |
|
2572 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
|
2573 "element was busy with async state change"); |
|
2574 GST_OBJECT_UNLOCK (element); |
|
2575 |
|
2576 GST_STATE_UNLOCK (element); |
|
2577 |
|
2578 return GST_STATE_CHANGE_ASYNC; |
|
2579 } |
|
2580 } |
|
2581 |
|
2582 /** |
|
2583 * gst_element_change_state: |
|
2584 * @element: a #GstElement |
|
2585 * @transition: the requested transition |
|
2586 * |
|
2587 * Perform @transition on @element. |
|
2588 * |
|
2589 * This function must be called with STATE_LOCK held and is mainly used |
|
2590 * internally. |
|
2591 * |
|
2592 * Returns: the #GstStateChangeReturn of the state transition. |
|
2593 */ |
|
2594 #ifdef __SYMBIAN32__ |
|
2595 EXPORT_C |
|
2596 #endif |
|
2597 |
|
2598 GstStateChangeReturn |
|
2599 gst_element_change_state (GstElement * element, GstStateChange transition) |
|
2600 { |
|
2601 GstElementClass *oclass; |
|
2602 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; |
|
2603 GstState current; |
|
2604 GstState next; |
|
2605 |
|
2606 oclass = GST_ELEMENT_GET_CLASS (element); |
|
2607 |
|
2608 /* start with the current state. */ |
|
2609 current = (GstState) GST_STATE_TRANSITION_CURRENT (transition); |
|
2610 next = GST_STATE_TRANSITION_NEXT (transition); |
|
2611 |
|
2612 /* call the state change function so it can set the state */ |
|
2613 if (oclass->change_state) |
|
2614 ret = (oclass->change_state) (element, transition); |
|
2615 else |
|
2616 ret = GST_STATE_CHANGE_FAILURE; |
|
2617 |
|
2618 switch (ret) { |
|
2619 case GST_STATE_CHANGE_FAILURE: |
|
2620 GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
|
2621 "have FAILURE change_state return"); |
|
2622 /* state change failure */ |
|
2623 gst_element_abort_state (element); |
|
2624 break; |
|
2625 case GST_STATE_CHANGE_ASYNC: |
|
2626 { |
|
2627 GstState target; |
|
2628 |
|
2629 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
|
2630 "element will change state ASYNC"); |
|
2631 |
|
2632 target = GST_STATE_TARGET (element); |
|
2633 |
|
2634 if (target > GST_STATE_READY) |
|
2635 goto async; |
|
2636 |
|
2637 /* else we just continue the state change downwards */ |
|
2638 GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
|
2639 "forcing commit state %s <= %s", |
|
2640 gst_element_state_get_name (target), |
|
2641 gst_element_state_get_name (GST_STATE_READY)); |
|
2642 |
|
2643 ret = gst_element_continue_state (element, GST_STATE_CHANGE_SUCCESS); |
|
2644 break; |
|
2645 } |
|
2646 case GST_STATE_CHANGE_SUCCESS: |
|
2647 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
|
2648 "element changed state SUCCESS"); |
|
2649 /* we can commit the state now which will proceeed to |
|
2650 * the next state */ |
|
2651 ret = gst_element_continue_state (element, ret); |
|
2652 break; |
|
2653 case GST_STATE_CHANGE_NO_PREROLL: |
|
2654 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
|
2655 "element changed state NO_PREROLL"); |
|
2656 /* we can commit the state now which will proceeed to |
|
2657 * the next state */ |
|
2658 ret = gst_element_continue_state (element, ret); |
|
2659 break; |
|
2660 default: |
|
2661 goto invalid_return; |
|
2662 } |
|
2663 |
|
2664 GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, "exit state change %d", ret); |
|
2665 |
|
2666 return ret; |
|
2667 |
|
2668 async: |
|
2669 GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, "exit async state change %d", |
|
2670 ret); |
|
2671 |
|
2672 return ret; |
|
2673 |
|
2674 /* ERROR */ |
|
2675 invalid_return: |
|
2676 { |
|
2677 GST_OBJECT_LOCK (element); |
|
2678 /* somebody added a GST_STATE_ and forgot to do stuff here ! */ |
|
2679 g_critical ("%s: unknown return value %d from a state change function", |
|
2680 GST_ELEMENT_NAME (element), ret); |
|
2681 |
|
2682 /* we are in error now */ |
|
2683 ret = GST_STATE_CHANGE_FAILURE; |
|
2684 GST_STATE_RETURN (element) = ret; |
|
2685 GST_OBJECT_UNLOCK (element); |
|
2686 |
|
2687 return ret; |
|
2688 } |
|
2689 } |
|
2690 |
|
2691 /* gst_iterator_fold functions for pads_activate |
|
2692 * Note how we don't stop the iterator when we fail an activation. This is |
|
2693 * probably a FIXME since when one pad activation fails, we don't want to |
|
2694 * continue our state change. */ |
|
2695 static gboolean |
|
2696 activate_pads (GstPad * pad, GValue * ret, gboolean * active) |
|
2697 { |
|
2698 if (!gst_pad_set_active (pad, *active)) |
|
2699 g_value_set_boolean (ret, FALSE); |
|
2700 |
|
2701 /* unref the object that was reffed for us by _fold */ |
|
2702 gst_object_unref (pad); |
|
2703 return TRUE; |
|
2704 } |
|
2705 |
|
2706 /* set the caps on the pad to NULL */ |
|
2707 static gboolean |
|
2708 clear_caps (GstPad * pad, GValue * ret, gboolean * active) |
|
2709 { |
|
2710 gst_pad_set_caps (pad, NULL); |
|
2711 gst_object_unref (pad); |
|
2712 return TRUE; |
|
2713 } |
|
2714 |
|
2715 /* returns false on error or early cutout (will never happen because the fold |
|
2716 * function always returns TRUE, see FIXME above) of the fold, true if all |
|
2717 * pads in @iter were (de)activated successfully. */ |
|
2718 static gboolean |
|
2719 iterator_activate_fold_with_resync (GstIterator * iter, |
|
2720 GstIteratorFoldFunction func, gpointer user_data) |
|
2721 { |
|
2722 GstIteratorResult ires; |
|
2723 GValue ret = { 0 }; |
|
2724 |
|
2725 /* no need to unset this later, it's just a boolean */ |
|
2726 g_value_init (&ret, G_TYPE_BOOLEAN); |
|
2727 g_value_set_boolean (&ret, TRUE); |
|
2728 |
|
2729 while (1) { |
|
2730 ires = gst_iterator_fold (iter, func, &ret, user_data); |
|
2731 switch (ires) { |
|
2732 case GST_ITERATOR_RESYNC: |
|
2733 /* need to reset the result again */ |
|
2734 g_value_set_boolean (&ret, TRUE); |
|
2735 gst_iterator_resync (iter); |
|
2736 break; |
|
2737 case GST_ITERATOR_DONE: |
|
2738 /* all pads iterated, return collected value */ |
|
2739 goto done; |
|
2740 default: |
|
2741 /* iterator returned _ERROR or premature end with _OK, |
|
2742 * mark an error and exit */ |
|
2743 g_value_set_boolean (&ret, FALSE); |
|
2744 goto done; |
|
2745 } |
|
2746 } |
|
2747 done: |
|
2748 /* return collected value */ |
|
2749 return g_value_get_boolean (&ret); |
|
2750 } |
|
2751 |
|
2752 /* is called with STATE_LOCK |
|
2753 * |
|
2754 * Pads are activated from source pads to sinkpads. |
|
2755 */ |
|
2756 static gboolean |
|
2757 gst_element_pads_activate (GstElement * element, gboolean active) |
|
2758 { |
|
2759 GstIterator *iter; |
|
2760 gboolean res; |
|
2761 |
|
2762 GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element, |
|
2763 "pads_activate with active %d", active); |
|
2764 |
|
2765 iter = gst_element_iterate_src_pads (element); |
|
2766 res = |
|
2767 iterator_activate_fold_with_resync (iter, |
|
2768 (GstIteratorFoldFunction) activate_pads, &active); |
|
2769 gst_iterator_free (iter); |
|
2770 if (G_UNLIKELY (!res)) |
|
2771 goto src_failed; |
|
2772 |
|
2773 iter = gst_element_iterate_sink_pads (element); |
|
2774 res = |
|
2775 iterator_activate_fold_with_resync (iter, |
|
2776 (GstIteratorFoldFunction) activate_pads, &active); |
|
2777 gst_iterator_free (iter); |
|
2778 if (G_UNLIKELY (!res)) |
|
2779 goto sink_failed; |
|
2780 |
|
2781 if (!active) { |
|
2782 /* clear the caps on all pads, this should never fail */ |
|
2783 iter = gst_element_iterate_pads (element); |
|
2784 res = |
|
2785 iterator_activate_fold_with_resync (iter, |
|
2786 (GstIteratorFoldFunction) clear_caps, &active); |
|
2787 gst_iterator_free (iter); |
|
2788 if (G_UNLIKELY (!res)) |
|
2789 goto caps_failed; |
|
2790 } |
|
2791 |
|
2792 GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element, |
|
2793 "pads_activate successful"); |
|
2794 |
|
2795 return TRUE; |
|
2796 |
|
2797 /* ERRORS */ |
|
2798 src_failed: |
|
2799 { |
|
2800 GST_DEBUG_OBJECT (element, "source pads_activate failed"); |
|
2801 return FALSE; |
|
2802 } |
|
2803 sink_failed: |
|
2804 { |
|
2805 GST_DEBUG_OBJECT (element, "sink pads_activate failed"); |
|
2806 return FALSE; |
|
2807 } |
|
2808 caps_failed: |
|
2809 { |
|
2810 GST_DEBUG_OBJECT (element, "failed to clear caps on pads"); |
|
2811 return FALSE; |
|
2812 } |
|
2813 } |
|
2814 |
|
2815 /* is called with STATE_LOCK */ |
|
2816 static GstStateChangeReturn |
|
2817 gst_element_change_state_func (GstElement * element, GstStateChange transition) |
|
2818 { |
|
2819 GstState state, next; |
|
2820 GstStateChangeReturn result = GST_STATE_CHANGE_SUCCESS; |
|
2821 |
|
2822 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE); |
|
2823 |
|
2824 state = (GstState) GST_STATE_TRANSITION_CURRENT (transition); |
|
2825 next = GST_STATE_TRANSITION_NEXT (transition); |
|
2826 |
|
2827 /* if the element already is in the given state, we just return success */ |
|
2828 if (next == GST_STATE_VOID_PENDING || state == next) |
|
2829 goto was_ok; |
|
2830 |
|
2831 GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, |
|
2832 "default handler tries setting state from %s to %s (%04x)", |
|
2833 gst_element_state_get_name (state), |
|
2834 gst_element_state_get_name (next), transition); |
|
2835 |
|
2836 switch (transition) { |
|
2837 case GST_STATE_CHANGE_NULL_TO_READY: |
|
2838 break; |
|
2839 case GST_STATE_CHANGE_READY_TO_PAUSED: |
|
2840 if (!gst_element_pads_activate (element, TRUE)) { |
|
2841 result = GST_STATE_CHANGE_FAILURE; |
|
2842 } |
|
2843 break; |
|
2844 case GST_STATE_CHANGE_PAUSED_TO_PLAYING: |
|
2845 break; |
|
2846 case GST_STATE_CHANGE_PLAYING_TO_PAUSED: |
|
2847 break; |
|
2848 case GST_STATE_CHANGE_PAUSED_TO_READY: |
|
2849 case GST_STATE_CHANGE_READY_TO_NULL: |
|
2850 /* deactivate pads in both cases, since they are activated on |
|
2851 ready->paused but the element might not have made it to paused */ |
|
2852 if (!gst_element_pads_activate (element, FALSE)) { |
|
2853 result = GST_STATE_CHANGE_FAILURE; |
|
2854 } else { |
|
2855 gst_element_set_base_time (element, 0); |
|
2856 } |
|
2857 break; |
|
2858 default: |
|
2859 /* this will catch real but unhandled state changes; |
|
2860 * can only be caused by: |
|
2861 * - a new state was added |
|
2862 * - somehow the element was asked to jump across an intermediate state |
|
2863 */ |
|
2864 g_warning ("Unhandled state change from %s to %s", |
|
2865 gst_element_state_get_name (state), |
|
2866 gst_element_state_get_name (next)); |
|
2867 break; |
|
2868 } |
|
2869 return result; |
|
2870 |
|
2871 was_ok: |
|
2872 { |
|
2873 GST_OBJECT_LOCK (element); |
|
2874 result = GST_STATE_RETURN (element); |
|
2875 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
|
2876 "element is already in the %s state", |
|
2877 gst_element_state_get_name (state)); |
|
2878 GST_OBJECT_UNLOCK (element); |
|
2879 |
|
2880 return result; |
|
2881 } |
|
2882 } |
|
2883 |
|
2884 /** |
|
2885 * gst_element_get_factory: |
|
2886 * @element: a #GstElement to request the element factory of. |
|
2887 * |
|
2888 * Retrieves the factory that was used to create this element. |
|
2889 * |
|
2890 * Returns: the #GstElementFactory used for creating this element. |
|
2891 * no refcounting is needed. |
|
2892 */ |
|
2893 #ifdef __SYMBIAN32__ |
|
2894 EXPORT_C |
|
2895 #endif |
|
2896 |
|
2897 GstElementFactory * |
|
2898 gst_element_get_factory (GstElement * element) |
|
2899 { |
|
2900 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
|
2901 |
|
2902 return GST_ELEMENT_GET_CLASS (element)->elementfactory; |
|
2903 } |
|
2904 |
|
2905 static void |
|
2906 gst_element_dispose (GObject * object) |
|
2907 { |
|
2908 GstElement *element = GST_ELEMENT (object); |
|
2909 GstClock **clock_p; |
|
2910 GstBus **bus_p; |
|
2911 |
|
2912 GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "dispose"); |
|
2913 |
|
2914 if (GST_STATE (element) != GST_STATE_NULL) |
|
2915 goto not_null; |
|
2916 |
|
2917 GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element, |
|
2918 "removing %d pads", g_list_length (element->pads)); |
|
2919 /* first we break all our links with the outside */ |
|
2920 while (element->pads && element->pads->data) { |
|
2921 /* don't call _remove_pad with NULL */ |
|
2922 gst_element_remove_pad (element, GST_PAD_CAST (element->pads->data)); |
|
2923 } |
|
2924 if (G_UNLIKELY (element->pads != 0)) { |
|
2925 g_critical ("could not remove pads from element %s", |
|
2926 GST_STR_NULL (GST_OBJECT_NAME (object))); |
|
2927 } |
|
2928 |
|
2929 GST_OBJECT_LOCK (element); |
|
2930 clock_p = &element->clock; |
|
2931 bus_p = &element->bus; |
|
2932 gst_object_replace ((GstObject **) clock_p, NULL); |
|
2933 gst_object_replace ((GstObject **) bus_p, NULL); |
|
2934 GST_OBJECT_UNLOCK (element); |
|
2935 |
|
2936 GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "parent class dispose"); |
|
2937 |
|
2938 G_OBJECT_CLASS (parent_class)->dispose (object); |
|
2939 |
|
2940 return; |
|
2941 |
|
2942 /* ERRORS */ |
|
2943 not_null: |
|
2944 { |
|
2945 g_critical |
|
2946 ("\nTrying to dispose element %s, but it is not in the NULL state.\n" |
|
2947 "You need to explicitly set elements to the NULL state before\n" |
|
2948 "dropping the final reference, to allow them to clean up.\n", |
|
2949 GST_OBJECT_NAME (element)); |
|
2950 return; |
|
2951 } |
|
2952 } |
|
2953 |
|
2954 static void |
|
2955 gst_element_finalize (GObject * object) |
|
2956 { |
|
2957 GstElement *element = GST_ELEMENT (object); |
|
2958 |
|
2959 GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "finalize"); |
|
2960 |
|
2961 GST_STATE_LOCK (element); |
|
2962 if (element->state_cond) |
|
2963 g_cond_free (element->state_cond); |
|
2964 element->state_cond = NULL; |
|
2965 GST_STATE_UNLOCK (element); |
|
2966 g_static_rec_mutex_free (element->state_lock); |
|
2967 g_free (element->state_lock); |
|
2968 element->state_lock = NULL; |
|
2969 |
|
2970 GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "finalize parent"); |
|
2971 |
|
2972 G_OBJECT_CLASS (parent_class)->finalize (object); |
|
2973 } |
|
2974 |
|
2975 #ifndef GST_DISABLE_LOADSAVE |
|
2976 /** |
|
2977 * gst_element_save_thyself: |
|
2978 * @element: a #GstElement to save. |
|
2979 * @parent: the xml parent node. |
|
2980 * |
|
2981 * Saves the element as part of the given XML structure. |
|
2982 * |
|
2983 * Returns: the new #xmlNodePtr. |
|
2984 */ |
|
2985 static xmlNodePtr |
|
2986 gst_element_save_thyself (GstObject * object, xmlNodePtr parent) |
|
2987 { |
|
2988 GList *pads; |
|
2989 GstElementClass *oclass; |
|
2990 GParamSpec **specs, *spec; |
|
2991 guint nspecs; |
|
2992 guint i; |
|
2993 GValue value = { 0, }; |
|
2994 GstElement *element; |
|
2995 |
|
2996 g_return_val_if_fail (GST_IS_ELEMENT (object), parent); |
|
2997 |
|
2998 element = GST_ELEMENT (object); |
|
2999 |
|
3000 oclass = GST_ELEMENT_GET_CLASS (element); |
|
3001 |
|
3002 xmlNewChild (parent, NULL, (xmlChar *) "name", |
|
3003 (xmlChar *) GST_ELEMENT_NAME (element)); |
|
3004 |
|
3005 if (oclass->elementfactory != NULL) { |
|
3006 GstElementFactory *factory = (GstElementFactory *) oclass->elementfactory; |
|
3007 |
|
3008 xmlNewChild (parent, NULL, (xmlChar *) "type", |
|
3009 (xmlChar *) GST_PLUGIN_FEATURE (factory)->name); |
|
3010 } |
|
3011 |
|
3012 /* params */ |
|
3013 specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &nspecs); |
|
3014 |
|
3015 for (i = 0; i < nspecs; i++) { |
|
3016 spec = specs[i]; |
|
3017 if (spec->flags & G_PARAM_READABLE) { |
|
3018 xmlNodePtr param; |
|
3019 char *contents; |
|
3020 |
|
3021 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (spec)); |
|
3022 |
|
3023 g_object_get_property (G_OBJECT (element), spec->name, &value); |
|
3024 param = xmlNewChild (parent, NULL, (xmlChar *) "param", NULL); |
|
3025 xmlNewChild (param, NULL, (xmlChar *) "name", (xmlChar *) spec->name); |
|
3026 |
|
3027 if (G_IS_PARAM_SPEC_STRING (spec)) |
|
3028 contents = g_value_dup_string (&value); |
|
3029 else if (G_IS_PARAM_SPEC_ENUM (spec)) |
|
3030 contents = g_strdup_printf ("%d", g_value_get_enum (&value)); |
|
3031 else if (G_IS_PARAM_SPEC_INT64 (spec)) |
|
3032 contents = g_strdup_printf ("%" G_GINT64_FORMAT, |
|
3033 g_value_get_int64 (&value)); |
|
3034 else |
|
3035 contents = g_strdup_value_contents (&value); |
|
3036 |
|
3037 xmlNewChild (param, NULL, (xmlChar *) "value", (xmlChar *) contents); |
|
3038 g_free (contents); |
|
3039 |
|
3040 g_value_unset (&value); |
|
3041 } |
|
3042 } |
|
3043 |
|
3044 g_free (specs); |
|
3045 |
|
3046 pads = GST_ELEMENT_PADS (element); |
|
3047 |
|
3048 while (pads) { |
|
3049 GstPad *pad = GST_PAD_CAST (pads->data); |
|
3050 |
|
3051 /* figure out if it's a direct pad or a ghostpad */ |
|
3052 if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) { |
|
3053 xmlNodePtr padtag = xmlNewChild (parent, NULL, (xmlChar *) "pad", NULL); |
|
3054 |
|
3055 gst_object_save_thyself (GST_OBJECT_CAST (pad), padtag); |
|
3056 } |
|
3057 pads = g_list_next (pads); |
|
3058 } |
|
3059 |
|
3060 return parent; |
|
3061 } |
|
3062 |
|
3063 static void |
|
3064 gst_element_restore_thyself (GstObject * object, xmlNodePtr self) |
|
3065 { |
|
3066 xmlNodePtr children; |
|
3067 GstElement *element; |
|
3068 gchar *name = NULL; |
|
3069 gchar *value = NULL; |
|
3070 |
|
3071 element = GST_ELEMENT (object); |
|
3072 g_return_if_fail (element != NULL); |
|
3073 |
|
3074 /* parameters */ |
|
3075 children = self->xmlChildrenNode; |
|
3076 while (children) { |
|
3077 if (!strcmp ((char *) children->name, "param")) { |
|
3078 xmlNodePtr child = children->xmlChildrenNode; |
|
3079 |
|
3080 while (child) { |
|
3081 if (!strcmp ((char *) child->name, "name")) { |
|
3082 name = (gchar *) xmlNodeGetContent (child); |
|
3083 } else if (!strcmp ((char *) child->name, "value")) { |
|
3084 value = (gchar *) xmlNodeGetContent (child); |
|
3085 } |
|
3086 child = child->next; |
|
3087 } |
|
3088 /* FIXME: can this just be g_object_set ? */ |
|
3089 gst_util_set_object_arg (G_OBJECT (element), name, value); |
|
3090 /* g_object_set (G_OBJECT (element), name, value, NULL); */ |
|
3091 g_free (name); |
|
3092 g_free (value); |
|
3093 } |
|
3094 children = children->next; |
|
3095 } |
|
3096 |
|
3097 /* pads */ |
|
3098 children = self->xmlChildrenNode; |
|
3099 while (children) { |
|
3100 if (!strcmp ((char *) children->name, "pad")) { |
|
3101 gst_pad_load_and_link (children, GST_OBJECT_CAST (element)); |
|
3102 } |
|
3103 children = children->next; |
|
3104 } |
|
3105 |
|
3106 if (GST_OBJECT_CLASS (parent_class)->restore_thyself) |
|
3107 (GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self); |
|
3108 } |
|
3109 #endif /* GST_DISABLE_LOADSAVE */ |
|
3110 |
|
3111 static void |
|
3112 gst_element_set_bus_func (GstElement * element, GstBus * bus) |
|
3113 { |
|
3114 GstBus **bus_p; |
|
3115 |
|
3116 g_return_if_fail (GST_IS_ELEMENT (element)); |
|
3117 |
|
3118 GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element, "setting bus to %p", bus); |
|
3119 |
|
3120 GST_OBJECT_LOCK (element); |
|
3121 bus_p = &GST_ELEMENT_BUS (element); |
|
3122 gst_object_replace ((GstObject **) bus_p, GST_OBJECT_CAST (bus)); |
|
3123 GST_OBJECT_UNLOCK (element); |
|
3124 } |
|
3125 |
|
3126 /** |
|
3127 * gst_element_set_bus: |
|
3128 * @element: a #GstElement to set the bus of. |
|
3129 * @bus: the #GstBus to set. |
|
3130 * |
|
3131 * Sets the bus of the element. Increases the refcount on the bus. |
|
3132 * For internal use only, unless you're testing elements. |
|
3133 * |
|
3134 * MT safe. |
|
3135 */ |
|
3136 #ifdef __SYMBIAN32__ |
|
3137 EXPORT_C |
|
3138 #endif |
|
3139 |
|
3140 void |
|
3141 gst_element_set_bus (GstElement * element, GstBus * bus) |
|
3142 { |
|
3143 GstElementClass *oclass; |
|
3144 |
|
3145 g_return_if_fail (GST_IS_ELEMENT (element)); |
|
3146 |
|
3147 oclass = GST_ELEMENT_GET_CLASS (element); |
|
3148 |
|
3149 if (oclass->set_bus) |
|
3150 oclass->set_bus (element, bus); |
|
3151 } |
|
3152 |
|
3153 /** |
|
3154 * gst_element_get_bus: |
|
3155 * @element: a #GstElement to get the bus of. |
|
3156 * |
|
3157 * Returns the bus of the element. Note that only a #GstPipeline will provide a |
|
3158 * bus for the application. |
|
3159 * |
|
3160 * Returns: the element's #GstBus. unref after usage. |
|
3161 * |
|
3162 * MT safe. |
|
3163 */ |
|
3164 #ifdef __SYMBIAN32__ |
|
3165 EXPORT_C |
|
3166 #endif |
|
3167 |
|
3168 GstBus * |
|
3169 gst_element_get_bus (GstElement * element) |
|
3170 { |
|
3171 GstBus *result = NULL; |
|
3172 |
|
3173 g_return_val_if_fail (GST_IS_ELEMENT (element), result); |
|
3174 |
|
3175 GST_OBJECT_LOCK (element); |
|
3176 if ((result = GST_ELEMENT_BUS (element))) |
|
3177 gst_object_ref (result); |
|
3178 GST_OBJECT_UNLOCK (element); |
|
3179 |
|
3180 GST_CAT_DEBUG_OBJECT (GST_CAT_BUS, element, "got bus %" GST_PTR_FORMAT, |
|
3181 result); |
|
3182 |
|
3183 return result; |
|
3184 } |