/src/gstreamer/subprojects/gstreamer/gst/gstelement.c
Line | Count | Source |
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., 51 Franklin St, Fifth Floor, |
20 | | * Boston, MA 02110-1301, USA. |
21 | | */ |
22 | | |
23 | | /** |
24 | | * SECTION:gstelement |
25 | | * @title: GstElement |
26 | | * @short_description: Abstract base class for all pipeline elements |
27 | | * @see_also: #GstElementFactory, #GstPad |
28 | | * @symbols: |
29 | | * - GST_ELEMENT_METADATA_LONGNAME |
30 | | * - GST_ELEMENT_METADATA_KLASS |
31 | | * - GST_ELEMENT_METADATA_DESCRIPTION |
32 | | * - GST_ELEMENT_METADATA_AUTHOR |
33 | | * - GST_ELEMENT_METADATA_DOC_URI |
34 | | * - GST_ELEMENT_METADATA_ICON_NAME |
35 | | * |
36 | | * GstElement is the abstract base class needed to construct an element that |
37 | | * can be used in a GStreamer pipeline. Please refer to the plugin writers |
38 | | * guide for more information on creating #GstElement subclasses. |
39 | | * |
40 | | * The name of a #GstElement can be get with gst_element_get_name() and set with |
41 | | * gst_element_set_name(). For speed, GST_ELEMENT_NAME() can be used in the |
42 | | * core when using the appropriate locking. Do not use this in plug-ins or |
43 | | * applications in order to retain ABI compatibility. |
44 | | * |
45 | | * Elements can have pads (of the type #GstPad). These pads link to pads on |
46 | | * other elements. #GstBuffer flow between these linked pads. |
47 | | * A #GstElement has a #GList of #GstPad structures for all their input (or sink) |
48 | | * and output (or source) pads. |
49 | | * Core and plug-in writers can add and remove pads with gst_element_add_pad() |
50 | | * and gst_element_remove_pad(). |
51 | | * |
52 | | * An existing pad of an element can be retrieved by name with |
53 | | * gst_element_get_static_pad(). A new dynamic pad can be created using |
54 | | * gst_element_request_pad() with a #GstPadTemplate. |
55 | | * An iterator of all pads can be retrieved with gst_element_iterate_pads(). |
56 | | * |
57 | | * Elements can be linked through their pads. |
58 | | * If the link is straightforward, use the gst_element_link() |
59 | | * convenience function to link two elements, or gst_element_link_many() |
60 | | * for more elements in a row. |
61 | | * Use gst_element_link_filtered() to link two elements constrained by |
62 | | * a specified set of #GstCaps. |
63 | | * For finer control, use gst_element_link_pads() and |
64 | | * gst_element_link_pads_filtered() to specify the pads to link on |
65 | | * each element by name. |
66 | | * |
67 | | * Each element has a state (see #GstState). You can get and set the state |
68 | | * of an element with gst_element_get_state() and gst_element_set_state(). |
69 | | * Setting a state triggers a #GstStateChange. To get a string representation |
70 | | * of a #GstState, use gst_state_get_name(). |
71 | | * |
72 | | * You can get and set a #GstClock on an element using gst_element_get_clock() |
73 | | * and gst_element_set_clock(). |
74 | | * Some elements can provide a clock for the pipeline if |
75 | | * the #GST_ELEMENT_FLAG_PROVIDE_CLOCK flag is set. With the |
76 | | * gst_element_provide_clock() method one can retrieve the clock provided by |
77 | | * such an element. |
78 | | * Not all elements require a clock to operate correctly. If the |
79 | | * #GST_ELEMENT_FLAG_REQUIRE_CLOCK() flag is set, a clock should be set on the |
80 | | * element with gst_element_set_clock(). |
81 | | * |
82 | | * Note that clock selection and distribution is normally handled by the |
83 | | * toplevel #GstPipeline so the clock functions are only to be used in very |
84 | | * specific situations. |
85 | | */ |
86 | | |
87 | | #include "gst_private.h" |
88 | | #include <glib.h> |
89 | | #include <stdarg.h> |
90 | | #include <gobject/gvaluecollector.h> |
91 | | |
92 | | #include "gstelement.h" |
93 | | #include "gstelementmetadata.h" |
94 | | #include "gstenumtypes.h" |
95 | | #include "gstbus.h" |
96 | | #include "gsterror.h" |
97 | | #include "gstevent.h" |
98 | | #include "gstghostpad.h" |
99 | | #include "gstutils.h" |
100 | | #include "gstinfo.h" |
101 | | #include "gsttracerutils.h" |
102 | | #include "gstvalue.h" |
103 | | #include <glib/gi18n-lib.h> |
104 | | #include "glib-compat-private.h" |
105 | | |
106 | | #include "printf/printf.h" |
107 | | |
108 | | /* Element signals and args */ |
109 | | enum |
110 | | { |
111 | | PAD_ADDED, |
112 | | PAD_REMOVED, |
113 | | NO_MORE_PADS, |
114 | | /* add more above */ |
115 | | LAST_SIGNAL |
116 | | }; |
117 | | |
118 | | enum |
119 | | { |
120 | | ARG_0 |
121 | | /* FILL ME */ |
122 | | }; |
123 | | |
124 | | static void gst_element_class_init (GstElementClass * klass); |
125 | | static void gst_element_init (GstElement * element); |
126 | | static void gst_element_base_class_init (gpointer g_class); |
127 | | |
128 | | static void gst_element_constructed (GObject * object); |
129 | | static void gst_element_dispose (GObject * object); |
130 | | static void gst_element_finalize (GObject * object); |
131 | | |
132 | | static GstStateChangeReturn gst_element_change_state_func (GstElement * element, |
133 | | GstStateChange transition); |
134 | | static GstStateChangeReturn gst_element_get_state_func (GstElement * element, |
135 | | GstState * state, GstState * pending, GstClockTime timeout); |
136 | | static GstStateChangeReturn gst_element_set_state_func (GstElement * element, |
137 | | GstState state); |
138 | | static gboolean gst_element_set_clock_func (GstElement * element, |
139 | | GstClock * clock); |
140 | | static void gst_element_set_bus_func (GstElement * element, GstBus * bus); |
141 | | static gboolean gst_element_post_message_default (GstElement * element, |
142 | | GstMessage * message); |
143 | | static void gst_element_set_context_default (GstElement * element, |
144 | | GstContext * context); |
145 | | |
146 | | static gboolean gst_element_default_send_event (GstElement * element, |
147 | | GstEvent * event); |
148 | | static gboolean gst_element_default_query (GstElement * element, |
149 | | GstQuery * query); |
150 | | |
151 | | static GstPadTemplate |
152 | | * gst_element_class_request_pad_simple_template (GstElementClass * |
153 | | element_class, const gchar * name); |
154 | | |
155 | | static GstObjectClass *parent_class = NULL; |
156 | | static guint gst_element_signals[LAST_SIGNAL] = { 0 }; |
157 | | |
158 | | /* this is used in gstelementfactory.c:gst_element_register() */ |
159 | | GQuark __gst_elementclass_factory = 0; |
160 | | |
161 | | /* used for gst_element_type_set_skip_documentation() and |
162 | | * gst_element_factory_get_skip_documentation() */ |
163 | | GQuark __gst_elementclass_skip_doc = 0; |
164 | | |
165 | | GType |
166 | | gst_element_get_type (void) |
167 | 4.88M | { |
168 | 4.88M | static gsize gst_element_type = 0; |
169 | | |
170 | 4.88M | if (g_once_init_enter (&gst_element_type)) { |
171 | 2 | GType _type; |
172 | 2 | static const GTypeInfo element_info = { |
173 | 2 | sizeof (GstElementClass), |
174 | 2 | gst_element_base_class_init, |
175 | 2 | NULL, /* base_class_finalize */ |
176 | 2 | (GClassInitFunc) gst_element_class_init, |
177 | 2 | NULL, |
178 | 2 | NULL, |
179 | 2 | sizeof (GstElement), |
180 | 2 | 0, |
181 | 2 | (GInstanceInitFunc) gst_element_init, |
182 | 2 | NULL |
183 | 2 | }; |
184 | | |
185 | 2 | _type = g_type_register_static (GST_TYPE_OBJECT, "GstElement", |
186 | 2 | &element_info, G_TYPE_FLAG_ABSTRACT); |
187 | | |
188 | 2 | __gst_elementclass_factory = |
189 | 2 | g_quark_from_static_string ("GST_ELEMENTCLASS_FACTORY"); |
190 | 2 | __gst_elementclass_skip_doc = |
191 | 2 | g_quark_from_static_string ("GST_ELEMENTCLASS_SKIP_DOCUMENTATION"); |
192 | 2 | g_once_init_leave (&gst_element_type, _type); |
193 | 2 | } |
194 | 4.88M | return gst_element_type; |
195 | 4.88M | } |
196 | | |
197 | | static void |
198 | | gst_element_class_init (GstElementClass * klass) |
199 | 2 | { |
200 | 2 | GObjectClass *gobject_class; |
201 | | |
202 | 2 | gobject_class = (GObjectClass *) klass; |
203 | | |
204 | 2 | parent_class = g_type_class_peek_parent (klass); |
205 | | |
206 | | /** |
207 | | * GstElement::pad-added: |
208 | | * @gstelement: the object which received the signal |
209 | | * @new_pad: the pad that has been added |
210 | | * |
211 | | * a new #GstPad has been added to the element. Note that this signal will |
212 | | * usually be emitted from the context of the streaming thread. Also keep in |
213 | | * mind that if you add new elements to the pipeline in the signal handler |
214 | | * you will need to set them to the desired target state with |
215 | | * gst_element_set_state() or gst_element_sync_state_with_parent(). |
216 | | */ |
217 | 2 | gst_element_signals[PAD_ADDED] = |
218 | 2 | g_signal_new ("pad-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, |
219 | 2 | G_STRUCT_OFFSET (GstElementClass, pad_added), NULL, NULL, |
220 | 2 | NULL, G_TYPE_NONE, 1, GST_TYPE_PAD); |
221 | | /** |
222 | | * GstElement::pad-removed: |
223 | | * @gstelement: the object which received the signal |
224 | | * @old_pad: the pad that has been removed |
225 | | * |
226 | | * a #GstPad has been removed from the element |
227 | | */ |
228 | 2 | gst_element_signals[PAD_REMOVED] = |
229 | 2 | g_signal_new ("pad-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, |
230 | 2 | G_STRUCT_OFFSET (GstElementClass, pad_removed), NULL, NULL, |
231 | 2 | NULL, G_TYPE_NONE, 1, GST_TYPE_PAD); |
232 | | /** |
233 | | * GstElement::no-more-pads: |
234 | | * @gstelement: the object which received the signal |
235 | | * |
236 | | * This signals that the element will not generate more dynamic pads. |
237 | | * Note that this signal will usually be emitted from the context of |
238 | | * the streaming thread. |
239 | | */ |
240 | 2 | gst_element_signals[NO_MORE_PADS] = |
241 | 2 | g_signal_new ("no-more-pads", G_TYPE_FROM_CLASS (klass), |
242 | 2 | G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstElementClass, no_more_pads), NULL, |
243 | 2 | NULL, NULL, G_TYPE_NONE, 0); |
244 | | |
245 | 2 | gobject_class->dispose = gst_element_dispose; |
246 | 2 | gobject_class->finalize = gst_element_finalize; |
247 | 2 | gobject_class->constructed = gst_element_constructed; |
248 | | |
249 | 2 | klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state_func); |
250 | 2 | klass->set_state = GST_DEBUG_FUNCPTR (gst_element_set_state_func); |
251 | 2 | klass->get_state = GST_DEBUG_FUNCPTR (gst_element_get_state_func); |
252 | 2 | klass->set_clock = GST_DEBUG_FUNCPTR (gst_element_set_clock_func); |
253 | 2 | klass->set_bus = GST_DEBUG_FUNCPTR (gst_element_set_bus_func); |
254 | 2 | klass->query = GST_DEBUG_FUNCPTR (gst_element_default_query); |
255 | 2 | klass->send_event = GST_DEBUG_FUNCPTR (gst_element_default_send_event); |
256 | 2 | klass->numpadtemplates = 0; |
257 | 2 | klass->post_message = GST_DEBUG_FUNCPTR (gst_element_post_message_default); |
258 | 2 | klass->set_context = GST_DEBUG_FUNCPTR (gst_element_set_context_default); |
259 | | |
260 | 2 | klass->elementfactory = NULL; |
261 | 2 | } |
262 | | |
263 | | static void |
264 | | gst_element_base_class_init (gpointer g_class) |
265 | 218 | { |
266 | 218 | GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); |
267 | 218 | GList *node, *padtemplates; |
268 | | |
269 | | /* Copy the element details here so elements can inherit the |
270 | | * details from their base class and classes only need to set |
271 | | * the details in class_init instead of base_init */ |
272 | 218 | element_class->metadata = |
273 | 218 | element_class->metadata ? gst_structure_copy (element_class->metadata) : |
274 | 218 | gst_structure_new_empty ("metadata"); |
275 | | |
276 | | /* Copy the pad templates so elements inherit them |
277 | | * from their base class but elements can add pad templates in class_init |
278 | | * instead of base_init. |
279 | | */ |
280 | 218 | padtemplates = g_list_copy (element_class->padtemplates); |
281 | 260 | for (node = padtemplates; node != NULL; node = node->next) { |
282 | 42 | GstPadTemplate *tmpl = (GstPadTemplate *) node->data; |
283 | 42 | gst_object_ref (tmpl); |
284 | 42 | } |
285 | 218 | element_class->padtemplates = padtemplates; |
286 | | |
287 | | /* set the factory, see gst_element_register() */ |
288 | 218 | element_class->elementfactory = |
289 | 218 | g_type_get_qdata (G_TYPE_FROM_CLASS (element_class), |
290 | 218 | __gst_elementclass_factory); |
291 | 218 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "type %s : factory %p", |
292 | 218 | G_OBJECT_CLASS_NAME (element_class), element_class->elementfactory); |
293 | 218 | } |
294 | | |
295 | | static void |
296 | | gst_element_init (GstElement * element) |
297 | 61.1k | { |
298 | 61.1k | GST_STATE (element) = GST_STATE_NULL; |
299 | 61.1k | GST_STATE_TARGET (element) = GST_STATE_NULL; |
300 | 61.1k | GST_STATE_NEXT (element) = GST_STATE_VOID_PENDING; |
301 | 61.1k | GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING; |
302 | 61.1k | GST_STATE_RETURN (element) = GST_STATE_CHANGE_SUCCESS; |
303 | | |
304 | 61.1k | g_rec_mutex_init (&element->state_lock); |
305 | 61.1k | g_cond_init (&element->state_cond); |
306 | 61.1k | } |
307 | | |
308 | | static void |
309 | | gst_element_constructed (GObject * object) |
310 | 61.1k | { |
311 | 61.1k | GST_TRACER_ELEMENT_NEW (GST_ELEMENT_CAST (object)); |
312 | 61.1k | G_OBJECT_CLASS (parent_class)->constructed (object); |
313 | 61.1k | } |
314 | | |
315 | | /** |
316 | | * gst_element_release_request_pad: |
317 | | * @element: a #GstElement to release the request pad of. |
318 | | * @pad: the #GstPad to release. |
319 | | * |
320 | | * Makes the element free the previously requested pad as obtained |
321 | | * with gst_element_request_pad(). |
322 | | * |
323 | | * This does not unref the pad. If the pad was created by using |
324 | | * gst_element_request_pad(), gst_element_release_request_pad() needs to be |
325 | | * followed by gst_object_unref() to free the @pad. |
326 | | * |
327 | | * MT safe. |
328 | | */ |
329 | | void |
330 | | gst_element_release_request_pad (GstElement * element, GstPad * pad) |
331 | 995 | { |
332 | 995 | GstElementClass *oclass; |
333 | | |
334 | 995 | g_return_if_fail (GST_IS_ELEMENT (element)); |
335 | 995 | g_return_if_fail (GST_IS_PAD (pad)); |
336 | 995 | g_return_if_fail (GST_PAD_PAD_TEMPLATE (pad) == NULL || |
337 | 995 | GST_PAD_TEMPLATE_PRESENCE (GST_PAD_PAD_TEMPLATE (pad)) == |
338 | 995 | GST_PAD_REQUEST); |
339 | 995 | g_return_if_fail (GST_PAD_PARENT (pad) == element); |
340 | | |
341 | 995 | oclass = GST_ELEMENT_GET_CLASS (element); |
342 | | |
343 | | /* if the element implements a custom release function we call that, else we |
344 | | * simply remove the pad from the element */ |
345 | 995 | if (oclass->release_pad) |
346 | 995 | oclass->release_pad (element, pad); |
347 | 0 | else |
348 | 0 | gst_element_remove_pad (element, pad); |
349 | 995 | } |
350 | | |
351 | | /** |
352 | | * gst_element_provide_clock: |
353 | | * @element: a #GstElement to query |
354 | | * |
355 | | * Get the clock provided by the given element. |
356 | | * > An element is only required to provide a clock in the PAUSED |
357 | | * > state. Some elements can provide a clock in other states. |
358 | | * |
359 | | * Returns: (transfer full) (nullable): the GstClock provided by the |
360 | | * element or %NULL if no clock could be provided. Unref after usage. |
361 | | * |
362 | | * MT safe. |
363 | | */ |
364 | | GstClock * |
365 | | gst_element_provide_clock (GstElement * element) |
366 | 12 | { |
367 | 12 | GstClock *result = NULL; |
368 | 12 | GstElementClass *oclass; |
369 | | |
370 | 12 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
371 | | |
372 | 12 | oclass = GST_ELEMENT_GET_CLASS (element); |
373 | | |
374 | 12 | if (oclass->provide_clock) |
375 | 12 | result = oclass->provide_clock (element); |
376 | | |
377 | 12 | return result; |
378 | 12 | } |
379 | | |
380 | | static gboolean |
381 | | gst_element_set_clock_func (GstElement * element, GstClock * clock) |
382 | 106k | { |
383 | 106k | GstClock **clock_p; |
384 | | |
385 | 106k | GST_OBJECT_LOCK (element); |
386 | 106k | clock_p = &element->clock; |
387 | 106k | gst_object_replace ((GstObject **) clock_p, (GstObject *) clock); |
388 | 106k | GST_OBJECT_UNLOCK (element); |
389 | | |
390 | 106k | return TRUE; |
391 | 106k | } |
392 | | |
393 | | /** |
394 | | * gst_element_set_clock: |
395 | | * @element: a #GstElement to set the clock for. |
396 | | * @clock: (transfer none) (nullable): the #GstClock to set for the element. |
397 | | * |
398 | | * Sets the clock for the element. This function increases the |
399 | | * refcount on the clock. Any previously set clock on the object |
400 | | * is unreffed. |
401 | | * |
402 | | * Returns: %TRUE if the element accepted the clock. An element can refuse a |
403 | | * clock when it, for example, is not able to slave its internal clock to the |
404 | | * @clock or when it requires a specific clock to operate. |
405 | | * |
406 | | * MT safe. |
407 | | */ |
408 | | gboolean |
409 | | gst_element_set_clock (GstElement * element, GstClock * clock) |
410 | 106k | { |
411 | 106k | GstElementClass *oclass; |
412 | 106k | gboolean res = FALSE; |
413 | | |
414 | 106k | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
415 | 106k | g_return_val_if_fail (clock == NULL || GST_IS_CLOCK (clock), FALSE); |
416 | | |
417 | 106k | oclass = GST_ELEMENT_GET_CLASS (element); |
418 | | |
419 | 106k | GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, element, "setting clock %p", clock); |
420 | | |
421 | 106k | if (oclass->set_clock) |
422 | 106k | res = oclass->set_clock (element, clock); |
423 | | |
424 | 106k | return res; |
425 | 106k | } |
426 | | |
427 | | /** |
428 | | * gst_element_get_clock: |
429 | | * @element: a #GstElement to get the clock of. |
430 | | * |
431 | | * Gets the currently configured clock of the element. This is the clock as was |
432 | | * last set with gst_element_set_clock(). |
433 | | * |
434 | | * Elements in a pipeline will only have their clock set when the |
435 | | * pipeline is in the PLAYING state. |
436 | | * |
437 | | * Returns: (transfer full) (nullable): the #GstClock of the element. unref after usage. |
438 | | * |
439 | | * MT safe. |
440 | | */ |
441 | | GstClock * |
442 | | gst_element_get_clock (GstElement * element) |
443 | 0 | { |
444 | 0 | GstClock *result; |
445 | |
|
446 | 0 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
447 | | |
448 | 0 | GST_OBJECT_LOCK (element); |
449 | 0 | if ((result = element->clock)) |
450 | 0 | gst_object_ref (result); |
451 | 0 | GST_OBJECT_UNLOCK (element); |
452 | |
|
453 | 0 | return result; |
454 | 0 | } |
455 | | |
456 | | /** |
457 | | * gst_element_set_base_time: |
458 | | * @element: a #GstElement. |
459 | | * @time: the base time to set. |
460 | | * |
461 | | * Set the base time of an element. See gst_element_get_base_time(). |
462 | | * |
463 | | * MT safe. |
464 | | */ |
465 | | void |
466 | | gst_element_set_base_time (GstElement * element, GstClockTime time) |
467 | 47.7k | { |
468 | 47.7k | GstClockTime old; |
469 | | |
470 | 47.7k | g_return_if_fail (GST_IS_ELEMENT (element)); |
471 | 47.7k | g_return_if_fail (GST_CLOCK_TIME_IS_VALID (time)); |
472 | | |
473 | 47.7k | GST_OBJECT_LOCK (element); |
474 | 47.7k | old = element->base_time; |
475 | 47.7k | element->base_time = time; |
476 | 47.7k | GST_OBJECT_UNLOCK (element); |
477 | | |
478 | 47.7k | GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, element, |
479 | 47.7k | "set base_time=%" GST_TIME_FORMAT ", old %" GST_TIME_FORMAT, |
480 | 47.7k | GST_TIME_ARGS (time), GST_TIME_ARGS (old)); |
481 | 47.7k | } |
482 | | |
483 | | /** |
484 | | * gst_element_get_base_time: |
485 | | * @element: a #GstElement. |
486 | | * |
487 | | * Returns the base time of the element. The base time is the |
488 | | * absolute time of the clock when this element was last put to |
489 | | * PLAYING. Subtracting the base time from the clock time gives |
490 | | * the running time of the element. |
491 | | * |
492 | | * Returns: the base time of the element. |
493 | | * |
494 | | * MT safe. |
495 | | */ |
496 | | GstClockTime |
497 | | gst_element_get_base_time (GstElement * element) |
498 | 104k | { |
499 | 104k | GstClockTime result; |
500 | | |
501 | 104k | g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_TIME_NONE); |
502 | | |
503 | 104k | GST_OBJECT_LOCK (element); |
504 | 104k | result = element->base_time; |
505 | 104k | GST_OBJECT_UNLOCK (element); |
506 | | |
507 | 104k | return result; |
508 | 104k | } |
509 | | |
510 | | /** |
511 | | * gst_element_set_start_time: |
512 | | * @element: a #GstElement. |
513 | | * @time: the base time to set. |
514 | | * |
515 | | * Set the start time of an element. The start time of the element is the |
516 | | * running time of the element when it last went to the PAUSED state. In READY |
517 | | * or after a flushing seek, it is set to 0. |
518 | | * |
519 | | * Toplevel elements like #GstPipeline will manage the start_time and |
520 | | * base_time on its children. Setting the start_time to #GST_CLOCK_TIME_NONE |
521 | | * on such a toplevel element will disable the distribution of the base_time to |
522 | | * the children and can be useful if the application manages the base_time |
523 | | * itself, for example if you want to synchronize capture from multiple |
524 | | * pipelines, and you can also ensure that the pipelines have the same clock. |
525 | | * |
526 | | * MT safe. |
527 | | */ |
528 | | void |
529 | | gst_element_set_start_time (GstElement * element, GstClockTime time) |
530 | 47.7k | { |
531 | 47.7k | GstClockTime old; |
532 | | |
533 | 47.7k | g_return_if_fail (GST_IS_ELEMENT (element)); |
534 | | |
535 | 47.7k | GST_OBJECT_LOCK (element); |
536 | 47.7k | old = GST_ELEMENT_START_TIME (element); |
537 | 47.7k | GST_ELEMENT_START_TIME (element) = time; |
538 | 47.7k | GST_OBJECT_UNLOCK (element); |
539 | | |
540 | 47.7k | GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, element, |
541 | 47.7k | "set start_time=%" GST_TIME_FORMAT ", old %" GST_TIME_FORMAT, |
542 | 47.7k | GST_TIME_ARGS (time), GST_TIME_ARGS (old)); |
543 | 47.7k | } |
544 | | |
545 | | /** |
546 | | * gst_element_get_start_time: |
547 | | * @element: a #GstElement. |
548 | | * |
549 | | * Returns the start time of the element. The start time is the |
550 | | * running time of the clock when this element was last put to PAUSED. |
551 | | * |
552 | | * Usually the start_time is managed by a toplevel element such as |
553 | | * #GstPipeline. |
554 | | * |
555 | | * MT safe. |
556 | | * |
557 | | * Returns: the start time of the element. |
558 | | */ |
559 | | GstClockTime |
560 | | gst_element_get_start_time (GstElement * element) |
561 | 104k | { |
562 | 104k | GstClockTime result; |
563 | | |
564 | 104k | g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_TIME_NONE); |
565 | | |
566 | 104k | GST_OBJECT_LOCK (element); |
567 | 104k | result = GST_ELEMENT_START_TIME (element); |
568 | 104k | GST_OBJECT_UNLOCK (element); |
569 | | |
570 | 104k | return result; |
571 | 104k | } |
572 | | |
573 | | /** |
574 | | * gst_element_get_current_running_time: |
575 | | * @element: a #GstElement. |
576 | | * |
577 | | * Returns the running time of the element. The running time is the |
578 | | * element's clock time minus its base time. Will return GST_CLOCK_TIME_NONE |
579 | | * if the element has no clock, or if its base time has not been set. |
580 | | * |
581 | | * Returns: the running time of the element, or GST_CLOCK_TIME_NONE if the |
582 | | * element has no clock or its base time has not been set. |
583 | | * |
584 | | * Since: 1.18 |
585 | | */ |
586 | | GstClockTime |
587 | | gst_element_get_current_running_time (GstElement * element) |
588 | 0 | { |
589 | 0 | GstClockTime base_time, clock_time; |
590 | |
|
591 | 0 | g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_TIME_NONE); |
592 | | |
593 | 0 | base_time = gst_element_get_base_time (element); |
594 | |
|
595 | 0 | if (!GST_CLOCK_TIME_IS_VALID (base_time)) { |
596 | 0 | GST_DEBUG_OBJECT (element, "Could not determine base time"); |
597 | 0 | return GST_CLOCK_TIME_NONE; |
598 | 0 | } |
599 | | |
600 | 0 | clock_time = gst_element_get_current_clock_time (element); |
601 | |
|
602 | 0 | if (!GST_CLOCK_TIME_IS_VALID (clock_time)) { |
603 | 0 | return GST_CLOCK_TIME_NONE; |
604 | 0 | } |
605 | | |
606 | 0 | if (clock_time < base_time) { |
607 | 0 | GST_DEBUG_OBJECT (element, "Got negative current running time"); |
608 | 0 | return GST_CLOCK_TIME_NONE; |
609 | 0 | } |
610 | | |
611 | 0 | return clock_time - base_time; |
612 | 0 | } |
613 | | |
614 | | /** |
615 | | * gst_element_get_current_clock_time: |
616 | | * @element: a #GstElement. |
617 | | * |
618 | | * Returns the current clock time of the element, as in, the time of the |
619 | | * element's clock, or GST_CLOCK_TIME_NONE if there is no clock. |
620 | | * |
621 | | * Returns: the clock time of the element, or GST_CLOCK_TIME_NONE if there is |
622 | | * no clock. |
623 | | * |
624 | | * Since: 1.18 |
625 | | */ |
626 | | GstClockTime |
627 | | gst_element_get_current_clock_time (GstElement * element) |
628 | 0 | { |
629 | 0 | GstClock *clock = NULL; |
630 | 0 | GstClockTime ret; |
631 | |
|
632 | 0 | g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_TIME_NONE); |
633 | | |
634 | 0 | clock = gst_element_get_clock (element); |
635 | |
|
636 | 0 | if (!clock) { |
637 | 0 | GST_DEBUG_OBJECT (element, "Element has no clock"); |
638 | 0 | return GST_CLOCK_TIME_NONE; |
639 | 0 | } |
640 | | |
641 | 0 | ret = gst_clock_get_time (clock); |
642 | 0 | gst_object_unref (clock); |
643 | |
|
644 | 0 | return ret; |
645 | 0 | } |
646 | | |
647 | | #if 0 |
648 | | /** |
649 | | * gst_element_set_index: |
650 | | * @element: a #GstElement. |
651 | | * @index: (transfer none): a #GstIndex. |
652 | | * |
653 | | * Set @index on the element. The refcount of the index |
654 | | * will be increased, any previously set index is unreffed. |
655 | | * |
656 | | * MT safe. |
657 | | */ |
658 | | void |
659 | | gst_element_set_index (GstElement * element, GstIndex * index) |
660 | | { |
661 | | GstElementClass *oclass; |
662 | | |
663 | | g_return_if_fail (GST_IS_ELEMENT (element)); |
664 | | g_return_if_fail (index == NULL || GST_IS_INDEX (index)); |
665 | | |
666 | | oclass = GST_ELEMENT_GET_CLASS (element); |
667 | | |
668 | | if (oclass->set_index) |
669 | | oclass->set_index (element, index); |
670 | | } |
671 | | |
672 | | /** |
673 | | * gst_element_get_index: |
674 | | * @element: a #GstElement. |
675 | | * |
676 | | * Gets the index from the element. |
677 | | * |
678 | | * Returns: (transfer full) (nullable): a #GstIndex or %NULL when no |
679 | | * index was set on the element. unref after usage. |
680 | | * |
681 | | * MT safe. |
682 | | */ |
683 | | GstIndex * |
684 | | gst_element_get_index (GstElement * element) |
685 | | { |
686 | | GstElementClass *oclass; |
687 | | GstIndex *result = NULL; |
688 | | |
689 | | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
690 | | |
691 | | oclass = GST_ELEMENT_GET_CLASS (element); |
692 | | |
693 | | if (oclass->get_index) |
694 | | result = oclass->get_index (element); |
695 | | |
696 | | return result; |
697 | | } |
698 | | #endif |
699 | | |
700 | | /** |
701 | | * gst_element_add_pad: |
702 | | * @element: a #GstElement to add the pad to. |
703 | | * @pad: (transfer floating): the #GstPad to add to the element. |
704 | | * |
705 | | * Adds a pad (link point) to @element. @pad's parent will be set to @element; |
706 | | * see gst_object_set_parent() for refcounting information. |
707 | | * |
708 | | * Pads are automatically activated when added in the PAUSED or PLAYING |
709 | | * state. |
710 | | * |
711 | | * The pad and the element should be unlocked when calling this function. |
712 | | * |
713 | | * This function will emit the #GstElement::pad-added signal on the element. |
714 | | * |
715 | | * Returns: %TRUE if the pad could be added. This function can fail when |
716 | | * a pad with the same name already existed or the pad already had another |
717 | | * parent. |
718 | | * |
719 | | * MT safe. |
720 | | */ |
721 | | gboolean |
722 | | gst_element_add_pad (GstElement * element, GstPad * pad) |
723 | 59.6k | { |
724 | 59.6k | gchar *pad_name; |
725 | 59.6k | gboolean active; |
726 | 59.6k | gboolean should_activate; |
727 | | |
728 | 59.6k | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
729 | 59.6k | g_return_val_if_fail (GST_IS_PAD (pad), FALSE); |
730 | | |
731 | | /* locking pad to look at the name */ |
732 | 59.6k | GST_OBJECT_LOCK (pad); |
733 | 59.6k | pad_name = g_strdup (GST_PAD_NAME (pad)); |
734 | 59.6k | GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element, "adding pad '%s'", |
735 | 59.6k | GST_STR_NULL (pad_name)); |
736 | 59.6k | active = GST_PAD_IS_ACTIVE (pad); |
737 | 59.6k | GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_NEED_PARENT); |
738 | 59.6k | GST_OBJECT_UNLOCK (pad); |
739 | | |
740 | | /* then check to see if there's already a pad by that name here */ |
741 | 59.6k | GST_OBJECT_LOCK (element); |
742 | 59.6k | if (G_UNLIKELY (!gst_object_check_uniqueness (element->pads, pad_name))) |
743 | 0 | goto name_exists; |
744 | | |
745 | | /* try to set the pad's parent */ |
746 | 59.6k | if (G_UNLIKELY (!gst_object_set_parent (GST_OBJECT_CAST (pad), |
747 | 59.6k | GST_OBJECT_CAST (element)))) |
748 | 0 | goto had_parent; |
749 | | |
750 | | /* check for active pads */ |
751 | 59.6k | should_activate = !active && (GST_STATE (element) > GST_STATE_READY || |
752 | 50.0k | GST_STATE_NEXT (element) == GST_STATE_PAUSED); |
753 | | |
754 | 59.6k | g_free (pad_name); |
755 | | |
756 | | /* add it to the list */ |
757 | 59.6k | switch (gst_pad_get_direction (pad)) { |
758 | 30.6k | case GST_PAD_SRC: |
759 | 30.6k | element->srcpads = g_list_append (element->srcpads, pad); |
760 | 30.6k | element->numsrcpads++; |
761 | 30.6k | break; |
762 | 29.0k | case GST_PAD_SINK: |
763 | 29.0k | element->sinkpads = g_list_append (element->sinkpads, pad); |
764 | 29.0k | element->numsinkpads++; |
765 | 29.0k | break; |
766 | 0 | default: |
767 | 0 | goto no_direction; |
768 | 59.6k | } |
769 | 59.6k | element->pads = g_list_append (element->pads, pad); |
770 | 59.6k | element->numpads++; |
771 | 59.6k | element->pads_cookie++; |
772 | 59.6k | GST_OBJECT_UNLOCK (element); |
773 | | |
774 | 59.6k | if (should_activate) |
775 | 0 | gst_pad_set_active (pad, TRUE); |
776 | | |
777 | | /* emit the PAD_ADDED signal */ |
778 | 59.6k | g_signal_emit (element, gst_element_signals[PAD_ADDED], 0, pad); |
779 | 59.6k | GST_TRACER_ELEMENT_ADD_PAD (element, pad); |
780 | 59.6k | return TRUE; |
781 | | |
782 | | /* ERROR cases */ |
783 | 0 | name_exists: |
784 | 0 | { |
785 | 0 | g_critical ("Padname %s is not unique in element %s, not adding", |
786 | 0 | pad_name, GST_ELEMENT_NAME (element)); |
787 | 0 | GST_OBJECT_UNLOCK (element); |
788 | 0 | g_free (pad_name); |
789 | 0 | gst_object_ref_sink (pad); |
790 | 0 | gst_object_unref (pad); |
791 | 0 | return FALSE; |
792 | 59.6k | } |
793 | 0 | had_parent: |
794 | 0 | { |
795 | 0 | g_critical |
796 | 0 | ("Pad %s already has parent when trying to add to element %s", |
797 | 0 | pad_name, GST_ELEMENT_NAME (element)); |
798 | 0 | GST_OBJECT_UNLOCK (element); |
799 | 0 | g_free (pad_name); |
800 | 0 | return FALSE; |
801 | 59.6k | } |
802 | 0 | no_direction: |
803 | 0 | { |
804 | 0 | GST_OBJECT_LOCK (pad); |
805 | 0 | g_critical |
806 | 0 | ("Trying to add pad %s to element %s, but it has no direction", |
807 | 0 | GST_OBJECT_NAME (pad), GST_ELEMENT_NAME (element)); |
808 | 0 | GST_OBJECT_UNLOCK (pad); |
809 | 0 | GST_OBJECT_UNLOCK (element); |
810 | 0 | return FALSE; |
811 | 59.6k | } |
812 | 59.6k | } |
813 | | |
814 | | /** |
815 | | * gst_element_remove_pad: |
816 | | * @element: a #GstElement to remove pad from. |
817 | | * @pad: (transfer none): the #GstPad to remove from the element. |
818 | | * |
819 | | * Removes @pad from @element. @pad will be destroyed if it has not been |
820 | | * referenced elsewhere using gst_object_unparent(). |
821 | | * |
822 | | * This function is used by plugin developers and should not be used |
823 | | * by applications. Pads that were dynamically requested from elements |
824 | | * with gst_element_request_pad() should be released with the |
825 | | * gst_element_release_request_pad() function instead. |
826 | | * |
827 | | * Pads are not automatically deactivated so elements should perform the needed |
828 | | * steps to deactivate the pad in case this pad is removed in the PAUSED or |
829 | | * PLAYING state. See gst_pad_set_active() for more information about |
830 | | * deactivating pads. |
831 | | * |
832 | | * The pad and the element should be unlocked when calling this function. |
833 | | * |
834 | | * This function will emit the #GstElement::pad-removed signal on the element. |
835 | | * |
836 | | * Returns: %TRUE if the pad could be removed. Can return %FALSE if the |
837 | | * pad does not belong to the provided element. |
838 | | * |
839 | | * MT safe. |
840 | | */ |
841 | | gboolean |
842 | | gst_element_remove_pad (GstElement * element, GstPad * pad) |
843 | 59.6k | { |
844 | 59.6k | GstPad *peer; |
845 | | |
846 | 59.6k | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
847 | 59.6k | g_return_val_if_fail (GST_IS_PAD (pad), FALSE); |
848 | | |
849 | | /* locking pad to look at the name and parent */ |
850 | 59.6k | GST_OBJECT_LOCK (pad); |
851 | 59.6k | GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element, "removing pad '%s'", |
852 | 59.6k | GST_STR_NULL (GST_PAD_NAME (pad))); |
853 | | |
854 | 59.6k | if (G_UNLIKELY (GST_PAD_PARENT (pad) != element)) |
855 | 0 | goto not_our_pad; |
856 | 59.6k | GST_OBJECT_UNLOCK (pad); |
857 | | |
858 | | /* unlink */ |
859 | 59.6k | if ((peer = gst_pad_get_peer (pad))) { |
860 | | /* window for MT unsafeness, someone else could unlink here |
861 | | * and then we call unlink with wrong pads. The unlink |
862 | | * function would catch this and safely return failed. */ |
863 | 2.16k | if (GST_PAD_IS_SRC (pad)) |
864 | 2.16k | gst_pad_unlink (pad, peer); |
865 | 0 | else |
866 | 0 | gst_pad_unlink (peer, pad); |
867 | | |
868 | 2.16k | gst_object_unref (peer); |
869 | 2.16k | } |
870 | | |
871 | | /* if this is a ghost pad we also need to unset the target or it |
872 | | * will stay linked although not allowed according to the topology. |
873 | | * |
874 | | * FIXME 2.0: Do this generically somehow from inside GstGhostPad |
875 | | * when it gets unparented. |
876 | | */ |
877 | 59.6k | if (GST_IS_GHOST_PAD (pad)) { |
878 | 6.60k | gst_ghost_pad_set_target (GST_GHOST_PAD (pad), NULL); |
879 | 6.60k | } |
880 | | |
881 | 59.6k | GST_OBJECT_LOCK (element); |
882 | | /* remove it from the list */ |
883 | 59.6k | switch (gst_pad_get_direction (pad)) { |
884 | 30.6k | case GST_PAD_SRC: |
885 | 30.6k | element->srcpads = g_list_remove (element->srcpads, pad); |
886 | 30.6k | element->numsrcpads--; |
887 | 30.6k | break; |
888 | 29.0k | case GST_PAD_SINK: |
889 | 29.0k | element->sinkpads = g_list_remove (element->sinkpads, pad); |
890 | 29.0k | element->numsinkpads--; |
891 | 29.0k | break; |
892 | 0 | default: |
893 | 0 | g_critical ("Removing pad without direction???"); |
894 | 0 | break; |
895 | 59.6k | } |
896 | 59.6k | element->pads = g_list_remove (element->pads, pad); |
897 | 59.6k | element->numpads--; |
898 | 59.6k | element->pads_cookie++; |
899 | 59.6k | GST_OBJECT_UNLOCK (element); |
900 | | |
901 | | /* emit the PAD_REMOVED signal before unparenting and losing the last ref. */ |
902 | 59.6k | g_signal_emit (element, gst_element_signals[PAD_REMOVED], 0, pad); |
903 | 59.6k | GST_TRACER_ELEMENT_REMOVE_PAD (element, pad); |
904 | 59.6k | gst_object_unparent (GST_OBJECT_CAST (pad)); |
905 | | |
906 | 59.6k | return TRUE; |
907 | | |
908 | | /* ERRORS */ |
909 | 0 | not_our_pad: |
910 | 0 | { |
911 | | /* locking order is element > pad */ |
912 | 0 | GST_OBJECT_UNLOCK (pad); |
913 | |
|
914 | 0 | GST_OBJECT_LOCK (element); |
915 | 0 | GST_OBJECT_LOCK (pad); |
916 | 0 | g_critical ("Padname %s:%s does not belong to element %s when removing", |
917 | 0 | GST_DEBUG_PAD_NAME (pad), GST_ELEMENT_NAME (element)); |
918 | 0 | GST_OBJECT_UNLOCK (pad); |
919 | 0 | GST_OBJECT_UNLOCK (element); |
920 | 0 | return FALSE; |
921 | 59.6k | } |
922 | 59.6k | } |
923 | | |
924 | | /** |
925 | | * gst_element_no_more_pads: |
926 | | * @element: a #GstElement |
927 | | * |
928 | | * Use this function to signal that the element does not expect any more pads |
929 | | * to show up in the current pipeline. This function should be called whenever |
930 | | * pads have been added by the element itself. Elements with #GST_PAD_SOMETIMES |
931 | | * pad templates use this in combination with autopluggers to figure out that |
932 | | * the element is done initializing its pads. |
933 | | * |
934 | | * This function emits the #GstElement::no-more-pads signal. |
935 | | * |
936 | | * MT safe. |
937 | | */ |
938 | | void |
939 | | gst_element_no_more_pads (GstElement * element) |
940 | 2.00k | { |
941 | 2.00k | g_return_if_fail (GST_IS_ELEMENT (element)); |
942 | | |
943 | 2.00k | g_signal_emit (element, gst_element_signals[NO_MORE_PADS], 0); |
944 | 2.00k | } |
945 | | |
946 | | static gint |
947 | | pad_compare_name (GstPad * pad1, const gchar * name) |
948 | 29.2k | { |
949 | 29.2k | gint result; |
950 | | |
951 | 29.2k | GST_OBJECT_LOCK (pad1); |
952 | 29.2k | result = strcmp (GST_PAD_NAME (pad1), name); |
953 | 29.2k | GST_OBJECT_UNLOCK (pad1); |
954 | | |
955 | 29.2k | return result; |
956 | 29.2k | } |
957 | | |
958 | | /** |
959 | | * gst_element_get_static_pad: |
960 | | * @element: a #GstElement to find a static pad of. |
961 | | * @name: the name of the static #GstPad to retrieve. |
962 | | * |
963 | | * Retrieves a pad from @element by name. This version only retrieves |
964 | | * already-existing (i.e. 'static') pads. |
965 | | * |
966 | | * Returns: (transfer full) (nullable): the requested #GstPad if |
967 | | * found, otherwise %NULL. unref after usage. |
968 | | * |
969 | | * MT safe. |
970 | | */ |
971 | | GstPad * |
972 | | gst_element_get_static_pad (GstElement * element, const gchar * name) |
973 | 28.5k | { |
974 | 28.5k | GList *find; |
975 | 28.5k | GstPad *result = NULL; |
976 | | |
977 | 28.5k | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
978 | 28.5k | g_return_val_if_fail (name != NULL, NULL); |
979 | | |
980 | 28.5k | GST_OBJECT_LOCK (element); |
981 | 28.5k | find = |
982 | 28.5k | g_list_find_custom (element->pads, name, (GCompareFunc) pad_compare_name); |
983 | 28.5k | if (find) { |
984 | 15.1k | result = GST_PAD_CAST (find->data); |
985 | 15.1k | gst_object_ref (result); |
986 | 15.1k | } |
987 | | |
988 | 28.5k | if (result == NULL) { |
989 | 13.4k | GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "no such pad '%s' in element \"%s\"", |
990 | 13.4k | name, GST_ELEMENT_NAME (element)); |
991 | 15.1k | } else { |
992 | 15.1k | GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "found pad %s:%s", |
993 | 15.1k | GST_ELEMENT_NAME (element), name); |
994 | 15.1k | } |
995 | 28.5k | GST_OBJECT_UNLOCK (element); |
996 | | |
997 | 28.5k | return result; |
998 | 28.5k | } |
999 | | |
1000 | | static gboolean |
1001 | | gst_element_is_valid_request_template_name (const gchar * templ_name, |
1002 | | const gchar * name) |
1003 | 0 | { |
1004 | 0 | gchar *endptr; |
1005 | 0 | const gchar *templ_name_ptr, *name_ptr; |
1006 | 0 | gboolean next_specifier; |
1007 | 0 | guint templ_postfix_len = 0, name_postfix_len = 0; |
1008 | |
|
1009 | 0 | g_return_val_if_fail (templ_name != NULL, FALSE); |
1010 | 0 | g_return_val_if_fail (name != NULL, FALSE); |
1011 | | |
1012 | | /* Is this the template name? */ |
1013 | 0 | if (strcmp (templ_name, name) == 0) |
1014 | 0 | return TRUE; |
1015 | | |
1016 | | /* otherwise check all the specifiers */ |
1017 | 0 | do { |
1018 | | /* Because of sanity checks in gst_pad_template_new(), we know that %s |
1019 | | * and %d and %u, occurring at the template_name */ |
1020 | 0 | templ_name_ptr = strchr (templ_name, '%'); |
1021 | | |
1022 | | /* check characters ahead of the specifier */ |
1023 | 0 | if (!templ_name_ptr || strlen (name) <= templ_name_ptr - templ_name |
1024 | 0 | || strncmp (templ_name, name, templ_name_ptr - templ_name) != 0) { |
1025 | 0 | return FALSE; |
1026 | 0 | } |
1027 | | |
1028 | | /* %s is not allowed for multiple specifiers, just a single specifier can be |
1029 | | * accepted in gst_pad_template_new() and can not be mixed with other |
1030 | | * specifier '%u' and '%d' */ |
1031 | 0 | if (*(templ_name_ptr + 1) == 's') { |
1032 | 0 | return TRUE; |
1033 | 0 | } |
1034 | | |
1035 | 0 | name_ptr = name + (templ_name_ptr - templ_name); |
1036 | | |
1037 | | /* search next specifier, each of specifier should be separated by '_' */ |
1038 | 0 | templ_name = strchr (templ_name_ptr, '_'); |
1039 | 0 | name = strchr (name_ptr, '_'); |
1040 | | |
1041 | | /* don't match the number of specifiers */ |
1042 | 0 | if ((templ_name && !name) || (!templ_name && name)) |
1043 | 0 | return FALSE; |
1044 | | |
1045 | 0 | if (templ_name && name) |
1046 | 0 | next_specifier = TRUE; |
1047 | 0 | else |
1048 | 0 | next_specifier = FALSE; |
1049 | | |
1050 | | /* check characters followed by the specifier */ |
1051 | 0 | if (*(templ_name_ptr + 2) != '\0' && *(templ_name_ptr + 2) != '_') { |
1052 | 0 | if (next_specifier) { |
1053 | 0 | templ_postfix_len = templ_name - (templ_name_ptr + 2); |
1054 | 0 | name_postfix_len = name - name_ptr; |
1055 | 0 | } else { |
1056 | 0 | templ_postfix_len = strlen (templ_name_ptr + 2); |
1057 | 0 | name_postfix_len = strlen (name_ptr); |
1058 | 0 | } |
1059 | |
|
1060 | 0 | if (strncmp (templ_name_ptr + 2, |
1061 | 0 | name_ptr + name_postfix_len - templ_postfix_len, |
1062 | 0 | templ_postfix_len) != 0) { |
1063 | 0 | return FALSE; |
1064 | 0 | } |
1065 | 0 | } |
1066 | | |
1067 | | /* verify the specifier */ |
1068 | 0 | if (*(name_ptr) == '%') { |
1069 | 0 | guint len; |
1070 | |
|
1071 | 0 | len = (next_specifier) ? name - name_ptr : strlen (name_ptr); |
1072 | |
|
1073 | 0 | if (strncmp (name_ptr, templ_name_ptr, len) != 0) |
1074 | 0 | return FALSE; |
1075 | |
|
1076 | 0 | } else { |
1077 | 0 | const gchar *specifier; |
1078 | 0 | gchar *target = NULL; |
1079 | | |
1080 | | /* extract specifier when it has postfix characters */ |
1081 | 0 | if (name_postfix_len > templ_postfix_len) { |
1082 | 0 | target = g_strndup (name_ptr, name_postfix_len - templ_postfix_len); |
1083 | 0 | } |
1084 | 0 | specifier = target ? target : name_ptr; |
1085 | |
|
1086 | 0 | if (*(templ_name_ptr + 1) == 'd') { |
1087 | 0 | gint64 tmp; |
1088 | | |
1089 | | /* it's an int */ |
1090 | 0 | tmp = g_ascii_strtoll (specifier, &endptr, 10); |
1091 | 0 | if (tmp < G_MININT || tmp > G_MAXINT || (*endptr != '\0' |
1092 | 0 | && *endptr != '_')) |
1093 | 0 | return FALSE; |
1094 | 0 | } else if (*(templ_name_ptr + 1) == 'u') { |
1095 | 0 | guint64 tmp; |
1096 | | |
1097 | | /* it's an int */ |
1098 | 0 | tmp = g_ascii_strtoull (specifier, &endptr, 10); |
1099 | 0 | if (tmp > G_MAXUINT || (*endptr != '\0' && *endptr != '_')) |
1100 | 0 | return FALSE; |
1101 | 0 | } |
1102 | | |
1103 | 0 | g_free (target); |
1104 | 0 | } |
1105 | | |
1106 | | /* otherwise we increment these from NULL to 1 */ |
1107 | 0 | if (next_specifier) { |
1108 | 0 | templ_name++; |
1109 | 0 | name++; |
1110 | 0 | } |
1111 | 0 | } while (next_specifier); |
1112 | | |
1113 | 0 | return TRUE; |
1114 | 0 | } |
1115 | | |
1116 | | static GstPad * |
1117 | | _gst_element_request_pad (GstElement * element, GstPadTemplate * templ, |
1118 | | const gchar * name, const GstCaps * caps) |
1119 | 995 | { |
1120 | 995 | GstPad *newpad = NULL; |
1121 | 995 | GstElementClass *oclass; |
1122 | | |
1123 | 995 | oclass = GST_ELEMENT_GET_CLASS (element); |
1124 | | |
1125 | 995 | #ifndef G_DISABLE_CHECKS |
1126 | | /* Some sanity checking here */ |
1127 | 995 | if (name) { |
1128 | 0 | GstPad *pad; |
1129 | |
|
1130 | 0 | g_return_val_if_fail (gst_element_is_valid_request_template_name |
1131 | 0 | (templ->name_template, name), NULL); |
1132 | | |
1133 | 0 | pad = gst_element_get_static_pad (element, name); |
1134 | 0 | if (pad) { |
1135 | 0 | gst_object_unref (pad); |
1136 | | /* FIXME 2.0: Change this to g_return_val_if_fail() */ |
1137 | 0 | g_critical ("Element %s already has a pad named %s, the behaviour of " |
1138 | 0 | " gst_element_get_request_pad() for existing pads is undefined!", |
1139 | 0 | GST_ELEMENT_NAME (element), name); |
1140 | 0 | } |
1141 | 0 | } |
1142 | 995 | #endif |
1143 | | |
1144 | 995 | #ifdef GST_ENABLE_EXTRA_CHECKS |
1145 | 995 | { |
1146 | 995 | if (!g_list_find (oclass->padtemplates, templ)) { |
1147 | | /* FIXME 2.0: Change this to g_return_val_if_fail() */ |
1148 | 0 | g_critical ("Element type %s does not have a pad template %s (%p)", |
1149 | 0 | g_type_name (G_OBJECT_TYPE (element)), templ->name_template, templ); |
1150 | 0 | } |
1151 | 995 | } |
1152 | 995 | #endif |
1153 | | |
1154 | 995 | if (oclass->request_new_pad) |
1155 | 995 | newpad = (oclass->request_new_pad) (element, templ, name, caps); |
1156 | | |
1157 | 995 | if (newpad) |
1158 | 995 | gst_object_ref (newpad); |
1159 | | |
1160 | 995 | return newpad; |
1161 | 995 | } |
1162 | | |
1163 | | #ifndef GST_REMOVE_DEPRECATED |
1164 | | /** |
1165 | | * gst_element_get_request_pad: |
1166 | | * @element: a #GstElement to find a request pad of. |
1167 | | * @name: the name of the request #GstPad to retrieve. |
1168 | | * |
1169 | | * The name of this function is confusing to people learning GStreamer. |
1170 | | * gst_element_request_pad_simple() aims at making it more explicit it is |
1171 | | * a simplified gst_element_request_pad(). |
1172 | | * |
1173 | | * Deprecated: 1.20: Prefer using gst_element_request_pad_simple() which |
1174 | | * provides the exact same functionality. |
1175 | | * |
1176 | | * Returns: (transfer full) (nullable): requested #GstPad if found, |
1177 | | * otherwise %NULL. Release after usage. |
1178 | | */ |
1179 | | GstPad * |
1180 | | gst_element_get_request_pad (GstElement * element, const gchar * name) |
1181 | 0 | { |
1182 | 0 | return gst_element_request_pad_simple (element, name); |
1183 | 0 | } |
1184 | | #endif |
1185 | | |
1186 | | /** |
1187 | | * gst_element_request_pad_simple: |
1188 | | * @element: a #GstElement to find a request pad of. |
1189 | | * @name: the name of the request #GstPad to retrieve. |
1190 | | * |
1191 | | * Retrieves a pad from the element by name (e.g. "src_\%d"). This version only |
1192 | | * retrieves request pads. The pad should be released with |
1193 | | * gst_element_release_request_pad(). |
1194 | | * |
1195 | | * This method is slower than manually getting the pad template and calling |
1196 | | * gst_element_request_pad() if the pads should have a specific name (e.g. |
1197 | | * @name is "src_1" instead of "src_\%u"). |
1198 | | * |
1199 | | * Note that this function was introduced in GStreamer 1.20 in order to provide |
1200 | | * a better name to gst_element_get_request_pad(). Prior to 1.20, users |
1201 | | * should use gst_element_get_request_pad() which provides the same |
1202 | | * functionality. |
1203 | | * |
1204 | | * Returns: (transfer full) (nullable): requested #GstPad if found, |
1205 | | * otherwise %NULL. Release after usage. |
1206 | | * |
1207 | | * Since: 1.20 |
1208 | | */ |
1209 | | GstPad * |
1210 | | gst_element_request_pad_simple (GstElement * element, const gchar * name) |
1211 | 995 | { |
1212 | 995 | GstPadTemplate *templ = NULL; |
1213 | 995 | GstPad *pad; |
1214 | 995 | const gchar *req_name = NULL; |
1215 | 995 | gboolean templ_found = FALSE; |
1216 | 995 | GList *list; |
1217 | 995 | GstElementClass *class; |
1218 | | |
1219 | 995 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
1220 | 995 | g_return_val_if_fail (name != NULL, NULL); |
1221 | | |
1222 | 995 | class = GST_ELEMENT_GET_CLASS (element); |
1223 | | |
1224 | 995 | templ = gst_element_class_request_pad_simple_template (class, name); |
1225 | 995 | if (templ) { |
1226 | 995 | req_name = strstr (name, "%") ? NULL : name; |
1227 | 995 | templ_found = TRUE; |
1228 | 995 | } else { |
1229 | | /* there is no % in the name, try to find a matching template */ |
1230 | 0 | list = class->padtemplates; |
1231 | 0 | while (!templ_found && list) { |
1232 | 0 | templ = (GstPadTemplate *) list->data; |
1233 | 0 | if (templ->presence == GST_PAD_REQUEST) { |
1234 | 0 | GST_CAT_DEBUG (GST_CAT_PADS, "comparing %s to %s", name, |
1235 | 0 | templ->name_template); |
1236 | 0 | if (gst_element_is_valid_request_template_name (templ->name_template, |
1237 | 0 | name)) { |
1238 | 0 | templ_found = TRUE; |
1239 | 0 | req_name = name; |
1240 | 0 | break; |
1241 | 0 | } |
1242 | 0 | } |
1243 | 0 | list = list->next; |
1244 | 0 | } |
1245 | 0 | } |
1246 | | |
1247 | 995 | if (!templ_found) |
1248 | 0 | return NULL; |
1249 | | |
1250 | 995 | pad = _gst_element_request_pad (element, templ, req_name, NULL); |
1251 | | |
1252 | 995 | return pad; |
1253 | 995 | } |
1254 | | |
1255 | | /** |
1256 | | * gst_element_request_pad: (virtual request_new_pad) |
1257 | | * @element: a #GstElement to find a request pad of. |
1258 | | * @templ: a #GstPadTemplate of which we want a pad of. |
1259 | | * @name: (transfer none) (allow-none): the name of the request #GstPad |
1260 | | * to retrieve. Can be %NULL. |
1261 | | * @caps: (transfer none) (allow-none): the caps of the pad we want to |
1262 | | * request. Can be %NULL. |
1263 | | * |
1264 | | * Retrieves a request pad from the element according to the provided template. |
1265 | | * Pad templates can be looked up using |
1266 | | * gst_element_factory_get_static_pad_templates(). |
1267 | | * |
1268 | | * The pad should be released with gst_element_release_request_pad(). |
1269 | | * |
1270 | | * Returns: (transfer full) (nullable): requested #GstPad if found, |
1271 | | * otherwise %NULL. Release after usage. |
1272 | | */ |
1273 | | GstPad * |
1274 | | gst_element_request_pad (GstElement * element, |
1275 | | GstPadTemplate * templ, const gchar * name, const GstCaps * caps) |
1276 | 0 | { |
1277 | 0 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
1278 | 0 | g_return_val_if_fail (templ != NULL, NULL); |
1279 | 0 | g_return_val_if_fail (templ->presence == GST_PAD_REQUEST, NULL); |
1280 | | |
1281 | 0 | return _gst_element_request_pad (element, templ, name, caps); |
1282 | 0 | } |
1283 | | |
1284 | | static GstIterator * |
1285 | | gst_element_iterate_pad_list (GstElement * element, GList ** padlist) |
1286 | 529k | { |
1287 | 529k | GstIterator *result; |
1288 | | |
1289 | 529k | GST_OBJECT_LOCK (element); |
1290 | 529k | result = gst_iterator_new_list (GST_TYPE_PAD, |
1291 | 529k | GST_OBJECT_GET_LOCK (element), |
1292 | 529k | &element->pads_cookie, padlist, (GObject *) element, NULL); |
1293 | 529k | GST_OBJECT_UNLOCK (element); |
1294 | | |
1295 | 529k | return result; |
1296 | 529k | } |
1297 | | |
1298 | | /** |
1299 | | * gst_element_iterate_pads: |
1300 | | * @element: a #GstElement to iterate pads of. |
1301 | | * |
1302 | | * Retrieves an iterator of @element's pads. The iterator should |
1303 | | * be freed after usage. Also more specialized iterators exists such as |
1304 | | * gst_element_iterate_src_pads() or gst_element_iterate_sink_pads(). |
1305 | | * |
1306 | | * The order of pads returned by the iterator will be the order in which |
1307 | | * the pads were added to the element. |
1308 | | * |
1309 | | * Returns: (transfer full): the #GstIterator of #GstPad. |
1310 | | * |
1311 | | * MT safe. |
1312 | | */ |
1313 | | GstIterator * |
1314 | | gst_element_iterate_pads (GstElement * element) |
1315 | 96.0k | { |
1316 | 96.0k | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
1317 | | |
1318 | 96.0k | return gst_element_iterate_pad_list (element, &element->pads); |
1319 | 96.0k | } |
1320 | | |
1321 | | /** |
1322 | | * gst_element_iterate_src_pads: |
1323 | | * @element: a #GstElement. |
1324 | | * |
1325 | | * Retrieves an iterator of @element's source pads. |
1326 | | * |
1327 | | * The order of pads returned by the iterator will be the order in which |
1328 | | * the pads were added to the element. |
1329 | | * |
1330 | | * Returns: (transfer full): the #GstIterator of #GstPad. |
1331 | | * |
1332 | | * MT safe. |
1333 | | */ |
1334 | | GstIterator * |
1335 | | gst_element_iterate_src_pads (GstElement * element) |
1336 | 243k | { |
1337 | 243k | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
1338 | | |
1339 | 243k | return gst_element_iterate_pad_list (element, &element->srcpads); |
1340 | 243k | } |
1341 | | |
1342 | | /** |
1343 | | * gst_element_iterate_sink_pads: |
1344 | | * @element: a #GstElement. |
1345 | | * |
1346 | | * Retrieves an iterator of @element's sink pads. |
1347 | | * |
1348 | | * The order of pads returned by the iterator will be the order in which |
1349 | | * the pads were added to the element. |
1350 | | * |
1351 | | * Returns: (transfer full): the #GstIterator of #GstPad. |
1352 | | * |
1353 | | * MT safe. |
1354 | | */ |
1355 | | GstIterator * |
1356 | | gst_element_iterate_sink_pads (GstElement * element) |
1357 | 190k | { |
1358 | 190k | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
1359 | | |
1360 | 190k | return gst_element_iterate_pad_list (element, &element->sinkpads); |
1361 | 190k | } |
1362 | | |
1363 | | static gboolean |
1364 | | gst_element_do_foreach_pad (GstElement * element, |
1365 | | GstElementForeachPadFunc func, gpointer user_data, |
1366 | | GList ** p_pads, guint16 * p_npads) |
1367 | 5.42k | { |
1368 | 5.42k | gboolean ret = TRUE; |
1369 | 5.42k | GstPad **pads; |
1370 | 5.42k | guint n_pads, i; |
1371 | 5.42k | GList *l; |
1372 | | |
1373 | 5.42k | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
1374 | 5.42k | g_return_val_if_fail (func != NULL, FALSE); |
1375 | | |
1376 | 5.42k | GST_OBJECT_LOCK (element); |
1377 | 5.42k | n_pads = *p_npads; |
1378 | 5.42k | pads = g_newa (GstPad *, n_pads + 1); |
1379 | 10.8k | for (l = *p_pads, i = 0; l != NULL; l = l->next) { |
1380 | 5.42k | g_assert (i < n_pads); |
1381 | 5.42k | pads[i++] = gst_object_ref (l->data); |
1382 | 5.42k | } |
1383 | 5.42k | GST_OBJECT_UNLOCK (element); |
1384 | | |
1385 | 5.42k | if (n_pads == 0) |
1386 | 0 | return FALSE; |
1387 | | |
1388 | 10.8k | for (i = 0; i < n_pads; ++i) { |
1389 | 5.42k | ret = func (element, pads[i], user_data); |
1390 | 5.42k | if (!ret) |
1391 | 0 | break; |
1392 | 5.42k | } |
1393 | | |
1394 | 10.8k | for (i = 0; i < n_pads; ++i) |
1395 | 5.42k | gst_object_unref (pads[i]); |
1396 | | |
1397 | 5.42k | return ret; |
1398 | 5.42k | } |
1399 | | |
1400 | | /** |
1401 | | * gst_element_foreach_sink_pad: |
1402 | | * @element: a #GstElement to iterate sink pads of |
1403 | | * @func: (scope call) (closure user_data): function to call for each sink pad |
1404 | | * @user_data: user data passed to @func |
1405 | | * |
1406 | | * Call @func with @user_data for each of @element's sink pads. @func will be |
1407 | | * called exactly once for each sink pad that exists at the time of this call, |
1408 | | * unless one of the calls to @func returns %FALSE in which case we will stop |
1409 | | * iterating pads and return early. If new sink pads are added or sink pads |
1410 | | * are removed while the sink pads are being iterated, this will not be taken |
1411 | | * into account until next time this function is used. |
1412 | | * |
1413 | | * Returns: %FALSE if @element had no sink pads or if one of the calls to @func |
1414 | | * returned %FALSE. |
1415 | | * |
1416 | | * Since: 1.14 |
1417 | | */ |
1418 | | gboolean |
1419 | | gst_element_foreach_sink_pad (GstElement * element, |
1420 | | GstElementForeachPadFunc func, gpointer user_data) |
1421 | 0 | { |
1422 | 0 | return gst_element_do_foreach_pad (element, func, user_data, |
1423 | 0 | &element->sinkpads, &element->numsinkpads); |
1424 | 0 | } |
1425 | | |
1426 | | /** |
1427 | | * gst_element_foreach_src_pad: |
1428 | | * @element: a #GstElement to iterate source pads of |
1429 | | * @func: (scope call) (closure user_data): function to call for each source pad |
1430 | | * @user_data: user data passed to @func |
1431 | | * |
1432 | | * Call @func with @user_data for each of @element's source pads. @func will be |
1433 | | * called exactly once for each source pad that exists at the time of this call, |
1434 | | * unless one of the calls to @func returns %FALSE in which case we will stop |
1435 | | * iterating pads and return early. If new source pads are added or source pads |
1436 | | * are removed while the source pads are being iterated, this will not be taken |
1437 | | * into account until next time this function is used. |
1438 | | * |
1439 | | * Returns: %FALSE if @element had no source pads or if one of the calls |
1440 | | * to @func returned %FALSE. |
1441 | | * |
1442 | | * Since: 1.14 |
1443 | | */ |
1444 | | gboolean |
1445 | | gst_element_foreach_src_pad (GstElement * element, |
1446 | | GstElementForeachPadFunc func, gpointer user_data) |
1447 | 5.42k | { |
1448 | 5.42k | return gst_element_do_foreach_pad (element, func, user_data, |
1449 | 5.42k | &element->srcpads, &element->numsrcpads); |
1450 | 5.42k | } |
1451 | | |
1452 | | /** |
1453 | | * gst_element_foreach_pad: |
1454 | | * @element: a #GstElement to iterate pads of |
1455 | | * @func: (scope call) (closure user_data): function to call for each pad |
1456 | | * @user_data: user data passed to @func |
1457 | | * |
1458 | | * Call @func with @user_data for each of @element's pads. @func will be called |
1459 | | * exactly once for each pad that exists at the time of this call, unless |
1460 | | * one of the calls to @func returns %FALSE in which case we will stop |
1461 | | * iterating pads and return early. If new pads are added or pads are removed |
1462 | | * while pads are being iterated, this will not be taken into account until |
1463 | | * next time this function is used. |
1464 | | * |
1465 | | * Returns: %FALSE if @element had no pads or if one of the calls to @func |
1466 | | * returned %FALSE. |
1467 | | * |
1468 | | * Since: 1.14 |
1469 | | */ |
1470 | | gboolean |
1471 | | gst_element_foreach_pad (GstElement * element, GstElementForeachPadFunc func, |
1472 | | gpointer user_data) |
1473 | 0 | { |
1474 | 0 | return gst_element_do_foreach_pad (element, func, user_data, |
1475 | 0 | &element->pads, &element->numpads); |
1476 | 0 | } |
1477 | | |
1478 | | /** |
1479 | | * gst_element_class_add_pad_template: |
1480 | | * @klass: the #GstElementClass to add the pad template to. |
1481 | | * @templ: (transfer floating): a #GstPadTemplate to add to the element class. |
1482 | | * |
1483 | | * Adds a padtemplate to an element class. This is mainly used in the _class_init |
1484 | | * functions of classes. If a pad template with the same name as an already |
1485 | | * existing one is added the old one is replaced by the new one. |
1486 | | * |
1487 | | * @templ's reference count will be incremented, and any floating |
1488 | | * reference will be removed (see gst_object_ref_sink()) |
1489 | | * |
1490 | | */ |
1491 | | void |
1492 | | gst_element_class_add_pad_template (GstElementClass * klass, |
1493 | | GstPadTemplate * templ) |
1494 | 292 | { |
1495 | 292 | GList *template_list = klass->padtemplates; |
1496 | | |
1497 | 292 | g_return_if_fail (GST_IS_ELEMENT_CLASS (klass)); |
1498 | 292 | g_return_if_fail (GST_IS_PAD_TEMPLATE (templ)); |
1499 | | |
1500 | | /* If we already have a pad template with the same name replace the |
1501 | | * old one. */ |
1502 | 500 | while (template_list) { |
1503 | 208 | GstPadTemplate *padtempl = (GstPadTemplate *) template_list->data; |
1504 | | |
1505 | | /* Found pad with the same name, replace and return */ |
1506 | 208 | if (strcmp (templ->name_template, padtempl->name_template) == 0) { |
1507 | 0 | gst_object_unref (padtempl); |
1508 | 0 | gst_object_ref_sink (templ); |
1509 | 0 | template_list->data = templ; |
1510 | 0 | return; |
1511 | 0 | } |
1512 | 208 | template_list = g_list_next (template_list); |
1513 | 208 | } |
1514 | | |
1515 | | /* Take ownership of the floating ref */ |
1516 | 292 | gst_object_ref_sink (templ); |
1517 | | |
1518 | 292 | klass->padtemplates = g_list_append (klass->padtemplates, templ); |
1519 | 292 | klass->numpadtemplates++; |
1520 | 292 | } |
1521 | | |
1522 | | /** |
1523 | | * gst_element_class_add_static_pad_template: |
1524 | | * @klass: the #GstElementClass to add the pad template to. |
1525 | | * @static_templ: #GstStaticPadTemplate to add as pad template to the element class. |
1526 | | * |
1527 | | * Adds a pad template to an element class based on the static pad template |
1528 | | * @templ. This is mainly used in the _class_init functions of element |
1529 | | * implementations. If a pad template with the same name already exists, |
1530 | | * the old one is replaced by the new one. |
1531 | | * |
1532 | | * Since: 1.8 |
1533 | | */ |
1534 | | void |
1535 | | gst_element_class_add_static_pad_template (GstElementClass * klass, |
1536 | | GstStaticPadTemplate * static_templ) |
1537 | 214 | { |
1538 | 214 | gst_element_class_add_pad_template (klass, |
1539 | 214 | gst_static_pad_template_get (static_templ)); |
1540 | 214 | } |
1541 | | |
1542 | | /** |
1543 | | * gst_element_class_add_static_pad_template_with_gtype: |
1544 | | * @klass: the #GstElementClass to add the pad template to. |
1545 | | * @static_templ: #GstStaticPadTemplate to add as pad template to the element class. |
1546 | | * @pad_type: The #GType of the pad to create |
1547 | | * |
1548 | | * Adds a pad template to an element class based on the static pad template |
1549 | | * @templ. This is mainly used in the _class_init functions of element |
1550 | | * implementations. If a pad template with the same name already exists, |
1551 | | * the old one is replaced by the new one. |
1552 | | * |
1553 | | * Since: 1.14 |
1554 | | */ |
1555 | | void |
1556 | | gst_element_class_add_static_pad_template_with_gtype (GstElementClass * klass, |
1557 | | GstStaticPadTemplate * static_templ, GType pad_type) |
1558 | 18 | { |
1559 | 18 | gst_element_class_add_pad_template (klass, |
1560 | 18 | gst_pad_template_new_from_static_pad_template_with_gtype (static_templ, |
1561 | 18 | pad_type)); |
1562 | 18 | } |
1563 | | |
1564 | | /** |
1565 | | * gst_element_class_add_metadata: |
1566 | | * @klass: class to set metadata for |
1567 | | * @key: the key to set |
1568 | | * @value: the value to set |
1569 | | * |
1570 | | * Set @key with @value as metadata in @klass. |
1571 | | */ |
1572 | | void |
1573 | | gst_element_class_add_metadata (GstElementClass * klass, |
1574 | | const gchar * key, const gchar * value) |
1575 | 0 | { |
1576 | 0 | g_return_if_fail (GST_IS_ELEMENT_CLASS (klass)); |
1577 | 0 | g_return_if_fail (key != NULL); |
1578 | 0 | g_return_if_fail (value != NULL); |
1579 | | |
1580 | 0 | gst_structure_set ((GstStructure *) klass->metadata, |
1581 | 0 | key, G_TYPE_STRING, value, NULL); |
1582 | 0 | } |
1583 | | |
1584 | | /** |
1585 | | * gst_element_class_add_static_metadata: |
1586 | | * @klass: class to set metadata for |
1587 | | * @key: the key to set |
1588 | | * @value: the value to set |
1589 | | * |
1590 | | * Set @key with @value as metadata in @klass. |
1591 | | * |
1592 | | * Same as gst_element_class_add_metadata(), but @value must be a static string |
1593 | | * or an inlined string, as it will not be copied. (GStreamer plugins will |
1594 | | * be made resident once loaded, so this function can be used even from |
1595 | | * dynamically loaded plugins.) |
1596 | | */ |
1597 | | void |
1598 | | gst_element_class_add_static_metadata (GstElementClass * klass, |
1599 | | const gchar * key, const gchar * value) |
1600 | 0 | { |
1601 | 0 | GValue val = G_VALUE_INIT; |
1602 | |
|
1603 | 0 | g_return_if_fail (GST_IS_ELEMENT_CLASS (klass)); |
1604 | 0 | g_return_if_fail (key != NULL); |
1605 | 0 | g_return_if_fail (value != NULL); |
1606 | | |
1607 | 0 | g_value_init (&val, G_TYPE_STRING); |
1608 | 0 | g_value_set_static_string (&val, value); |
1609 | 0 | gst_structure_take_value ((GstStructure *) klass->metadata, key, &val); |
1610 | 0 | } |
1611 | | |
1612 | | /** |
1613 | | * gst_element_class_set_metadata: |
1614 | | * @klass: class to set metadata for |
1615 | | * @longname: The long English name of the element. E.g. "File Sink" |
1616 | | * @classification: String describing the type of element, as an unordered list |
1617 | | * separated with slashes ('/'). See draft-klass.txt of the design docs |
1618 | | * for more details and common types. E.g: "Sink/File" |
1619 | | * @description: Sentence describing the purpose of the element. |
1620 | | * E.g: "Write stream to a file" |
1621 | | * @author: Name and contact details of the author(s). Use \n to separate |
1622 | | * multiple author metadata. E.g: "Joe Bloggs <joe.blogs at foo.com>" |
1623 | | * |
1624 | | * Sets the detailed information for a #GstElementClass. |
1625 | | * > This function is for use in _class_init functions only. |
1626 | | */ |
1627 | | void |
1628 | | gst_element_class_set_metadata (GstElementClass * klass, |
1629 | | const gchar * longname, const gchar * classification, |
1630 | | const gchar * description, const gchar * author) |
1631 | 0 | { |
1632 | 0 | g_return_if_fail (GST_IS_ELEMENT_CLASS (klass)); |
1633 | 0 | g_return_if_fail (longname != NULL && *longname != '\0'); |
1634 | 0 | g_return_if_fail (classification != NULL && *classification != '\0'); |
1635 | 0 | g_return_if_fail (description != NULL && *description != '\0'); |
1636 | 0 | g_return_if_fail (author != NULL && *author != '\0'); |
1637 | | |
1638 | 0 | gst_structure_set_static_str ((GstStructure *) klass->metadata, |
1639 | 0 | GST_ELEMENT_METADATA_LONGNAME, G_TYPE_STRING, longname, |
1640 | 0 | GST_ELEMENT_METADATA_KLASS, G_TYPE_STRING, classification, |
1641 | 0 | GST_ELEMENT_METADATA_DESCRIPTION, G_TYPE_STRING, description, |
1642 | 0 | GST_ELEMENT_METADATA_AUTHOR, G_TYPE_STRING, author, NULL); |
1643 | 0 | } |
1644 | | |
1645 | | /** |
1646 | | * gst_element_class_set_static_metadata: |
1647 | | * @klass: class to set metadata for |
1648 | | * @longname: The long English name of the element. E.g. "File Sink" |
1649 | | * @classification: String describing the type of element, as an unordered list |
1650 | | * separated with slashes ('/'). See draft-klass.txt of the design docs |
1651 | | * for more details and common types. E.g: "Sink/File" |
1652 | | * @description: Sentence describing the purpose of the element. |
1653 | | * E.g: "Write stream to a file" |
1654 | | * @author: Name and contact details of the author(s). Use \n to separate |
1655 | | * multiple author metadata. E.g: "Joe Bloggs <joe.blogs at foo.com>" |
1656 | | * |
1657 | | * Sets the detailed information for a #GstElementClass. |
1658 | | * |
1659 | | * > This function is for use in _class_init functions only. |
1660 | | * |
1661 | | * Same as gst_element_class_set_metadata(), but @longname, @classification, |
1662 | | * @description, and @author must be static strings or inlined strings, as |
1663 | | * they will not be copied. (GStreamer plugins will be made resident once |
1664 | | * loaded, so this function can be used even from dynamically loaded plugins.) |
1665 | | */ |
1666 | | void |
1667 | | gst_element_class_set_static_metadata (GstElementClass * klass, |
1668 | | const gchar * longname, const gchar * classification, |
1669 | | const gchar * description, const gchar * author) |
1670 | 176 | { |
1671 | 176 | GstStructure *s = (GstStructure *) klass->metadata; |
1672 | 176 | GValue val = G_VALUE_INIT; |
1673 | | |
1674 | 176 | g_return_if_fail (GST_IS_ELEMENT_CLASS (klass)); |
1675 | 176 | g_return_if_fail (longname != NULL && *longname != '\0'); |
1676 | 176 | g_return_if_fail (classification != NULL && *classification != '\0'); |
1677 | 176 | g_return_if_fail (description != NULL && *description != '\0'); |
1678 | 176 | g_return_if_fail (author != NULL && *author != '\0'); |
1679 | | |
1680 | 176 | g_value_init (&val, G_TYPE_STRING); |
1681 | | |
1682 | 176 | g_value_set_static_string (&val, longname); |
1683 | 176 | gst_structure_set_value_static_str (s, GST_ELEMENT_METADATA_LONGNAME, &val); |
1684 | | |
1685 | 176 | g_value_set_static_string (&val, classification); |
1686 | 176 | gst_structure_set_value_static_str (s, GST_ELEMENT_METADATA_KLASS, &val); |
1687 | | |
1688 | 176 | g_value_set_static_string (&val, description); |
1689 | 176 | gst_structure_set_value_static_str (s, GST_ELEMENT_METADATA_DESCRIPTION, |
1690 | 176 | &val); |
1691 | | |
1692 | 176 | g_value_set_static_string (&val, author); |
1693 | 176 | gst_structure_take_value_static_str (s, GST_ELEMENT_METADATA_AUTHOR, &val); |
1694 | 176 | } |
1695 | | |
1696 | | /** |
1697 | | * gst_element_class_get_metadata: |
1698 | | * @klass: class to get metadata for |
1699 | | * @key: the key to get |
1700 | | * |
1701 | | * Get metadata with @key in @klass. |
1702 | | * |
1703 | | * Returns: the metadata for @key. |
1704 | | */ |
1705 | | const gchar * |
1706 | | gst_element_class_get_metadata (GstElementClass * klass, const gchar * key) |
1707 | 704 | { |
1708 | 704 | g_return_val_if_fail (GST_IS_ELEMENT_CLASS (klass), NULL); |
1709 | 704 | g_return_val_if_fail (key != NULL, NULL); |
1710 | | |
1711 | 704 | return gst_structure_get_string ((GstStructure *) klass->metadata, key); |
1712 | 704 | } |
1713 | | |
1714 | | /** |
1715 | | * gst_element_get_metadata: |
1716 | | * @element: class to get metadata for |
1717 | | * @key: the key to get |
1718 | | * |
1719 | | * Get metadata with @key in @klass. |
1720 | | * |
1721 | | * Returns: the metadata for @key. |
1722 | | * |
1723 | | * Since: 1.14 |
1724 | | */ |
1725 | | const gchar * |
1726 | | gst_element_get_metadata (GstElement * element, const gchar * key) |
1727 | 0 | { |
1728 | 0 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
1729 | 0 | g_return_val_if_fail (key != NULL, NULL); |
1730 | | |
1731 | 0 | return gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (element), key); |
1732 | 0 | } |
1733 | | |
1734 | | /** |
1735 | | * gst_element_class_get_pad_template_list: |
1736 | | * @element_class: a #GstElementClass to get pad templates of. |
1737 | | * |
1738 | | * Retrieves a list of the pad templates associated with @element_class. The |
1739 | | * list must not be modified by the calling code. |
1740 | | * > If you use this function in the GInstanceInitFunc of an object class |
1741 | | * > that has subclasses, make sure to pass the g_class parameter of the |
1742 | | * > GInstanceInitFunc here. |
1743 | | * |
1744 | | * Returns: (transfer none) (element-type Gst.PadTemplate): the #GList of |
1745 | | * pad templates. |
1746 | | */ |
1747 | | GList * |
1748 | | gst_element_class_get_pad_template_list (GstElementClass * element_class) |
1749 | 14 | { |
1750 | 14 | g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL); |
1751 | | |
1752 | 14 | return element_class->padtemplates; |
1753 | 14 | } |
1754 | | |
1755 | | /** |
1756 | | * gst_element_get_pad_template_list: |
1757 | | * @element: a #GstElement to get pad templates of. |
1758 | | * |
1759 | | * Retrieves a list of the pad templates associated with @element. The |
1760 | | * list must not be modified by the calling code. |
1761 | | * |
1762 | | * Returns: (transfer none) (element-type Gst.PadTemplate): the #GList of |
1763 | | * pad templates. |
1764 | | * |
1765 | | * Since: 1.14 |
1766 | | */ |
1767 | | GList * |
1768 | | gst_element_get_pad_template_list (GstElement * element) |
1769 | 0 | { |
1770 | 0 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
1771 | | |
1772 | 0 | return |
1773 | 0 | gst_element_class_get_pad_template_list (GST_ELEMENT_GET_CLASS (element)); |
1774 | 0 | } |
1775 | | |
1776 | | /** |
1777 | | * gst_element_class_get_pad_template: |
1778 | | * @element_class: a #GstElementClass to get the pad template of. |
1779 | | * @name: the name of the #GstPadTemplate to get. |
1780 | | * |
1781 | | * Retrieves a padtemplate from @element_class with the given name. |
1782 | | * > If you use this function in the GInstanceInitFunc of an object class |
1783 | | * > that has subclasses, make sure to pass the g_class parameter of the |
1784 | | * > GInstanceInitFunc here. |
1785 | | * |
1786 | | * Returns: (transfer none) (nullable): the #GstPadTemplate with the |
1787 | | * given name, or %NULL if none was found. No unreferencing is |
1788 | | * necessary. |
1789 | | */ |
1790 | | GstPadTemplate * |
1791 | | gst_element_class_get_pad_template (GstElementClass * |
1792 | | element_class, const gchar * name) |
1793 | 44.8k | { |
1794 | 44.8k | GList *padlist; |
1795 | | |
1796 | 44.8k | g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL); |
1797 | 44.8k | g_return_val_if_fail (name != NULL, NULL); |
1798 | | |
1799 | 44.8k | padlist = element_class->padtemplates; |
1800 | | |
1801 | 44.9k | while (padlist) { |
1802 | 44.9k | GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data; |
1803 | | |
1804 | 44.9k | if (strcmp (padtempl->name_template, name) == 0) |
1805 | 44.8k | return padtempl; |
1806 | | |
1807 | 91 | padlist = g_list_next (padlist); |
1808 | 91 | } |
1809 | | |
1810 | 1 | return NULL; |
1811 | 44.8k | } |
1812 | | |
1813 | | /** |
1814 | | * gst_element_get_pad_template: |
1815 | | * @element: a #GstElement to get the pad template of. |
1816 | | * @name: the name of the #GstPadTemplate to get. |
1817 | | * |
1818 | | * Retrieves a padtemplate from @element with the given name. |
1819 | | * |
1820 | | * Returns: (transfer none) (nullable): the #GstPadTemplate with the |
1821 | | * given name, or %NULL if none was found. No unreferencing is |
1822 | | * necessary. |
1823 | | * |
1824 | | * Since: 1.14 |
1825 | | */ |
1826 | | GstPadTemplate * |
1827 | | gst_element_get_pad_template (GstElement * element, const gchar * name) |
1828 | 0 | { |
1829 | 0 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
1830 | 0 | g_return_val_if_fail (name != NULL, NULL); |
1831 | | |
1832 | 0 | return gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (element), |
1833 | 0 | name); |
1834 | 0 | } |
1835 | | |
1836 | | static GstPadTemplate * |
1837 | | gst_element_class_request_pad_simple_template (GstElementClass * |
1838 | | element_class, const gchar * name) |
1839 | 995 | { |
1840 | 995 | GstPadTemplate *tmpl; |
1841 | | |
1842 | 995 | tmpl = gst_element_class_get_pad_template (element_class, name); |
1843 | 995 | if (tmpl != NULL && tmpl->presence == GST_PAD_REQUEST) |
1844 | 995 | return tmpl; |
1845 | | |
1846 | 0 | return NULL; |
1847 | 995 | } |
1848 | | |
1849 | | /* get a random pad on element of the given direction. |
1850 | | * The pad is random in a sense that it is the first pad that is (optionally) linked. |
1851 | | */ |
1852 | | static GstPad * |
1853 | | gst_element_get_random_pad (GstElement * element, |
1854 | | gboolean need_linked, GstPadDirection dir) |
1855 | 18.8k | { |
1856 | 18.8k | GstPad *result = NULL; |
1857 | 18.8k | GList *pads; |
1858 | | |
1859 | 18.8k | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "getting a random pad"); |
1860 | | |
1861 | 18.8k | switch (dir) { |
1862 | 18.8k | case GST_PAD_SRC: |
1863 | 18.8k | GST_OBJECT_LOCK (element); |
1864 | 18.8k | pads = element->srcpads; |
1865 | 18.8k | break; |
1866 | 0 | case GST_PAD_SINK: |
1867 | 0 | GST_OBJECT_LOCK (element); |
1868 | 0 | pads = element->sinkpads; |
1869 | 0 | break; |
1870 | 0 | default: |
1871 | 0 | goto wrong_direction; |
1872 | 18.8k | } |
1873 | 18.8k | for (; pads; pads = g_list_next (pads)) { |
1874 | 18.8k | GstPad *pad = GST_PAD_CAST (pads->data); |
1875 | | |
1876 | 18.8k | GST_OBJECT_LOCK (pad); |
1877 | 18.8k | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "checking pad %s:%s", |
1878 | 18.8k | GST_DEBUG_PAD_NAME (pad)); |
1879 | | |
1880 | 18.8k | if (need_linked && !GST_PAD_IS_LINKED (pad)) { |
1881 | | /* if we require a linked pad, and it is not linked, continue the |
1882 | | * search */ |
1883 | 0 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is not linked", |
1884 | 0 | GST_DEBUG_PAD_NAME (pad)); |
1885 | 0 | GST_OBJECT_UNLOCK (pad); |
1886 | 0 | continue; |
1887 | 18.8k | } else { |
1888 | | /* found a pad, stop search */ |
1889 | 18.8k | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "found pad %s:%s", |
1890 | 18.8k | GST_DEBUG_PAD_NAME (pad)); |
1891 | 18.8k | GST_OBJECT_UNLOCK (pad); |
1892 | 18.8k | result = pad; |
1893 | 18.8k | break; |
1894 | 18.8k | } |
1895 | 18.8k | } |
1896 | 18.8k | if (result) |
1897 | 18.8k | gst_object_ref (result); |
1898 | | |
1899 | 18.8k | GST_OBJECT_UNLOCK (element); |
1900 | | |
1901 | 18.8k | return result; |
1902 | | |
1903 | | /* ERROR handling */ |
1904 | 0 | wrong_direction: |
1905 | 0 | { |
1906 | 0 | g_warning ("unknown pad direction %d", dir); |
1907 | 0 | return NULL; |
1908 | 18.8k | } |
1909 | 18.8k | } |
1910 | | |
1911 | | static gboolean |
1912 | | gst_element_default_send_event (GstElement * element, GstEvent * event) |
1913 | 0 | { |
1914 | 0 | gboolean result = FALSE; |
1915 | 0 | GstPad *pad; |
1916 | |
|
1917 | 0 | pad = GST_EVENT_IS_DOWNSTREAM (event) ? |
1918 | 0 | gst_element_get_random_pad (element, TRUE, GST_PAD_SINK) : |
1919 | 0 | gst_element_get_random_pad (element, TRUE, GST_PAD_SRC); |
1920 | |
|
1921 | 0 | if (pad) { |
1922 | 0 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, |
1923 | 0 | "pushing %s event to random %s pad %s:%s", |
1924 | 0 | GST_EVENT_TYPE_NAME (event), |
1925 | 0 | (GST_PAD_DIRECTION (pad) == GST_PAD_SRC ? "src" : "sink"), |
1926 | 0 | GST_DEBUG_PAD_NAME (pad)); |
1927 | |
|
1928 | 0 | result = gst_pad_send_event (pad, event); |
1929 | 0 | gst_object_unref (pad); |
1930 | 0 | } else { |
1931 | 0 | GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "can't send %s event on element %s", |
1932 | 0 | GST_EVENT_TYPE_NAME (event), GST_ELEMENT_NAME (element)); |
1933 | 0 | gst_event_unref (event); |
1934 | 0 | } |
1935 | 0 | return result; |
1936 | 0 | } |
1937 | | |
1938 | | /** |
1939 | | * gst_element_send_event: |
1940 | | * @element: a #GstElement to send the event to. |
1941 | | * @event: (transfer full): the #GstEvent to send to the element. |
1942 | | * |
1943 | | * Sends an event to an element. If the element doesn't implement an |
1944 | | * event handler, the event will be pushed on a random linked sink pad for |
1945 | | * downstream events or a random linked source pad for upstream events. |
1946 | | * |
1947 | | * This function takes ownership of the provided event so you should |
1948 | | * gst_event_ref() it if you want to reuse the event after this call. |
1949 | | * |
1950 | | * MT safe. |
1951 | | * |
1952 | | * Returns: %TRUE if the event was handled. Events that trigger a preroll (such |
1953 | | * as flushing seeks and steps) will emit %GST_MESSAGE_ASYNC_DONE. |
1954 | | */ |
1955 | | gboolean |
1956 | | gst_element_send_event (GstElement * element, GstEvent * event) |
1957 | 24 | { |
1958 | 24 | GstElementClass *oclass; |
1959 | 24 | gboolean result = FALSE; |
1960 | | |
1961 | 24 | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
1962 | 24 | g_return_val_if_fail (event != NULL, FALSE); |
1963 | | |
1964 | 24 | oclass = GST_ELEMENT_GET_CLASS (element); |
1965 | | |
1966 | 24 | GST_STATE_LOCK (element); |
1967 | 24 | if (oclass->send_event) { |
1968 | 24 | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "send %s event on element %s", |
1969 | 24 | GST_EVENT_TYPE_NAME (event), GST_ELEMENT_NAME (element)); |
1970 | 24 | result = oclass->send_event (element, event); |
1971 | 24 | } else { |
1972 | 0 | gst_event_unref (event); |
1973 | 0 | } |
1974 | 24 | GST_STATE_UNLOCK (element); |
1975 | | |
1976 | 24 | return result; |
1977 | 24 | } |
1978 | | |
1979 | | /** |
1980 | | * gst_element_seek: |
1981 | | * @element: a #GstElement to send the event to. |
1982 | | * @rate: The new playback rate |
1983 | | * @format: The format of the seek values |
1984 | | * @flags: The optional seek flags. |
1985 | | * @start_type: The type and flags for the new start position |
1986 | | * @start: The value of the new start position |
1987 | | * @stop_type: The type and flags for the new stop position |
1988 | | * @stop: The value of the new stop position |
1989 | | * |
1990 | | * Sends a seek event to an element. See gst_event_new_seek() for the details of |
1991 | | * the parameters. The seek event is sent to the element using |
1992 | | * gst_element_send_event(). |
1993 | | * |
1994 | | * MT safe. |
1995 | | * |
1996 | | * Returns: %TRUE if the event was handled. Flushing seeks will trigger a |
1997 | | * preroll, which will emit %GST_MESSAGE_ASYNC_DONE. |
1998 | | */ |
1999 | | gboolean |
2000 | | gst_element_seek (GstElement * element, gdouble rate, GstFormat format, |
2001 | | GstSeekFlags flags, GstSeekType start_type, gint64 start, |
2002 | | GstSeekType stop_type, gint64 stop) |
2003 | 0 | { |
2004 | 0 | GstEvent *event; |
2005 | 0 | gboolean result; |
2006 | |
|
2007 | 0 | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
2008 | | |
2009 | 0 | event = |
2010 | 0 | gst_event_new_seek (rate, format, flags, start_type, start, stop_type, |
2011 | 0 | stop); |
2012 | 0 | result = gst_element_send_event (element, event); |
2013 | |
|
2014 | 0 | return result; |
2015 | 0 | } |
2016 | | |
2017 | | static gboolean |
2018 | | gst_element_default_query (GstElement * element, GstQuery * query) |
2019 | 18.8k | { |
2020 | 18.8k | gboolean result = FALSE; |
2021 | 18.8k | GstPad *pad; |
2022 | | |
2023 | 18.8k | pad = gst_element_get_random_pad (element, FALSE, GST_PAD_SRC); |
2024 | 18.8k | if (pad) { |
2025 | 18.8k | result = gst_pad_query (pad, query); |
2026 | | |
2027 | 18.8k | gst_object_unref (pad); |
2028 | 18.8k | } else { |
2029 | 0 | pad = gst_element_get_random_pad (element, TRUE, GST_PAD_SINK); |
2030 | 0 | if (pad) { |
2031 | 0 | GstPad *peer = gst_pad_get_peer (pad); |
2032 | |
|
2033 | 0 | if (peer) { |
2034 | 0 | result = gst_pad_query (peer, query); |
2035 | |
|
2036 | 0 | gst_object_unref (peer); |
2037 | 0 | } |
2038 | 0 | gst_object_unref (pad); |
2039 | 0 | } |
2040 | 0 | } |
2041 | 18.8k | return result; |
2042 | 18.8k | } |
2043 | | |
2044 | | /** |
2045 | | * gst_element_query: |
2046 | | * @element: a #GstElement to perform the query on. |
2047 | | * @query: (transfer none): the #GstQuery. |
2048 | | * |
2049 | | * Performs a query on the given element. |
2050 | | * |
2051 | | * For elements that don't implement a query handler, this function |
2052 | | * forwards the query to a random srcpad or to the peer of a |
2053 | | * random linked sinkpad of this element. |
2054 | | * |
2055 | | * Please note that some queries might need a running pipeline to work. |
2056 | | * |
2057 | | * Returns: %TRUE if the query could be performed. |
2058 | | * |
2059 | | * MT safe. |
2060 | | */ |
2061 | | gboolean |
2062 | | gst_element_query (GstElement * element, GstQuery * query) |
2063 | 18.9k | { |
2064 | 18.9k | GstElementClass *klass; |
2065 | 18.9k | gboolean res = FALSE; |
2066 | | |
2067 | 18.9k | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
2068 | 18.9k | g_return_val_if_fail (query != NULL, FALSE); |
2069 | | |
2070 | 18.9k | GST_TRACER_ELEMENT_QUERY_PRE (element, query); |
2071 | | |
2072 | 18.9k | klass = GST_ELEMENT_GET_CLASS (element); |
2073 | 18.9k | if (klass->query) { |
2074 | 18.9k | GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "send query on element %s", |
2075 | 18.9k | GST_ELEMENT_NAME (element)); |
2076 | 18.9k | res = klass->query (element, query); |
2077 | 18.9k | } |
2078 | | |
2079 | 18.9k | GST_TRACER_ELEMENT_QUERY_POST (element, query, res); |
2080 | 18.9k | return res; |
2081 | 18.9k | } |
2082 | | |
2083 | | static gboolean |
2084 | | gst_element_post_message_default (GstElement * element, GstMessage * message) |
2085 | 804k | { |
2086 | 804k | GstBus *bus; |
2087 | 804k | gboolean result = FALSE; |
2088 | | |
2089 | 804k | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
2090 | 804k | g_return_val_if_fail (message != NULL, FALSE); |
2091 | | |
2092 | 804k | GST_OBJECT_LOCK (element); |
2093 | 804k | bus = element->bus; |
2094 | | |
2095 | 804k | if (G_UNLIKELY (bus == NULL)) |
2096 | 3.57k | goto no_bus; |
2097 | | |
2098 | 800k | gst_object_ref (bus); |
2099 | 800k | GST_OBJECT_UNLOCK (element); |
2100 | | |
2101 | | /* we release the element lock when posting the message so that any |
2102 | | * (synchronous) message handlers can operate on the element */ |
2103 | 800k | result = gst_bus_post (bus, message); |
2104 | 800k | gst_object_unref (bus); |
2105 | | |
2106 | 800k | return result; |
2107 | | |
2108 | | /* ERRORS */ |
2109 | 3.57k | no_bus: |
2110 | 3.57k | { |
2111 | 3.57k | GST_CAT_DEBUG_OBJECT (GST_CAT_MESSAGE, element, |
2112 | 3.57k | "not posting message %p: no bus", message); |
2113 | 3.57k | GST_OBJECT_UNLOCK (element); |
2114 | 3.57k | gst_message_unref (message); |
2115 | 3.57k | return FALSE; |
2116 | 804k | } |
2117 | 804k | } |
2118 | | |
2119 | | /** |
2120 | | * gst_element_post_message: |
2121 | | * @element: a #GstElement posting the message |
2122 | | * @message: (transfer full): a #GstMessage to post |
2123 | | * |
2124 | | * Post a message on the element's #GstBus. This function takes ownership of the |
2125 | | * message; if you want to access the message after this call, you should add an |
2126 | | * additional reference before calling. |
2127 | | * |
2128 | | * Returns: %TRUE if the message was successfully posted. The function returns |
2129 | | * %FALSE if the element did not have a bus. |
2130 | | * |
2131 | | * MT safe. |
2132 | | */ |
2133 | | gboolean |
2134 | | gst_element_post_message (GstElement * element, GstMessage * message) |
2135 | 804k | { |
2136 | 804k | GstElementClass *klass; |
2137 | 804k | gboolean res = FALSE; |
2138 | | |
2139 | 804k | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
2140 | 804k | g_return_val_if_fail (message != NULL, FALSE); |
2141 | | |
2142 | 804k | GST_TRACER_ELEMENT_POST_MESSAGE_PRE (element, message); |
2143 | | |
2144 | 804k | klass = GST_ELEMENT_GET_CLASS (element); |
2145 | 804k | if (klass->post_message) |
2146 | 804k | res = klass->post_message (element, message); |
2147 | 18.4E | else |
2148 | 18.4E | gst_message_unref (message); |
2149 | | |
2150 | 804k | GST_TRACER_ELEMENT_POST_MESSAGE_POST (element, res); |
2151 | 804k | return res; |
2152 | 804k | } |
2153 | | |
2154 | | /** |
2155 | | * _gst_element_error_printf: |
2156 | | * @format: (allow-none): the printf-like format to use, or %NULL |
2157 | | * |
2158 | | * This function is only used internally by the gst_element_error() macro. |
2159 | | * |
2160 | | * Returns: (transfer full) (nullable): a newly allocated string, or |
2161 | | * %NULL if the format was %NULL or "" |
2162 | | * |
2163 | | * MT safe. |
2164 | | */ |
2165 | | gchar * |
2166 | | _gst_element_error_printf (const gchar * format, ...) |
2167 | 19.2k | { |
2168 | 19.2k | va_list args; |
2169 | 19.2k | gchar *buffer; |
2170 | 19.2k | int len; |
2171 | | |
2172 | 19.2k | if (format == NULL) |
2173 | 18.2k | return NULL; |
2174 | 984 | if (format[0] == 0) |
2175 | 0 | return NULL; |
2176 | | |
2177 | 984 | va_start (args, format); |
2178 | | |
2179 | 984 | len = __gst_vasprintf (&buffer, format, args); |
2180 | | |
2181 | 984 | va_end (args); |
2182 | | |
2183 | 984 | if (len < 0) |
2184 | 0 | buffer = NULL; |
2185 | | |
2186 | 984 | return buffer; |
2187 | 984 | } |
2188 | | |
2189 | | /** |
2190 | | * gst_element_message_full_with_details: |
2191 | | * @element: a #GstElement to send message from |
2192 | | * @type: the #GstMessageType |
2193 | | * @domain: the GStreamer GError domain this message belongs to |
2194 | | * @code: the GError code belonging to the domain |
2195 | | * @text: (allow-none) (transfer full): an allocated text string to be used |
2196 | | * as a replacement for the default message connected to code, |
2197 | | * or %NULL |
2198 | | * @debug: (allow-none) (transfer full): an allocated debug message to be |
2199 | | * used as a replacement for the default debugging information, |
2200 | | * or %NULL |
2201 | | * @file: the source code file where the error was generated |
2202 | | * @function: the source code function where the error was generated |
2203 | | * @line: the source code line where the error was generated |
2204 | | * @structure:(transfer full): optional details structure |
2205 | | * |
2206 | | * Post an error, warning or info message on the bus from inside an element. |
2207 | | * |
2208 | | * @type must be of #GST_MESSAGE_ERROR, #GST_MESSAGE_WARNING or |
2209 | | * #GST_MESSAGE_INFO. |
2210 | | * |
2211 | | * Since: 1.10 |
2212 | | */ |
2213 | | void gst_element_message_full_with_details |
2214 | | (GstElement * element, GstMessageType type, |
2215 | | GQuark domain, gint code, gchar * text, |
2216 | | gchar * debug, const gchar * file, const gchar * function, gint line, |
2217 | | GstStructure * structure) |
2218 | 9.62k | { |
2219 | 9.62k | GError *gerror = NULL; |
2220 | 9.62k | gchar *name; |
2221 | 9.62k | gchar *sent_text; |
2222 | 9.62k | gchar *sent_debug; |
2223 | 9.62k | gboolean has_debug = TRUE; |
2224 | 9.62k | GstMessage *message = NULL; |
2225 | | |
2226 | | /* checks */ |
2227 | 9.62k | GST_CAT_DEBUG_OBJECT (GST_CAT_MESSAGE, element, "start"); |
2228 | 9.62k | g_return_if_fail (GST_IS_ELEMENT (element)); |
2229 | 9.62k | g_return_if_fail ((type == GST_MESSAGE_ERROR) || |
2230 | 9.62k | (type == GST_MESSAGE_WARNING) || (type == GST_MESSAGE_INFO)); |
2231 | | |
2232 | | /* check if we send the given text or the default error text */ |
2233 | 9.62k | if ((text == NULL) || (text[0] == 0)) { |
2234 | | /* text could have come from g_strdup_printf (""); */ |
2235 | 9.18k | g_free (text); |
2236 | 9.18k | sent_text = gst_error_get_message (domain, code); |
2237 | 9.18k | } else |
2238 | 445 | sent_text = text; |
2239 | | |
2240 | | /* construct a sent_debug with extra information from source */ |
2241 | 9.62k | if ((debug == NULL) || (debug[0] == 0)) { |
2242 | | /* debug could have come from g_strdup_printf (""); */ |
2243 | 9.08k | has_debug = FALSE; |
2244 | 9.08k | } |
2245 | | |
2246 | 9.62k | name = gst_object_get_path_string (GST_OBJECT_CAST (element)); |
2247 | 9.62k | if (has_debug) |
2248 | 539 | sent_debug = g_strdup_printf ("%s(%d): %s (): %s:\n%s", |
2249 | 539 | file, line, function, name, debug); |
2250 | 9.08k | else |
2251 | 9.08k | sent_debug = g_strdup_printf ("%s(%d): %s (): %s", |
2252 | 9.08k | file, line, function, name); |
2253 | 9.62k | g_free (name); |
2254 | 9.62k | g_free (debug); |
2255 | | |
2256 | | /* create gerror and post message */ |
2257 | 9.62k | GST_CAT_INFO_OBJECT (GST_CAT_ERROR_SYSTEM, element, "posting message: %s", |
2258 | 9.62k | sent_text); |
2259 | 9.62k | gerror = g_error_new_literal (domain, code, sent_text); |
2260 | | |
2261 | 9.62k | switch (type) { |
2262 | 9.54k | case GST_MESSAGE_ERROR: |
2263 | 9.54k | message = |
2264 | 9.54k | gst_message_new_error_with_details (GST_OBJECT_CAST (element), gerror, |
2265 | 9.54k | sent_debug, structure); |
2266 | 9.54k | break; |
2267 | 87 | case GST_MESSAGE_WARNING: |
2268 | 87 | message = |
2269 | 87 | gst_message_new_warning_with_details (GST_OBJECT_CAST (element), |
2270 | 87 | gerror, sent_debug, structure); |
2271 | 87 | break; |
2272 | 0 | case GST_MESSAGE_INFO: |
2273 | 0 | message = |
2274 | 0 | gst_message_new_info_with_details (GST_OBJECT_CAST (element), gerror, |
2275 | 0 | sent_debug, structure); |
2276 | 0 | break; |
2277 | 0 | default: |
2278 | 0 | g_assert_not_reached (); |
2279 | 0 | break; |
2280 | 9.62k | } |
2281 | | |
2282 | 9.62k | gst_element_post_message (element, message); |
2283 | | |
2284 | 9.62k | GST_CAT_INFO_OBJECT (GST_CAT_ERROR_SYSTEM, element, "posted %s message: %s", |
2285 | 9.62k | (type == GST_MESSAGE_ERROR ? "error" : "warning"), sent_text); |
2286 | | |
2287 | | /* cleanup */ |
2288 | 9.62k | g_error_free (gerror); |
2289 | 9.62k | g_free (sent_debug); |
2290 | 9.62k | g_free (sent_text); |
2291 | 9.62k | } |
2292 | | |
2293 | | /** |
2294 | | * gst_element_message_full: |
2295 | | * @element: a #GstElement to send message from |
2296 | | * @type: the #GstMessageType |
2297 | | * @domain: the GStreamer GError domain this message belongs to |
2298 | | * @code: the GError code belonging to the domain |
2299 | | * @text: (allow-none) (transfer full): an allocated text string to be used |
2300 | | * as a replacement for the default message connected to code, |
2301 | | * or %NULL |
2302 | | * @debug: (allow-none) (transfer full): an allocated debug message to be |
2303 | | * used as a replacement for the default debugging information, |
2304 | | * or %NULL |
2305 | | * @file: the source code file where the error was generated |
2306 | | * @function: the source code function where the error was generated |
2307 | | * @line: the source code line where the error was generated |
2308 | | * |
2309 | | * Post an error, warning or info message on the bus from inside an element. |
2310 | | * |
2311 | | * @type must be of #GST_MESSAGE_ERROR, #GST_MESSAGE_WARNING or |
2312 | | * #GST_MESSAGE_INFO. |
2313 | | * |
2314 | | * MT safe. |
2315 | | */ |
2316 | | void gst_element_message_full |
2317 | | (GstElement * element, GstMessageType type, |
2318 | | GQuark domain, gint code, gchar * text, |
2319 | | gchar * debug, const gchar * file, const gchar * function, gint line) |
2320 | 9.52k | { |
2321 | 9.52k | gst_element_message_full_with_details (element, type, domain, code, text, |
2322 | 9.52k | debug, file, function, line, NULL); |
2323 | 9.52k | } |
2324 | | |
2325 | | /** |
2326 | | * gst_element_is_locked_state: |
2327 | | * @element: a #GstElement. |
2328 | | * |
2329 | | * Checks if the state of an element is locked. |
2330 | | * If the state of an element is locked, state changes of the parent don't |
2331 | | * affect the element. |
2332 | | * This way you can leave currently unused elements inside bins. Just lock their |
2333 | | * state before changing the state from #GST_STATE_NULL. |
2334 | | * |
2335 | | * MT safe. |
2336 | | * |
2337 | | * Returns: %TRUE, if the element's state is locked. |
2338 | | */ |
2339 | | gboolean |
2340 | | gst_element_is_locked_state (GstElement * element) |
2341 | 0 | { |
2342 | 0 | gboolean result; |
2343 | |
|
2344 | 0 | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
2345 | | |
2346 | 0 | GST_OBJECT_LOCK (element); |
2347 | 0 | result = GST_ELEMENT_IS_LOCKED_STATE (element); |
2348 | 0 | GST_OBJECT_UNLOCK (element); |
2349 | |
|
2350 | 0 | return result; |
2351 | 0 | } |
2352 | | |
2353 | | /** |
2354 | | * gst_element_set_locked_state: |
2355 | | * @element: a #GstElement |
2356 | | * @locked_state: %TRUE to lock the element's state |
2357 | | * |
2358 | | * Locks the state of an element, so state changes of the parent don't affect |
2359 | | * this element anymore. |
2360 | | * |
2361 | | * Note that this is racy if the state lock of the parent bin is not taken. |
2362 | | * The parent bin might've just checked the flag in another thread and as the |
2363 | | * next step proceed to change the child element's state. |
2364 | | * |
2365 | | * MT safe. |
2366 | | * |
2367 | | * Returns: %TRUE if the state was changed, %FALSE if bad parameters were given |
2368 | | * or the elements state-locking needed no change. |
2369 | | */ |
2370 | | gboolean |
2371 | | gst_element_set_locked_state (GstElement * element, gboolean locked_state) |
2372 | 624 | { |
2373 | 624 | gboolean old; |
2374 | | |
2375 | 624 | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
2376 | | |
2377 | 624 | GST_OBJECT_LOCK (element); |
2378 | 624 | old = GST_ELEMENT_IS_LOCKED_STATE (element); |
2379 | | |
2380 | 624 | if (G_UNLIKELY (old == locked_state)) |
2381 | 0 | goto was_ok; |
2382 | | |
2383 | 624 | if (locked_state) { |
2384 | 511 | GST_CAT_DEBUG (GST_CAT_STATES, "locking state of element %s", |
2385 | 511 | GST_ELEMENT_NAME (element)); |
2386 | 511 | GST_OBJECT_FLAG_SET (element, GST_ELEMENT_FLAG_LOCKED_STATE); |
2387 | 511 | } else { |
2388 | 113 | GST_CAT_DEBUG (GST_CAT_STATES, "unlocking state of element %s", |
2389 | 113 | GST_ELEMENT_NAME (element)); |
2390 | 113 | GST_OBJECT_FLAG_UNSET (element, GST_ELEMENT_FLAG_LOCKED_STATE); |
2391 | 113 | } |
2392 | 624 | GST_OBJECT_UNLOCK (element); |
2393 | | |
2394 | 624 | return TRUE; |
2395 | | |
2396 | 0 | was_ok: |
2397 | 0 | { |
2398 | 0 | GST_CAT_DEBUG (GST_CAT_STATES, |
2399 | 0 | "elements %s was already in locked state %d", |
2400 | 0 | GST_ELEMENT_NAME (element), old); |
2401 | 0 | GST_OBJECT_UNLOCK (element); |
2402 | |
|
2403 | 0 | return FALSE; |
2404 | 624 | } |
2405 | 624 | } |
2406 | | |
2407 | | /** |
2408 | | * gst_element_sync_state_with_parent: |
2409 | | * @element: a #GstElement. |
2410 | | * |
2411 | | * Tries to change the state of the element to the same as its parent. |
2412 | | * If this function returns %FALSE, the state of element is undefined. |
2413 | | * |
2414 | | * Returns: %TRUE, if the element's state could be synced to the parent's state. |
2415 | | * |
2416 | | * MT safe. |
2417 | | */ |
2418 | | gboolean |
2419 | | gst_element_sync_state_with_parent (GstElement * element) |
2420 | 12.0k | { |
2421 | 12.0k | GstElement *parent; |
2422 | 12.0k | GstState target; |
2423 | 12.0k | GstStateChangeReturn ret; |
2424 | | |
2425 | 12.0k | g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); |
2426 | | |
2427 | 12.0k | if ((parent = GST_ELEMENT_CAST (gst_element_get_parent (element)))) { |
2428 | 12.0k | GstState parent_current, parent_pending; |
2429 | | |
2430 | 12.0k | GST_OBJECT_LOCK (parent); |
2431 | 12.0k | parent_current = GST_STATE (parent); |
2432 | 12.0k | parent_pending = GST_STATE_PENDING (parent); |
2433 | 12.0k | GST_OBJECT_UNLOCK (parent); |
2434 | | |
2435 | | /* set to pending if there is one, else we set it to the current state of |
2436 | | * the parent */ |
2437 | 12.0k | if (parent_pending != GST_STATE_VOID_PENDING) |
2438 | 11.0k | target = parent_pending; |
2439 | 983 | else |
2440 | 983 | target = parent_current; |
2441 | | |
2442 | 12.0k | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
2443 | 12.0k | "syncing state (%s) to parent %s %s (%s, %s)", |
2444 | 12.0k | gst_state_get_name (GST_STATE (element)), |
2445 | 12.0k | GST_ELEMENT_NAME (parent), gst_state_get_name (target), |
2446 | 12.0k | gst_state_get_name (parent_current), |
2447 | 12.0k | gst_state_get_name (parent_pending)); |
2448 | | |
2449 | 12.0k | ret = gst_element_set_state (element, target); |
2450 | 12.0k | if (ret == GST_STATE_CHANGE_FAILURE) |
2451 | 0 | goto failed; |
2452 | | |
2453 | 12.0k | gst_object_unref (parent); |
2454 | | |
2455 | 12.0k | return TRUE; |
2456 | 12.0k | } else { |
2457 | 0 | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "element has no parent"); |
2458 | 0 | } |
2459 | 0 | return FALSE; |
2460 | | |
2461 | | /* ERROR */ |
2462 | 0 | failed: |
2463 | 0 | { |
2464 | 0 | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
2465 | 0 | "syncing state failed (%s)", gst_state_change_return_get_name (ret)); |
2466 | 0 | gst_object_unref (parent); |
2467 | 0 | return FALSE; |
2468 | 12.0k | } |
2469 | 12.0k | } |
2470 | | |
2471 | | /* MT safe */ |
2472 | | static GstStateChangeReturn |
2473 | | gst_element_get_state_func (GstElement * element, |
2474 | | GstState * state, GstState * pending, GstClockTime timeout) |
2475 | 34.7k | { |
2476 | 34.7k | GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE; |
2477 | 34.7k | GstState old_pending; |
2478 | 34.7k | gint64 end_time; |
2479 | | |
2480 | 34.7k | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "getting state, timeout %" |
2481 | 34.7k | GST_TIME_FORMAT, GST_TIME_ARGS (timeout)); |
2482 | | |
2483 | 34.7k | GST_OBJECT_LOCK (element); |
2484 | | |
2485 | 34.7k | if (timeout != GST_CLOCK_TIME_NONE) { |
2486 | | /* make timeout absolute */ |
2487 | 26.7k | end_time = g_get_monotonic_time () + (timeout / 1000); |
2488 | 26.7k | } |
2489 | | |
2490 | 38.7k | do { |
2491 | 38.7k | ret = GST_STATE_RETURN (element); |
2492 | 38.7k | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "RETURN is %s", |
2493 | 38.7k | gst_state_change_return_get_name (ret)); |
2494 | | |
2495 | | /* we got an error, report immediately */ |
2496 | 38.7k | if (ret == GST_STATE_CHANGE_FAILURE) |
2497 | 4.00k | goto done; |
2498 | | |
2499 | | /* we got no_preroll, report immediately */ |
2500 | 34.7k | if (ret == GST_STATE_CHANGE_NO_PREROLL) |
2501 | 0 | goto done; |
2502 | | |
2503 | | /* no need to wait async if we are not async */ |
2504 | 34.7k | if (ret != GST_STATE_CHANGE_ASYNC) |
2505 | 13.3k | goto done; |
2506 | | |
2507 | 21.3k | old_pending = GST_STATE_PENDING (element); |
2508 | 21.3k | if (old_pending != GST_STATE_VOID_PENDING) { |
2509 | 21.3k | gboolean signaled = TRUE; |
2510 | 21.3k | guint32 cookie; |
2511 | | |
2512 | | /* get cookie to detect state changes during waiting */ |
2513 | 21.3k | cookie = element->state_cookie; |
2514 | | |
2515 | 21.3k | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
2516 | 21.3k | "waiting for element to commit state"); |
2517 | | |
2518 | | /* we have a pending state change, wait for it to complete or for |
2519 | | an interruption */ |
2520 | 21.3k | if (timeout != GST_CLOCK_TIME_NONE) { |
2521 | 13.3k | signaled = GST_STATE_WAIT_UNTIL (element, end_time); |
2522 | 13.3k | } else { |
2523 | 7.96k | GST_STATE_WAIT (element); |
2524 | 7.96k | signaled = TRUE; |
2525 | 7.96k | } |
2526 | | |
2527 | 21.3k | if (!signaled) { |
2528 | 13.3k | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "timed out"); |
2529 | | /* timeout triggered */ |
2530 | 13.3k | ret = GST_STATE_CHANGE_ASYNC; |
2531 | 13.3k | goto done; |
2532 | 13.3k | } else { |
2533 | 7.96k | if (cookie != element->state_cookie) |
2534 | 0 | goto interrupted; |
2535 | | |
2536 | | /* could be success or failure */ |
2537 | 7.96k | if (old_pending == GST_STATE (element)) { |
2538 | 3.95k | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "got success"); |
2539 | 3.95k | ret = GST_STATE_CHANGE_SUCCESS; |
2540 | 4.00k | } else { |
2541 | 4.00k | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "got failure"); |
2542 | 4.00k | ret = GST_STATE_CHANGE_FAILURE; |
2543 | 4.00k | } |
2544 | 7.96k | } |
2545 | | /* if nothing is pending anymore we can return SUCCESS */ |
2546 | 7.96k | if (GST_STATE_PENDING (element) == GST_STATE_VOID_PENDING) { |
2547 | 3.95k | GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, "nothing pending"); |
2548 | 3.95k | ret = GST_STATE_CHANGE_SUCCESS; |
2549 | 3.95k | } |
2550 | 7.96k | } |
2551 | 21.3k | } while (old_pending != GST_STATE (element)); |
2552 | | |
2553 | 34.7k | done: |
2554 | 34.7k | if (state) |
2555 | 34.7k | *state = GST_STATE (element); |
2556 | 34.7k | if (pending) |
2557 | 0 | *pending = GST_STATE_PENDING (element); |
2558 | | |
2559 | 34.7k | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
2560 | 34.7k | "state current: %s, pending: %s, result: %s", |
2561 | 34.7k | gst_state_get_name (GST_STATE (element)), |
2562 | 34.7k | gst_state_get_name (GST_STATE_PENDING (element)), |
2563 | 34.7k | gst_state_change_return_get_name (ret)); |
2564 | 34.7k | GST_OBJECT_UNLOCK (element); |
2565 | | |
2566 | 34.7k | return ret; |
2567 | | |
2568 | 0 | interrupted: |
2569 | 0 | { |
2570 | 0 | if (state) |
2571 | 0 | *state = GST_STATE_VOID_PENDING; |
2572 | 0 | if (pending) |
2573 | 0 | *pending = GST_STATE_VOID_PENDING; |
2574 | |
|
2575 | 0 | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "interrupted"); |
2576 | |
|
2577 | 0 | GST_OBJECT_UNLOCK (element); |
2578 | |
|
2579 | 0 | return GST_STATE_CHANGE_FAILURE; |
2580 | 34.7k | } |
2581 | 34.7k | } |
2582 | | |
2583 | | /** |
2584 | | * gst_element_get_state: |
2585 | | * @element: a #GstElement to get the state of. |
2586 | | * @state: (out) (allow-none): a pointer to #GstState to hold the state. |
2587 | | * Can be %NULL. |
2588 | | * @pending: (out) (allow-none): a pointer to #GstState to hold the pending |
2589 | | * state. Can be %NULL. |
2590 | | * @timeout: a #GstClockTime to specify the timeout for an async |
2591 | | * state change or %GST_CLOCK_TIME_NONE for infinite timeout. |
2592 | | * |
2593 | | * Gets the state of the element. |
2594 | | * |
2595 | | * For elements that performed an ASYNC state change, as reported by |
2596 | | * gst_element_set_state(), this function will block up to the |
2597 | | * specified timeout value for the state change to complete. |
2598 | | * If the element completes the state change or goes into |
2599 | | * an error, this function returns immediately with a return value of |
2600 | | * %GST_STATE_CHANGE_SUCCESS or %GST_STATE_CHANGE_FAILURE respectively. |
2601 | | * |
2602 | | * For elements that did not return %GST_STATE_CHANGE_ASYNC, this function |
2603 | | * returns the current and pending state immediately. |
2604 | | * |
2605 | | * This function returns %GST_STATE_CHANGE_NO_PREROLL if the element |
2606 | | * successfully changed its state but is not able to provide data yet. |
2607 | | * This mostly happens for live sources that only produce data in |
2608 | | * %GST_STATE_PLAYING. While the state change return is equivalent to |
2609 | | * %GST_STATE_CHANGE_SUCCESS, it is returned to the application to signal that |
2610 | | * some sink elements might not be able to complete their state change because |
2611 | | * an element is not producing data to complete the preroll. When setting the |
2612 | | * element to playing, the preroll will complete and playback will start. |
2613 | | * |
2614 | | * Returns: %GST_STATE_CHANGE_SUCCESS if the element has no more pending state |
2615 | | * and the last state change succeeded, %GST_STATE_CHANGE_ASYNC if the |
2616 | | * element is still performing a state change or |
2617 | | * %GST_STATE_CHANGE_FAILURE if the last state change failed. |
2618 | | * |
2619 | | * MT safe. |
2620 | | */ |
2621 | | GstStateChangeReturn |
2622 | | gst_element_get_state (GstElement * element, |
2623 | | GstState * state, GstState * pending, GstClockTime timeout) |
2624 | 34.7k | { |
2625 | 34.7k | GstElementClass *oclass; |
2626 | 34.7k | GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; |
2627 | | |
2628 | 34.7k | g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE); |
2629 | | |
2630 | 34.7k | oclass = GST_ELEMENT_GET_CLASS (element); |
2631 | | |
2632 | 34.7k | if (oclass->get_state) |
2633 | 34.7k | result = (oclass->get_state) (element, state, pending, timeout); |
2634 | | |
2635 | 34.7k | return result; |
2636 | 34.7k | } |
2637 | | |
2638 | | /** |
2639 | | * gst_element_abort_state: |
2640 | | * @element: a #GstElement to abort the state of. |
2641 | | * |
2642 | | * Abort the state change of the element. This function is used |
2643 | | * by elements that do asynchronous state changes and find out |
2644 | | * something is wrong. |
2645 | | * |
2646 | | * This function should be called with the STATE_LOCK held. |
2647 | | * |
2648 | | * MT safe. |
2649 | | */ |
2650 | | void |
2651 | | gst_element_abort_state (GstElement * element) |
2652 | 0 | { |
2653 | 0 | GstState pending; |
2654 | |
|
2655 | 0 | #ifndef GST_DISABLE_GST_DEBUG |
2656 | 0 | GstState old_state; |
2657 | 0 | #endif |
2658 | |
|
2659 | 0 | g_return_if_fail (GST_IS_ELEMENT (element)); |
2660 | | |
2661 | 0 | GST_OBJECT_LOCK (element); |
2662 | 0 | pending = GST_STATE_PENDING (element); |
2663 | |
|
2664 | 0 | if (pending == GST_STATE_VOID_PENDING || |
2665 | 0 | GST_STATE_RETURN (element) == GST_STATE_CHANGE_FAILURE) |
2666 | 0 | goto nothing_aborted; |
2667 | | |
2668 | 0 | #ifndef GST_DISABLE_GST_DEBUG |
2669 | 0 | old_state = GST_STATE (element); |
2670 | |
|
2671 | 0 | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
2672 | 0 | "aborting state from %s to %s", gst_state_get_name (old_state), |
2673 | 0 | gst_state_get_name (pending)); |
2674 | 0 | #endif |
2675 | | |
2676 | | /* flag error */ |
2677 | 0 | GST_STATE_RETURN (element) = GST_STATE_CHANGE_FAILURE; |
2678 | |
|
2679 | 0 | GST_STATE_BROADCAST (element); |
2680 | 0 | GST_OBJECT_UNLOCK (element); |
2681 | |
|
2682 | 0 | return; |
2683 | | |
2684 | 0 | nothing_aborted: |
2685 | 0 | { |
2686 | 0 | GST_OBJECT_UNLOCK (element); |
2687 | 0 | return; |
2688 | 0 | } |
2689 | 0 | } |
2690 | | |
2691 | | /* Not static because GstBin has manual state handling too */ |
2692 | | void |
2693 | | _priv_gst_element_state_changed (GstElement * element, GstState oldstate, |
2694 | | GstState newstate, GstState pending) |
2695 | 218k | { |
2696 | 218k | GstElementClass *klass = GST_ELEMENT_GET_CLASS (element); |
2697 | 218k | GstMessage *message; |
2698 | | |
2699 | 218k | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
2700 | 218k | "notifying about state-changed %s to %s (%s pending)", |
2701 | 218k | gst_state_get_name (oldstate), |
2702 | 218k | gst_state_get_name (newstate), gst_state_get_name (pending)); |
2703 | | |
2704 | 218k | if (klass->state_changed) |
2705 | 0 | klass->state_changed (element, oldstate, newstate, pending); |
2706 | | |
2707 | 218k | message = gst_message_new_state_changed (GST_OBJECT_CAST (element), |
2708 | 218k | oldstate, newstate, pending); |
2709 | 218k | gst_element_post_message (element, message); |
2710 | 218k | } |
2711 | | |
2712 | | /** |
2713 | | * gst_element_continue_state: |
2714 | | * @element: a #GstElement to continue the state change of. |
2715 | | * @ret: The previous state return value |
2716 | | * |
2717 | | * Commit the state change of the element and proceed to the next |
2718 | | * pending state if any. This function is used |
2719 | | * by elements that do asynchronous state changes. |
2720 | | * The core will normally call this method automatically when an |
2721 | | * element returned %GST_STATE_CHANGE_SUCCESS from the state change function. |
2722 | | * |
2723 | | * If after calling this method the element still has not reached |
2724 | | * the pending state, the next state change is performed. |
2725 | | * |
2726 | | * This method is used internally and should normally not be called by plugins |
2727 | | * or applications. |
2728 | | * |
2729 | | * This function must be called with STATE_LOCK held. |
2730 | | * |
2731 | | * Returns: The result of the commit state change. |
2732 | | * |
2733 | | * MT safe. |
2734 | | */ |
2735 | | GstStateChangeReturn |
2736 | | gst_element_continue_state (GstElement * element, GstStateChangeReturn ret) |
2737 | 225k | { |
2738 | 225k | GstStateChangeReturn old_ret; |
2739 | 225k | GstState old_state, old_next; |
2740 | 225k | GstState current, next, pending; |
2741 | 225k | GstStateChange transition; |
2742 | | |
2743 | 225k | GST_OBJECT_LOCK (element); |
2744 | 225k | old_ret = GST_STATE_RETURN (element); |
2745 | 225k | GST_STATE_RETURN (element) = ret; |
2746 | 225k | pending = GST_STATE_PENDING (element); |
2747 | | |
2748 | | /* check if there is something to commit */ |
2749 | 225k | if (pending == GST_STATE_VOID_PENDING) |
2750 | 0 | goto nothing_pending; |
2751 | | |
2752 | 225k | old_state = GST_STATE (element); |
2753 | | /* this is the state we should go to next */ |
2754 | 225k | old_next = GST_STATE_NEXT (element); |
2755 | | /* update current state */ |
2756 | 225k | current = GST_STATE (element) = old_next; |
2757 | | |
2758 | | /* see if we reached the final state */ |
2759 | 225k | if (pending == current) |
2760 | 184k | goto complete; |
2761 | | |
2762 | 41.3k | next = GST_STATE_GET_NEXT (current, pending); |
2763 | 41.3k | transition = (GstStateChange) GST_STATE_TRANSITION (current, next); |
2764 | | |
2765 | 41.3k | GST_STATE_NEXT (element) = next; |
2766 | | /* mark busy */ |
2767 | 41.3k | GST_STATE_RETURN (element) = GST_STATE_CHANGE_ASYNC; |
2768 | 41.3k | GST_OBJECT_UNLOCK (element); |
2769 | | |
2770 | 41.3k | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
2771 | 41.3k | "committing state from %s to %s, pending %s, next %s", |
2772 | 41.3k | gst_state_get_name (old_state), |
2773 | 41.3k | gst_state_get_name (old_next), |
2774 | 41.3k | gst_state_get_name (pending), gst_state_get_name (next)); |
2775 | | |
2776 | 41.3k | _priv_gst_element_state_changed (element, old_state, old_next, pending); |
2777 | | |
2778 | 41.3k | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
2779 | 41.3k | "continue state change %s to %s, final %s", |
2780 | 41.3k | gst_state_get_name (current), |
2781 | 41.3k | gst_state_get_name (next), gst_state_get_name (pending)); |
2782 | | |
2783 | 41.3k | ret = gst_element_change_state (element, transition); |
2784 | | |
2785 | 41.3k | return ret; |
2786 | | |
2787 | 0 | nothing_pending: |
2788 | 0 | { |
2789 | 0 | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "nothing pending"); |
2790 | 0 | GST_OBJECT_UNLOCK (element); |
2791 | 0 | return ret; |
2792 | 225k | } |
2793 | 184k | complete: |
2794 | 184k | { |
2795 | 184k | GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING; |
2796 | 184k | GST_STATE_NEXT (element) = GST_STATE_VOID_PENDING; |
2797 | | |
2798 | 184k | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
2799 | 184k | "completed state change to %s", gst_state_get_name (pending)); |
2800 | 184k | GST_OBJECT_UNLOCK (element); |
2801 | | |
2802 | | /* don't post silly messages with the same state. This can happen |
2803 | | * when an element state is changed to what it already was. For bins |
2804 | | * this can be the result of a lost state, which we check with the |
2805 | | * previous return value. |
2806 | | * We do signal the cond though as a _get_state() might be blocking |
2807 | | * on it. */ |
2808 | 184k | if (old_state != old_next || old_ret == GST_STATE_CHANGE_ASYNC) |
2809 | 172k | _priv_gst_element_state_changed (element, old_state, old_next, |
2810 | 172k | GST_STATE_VOID_PENDING); |
2811 | | |
2812 | 184k | GST_STATE_BROADCAST (element); |
2813 | | |
2814 | 184k | return ret; |
2815 | 225k | } |
2816 | 225k | } |
2817 | | |
2818 | | /** |
2819 | | * gst_element_lost_state: |
2820 | | * @element: a #GstElement the state is lost of |
2821 | | * |
2822 | | * Brings the element to the lost state. The current state of the |
2823 | | * element is copied to the pending state so that any call to |
2824 | | * gst_element_get_state() will return %GST_STATE_CHANGE_ASYNC. |
2825 | | * |
2826 | | * An ASYNC_START message is posted. If the element was PLAYING, it will |
2827 | | * go to PAUSED. The element will be restored to its PLAYING state by |
2828 | | * the parent pipeline when it prerolls again. |
2829 | | * |
2830 | | * This is mostly used for elements that lost their preroll buffer |
2831 | | * in the %GST_STATE_PAUSED or %GST_STATE_PLAYING state after a flush, |
2832 | | * they will go to their pending state again when a new preroll buffer is |
2833 | | * queued. This function can only be called when the element is currently |
2834 | | * not in error or an async state change. |
2835 | | * |
2836 | | * This function is used internally and should normally not be called from |
2837 | | * plugins or applications. |
2838 | | */ |
2839 | | void |
2840 | | gst_element_lost_state (GstElement * element) |
2841 | 0 | { |
2842 | 0 | GstState old_state, new_state; |
2843 | 0 | GstMessage *message; |
2844 | |
|
2845 | 0 | g_return_if_fail (GST_IS_ELEMENT (element)); |
2846 | | |
2847 | 0 | GST_OBJECT_LOCK (element); |
2848 | 0 | if (GST_STATE_RETURN (element) == GST_STATE_CHANGE_FAILURE) |
2849 | 0 | goto nothing_lost; |
2850 | | |
2851 | 0 | if (GST_STATE_PENDING (element) != GST_STATE_VOID_PENDING) |
2852 | 0 | goto only_async_start; |
2853 | | |
2854 | 0 | old_state = GST_STATE (element); |
2855 | | |
2856 | | /* when we were PLAYING, the new state is PAUSED. We will also not |
2857 | | * automatically go to PLAYING but let the parent bin(s) set us to PLAYING |
2858 | | * when we preroll. */ |
2859 | 0 | if (old_state > GST_STATE_PAUSED) |
2860 | 0 | new_state = GST_STATE_PAUSED; |
2861 | 0 | else |
2862 | 0 | new_state = old_state; |
2863 | |
|
2864 | 0 | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
2865 | 0 | "lost state of %s to %s", gst_state_get_name (old_state), |
2866 | 0 | gst_state_get_name (new_state)); |
2867 | |
|
2868 | 0 | GST_STATE (element) = new_state; |
2869 | 0 | GST_STATE_NEXT (element) = new_state; |
2870 | 0 | GST_STATE_PENDING (element) = new_state; |
2871 | 0 | GST_STATE_RETURN (element) = GST_STATE_CHANGE_ASYNC; |
2872 | 0 | GST_OBJECT_UNLOCK (element); |
2873 | |
|
2874 | 0 | _priv_gst_element_state_changed (element, new_state, new_state, new_state); |
2875 | |
|
2876 | 0 | message = gst_message_new_async_start (GST_OBJECT_CAST (element)); |
2877 | 0 | gst_element_post_message (element, message); |
2878 | |
|
2879 | 0 | return; |
2880 | | |
2881 | 0 | nothing_lost: |
2882 | 0 | { |
2883 | 0 | GST_OBJECT_UNLOCK (element); |
2884 | 0 | return; |
2885 | 0 | } |
2886 | 0 | only_async_start: |
2887 | 0 | { |
2888 | 0 | GST_OBJECT_UNLOCK (element); |
2889 | |
|
2890 | 0 | message = gst_message_new_async_start (GST_OBJECT_CAST (element)); |
2891 | 0 | gst_element_post_message (element, message); |
2892 | 0 | return; |
2893 | 0 | } |
2894 | 0 | } |
2895 | | |
2896 | | /** |
2897 | | * gst_element_set_state: |
2898 | | * @element: a #GstElement to change state of. |
2899 | | * @state: the element's new #GstState. |
2900 | | * |
2901 | | * Sets the state of the element. This function will try to set the |
2902 | | * requested state by going through all the intermediary states and calling |
2903 | | * the class's state change function for each. |
2904 | | * |
2905 | | * This function can return #GST_STATE_CHANGE_ASYNC, in which case the |
2906 | | * element will perform the remainder of the state change asynchronously in |
2907 | | * another thread. |
2908 | | * An application can use gst_element_get_state() to wait for the completion |
2909 | | * of the state change or it can wait for a %GST_MESSAGE_ASYNC_DONE or |
2910 | | * %GST_MESSAGE_STATE_CHANGED on the bus. |
2911 | | * |
2912 | | * State changes to %GST_STATE_READY or %GST_STATE_NULL never return |
2913 | | * #GST_STATE_CHANGE_ASYNC. |
2914 | | * |
2915 | | * Returns: Result of the state change using #GstStateChangeReturn. |
2916 | | * |
2917 | | * MT safe. |
2918 | | */ |
2919 | | GstStateChangeReturn |
2920 | | gst_element_set_state (GstElement * element, GstState state) |
2921 | 221k | { |
2922 | 221k | GstElementClass *oclass; |
2923 | 221k | GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; |
2924 | | |
2925 | 221k | g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE); |
2926 | | |
2927 | 221k | oclass = GST_ELEMENT_GET_CLASS (element); |
2928 | | |
2929 | 221k | if (oclass->set_state) |
2930 | 221k | result = (oclass->set_state) (element, state); |
2931 | | |
2932 | 221k | return result; |
2933 | 221k | } |
2934 | | |
2935 | | /* |
2936 | | * default set state function, calculates the next state based |
2937 | | * on current state and calls the change_state function |
2938 | | */ |
2939 | | static GstStateChangeReturn |
2940 | | gst_element_set_state_func (GstElement * element, GstState state) |
2941 | 221k | { |
2942 | 221k | GstState current, next, old_pending; |
2943 | 221k | GstStateChangeReturn ret; |
2944 | 221k | GstStateChange transition; |
2945 | 221k | GstStateChangeReturn old_ret; |
2946 | | |
2947 | 221k | g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE); |
2948 | | |
2949 | 221k | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "set_state to %s", |
2950 | 221k | gst_state_get_name (state)); |
2951 | | |
2952 | | /* state lock is taken to protect the set_state() and get_state() |
2953 | | * procedures, it does not lock any variables. */ |
2954 | 221k | GST_STATE_LOCK (element); |
2955 | | |
2956 | | /* now calculate how to get to the new state */ |
2957 | 221k | GST_OBJECT_LOCK (element); |
2958 | 221k | old_ret = GST_STATE_RETURN (element); |
2959 | | /* previous state change returned an error, remove all pending |
2960 | | * and next states */ |
2961 | 221k | if (old_ret == GST_STATE_CHANGE_FAILURE) { |
2962 | 19.9k | GST_STATE_NEXT (element) = GST_STATE_VOID_PENDING; |
2963 | 19.9k | GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING; |
2964 | 19.9k | GST_STATE_RETURN (element) = GST_STATE_CHANGE_SUCCESS; |
2965 | 19.9k | } |
2966 | | |
2967 | 221k | current = GST_STATE (element); |
2968 | 221k | next = GST_STATE_NEXT (element); |
2969 | 221k | old_pending = GST_STATE_PENDING (element); |
2970 | | |
2971 | | /* this is the (new) state we should go to. TARGET is the last state we set on |
2972 | | * the element. */ |
2973 | 221k | if (state != GST_STATE_TARGET (element)) { |
2974 | 205k | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
2975 | 205k | "setting target state to %s", gst_state_get_name (state)); |
2976 | 205k | GST_STATE_TARGET (element) = state; |
2977 | | /* increment state cookie so that we can track each state change. We only do |
2978 | | * this if this is actually a new state change. */ |
2979 | 205k | element->state_cookie++; |
2980 | 205k | } |
2981 | 221k | GST_STATE_PENDING (element) = state; |
2982 | | |
2983 | 221k | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
2984 | 221k | "current %s, old_pending %s, next %s, old return %s", |
2985 | 221k | gst_state_get_name (current), |
2986 | 221k | gst_state_get_name (old_pending), |
2987 | 221k | gst_state_get_name (next), gst_state_change_return_get_name (old_ret)); |
2988 | | |
2989 | | /* if the element was busy doing a state change, we just update the |
2990 | | * target state, it'll get to it async then. */ |
2991 | 221k | if (old_pending != GST_STATE_VOID_PENDING) { |
2992 | | /* upwards state change will happen ASYNC */ |
2993 | 5.77k | if (old_pending <= state) |
2994 | 5.42k | goto was_busy; |
2995 | | /* element is going to this state already */ |
2996 | 346 | else if (next == state) |
2997 | 0 | goto was_busy; |
2998 | | /* element was performing an ASYNC upward state change and |
2999 | | * we request to go downward again. Start from the next pending |
3000 | | * state then. */ |
3001 | 346 | else if (next > state |
3002 | 346 | && GST_STATE_RETURN (element) == GST_STATE_CHANGE_ASYNC) { |
3003 | 346 | current = next; |
3004 | 346 | } |
3005 | 5.77k | } |
3006 | 216k | next = GST_STATE_GET_NEXT (current, state); |
3007 | | /* now we store the next state */ |
3008 | 216k | GST_STATE_NEXT (element) = next; |
3009 | | /* mark busy, we need to check that there is actually a state change |
3010 | | * to be done else we could accidentally override SUCCESS/NO_PREROLL and |
3011 | | * the default element change_state function has no way to know what the |
3012 | | * old value was... could consider this a FIXME...*/ |
3013 | 216k | if (current != next) |
3014 | 205k | GST_STATE_RETURN (element) = GST_STATE_CHANGE_ASYNC; |
3015 | | |
3016 | 216k | transition = (GstStateChange) GST_STATE_TRANSITION (current, next); |
3017 | | |
3018 | 216k | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
3019 | 216k | "%s: setting state from %s to %s", |
3020 | 216k | (next != state ? "intermediate" : "final"), |
3021 | 216k | gst_state_get_name (current), gst_state_get_name (next)); |
3022 | | |
3023 | | /* now signal any waiters, they will error since the cookie was incremented */ |
3024 | 216k | GST_STATE_BROADCAST (element); |
3025 | | |
3026 | 216k | GST_OBJECT_UNLOCK (element); |
3027 | | |
3028 | 216k | ret = gst_element_change_state (element, transition); |
3029 | | |
3030 | 216k | GST_STATE_UNLOCK (element); |
3031 | | |
3032 | 216k | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "returned %s", |
3033 | 216k | gst_state_change_return_get_name (ret)); |
3034 | | |
3035 | 216k | return ret; |
3036 | | |
3037 | 5.42k | was_busy: |
3038 | 5.42k | { |
3039 | 5.42k | GST_STATE_RETURN (element) = GST_STATE_CHANGE_ASYNC; |
3040 | 5.42k | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
3041 | 5.42k | "element was busy with async state change"); |
3042 | 5.42k | GST_OBJECT_UNLOCK (element); |
3043 | | |
3044 | 5.42k | GST_STATE_UNLOCK (element); |
3045 | | |
3046 | 5.42k | return GST_STATE_CHANGE_ASYNC; |
3047 | 221k | } |
3048 | 221k | } |
3049 | | |
3050 | | /** |
3051 | | * gst_element_change_state: |
3052 | | * @element: a #GstElement |
3053 | | * @transition: the requested transition |
3054 | | * |
3055 | | * Perform @transition on @element. |
3056 | | * |
3057 | | * This function must be called with STATE_LOCK held and is mainly used |
3058 | | * internally. |
3059 | | * |
3060 | | * Returns: the #GstStateChangeReturn of the state transition. |
3061 | | */ |
3062 | | GstStateChangeReturn |
3063 | | gst_element_change_state (GstElement * element, GstStateChange transition) |
3064 | 257k | { |
3065 | 257k | GstElementClass *oclass; |
3066 | 257k | GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; |
3067 | | |
3068 | 257k | oclass = GST_ELEMENT_GET_CLASS (element); |
3069 | | |
3070 | 257k | GST_TRACER_ELEMENT_CHANGE_STATE_PRE (element, transition); |
3071 | | |
3072 | | /* call the state change function so it can set the state */ |
3073 | 257k | if (oclass->change_state) |
3074 | 257k | ret = (oclass->change_state) (element, transition); |
3075 | 0 | else |
3076 | 0 | ret = GST_STATE_CHANGE_FAILURE; |
3077 | | |
3078 | 257k | GST_TRACER_ELEMENT_CHANGE_STATE_POST (element, transition, ret); |
3079 | | |
3080 | 257k | switch (ret) { |
3081 | 0 | case GST_STATE_CHANGE_FAILURE: |
3082 | 0 | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
3083 | 0 | "have FAILURE change_state return"); |
3084 | | /* state change failure */ |
3085 | 0 | gst_element_abort_state (element); |
3086 | 0 | break; |
3087 | 32.2k | case GST_STATE_CHANGE_ASYNC: |
3088 | 32.2k | { |
3089 | 32.2k | GstState target; |
3090 | | |
3091 | 32.2k | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
3092 | 32.2k | "element will change state ASYNC"); |
3093 | | |
3094 | 32.2k | target = GST_STATE_TARGET (element); |
3095 | | |
3096 | 32.2k | if (target > GST_STATE_READY) |
3097 | 32.2k | goto async; |
3098 | | |
3099 | | /* else we just continue the state change downwards */ |
3100 | 0 | GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, |
3101 | 0 | "forcing commit state %s <= %s", |
3102 | 0 | gst_state_get_name (target), gst_state_get_name (GST_STATE_READY)); |
3103 | |
|
3104 | 0 | ret = gst_element_continue_state (element, GST_STATE_CHANGE_SUCCESS); |
3105 | 0 | break; |
3106 | 32.2k | } |
3107 | 225k | case GST_STATE_CHANGE_SUCCESS: |
3108 | 225k | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
3109 | 225k | "element changed state SUCCESS"); |
3110 | | /* we can commit the state now which will proceed to |
3111 | | * the next state */ |
3112 | 225k | ret = gst_element_continue_state (element, ret); |
3113 | 225k | break; |
3114 | 0 | case GST_STATE_CHANGE_NO_PREROLL: |
3115 | 0 | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
3116 | 0 | "element changed state NO_PREROLL"); |
3117 | | /* we can commit the state now which will proceed to |
3118 | | * the next state */ |
3119 | 0 | ret = gst_element_continue_state (element, ret); |
3120 | 0 | break; |
3121 | 0 | default: |
3122 | 0 | goto invalid_return; |
3123 | 257k | } |
3124 | | |
3125 | 225k | GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, "exit state change %d", ret); |
3126 | | |
3127 | 225k | return ret; |
3128 | | |
3129 | 32.2k | async: |
3130 | 32.2k | GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, "exit async state change %d", |
3131 | 32.2k | ret); |
3132 | | |
3133 | 32.2k | return ret; |
3134 | | |
3135 | | /* ERROR */ |
3136 | 0 | invalid_return: |
3137 | 0 | { |
3138 | 0 | GST_OBJECT_LOCK (element); |
3139 | | /* somebody added a GST_STATE_ and forgot to do stuff here ! */ |
3140 | 0 | g_critical ("%s: unknown return value %d from a state change function", |
3141 | 0 | GST_ELEMENT_NAME (element), ret); |
3142 | | |
3143 | | /* we are in error now */ |
3144 | 0 | ret = GST_STATE_CHANGE_FAILURE; |
3145 | 0 | GST_STATE_RETURN (element) = ret; |
3146 | 0 | GST_OBJECT_UNLOCK (element); |
3147 | |
|
3148 | 0 | return ret; |
3149 | 257k | } |
3150 | 257k | } |
3151 | | |
3152 | | /* gst_iterator_fold functions for pads_activate |
3153 | | * Stop the iterator if activating one pad failed, but only if that pad |
3154 | | * has not been removed from the element. */ |
3155 | | static gboolean |
3156 | | activate_pads (const GValue * vpad, GValue * ret, gboolean * active) |
3157 | 163k | { |
3158 | 163k | GstPad *pad = g_value_get_object (vpad); |
3159 | 163k | gboolean cont = TRUE; |
3160 | | |
3161 | 163k | if (!gst_pad_set_active (pad, *active)) { |
3162 | 0 | if (GST_PAD_PARENT (pad) != NULL) { |
3163 | 0 | cont = FALSE; |
3164 | 0 | g_value_set_boolean (ret, FALSE); |
3165 | 0 | } |
3166 | 0 | } |
3167 | | |
3168 | 163k | return cont; |
3169 | 163k | } |
3170 | | |
3171 | | /* returns false on error or early cutout of the fold, true if all |
3172 | | * pads in @iter were (de)activated successfully. */ |
3173 | | static gboolean |
3174 | | iterator_activate_fold_with_resync (GstIterator * iter, |
3175 | | GstIteratorFoldFunction func, gpointer user_data) |
3176 | 348k | { |
3177 | 348k | GstIteratorResult ires; |
3178 | 348k | GValue ret = { 0 }; |
3179 | | |
3180 | | /* no need to unset this later, it's just a boolean */ |
3181 | 348k | g_value_init (&ret, G_TYPE_BOOLEAN); |
3182 | 348k | g_value_set_boolean (&ret, TRUE); |
3183 | | |
3184 | 348k | while (1) { |
3185 | 348k | ires = gst_iterator_fold (iter, func, &ret, user_data); |
3186 | 348k | switch (ires) { |
3187 | 5 | case GST_ITERATOR_RESYNC: |
3188 | | /* need to reset the result again */ |
3189 | 5 | g_value_set_boolean (&ret, TRUE); |
3190 | 5 | gst_iterator_resync (iter); |
3191 | 5 | break; |
3192 | 348k | case GST_ITERATOR_DONE: |
3193 | | /* all pads iterated, return collected value */ |
3194 | 348k | goto done; |
3195 | 0 | default: |
3196 | | /* iterator returned _ERROR or premature end with _OK, |
3197 | | * mark an error and exit */ |
3198 | 0 | g_value_set_boolean (&ret, FALSE); |
3199 | 0 | goto done; |
3200 | 348k | } |
3201 | 348k | } |
3202 | 348k | done: |
3203 | | /* return collected value */ |
3204 | 348k | return g_value_get_boolean (&ret); |
3205 | 348k | } |
3206 | | |
3207 | | /* is called with STATE_LOCK |
3208 | | * |
3209 | | * Pads are activated from source pads to sinkpads. |
3210 | | */ |
3211 | | static gboolean |
3212 | | gst_element_pads_activate (GstElement * element, gboolean active) |
3213 | 174k | { |
3214 | 174k | GstIterator *iter; |
3215 | 174k | gboolean res; |
3216 | | |
3217 | 174k | GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element, |
3218 | 174k | "%s pads", active ? "activate" : "deactivate"); |
3219 | | |
3220 | 174k | iter = gst_element_iterate_src_pads (element); |
3221 | 174k | res = |
3222 | 174k | iterator_activate_fold_with_resync (iter, |
3223 | 174k | (GstIteratorFoldFunction) activate_pads, &active); |
3224 | 174k | gst_iterator_free (iter); |
3225 | 174k | if (G_UNLIKELY (!res)) |
3226 | 0 | goto src_failed; |
3227 | | |
3228 | 174k | iter = gst_element_iterate_sink_pads (element); |
3229 | 174k | res = |
3230 | 174k | iterator_activate_fold_with_resync (iter, |
3231 | 174k | (GstIteratorFoldFunction) activate_pads, &active); |
3232 | 174k | gst_iterator_free (iter); |
3233 | 174k | if (G_UNLIKELY (!res)) |
3234 | 0 | goto sink_failed; |
3235 | | |
3236 | 174k | GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element, |
3237 | 174k | "pad %sactivation successful", active ? "" : "de"); |
3238 | | |
3239 | 174k | return TRUE; |
3240 | | |
3241 | | /* ERRORS */ |
3242 | 0 | src_failed: |
3243 | 0 | { |
3244 | 0 | GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element, |
3245 | 0 | "pad %sactivation failed", active ? "" : "de"); |
3246 | 0 | return FALSE; |
3247 | 174k | } |
3248 | 0 | sink_failed: |
3249 | 0 | { |
3250 | 0 | GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element, |
3251 | 0 | "sink pads_activate failed"); |
3252 | 0 | return FALSE; |
3253 | 174k | } |
3254 | 174k | } |
3255 | | |
3256 | | /* is called with STATE_LOCK */ |
3257 | | static GstStateChangeReturn |
3258 | | gst_element_change_state_func (GstElement * element, GstStateChange transition) |
3259 | 257k | { |
3260 | 257k | GstState state, next; |
3261 | 257k | GstStateChangeReturn result = GST_STATE_CHANGE_SUCCESS; |
3262 | | |
3263 | 257k | g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE); |
3264 | | |
3265 | 257k | state = (GstState) GST_STATE_TRANSITION_CURRENT (transition); |
3266 | 257k | next = GST_STATE_TRANSITION_NEXT (transition); |
3267 | | |
3268 | | /* if the element already is in the given state, we just return success */ |
3269 | 257k | if (next == GST_STATE_VOID_PENDING || state == next) |
3270 | 11.2k | goto was_ok; |
3271 | | |
3272 | 246k | GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, |
3273 | 246k | "default handler tries setting state from %s to %s (%04x)", |
3274 | 246k | gst_state_get_name (state), gst_state_get_name (next), transition); |
3275 | | |
3276 | 246k | switch (transition) { |
3277 | 71.9k | case GST_STATE_CHANGE_NULL_TO_READY: |
3278 | 71.9k | break; |
3279 | 61.1k | case GST_STATE_CHANGE_READY_TO_PAUSED: |
3280 | 61.1k | if (!gst_element_pads_activate (element, TRUE)) { |
3281 | 0 | result = GST_STATE_CHANGE_FAILURE; |
3282 | 0 | } |
3283 | 61.1k | break; |
3284 | 110 | case GST_STATE_CHANGE_PAUSED_TO_PLAYING: |
3285 | 110 | break; |
3286 | 110 | case GST_STATE_CHANGE_PLAYING_TO_PAUSED: |
3287 | 110 | break; |
3288 | 41.1k | case GST_STATE_CHANGE_PAUSED_TO_READY: |
3289 | 113k | case GST_STATE_CHANGE_READY_TO_NULL:{ |
3290 | 113k | GList *l; |
3291 | | |
3292 | | /* deactivate pads in both cases, since they are activated on |
3293 | | ready->paused but the element might not have made it to paused */ |
3294 | 113k | if (!gst_element_pads_activate (element, FALSE)) { |
3295 | 0 | result = GST_STATE_CHANGE_FAILURE; |
3296 | 0 | } |
3297 | | |
3298 | | /* Remove all non-persistent contexts */ |
3299 | 113k | GST_OBJECT_LOCK (element); |
3300 | 113k | for (l = element->contexts; l;) { |
3301 | 0 | GstContext *context = l->data; |
3302 | |
|
3303 | 0 | if (!gst_context_is_persistent (context)) { |
3304 | 0 | GList *next; |
3305 | |
|
3306 | 0 | gst_context_unref (context); |
3307 | 0 | next = l->next; |
3308 | 0 | element->contexts = g_list_delete_link (element->contexts, l); |
3309 | 0 | l = next; |
3310 | 0 | } else { |
3311 | 0 | l = l->next; |
3312 | 0 | } |
3313 | 0 | } |
3314 | 113k | GST_OBJECT_UNLOCK (element); |
3315 | 113k | break; |
3316 | 41.1k | } |
3317 | 0 | default: |
3318 | | /* this will catch real but unhandled state changes; |
3319 | | * can only be caused by: |
3320 | | * - a new state was added |
3321 | | * - somehow the element was asked to jump across an intermediate state |
3322 | | */ |
3323 | 0 | g_warning ("Unhandled state change from %s to %s", |
3324 | 0 | gst_state_get_name (state), gst_state_get_name (next)); |
3325 | 0 | break; |
3326 | 246k | } |
3327 | 246k | return result; |
3328 | | |
3329 | 11.2k | was_ok: |
3330 | 11.2k | { |
3331 | 11.2k | GST_OBJECT_LOCK (element); |
3332 | 11.2k | result = GST_STATE_RETURN (element); |
3333 | 11.2k | GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, |
3334 | 11.2k | "element is already in the %s state", gst_state_get_name (state)); |
3335 | 11.2k | GST_OBJECT_UNLOCK (element); |
3336 | | |
3337 | 11.2k | return result; |
3338 | 246k | } |
3339 | 246k | } |
3340 | | |
3341 | | /** |
3342 | | * gst_element_get_factory: |
3343 | | * @element: a #GstElement to request the element factory of. |
3344 | | * |
3345 | | * Retrieves the factory that was used to create this element. |
3346 | | * |
3347 | | * Returns: (transfer none) (nullable): the #GstElementFactory used for creating this |
3348 | | * element or %NULL if element has not been registered (static element). no refcounting is needed. |
3349 | | */ |
3350 | | GstElementFactory * |
3351 | | gst_element_get_factory (GstElement * element) |
3352 | 340 | { |
3353 | 340 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
3354 | | |
3355 | 340 | return GST_ELEMENT_GET_CLASS (element)->elementfactory; |
3356 | 340 | } |
3357 | | |
3358 | | static void |
3359 | | gst_element_dispose (GObject * object) |
3360 | 61.1k | { |
3361 | 61.1k | GstElement *element = GST_ELEMENT_CAST (object); |
3362 | 61.1k | GstClock **clock_p; |
3363 | 61.1k | GstBus **bus_p; |
3364 | 61.1k | GstElementClass *oclass; |
3365 | 61.1k | GList *walk; |
3366 | | |
3367 | 61.1k | oclass = GST_ELEMENT_GET_CLASS (element); |
3368 | | |
3369 | 61.1k | GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "%p dispose", element); |
3370 | | |
3371 | 61.1k | if (GST_STATE (element) != GST_STATE_NULL) |
3372 | 0 | goto not_null; |
3373 | | |
3374 | | /* start by releasing all request pads, this might also remove some dynamic |
3375 | | * pads */ |
3376 | 61.1k | walk = element->pads; |
3377 | 116k | while (walk) { |
3378 | 55.5k | GstPad *pad = GST_PAD_CAST (walk->data); |
3379 | | |
3380 | 55.5k | walk = walk->next; |
3381 | | |
3382 | 55.5k | if (oclass->release_pad && GST_PAD_PAD_TEMPLATE (pad) && |
3383 | 0 | GST_PAD_TEMPLATE_PRESENCE (GST_PAD_PAD_TEMPLATE (pad)) |
3384 | 0 | == GST_PAD_REQUEST) { |
3385 | 0 | GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element, |
3386 | 0 | "removing request pad %s:%s", GST_DEBUG_PAD_NAME (pad)); |
3387 | 0 | oclass->release_pad (element, pad); |
3388 | | |
3389 | | /* in case the release_pad function removed the next pad too */ |
3390 | 0 | if (walk && g_list_position (element->pads, walk) == -1) |
3391 | 0 | walk = element->pads; |
3392 | 0 | } |
3393 | 55.5k | } |
3394 | | /* remove the remaining pads */ |
3395 | 116k | while (element->pads) { |
3396 | 55.5k | GstPad *pad = GST_PAD_CAST (element->pads->data); |
3397 | 55.5k | GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element, |
3398 | 55.5k | "removing pad %s:%s", GST_DEBUG_PAD_NAME (pad)); |
3399 | 55.5k | if (!gst_element_remove_pad (element, pad)) { |
3400 | | /* only happens when someone unparented our pad.. */ |
3401 | 0 | g_critical ("failed to remove pad %s:%s", GST_DEBUG_PAD_NAME (pad)); |
3402 | 0 | break; |
3403 | 0 | } |
3404 | 55.5k | } |
3405 | | |
3406 | 61.1k | GST_OBJECT_LOCK (element); |
3407 | 61.1k | clock_p = &element->clock; |
3408 | 61.1k | bus_p = &element->bus; |
3409 | 61.1k | gst_object_replace ((GstObject **) clock_p, NULL); |
3410 | 61.1k | gst_object_replace ((GstObject **) bus_p, NULL); |
3411 | 61.1k | g_list_free_full (element->contexts, (GDestroyNotify) gst_context_unref); |
3412 | 61.1k | element->contexts = NULL; |
3413 | 61.1k | GST_OBJECT_UNLOCK (element); |
3414 | | |
3415 | 61.1k | GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "%p parent class dispose", |
3416 | 61.1k | element); |
3417 | | |
3418 | 61.1k | G_OBJECT_CLASS (parent_class)->dispose (object); |
3419 | | |
3420 | 61.1k | return; |
3421 | | |
3422 | | /* ERRORS */ |
3423 | 0 | not_null: |
3424 | 0 | { |
3425 | 0 | gboolean is_locked; |
3426 | |
|
3427 | 0 | is_locked = GST_ELEMENT_IS_LOCKED_STATE (element); |
3428 | 0 | g_critical |
3429 | 0 | ("\nTrying to dispose element %s, but it is in %s%s instead of the NULL" |
3430 | 0 | " state.\n" |
3431 | 0 | "You need to explicitly set elements to the NULL state before\n" |
3432 | 0 | "dropping the final reference, to allow them to clean up.\n" |
3433 | 0 | "This problem may also be caused by a refcounting bug in the\n" |
3434 | 0 | "application or some element.\n", |
3435 | 0 | GST_OBJECT_NAME (element), |
3436 | 0 | gst_state_get_name (GST_STATE (element)), is_locked ? " (locked)" : ""); |
3437 | 0 | return; |
3438 | 61.1k | } |
3439 | 61.1k | } |
3440 | | |
3441 | | static void |
3442 | | gst_element_finalize (GObject * object) |
3443 | 61.1k | { |
3444 | 61.1k | GstElement *element = GST_ELEMENT_CAST (object); |
3445 | | |
3446 | 61.1k | GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "%p finalize", element); |
3447 | | |
3448 | 61.1k | g_cond_clear (&element->state_cond); |
3449 | 61.1k | g_rec_mutex_clear (&element->state_lock); |
3450 | | |
3451 | 61.1k | GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "%p finalize parent", |
3452 | 61.1k | element); |
3453 | | |
3454 | 61.1k | G_OBJECT_CLASS (parent_class)->finalize (object); |
3455 | 61.1k | } |
3456 | | |
3457 | | static void |
3458 | | gst_element_set_bus_func (GstElement * element, GstBus * bus) |
3459 | 108k | { |
3460 | 108k | GstBus **bus_p; |
3461 | | |
3462 | 108k | g_return_if_fail (GST_IS_ELEMENT (element)); |
3463 | | |
3464 | 108k | GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element, "setting bus to %p", bus); |
3465 | | |
3466 | 108k | GST_OBJECT_LOCK (element); |
3467 | 108k | bus_p = &GST_ELEMENT_BUS (element); |
3468 | 108k | gst_object_replace ((GstObject **) bus_p, GST_OBJECT_CAST (bus)); |
3469 | 108k | GST_OBJECT_UNLOCK (element); |
3470 | 108k | } |
3471 | | |
3472 | | /** |
3473 | | * gst_element_set_bus: |
3474 | | * @element: a #GstElement to set the bus of. |
3475 | | * @bus: (transfer none) (allow-none): the #GstBus to set. |
3476 | | * |
3477 | | * Sets the bus of the element. Increases the refcount on the bus. |
3478 | | * For internal use only, unless you're testing elements. |
3479 | | * |
3480 | | * MT safe. |
3481 | | */ |
3482 | | void |
3483 | | gst_element_set_bus (GstElement * element, GstBus * bus) |
3484 | 108k | { |
3485 | 108k | GstElementClass *oclass; |
3486 | | |
3487 | 108k | g_return_if_fail (GST_IS_ELEMENT (element)); |
3488 | | |
3489 | 108k | oclass = GST_ELEMENT_GET_CLASS (element); |
3490 | | |
3491 | 108k | if (oclass->set_bus) |
3492 | 108k | oclass->set_bus (element, bus); |
3493 | 108k | } |
3494 | | |
3495 | | /** |
3496 | | * gst_element_get_bus: |
3497 | | * @element: a #GstElement to get the bus of. |
3498 | | * |
3499 | | * Returns the bus of the element. Note that only a #GstPipeline will provide a |
3500 | | * bus for the application. |
3501 | | * |
3502 | | * Returns: (transfer full) (nullable): the element's #GstBus. unref after |
3503 | | * usage. |
3504 | | * |
3505 | | * MT safe. |
3506 | | */ |
3507 | | GstBus * |
3508 | | gst_element_get_bus (GstElement * element) |
3509 | 5.42k | { |
3510 | 5.42k | GstBus *result = NULL; |
3511 | | |
3512 | 5.42k | g_return_val_if_fail (GST_IS_ELEMENT (element), result); |
3513 | | |
3514 | 5.42k | GST_OBJECT_LOCK (element); |
3515 | 5.42k | if ((result = GST_ELEMENT_BUS (element))) |
3516 | 5.42k | gst_object_ref (result); |
3517 | 5.42k | GST_OBJECT_UNLOCK (element); |
3518 | | |
3519 | 5.42k | GST_CAT_DEBUG_OBJECT (GST_CAT_BUS, element, "got bus %" GST_PTR_FORMAT, |
3520 | 5.42k | result); |
3521 | | |
3522 | 5.42k | return result; |
3523 | 5.42k | } |
3524 | | |
3525 | | static void |
3526 | | gst_element_set_context_default (GstElement * element, GstContext * context) |
3527 | 0 | { |
3528 | 0 | const gchar *context_type; |
3529 | 0 | GList *l; |
3530 | |
|
3531 | 0 | g_return_if_fail (GST_IS_CONTEXT (context)); |
3532 | 0 | context_type = gst_context_get_context_type (context); |
3533 | 0 | g_return_if_fail (context_type != NULL); |
3534 | | |
3535 | 0 | GST_OBJECT_LOCK (element); |
3536 | 0 | for (l = element->contexts; l; l = l->next) { |
3537 | 0 | GstContext *tmp = l->data; |
3538 | 0 | const gchar *tmp_type = gst_context_get_context_type (tmp); |
3539 | | |
3540 | | /* Always store newest context but never replace |
3541 | | * a persistent one by a non-persistent one */ |
3542 | 0 | if (g_strcmp0 (context_type, tmp_type) == 0 && |
3543 | 0 | (gst_context_is_persistent (context) || |
3544 | 0 | !gst_context_is_persistent (tmp))) { |
3545 | 0 | gst_context_replace ((GstContext **) & l->data, context); |
3546 | 0 | break; |
3547 | 0 | } |
3548 | 0 | } |
3549 | | /* Not found? Add */ |
3550 | 0 | if (l == NULL) { |
3551 | 0 | element->contexts = |
3552 | 0 | g_list_prepend (element->contexts, gst_context_ref (context)); |
3553 | 0 | } |
3554 | 0 | GST_OBJECT_UNLOCK (element); |
3555 | 0 | } |
3556 | | |
3557 | | /** |
3558 | | * gst_element_set_context: |
3559 | | * @element: a #GstElement to set the context of. |
3560 | | * @context: (transfer none): the #GstContext to set. |
3561 | | * |
3562 | | * Sets the context of the element. Increases the refcount of the context. |
3563 | | * |
3564 | | * MT safe. |
3565 | | */ |
3566 | | void |
3567 | | gst_element_set_context (GstElement * element, GstContext * context) |
3568 | 0 | { |
3569 | 0 | GstElementClass *oclass; |
3570 | |
|
3571 | 0 | g_return_if_fail (GST_IS_ELEMENT (element)); |
3572 | 0 | g_return_if_fail (GST_IS_CONTEXT (context)); |
3573 | | |
3574 | 0 | oclass = GST_ELEMENT_GET_CLASS (element); |
3575 | |
|
3576 | 0 | GST_CAT_DEBUG_OBJECT (GST_CAT_CONTEXT, element, |
3577 | 0 | "set context %p %" GST_PTR_FORMAT, context, |
3578 | 0 | gst_context_get_structure (context)); |
3579 | |
|
3580 | 0 | if (oclass->set_context) |
3581 | 0 | oclass->set_context (element, context); |
3582 | 0 | } |
3583 | | |
3584 | | /** |
3585 | | * gst_element_get_contexts: |
3586 | | * @element: a #GstElement to set the context of. |
3587 | | * |
3588 | | * Gets the contexts set on the element. |
3589 | | * |
3590 | | * MT safe. |
3591 | | * |
3592 | | * Returns: (element-type Gst.Context) (transfer full): List of #GstContext |
3593 | | * |
3594 | | * Since: 1.8 |
3595 | | */ |
3596 | | GList * |
3597 | | gst_element_get_contexts (GstElement * element) |
3598 | 47.7k | { |
3599 | 47.7k | GList *ret; |
3600 | | |
3601 | 47.7k | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
3602 | | |
3603 | 47.7k | GST_OBJECT_LOCK (element); |
3604 | 47.7k | ret = g_list_copy_deep (element->contexts, (GCopyFunc) gst_context_ref, NULL); |
3605 | 47.7k | GST_OBJECT_UNLOCK (element); |
3606 | | |
3607 | 47.7k | return ret; |
3608 | 47.7k | } |
3609 | | |
3610 | | static gint |
3611 | | _match_context_type (GstContext * c1, const gchar * context_type) |
3612 | 0 | { |
3613 | 0 | const gchar *c1_type; |
3614 | |
|
3615 | 0 | c1_type = gst_context_get_context_type (c1); |
3616 | |
|
3617 | 0 | return g_strcmp0 (c1_type, context_type); |
3618 | 0 | } |
3619 | | |
3620 | | /** |
3621 | | * gst_element_get_context_unlocked: |
3622 | | * @element: a #GstElement to get the context of. |
3623 | | * @context_type: a name of a context to retrieve |
3624 | | * |
3625 | | * Gets the context with @context_type set on the element or NULL. |
3626 | | * |
3627 | | * Returns: (transfer full) (nullable): A #GstContext or NULL |
3628 | | * |
3629 | | * Since: 1.8 |
3630 | | */ |
3631 | | GstContext * |
3632 | | gst_element_get_context_unlocked (GstElement * element, |
3633 | | const gchar * context_type) |
3634 | 0 | { |
3635 | 0 | GstContext *ret = NULL; |
3636 | 0 | GList *node; |
3637 | |
|
3638 | 0 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
3639 | | |
3640 | 0 | node = |
3641 | 0 | g_list_find_custom (element->contexts, context_type, |
3642 | 0 | (GCompareFunc) _match_context_type); |
3643 | 0 | if (node && node->data) |
3644 | 0 | ret = gst_context_ref (node->data); |
3645 | |
|
3646 | 0 | return ret; |
3647 | 0 | } |
3648 | | |
3649 | | /** |
3650 | | * gst_element_get_context: |
3651 | | * @element: a #GstElement to get the context of. |
3652 | | * @context_type: a name of a context to retrieve |
3653 | | * |
3654 | | * Gets the context with @context_type set on the element or NULL. |
3655 | | * |
3656 | | * MT safe. |
3657 | | * |
3658 | | * Returns: (transfer full) (nullable): A #GstContext or NULL |
3659 | | * |
3660 | | * Since: 1.8 |
3661 | | */ |
3662 | | GstContext * |
3663 | | gst_element_get_context (GstElement * element, const gchar * context_type) |
3664 | 0 | { |
3665 | 0 | GstContext *ret = NULL; |
3666 | |
|
3667 | 0 | g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); |
3668 | | |
3669 | 0 | GST_OBJECT_LOCK (element); |
3670 | 0 | ret = gst_element_get_context_unlocked (element, context_type); |
3671 | 0 | GST_OBJECT_UNLOCK (element); |
3672 | |
|
3673 | 0 | return ret; |
3674 | 0 | } |
3675 | | |
3676 | | static void |
3677 | | gst_element_property_post_notify_msg (GstElement * element, GObject * obj, |
3678 | | GParamSpec * pspec, gboolean include_value) |
3679 | 0 | { |
3680 | 0 | GValue val = G_VALUE_INIT; |
3681 | 0 | GValue *v; |
3682 | |
|
3683 | 0 | GST_LOG_OBJECT (element, "property '%s' of object %" GST_PTR_FORMAT " has " |
3684 | 0 | "changed, posting message with%s value", pspec->name, obj, |
3685 | 0 | include_value ? "" : "out"); |
3686 | |
|
3687 | 0 | if (include_value && (pspec->flags & G_PARAM_READABLE) != 0) { |
3688 | 0 | g_value_init (&val, pspec->value_type); |
3689 | 0 | g_object_get_property (obj, pspec->name, &val); |
3690 | 0 | v = &val; |
3691 | 0 | } else { |
3692 | 0 | v = NULL; |
3693 | 0 | } |
3694 | 0 | gst_element_post_message (element, |
3695 | 0 | gst_message_new_property_notify (GST_OBJECT_CAST (obj), pspec->name, v)); |
3696 | 0 | } |
3697 | | |
3698 | | static void |
3699 | | gst_element_property_deep_notify_cb (GstElement * element, GObject * prop_obj, |
3700 | | GParamSpec * pspec, gpointer user_data) |
3701 | 0 | { |
3702 | 0 | gboolean include_value = GPOINTER_TO_INT (user_data); |
3703 | |
|
3704 | 0 | gst_element_property_post_notify_msg (element, prop_obj, pspec, |
3705 | 0 | include_value); |
3706 | 0 | } |
3707 | | |
3708 | | static void |
3709 | | gst_element_property_notify_cb (GObject * obj, GParamSpec * pspec, |
3710 | | gpointer user_data) |
3711 | 0 | { |
3712 | 0 | gboolean include_value = GPOINTER_TO_INT (user_data); |
3713 | |
|
3714 | 0 | gst_element_property_post_notify_msg (GST_ELEMENT_CAST (obj), obj, pspec, |
3715 | 0 | include_value); |
3716 | 0 | } |
3717 | | |
3718 | | /** |
3719 | | * gst_element_add_property_notify_watch: |
3720 | | * @element: a #GstElement to watch for property changes |
3721 | | * @property_name: (allow-none): name of property to watch for changes, or |
3722 | | * NULL to watch all properties |
3723 | | * @include_value: whether to include the new property value in the message |
3724 | | * |
3725 | | * Returns: a watch id, which can be used in connection with |
3726 | | * gst_element_remove_property_notify_watch() to remove the watch again. |
3727 | | * |
3728 | | * Since: 1.10 |
3729 | | */ |
3730 | | gulong |
3731 | | gst_element_add_property_notify_watch (GstElement * element, |
3732 | | const gchar * property_name, gboolean include_value) |
3733 | 0 | { |
3734 | 0 | const gchar *sep; |
3735 | 0 | gchar *signal_name; |
3736 | 0 | gulong id; |
3737 | |
|
3738 | 0 | g_return_val_if_fail (GST_IS_ELEMENT (element), 0); |
3739 | | |
3740 | 0 | sep = (property_name != NULL) ? "::" : NULL; |
3741 | 0 | signal_name = g_strconcat ("notify", sep, property_name, NULL); |
3742 | 0 | id = g_signal_connect (element, signal_name, |
3743 | 0 | G_CALLBACK (gst_element_property_notify_cb), |
3744 | 0 | GINT_TO_POINTER (include_value)); |
3745 | 0 | g_free (signal_name); |
3746 | |
|
3747 | 0 | return id; |
3748 | 0 | } |
3749 | | |
3750 | | /** |
3751 | | * gst_element_add_property_deep_notify_watch: |
3752 | | * @element: a #GstElement to watch (recursively) for property changes |
3753 | | * @property_name: (allow-none): name of property to watch for changes, or |
3754 | | * NULL to watch all properties |
3755 | | * @include_value: whether to include the new property value in the message |
3756 | | * |
3757 | | * Returns: a watch id, which can be used in connection with |
3758 | | * gst_element_remove_property_notify_watch() to remove the watch again. |
3759 | | * |
3760 | | * Since: 1.10 |
3761 | | */ |
3762 | | gulong |
3763 | | gst_element_add_property_deep_notify_watch (GstElement * element, |
3764 | | const gchar * property_name, gboolean include_value) |
3765 | 0 | { |
3766 | 0 | const gchar *sep; |
3767 | 0 | gchar *signal_name; |
3768 | 0 | gulong id; |
3769 | |
|
3770 | 0 | g_return_val_if_fail (GST_IS_ELEMENT (element), 0); |
3771 | | |
3772 | 0 | sep = (property_name != NULL) ? "::" : NULL; |
3773 | 0 | signal_name = g_strconcat ("deep-notify", sep, property_name, NULL); |
3774 | 0 | id = g_signal_connect (element, signal_name, |
3775 | 0 | G_CALLBACK (gst_element_property_deep_notify_cb), |
3776 | 0 | GINT_TO_POINTER (include_value)); |
3777 | 0 | g_free (signal_name); |
3778 | |
|
3779 | 0 | return id; |
3780 | 0 | } |
3781 | | |
3782 | | /** |
3783 | | * gst_element_remove_property_notify_watch: |
3784 | | * @element: a #GstElement being watched for property changes |
3785 | | * @watch_id: watch id to remove |
3786 | | * |
3787 | | * Since: 1.10 |
3788 | | */ |
3789 | | void |
3790 | | gst_element_remove_property_notify_watch (GstElement * element, gulong watch_id) |
3791 | 0 | { |
3792 | 0 | g_signal_handler_disconnect (element, watch_id); |
3793 | 0 | } |
3794 | | |
3795 | | /** |
3796 | | * gst_element_call_async: |
3797 | | * @element: a #GstElement |
3798 | | * @func: Function to call asynchronously from another thread |
3799 | | * @user_data: Data to pass to @func |
3800 | | * @destroy_notify: GDestroyNotify for @user_data |
3801 | | * |
3802 | | * Calls @func from another thread and passes @user_data to it. This is to be |
3803 | | * used for cases when a state change has to be performed from a streaming |
3804 | | * thread, directly via gst_element_set_state() or indirectly e.g. via SEEK |
3805 | | * events. |
3806 | | * |
3807 | | * Calling those functions directly from the streaming thread will cause |
3808 | | * deadlocks in many situations, as they might involve waiting for the |
3809 | | * streaming thread to shut down from this very streaming thread. |
3810 | | * |
3811 | | * MT safe. |
3812 | | * |
3813 | | * Deprecated: 1.28: Use gst_object_call_async() or gst_call_async() instead. |
3814 | | * |
3815 | | * Since: 1.10 |
3816 | | */ |
3817 | | void |
3818 | | gst_element_call_async (GstElement * element, GstElementCallAsyncFunc func, |
3819 | | gpointer user_data, GDestroyNotify destroy_notify) |
3820 | 0 | { |
3821 | 0 | g_return_if_fail (GST_IS_ELEMENT (element)); |
3822 | | |
3823 | 0 | _priv_gst_object_call_async (GST_OBJECT_CAST (element), (GFunc) func, |
3824 | 0 | user_data, destroy_notify); |
3825 | 0 | } |
3826 | | |
3827 | | /** |
3828 | | * gst_make_element_message_details: |
3829 | | * @name: Name of the first field to set |
3830 | | * @...: variable arguments in the same form as #GstStructure |
3831 | | * |
3832 | | * Create a #GstStructure to be used with #gst_element_message_full_with_details. |
3833 | | * %NULL terminator required. |
3834 | | * |
3835 | | * Since: 1.10 |
3836 | | */ |
3837 | | GstStructure * |
3838 | | gst_make_element_message_details (const char *name, ...) |
3839 | 104 | { |
3840 | 104 | GstStructure *structure; |
3841 | 104 | va_list varargs; |
3842 | | |
3843 | 104 | if (name == NULL) |
3844 | 0 | return NULL; |
3845 | | |
3846 | 104 | va_start (varargs, name); |
3847 | 104 | structure = gst_structure_new_valist ("details", name, varargs); |
3848 | 104 | va_end (varargs); |
3849 | | |
3850 | 104 | return structure; |
3851 | 104 | } |