|
1 /* GStreamer |
|
2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> |
|
3 * 2000 Wim Taymans <wtay@chello.be> |
|
4 * 2005 Andy Wingo <wingo@pobox.com> |
|
5 * 2006 Edward Hervey <bilboed@bilboed.com> |
|
6 * |
|
7 * gstghostpad.c: Proxy pads |
|
8 * |
|
9 * This library is free software; you can redistribute it and/or |
|
10 * modify it under the terms of the GNU Library General Public |
|
11 * License as published by the Free Software Foundation; either |
|
12 * version 2 of the License, or (at your option) any later version. |
|
13 * |
|
14 * This library is distributed in the hope that it will be useful, |
|
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
17 * Library General Public License for more details. |
|
18 * |
|
19 * You should have received a copy of the GNU Library General Public |
|
20 * License along with this library; if not, write to the |
|
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
22 * Boston, MA 02111-1307, USA. |
|
23 */ |
|
24 |
|
25 /** |
|
26 * SECTION:gstghostpad |
|
27 * @short_description: Pseudo link pads |
|
28 * @see_also: #GstPad |
|
29 * |
|
30 * GhostPads are useful when organizing pipelines with #GstBin like elements. |
|
31 * The idea here is to create hierarchical element graphs. The bin element |
|
32 * contains a sub-graph. Now one would like to treat the bin-element like other |
|
33 * #GstElements. This is where GhostPads come into play. A GhostPad acts as a |
|
34 * proxy for another pad. Thus the bin can have sink and source ghost-pads that |
|
35 * are associated with sink and source pads of the child elements. |
|
36 * |
|
37 * If the target pad is known at creation time, gst_ghost_pad_new() is the |
|
38 * function to use to get a ghost-pad. Otherwise one can use gst_ghost_pad_new_no_target() |
|
39 * to create the ghost-pad and use gst_ghost_pad_set_target() to establish the |
|
40 * association later on. |
|
41 * |
|
42 * Note that GhostPads add overhead to the data processing of a pipeline. |
|
43 * |
|
44 * Last reviewed on 2005-11-18 (0.9.5) |
|
45 */ |
|
46 |
|
47 #include "gst_private.h" |
|
48 #include "gstinfo.h" |
|
49 |
|
50 #include "gstghostpad.h" |
|
51 #include "gst.h" |
|
52 |
|
53 #ifdef __SYMBIAN32__ |
|
54 #include <glib_global.h> |
|
55 #endif |
|
56 |
|
57 #define GST_CAT_DEFAULT GST_CAT_PADS |
|
58 |
|
59 #define GST_TYPE_PROXY_PAD (gst_proxy_pad_get_type ()) |
|
60 #define GST_IS_PROXY_PAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PROXY_PAD)) |
|
61 #define GST_IS_PROXY_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PROXY_PAD)) |
|
62 #define GST_PROXY_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PROXY_PAD, GstProxyPad)) |
|
63 #define GST_PROXY_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PROXY_PAD, GstProxyPadClass)) |
|
64 #define GST_PROXY_PAD_CAST(obj) ((GstProxyPad *)obj) |
|
65 |
|
66 #define GST_PROXY_PAD_TARGET(pad) (GST_PROXY_PAD_CAST (pad)->target) |
|
67 #define GST_PROXY_PAD_INTERNAL(pad) (GST_PROXY_PAD_CAST (pad)->internal) |
|
68 |
|
69 typedef struct _GstProxyPad GstProxyPad; |
|
70 typedef struct _GstProxyPadClass GstProxyPadClass; |
|
71 |
|
72 #define GST_PROXY_GET_LOCK(pad) (GST_PROXY_PAD_CAST (pad)->proxy_lock) |
|
73 #define GST_PROXY_LOCK(pad) (g_mutex_lock (GST_PROXY_GET_LOCK (pad))) |
|
74 #define GST_PROXY_UNLOCK(pad) (g_mutex_unlock (GST_PROXY_GET_LOCK (pad))) |
|
75 |
|
76 struct _GstProxyPad |
|
77 { |
|
78 GstPad pad; |
|
79 |
|
80 /* with PROXY_LOCK */ |
|
81 GMutex *proxy_lock; |
|
82 GstPad *target; |
|
83 GstPad *internal; |
|
84 }; |
|
85 |
|
86 struct _GstProxyPadClass |
|
87 { |
|
88 GstPadClass parent_class; |
|
89 |
|
90 /*< private > */ |
|
91 gpointer _gst_reserved[1]; |
|
92 }; |
|
93 |
|
94 static GType gst_proxy_pad_get_type (void); |
|
95 |
|
96 G_DEFINE_TYPE (GstProxyPad, gst_proxy_pad, GST_TYPE_PAD); |
|
97 |
|
98 static GstPad *gst_proxy_pad_get_target (GstPad * pad); |
|
99 |
|
100 static void gst_proxy_pad_dispose (GObject * object); |
|
101 static void gst_proxy_pad_finalize (GObject * object); |
|
102 |
|
103 #ifndef GST_DISABLE_LOADSAVE |
|
104 static xmlNodePtr gst_proxy_pad_save_thyself (GstObject * object, |
|
105 xmlNodePtr parent); |
|
106 #endif |
|
107 |
|
108 |
|
109 static void |
|
110 gst_proxy_pad_class_init (GstProxyPadClass * klass) |
|
111 { |
|
112 GObjectClass *gobject_class = (GObjectClass *) klass; |
|
113 |
|
114 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_proxy_pad_dispose); |
|
115 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_proxy_pad_finalize); |
|
116 |
|
117 #ifndef GST_DISABLE_LOADSAVE |
|
118 { |
|
119 GstObjectClass *gstobject_class = (GstObjectClass *) klass; |
|
120 |
|
121 gstobject_class->save_thyself = |
|
122 GST_DEBUG_FUNCPTR (gst_proxy_pad_save_thyself); |
|
123 } |
|
124 #endif |
|
125 } |
|
126 |
|
127 static const GstQueryType * |
|
128 gst_proxy_pad_do_query_type (GstPad * pad) |
|
129 { |
|
130 GstPad *target = gst_proxy_pad_get_target (pad); |
|
131 const GstQueryType *res = NULL; |
|
132 |
|
133 if (target) { |
|
134 res = gst_pad_get_query_types (target); |
|
135 gst_object_unref (target); |
|
136 } |
|
137 return res; |
|
138 } |
|
139 |
|
140 static gboolean |
|
141 gst_proxy_pad_do_event (GstPad * pad, GstEvent * event) |
|
142 { |
|
143 gboolean res = FALSE; |
|
144 GstPad *internal = GST_PROXY_PAD_INTERNAL (pad); |
|
145 |
|
146 res = gst_pad_push_event (internal, event); |
|
147 |
|
148 return res; |
|
149 } |
|
150 |
|
151 static gboolean |
|
152 gst_proxy_pad_do_query (GstPad * pad, GstQuery * query) |
|
153 { |
|
154 gboolean res = FALSE; |
|
155 GstPad *target = gst_proxy_pad_get_target (pad); |
|
156 |
|
157 if (target) { |
|
158 res = gst_pad_query (target, query); |
|
159 gst_object_unref (target); |
|
160 } |
|
161 |
|
162 return res; |
|
163 } |
|
164 |
|
165 static GList * |
|
166 gst_proxy_pad_do_internal_link (GstPad * pad) |
|
167 { |
|
168 GList *res = NULL; |
|
169 GstPad *target = gst_proxy_pad_get_target (pad); |
|
170 |
|
171 if (target) { |
|
172 res = gst_pad_get_internal_links (target); |
|
173 gst_object_unref (target); |
|
174 } |
|
175 |
|
176 return res; |
|
177 } |
|
178 |
|
179 static GstFlowReturn |
|
180 gst_proxy_pad_do_bufferalloc (GstPad * pad, guint64 offset, guint size, |
|
181 GstCaps * caps, GstBuffer ** buf) |
|
182 { |
|
183 GstFlowReturn result; |
|
184 GstPad *internal = GST_PROXY_PAD_INTERNAL (pad); |
|
185 |
|
186 result = gst_pad_alloc_buffer (internal, offset, size, caps, buf); |
|
187 |
|
188 return result; |
|
189 } |
|
190 |
|
191 static GstFlowReturn |
|
192 gst_proxy_pad_do_chain (GstPad * pad, GstBuffer * buffer) |
|
193 { |
|
194 GstFlowReturn res; |
|
195 GstPad *internal = GST_PROXY_PAD_INTERNAL (pad); |
|
196 |
|
197 res = gst_pad_push (internal, buffer); |
|
198 |
|
199 return res; |
|
200 } |
|
201 |
|
202 static GstFlowReturn |
|
203 gst_proxy_pad_do_getrange (GstPad * pad, guint64 offset, guint size, |
|
204 GstBuffer ** buffer) |
|
205 { |
|
206 GstFlowReturn res; |
|
207 GstPad *internal = GST_PROXY_PAD_INTERNAL (pad); |
|
208 |
|
209 res = gst_pad_pull_range (internal, offset, size, buffer); |
|
210 |
|
211 return res; |
|
212 } |
|
213 |
|
214 static gboolean |
|
215 gst_proxy_pad_do_checkgetrange (GstPad * pad) |
|
216 { |
|
217 gboolean result; |
|
218 GstPad *internal = GST_PROXY_PAD_INTERNAL (pad); |
|
219 |
|
220 result = gst_pad_check_pull_range (internal); |
|
221 |
|
222 return result; |
|
223 } |
|
224 |
|
225 static GstCaps * |
|
226 gst_proxy_pad_do_getcaps (GstPad * pad) |
|
227 { |
|
228 GstPad *target = gst_proxy_pad_get_target (pad); |
|
229 GstCaps *res; |
|
230 GstPadTemplate *templ = GST_PAD_PAD_TEMPLATE (pad); |
|
231 |
|
232 if (target) { |
|
233 /* if we have a real target, proxy the call */ |
|
234 res = gst_pad_get_caps (target); |
|
235 gst_object_unref (target); |
|
236 |
|
237 GST_DEBUG_OBJECT (pad, "get caps of target: %" GST_PTR_FORMAT, res); |
|
238 |
|
239 /* filter against the template */ |
|
240 if (templ && res) { |
|
241 GstCaps *filt, *tmp; |
|
242 |
|
243 filt = GST_PAD_TEMPLATE_CAPS (templ); |
|
244 if (filt) { |
|
245 tmp = gst_caps_intersect (filt, res); |
|
246 gst_caps_unref (res); |
|
247 res = tmp; |
|
248 GST_DEBUG_OBJECT (pad, |
|
249 "filtered against template gives %" GST_PTR_FORMAT, res); |
|
250 } |
|
251 } |
|
252 } else { |
|
253 /* else, if we have a template, use its caps. */ |
|
254 if (templ) { |
|
255 res = GST_PAD_TEMPLATE_CAPS (templ); |
|
256 GST_DEBUG_OBJECT (pad, |
|
257 "using pad template %p with caps %p %" GST_PTR_FORMAT, templ, res, |
|
258 res); |
|
259 res = gst_caps_ref (res); |
|
260 goto done; |
|
261 } |
|
262 |
|
263 /* last resort, any caps */ |
|
264 GST_DEBUG_OBJECT (pad, "pad has no template, returning ANY"); |
|
265 res = gst_caps_new_any (); |
|
266 } |
|
267 |
|
268 done: |
|
269 return res; |
|
270 } |
|
271 |
|
272 static gboolean |
|
273 gst_proxy_pad_do_acceptcaps (GstPad * pad, GstCaps * caps) |
|
274 { |
|
275 GstPad *target = gst_proxy_pad_get_target (pad); |
|
276 gboolean res; |
|
277 |
|
278 if (target) { |
|
279 res = gst_pad_accept_caps (target, caps); |
|
280 gst_object_unref (target); |
|
281 } else { |
|
282 /* We don't have a target, we return TRUE and we assume that any future |
|
283 * target will be able to deal with any configured caps. */ |
|
284 res = TRUE; |
|
285 } |
|
286 |
|
287 return res; |
|
288 } |
|
289 |
|
290 static void |
|
291 gst_proxy_pad_do_fixatecaps (GstPad * pad, GstCaps * caps) |
|
292 { |
|
293 GstPad *target = gst_proxy_pad_get_target (pad); |
|
294 |
|
295 if (target) { |
|
296 gst_pad_fixate_caps (target, caps); |
|
297 gst_object_unref (target); |
|
298 } |
|
299 } |
|
300 |
|
301 static gboolean |
|
302 gst_proxy_pad_do_setcaps (GstPad * pad, GstCaps * caps) |
|
303 { |
|
304 GstPad *target = gst_proxy_pad_get_target (pad); |
|
305 gboolean res; |
|
306 |
|
307 if (target) { |
|
308 res = gst_pad_set_caps (target, caps); |
|
309 gst_object_unref (target); |
|
310 } else { |
|
311 /* We don't have any target, but we shouldn't return FALSE since this |
|
312 * would stop the actual push of a buffer (which might trigger a pad block |
|
313 * or probe, or properly return GST_FLOW_NOT_LINKED. |
|
314 */ |
|
315 res = TRUE; |
|
316 } |
|
317 return res; |
|
318 } |
|
319 |
|
320 static gboolean |
|
321 gst_proxy_pad_set_target_unlocked (GstPad * pad, GstPad * target) |
|
322 { |
|
323 GstPad *oldtarget; |
|
324 |
|
325 if (target) { |
|
326 GST_LOG_OBJECT (pad, "setting target %s:%s", GST_DEBUG_PAD_NAME (target)); |
|
327 |
|
328 if (G_UNLIKELY (GST_PAD_DIRECTION (pad) != GST_PAD_DIRECTION (target))) |
|
329 goto wrong_direction; |
|
330 } else |
|
331 GST_LOG_OBJECT (pad, "clearing target"); |
|
332 |
|
333 /* clear old target */ |
|
334 if ((oldtarget = GST_PROXY_PAD_TARGET (pad))) { |
|
335 gst_object_unref (oldtarget); |
|
336 } |
|
337 /* set and ref new target if any */ |
|
338 if (target) |
|
339 GST_PROXY_PAD_TARGET (pad) = gst_object_ref (target); |
|
340 else |
|
341 GST_PROXY_PAD_TARGET (pad) = NULL; |
|
342 |
|
343 return TRUE; |
|
344 |
|
345 /* ERRORS */ |
|
346 wrong_direction: |
|
347 { |
|
348 GST_ERROR_OBJECT (pad, |
|
349 "target pad doesn't have the same direction as ourself"); |
|
350 return FALSE; |
|
351 } |
|
352 } |
|
353 |
|
354 static gboolean |
|
355 gst_proxy_pad_set_target (GstPad * pad, GstPad * target) |
|
356 { |
|
357 gboolean result; |
|
358 |
|
359 GST_PROXY_LOCK (pad); |
|
360 result = gst_proxy_pad_set_target_unlocked (pad, target); |
|
361 GST_PROXY_UNLOCK (pad); |
|
362 |
|
363 return result; |
|
364 } |
|
365 |
|
366 static GstPad * |
|
367 gst_proxy_pad_get_target (GstPad * pad) |
|
368 { |
|
369 GstPad *target; |
|
370 |
|
371 GST_PROXY_LOCK (pad); |
|
372 target = GST_PROXY_PAD_TARGET (pad); |
|
373 if (target) |
|
374 gst_object_ref (target); |
|
375 GST_PROXY_UNLOCK (pad); |
|
376 |
|
377 return target; |
|
378 } |
|
379 |
|
380 static void |
|
381 gst_proxy_pad_dispose (GObject * object) |
|
382 { |
|
383 GstPad *pad = GST_PAD (object); |
|
384 GstPad **target_p; |
|
385 |
|
386 GST_PROXY_LOCK (pad); |
|
387 /* remove and unref the target */ |
|
388 target_p = &GST_PROXY_PAD_TARGET (pad); |
|
389 gst_object_replace ((GstObject **) target_p, NULL); |
|
390 /* The internal is only cleared by GstGhostPad::dispose, since it is the |
|
391 * parent of non-ghost GstProxyPad and owns the refcount on the internal. |
|
392 */ |
|
393 GST_PROXY_UNLOCK (pad); |
|
394 |
|
395 G_OBJECT_CLASS (gst_proxy_pad_parent_class)->dispose (object); |
|
396 } |
|
397 |
|
398 static void |
|
399 gst_proxy_pad_finalize (GObject * object) |
|
400 { |
|
401 GstProxyPad *pad = GST_PROXY_PAD (object); |
|
402 |
|
403 g_mutex_free (pad->proxy_lock); |
|
404 pad->proxy_lock = NULL; |
|
405 |
|
406 G_OBJECT_CLASS (gst_proxy_pad_parent_class)->finalize (object); |
|
407 } |
|
408 |
|
409 static void |
|
410 gst_proxy_pad_init (GstProxyPad * ppad) |
|
411 { |
|
412 GstPad *pad = (GstPad *) ppad; |
|
413 |
|
414 ppad->proxy_lock = g_mutex_new (); |
|
415 |
|
416 gst_pad_set_query_type_function (pad, |
|
417 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query_type)); |
|
418 gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_proxy_pad_do_event)); |
|
419 gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query)); |
|
420 gst_pad_set_internal_link_function (pad, |
|
421 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_internal_link)); |
|
422 |
|
423 gst_pad_set_getcaps_function (pad, |
|
424 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getcaps)); |
|
425 gst_pad_set_acceptcaps_function (pad, |
|
426 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_acceptcaps)); |
|
427 gst_pad_set_fixatecaps_function (pad, |
|
428 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_fixatecaps)); |
|
429 gst_pad_set_setcaps_function (pad, |
|
430 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_setcaps)); |
|
431 } |
|
432 |
|
433 #ifndef GST_DISABLE_LOADSAVE |
|
434 /** |
|
435 * gst_proxy_pad_save_thyself: |
|
436 * @pad: a ghost #GstPad to save. |
|
437 * @parent: the parent #xmlNodePtr to save the description in. |
|
438 * |
|
439 * Saves the ghost pad into an xml representation. |
|
440 * |
|
441 * Returns: the #xmlNodePtr representation of the pad. |
|
442 */ |
|
443 static xmlNodePtr |
|
444 gst_proxy_pad_save_thyself (GstObject * object, xmlNodePtr parent) |
|
445 { |
|
446 xmlNodePtr self; |
|
447 GstProxyPad *proxypad; |
|
448 GstPad *pad; |
|
449 GstPad *peer; |
|
450 |
|
451 g_return_val_if_fail (GST_IS_PROXY_PAD (object), NULL); |
|
452 |
|
453 self = xmlNewChild (parent, NULL, (xmlChar *) "ghostpad", NULL); |
|
454 xmlNewChild (self, NULL, (xmlChar *) "name", |
|
455 (xmlChar *) GST_OBJECT_NAME (object)); |
|
456 xmlNewChild (self, NULL, (xmlChar *) "parent", |
|
457 (xmlChar *) GST_OBJECT_NAME (GST_OBJECT_PARENT (object))); |
|
458 |
|
459 proxypad = GST_PROXY_PAD_CAST (object); |
|
460 pad = GST_PAD_CAST (proxypad); |
|
461 peer = GST_PAD_CAST (pad->peer); |
|
462 |
|
463 if (GST_IS_PAD (pad)) { |
|
464 if (GST_PAD_IS_SRC (pad)) |
|
465 xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "source"); |
|
466 else if (GST_PAD_IS_SINK (pad)) |
|
467 xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "sink"); |
|
468 else |
|
469 xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "unknown"); |
|
470 } else { |
|
471 xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "unknown"); |
|
472 } |
|
473 if (GST_IS_PAD (peer)) { |
|
474 gchar *content = g_strdup_printf ("%s.%s", |
|
475 GST_OBJECT_NAME (GST_PAD_PARENT (peer)), GST_PAD_NAME (peer)); |
|
476 |
|
477 xmlNewChild (self, NULL, (xmlChar *) "peer", (xmlChar *) content); |
|
478 g_free (content); |
|
479 } else { |
|
480 xmlNewChild (self, NULL, (xmlChar *) "peer", NULL); |
|
481 } |
|
482 |
|
483 return self; |
|
484 } |
|
485 #endif /* GST_DISABLE_LOADSAVE */ |
|
486 |
|
487 |
|
488 /*********************************************************************** |
|
489 * Ghost pads, implemented as a pair of proxy pads (sort of) |
|
490 */ |
|
491 |
|
492 |
|
493 struct _GstGhostPad |
|
494 { |
|
495 GstProxyPad pad; |
|
496 |
|
497 /* with PROXY_LOCK */ |
|
498 gulong notify_id; |
|
499 |
|
500 /*< private > */ |
|
501 gpointer _gst_reserved[GST_PADDING]; |
|
502 }; |
|
503 |
|
504 struct _GstGhostPadClass |
|
505 { |
|
506 GstProxyPadClass parent_class; |
|
507 |
|
508 /*< private > */ |
|
509 gpointer _gst_reserved[GST_PADDING]; |
|
510 }; |
|
511 |
|
512 |
|
513 G_DEFINE_TYPE (GstGhostPad, gst_ghost_pad, GST_TYPE_PROXY_PAD); |
|
514 |
|
515 static void gst_ghost_pad_dispose (GObject * object); |
|
516 |
|
517 static void |
|
518 gst_ghost_pad_class_init (GstGhostPadClass * klass) |
|
519 { |
|
520 GObjectClass *gobject_class = (GObjectClass *) klass; |
|
521 |
|
522 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ghost_pad_dispose); |
|
523 } |
|
524 |
|
525 /* see gstghostpad design docs */ |
|
526 static gboolean |
|
527 gst_ghost_pad_internal_do_activate_push (GstPad * pad, gboolean active) |
|
528 { |
|
529 gboolean ret; |
|
530 GstPad *other; |
|
531 |
|
532 GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, we're ok", |
|
533 (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad)); |
|
534 |
|
535 /* in both cases (SRC and SINK) we activate just the internal pad. The targets |
|
536 * will be activated later (or already in case of a ghost sinkpad). */ |
|
537 other = GST_PROXY_PAD_INTERNAL (pad); |
|
538 ret = gst_pad_activate_push (other, active); |
|
539 |
|
540 return ret; |
|
541 } |
|
542 |
|
543 static gboolean |
|
544 gst_ghost_pad_internal_do_activate_pull (GstPad * pad, gboolean active) |
|
545 { |
|
546 gboolean ret; |
|
547 GstPad *other; |
|
548 |
|
549 GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"), |
|
550 GST_DEBUG_PAD_NAME (pad)); |
|
551 |
|
552 if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) { |
|
553 /* we are activated in pull mode by our peer element, which is a sinkpad |
|
554 * that wants to operate in pull mode. This activation has to propagate |
|
555 * upstream throught the pipeline. We call the internal activation function, |
|
556 * which will trigger gst_ghost_pad_do_activate_pull, which propagates even |
|
557 * further upstream */ |
|
558 GST_LOG_OBJECT (pad, "pad is src, activate internal"); |
|
559 other = GST_PROXY_PAD_INTERNAL (pad); |
|
560 ret = gst_pad_activate_pull (other, active); |
|
561 } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) { |
|
562 /* We are SINK, the ghostpad is SRC, we propagate the activation upstream |
|
563 * since we hold a pointer to the upstream peer. */ |
|
564 GST_LOG_OBJECT (pad, "activating peer"); |
|
565 ret = gst_pad_activate_pull (other, active); |
|
566 gst_object_unref (other); |
|
567 } else { |
|
568 /* this is failure, we can't activate pull if there is no peer */ |
|
569 GST_LOG_OBJECT (pad, "not src and no peer, failing"); |
|
570 ret = FALSE; |
|
571 } |
|
572 |
|
573 return ret; |
|
574 } |
|
575 |
|
576 static gboolean |
|
577 gst_ghost_pad_do_activate_push (GstPad * pad, gboolean active) |
|
578 { |
|
579 gboolean ret; |
|
580 GstPad *other; |
|
581 |
|
582 GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, proxy internal", |
|
583 (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad)); |
|
584 |
|
585 /* just activate the internal pad */ |
|
586 other = GST_PROXY_PAD_INTERNAL (pad); |
|
587 ret = gst_pad_activate_push (other, active); |
|
588 |
|
589 return ret; |
|
590 } |
|
591 |
|
592 static gboolean |
|
593 gst_ghost_pad_do_activate_pull (GstPad * pad, gboolean active) |
|
594 { |
|
595 gboolean ret; |
|
596 GstPad *other; |
|
597 |
|
598 GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"), |
|
599 GST_DEBUG_PAD_NAME (pad)); |
|
600 |
|
601 if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) { |
|
602 /* the ghostpad is SRC and activated in pull mode by its peer, call the |
|
603 * activation function of the internal pad to propagate the activation |
|
604 * upstream */ |
|
605 GST_LOG_OBJECT (pad, "pad is src, activate internal"); |
|
606 other = GST_PROXY_PAD_INTERNAL (pad); |
|
607 ret = gst_pad_activate_pull (other, active); |
|
608 } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) { |
|
609 /* We are SINK and activated by the internal pad, propagate activation |
|
610 * upstream because we hold a ref to the upstream peer */ |
|
611 GST_LOG_OBJECT (pad, "activating peer"); |
|
612 ret = gst_pad_activate_pull (other, active); |
|
613 gst_object_unref (other); |
|
614 } else { |
|
615 /* no peer, we fail */ |
|
616 GST_LOG_OBJECT (pad, "pad not src and no peer, failing"); |
|
617 ret = FALSE; |
|
618 } |
|
619 |
|
620 return ret; |
|
621 } |
|
622 |
|
623 static GstPadLinkReturn |
|
624 gst_ghost_pad_do_link (GstPad * pad, GstPad * peer) |
|
625 { |
|
626 GstPadLinkReturn ret; |
|
627 GstPad *internal; |
|
628 |
|
629 GST_DEBUG_OBJECT (pad, "linking ghostpad"); |
|
630 |
|
631 internal = GST_PROXY_PAD_INTERNAL (pad); |
|
632 if (!gst_proxy_pad_set_target (internal, peer)) |
|
633 goto target_failed; |
|
634 |
|
635 ret = GST_PAD_LINK_OK; |
|
636 /* if we are a source pad, we should call the peer link function |
|
637 * if the peer has one, see design docs. */ |
|
638 if (GST_PAD_IS_SRC (pad)) { |
|
639 if (GST_PAD_LINKFUNC (peer)) { |
|
640 ret = GST_PAD_LINKFUNC (peer) (peer, pad); |
|
641 if (ret != GST_PAD_LINK_OK) |
|
642 goto link_failed; |
|
643 } |
|
644 } |
|
645 return ret; |
|
646 |
|
647 /* ERRORS */ |
|
648 target_failed: |
|
649 { |
|
650 GST_DEBUG_OBJECT (pad, "setting target failed"); |
|
651 return GST_PAD_LINK_REFUSED; |
|
652 } |
|
653 link_failed: |
|
654 { |
|
655 GST_DEBUG_OBJECT (pad, "linking failed"); |
|
656 /* clear target again */ |
|
657 gst_proxy_pad_set_target (internal, NULL); |
|
658 return ret; |
|
659 } |
|
660 } |
|
661 |
|
662 static void |
|
663 gst_ghost_pad_do_unlink (GstPad * pad) |
|
664 { |
|
665 GstPad *target; |
|
666 GstPad *internal; |
|
667 |
|
668 target = gst_proxy_pad_get_target (pad); |
|
669 internal = GST_PROXY_PAD_INTERNAL (pad); |
|
670 |
|
671 GST_DEBUG_OBJECT (pad, "unlinking ghostpad"); |
|
672 |
|
673 /* The target of the internal pad is no longer valid */ |
|
674 gst_proxy_pad_set_target (internal, NULL); |
|
675 |
|
676 if (target) { |
|
677 if (GST_PAD_UNLINKFUNC (target)) |
|
678 GST_PAD_UNLINKFUNC (target) (target); |
|
679 |
|
680 gst_object_unref (target); |
|
681 } |
|
682 } |
|
683 |
|
684 static void |
|
685 on_int_notify (GstPad * internal, GParamSpec * unused, GstGhostPad * pad) |
|
686 { |
|
687 GstCaps *caps; |
|
688 |
|
689 g_object_get (internal, "caps", &caps, NULL); |
|
690 |
|
691 GST_OBJECT_LOCK (pad); |
|
692 gst_caps_replace (&(GST_PAD_CAPS (pad)), caps); |
|
693 GST_OBJECT_UNLOCK (pad); |
|
694 |
|
695 g_object_notify (G_OBJECT (pad), "caps"); |
|
696 if (caps) |
|
697 gst_caps_unref (caps); |
|
698 } |
|
699 |
|
700 static void |
|
701 gst_ghost_pad_init (GstGhostPad * pad) |
|
702 { |
|
703 gst_pad_set_activatepull_function (GST_PAD_CAST (pad), |
|
704 GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_pull)); |
|
705 gst_pad_set_activatepush_function (GST_PAD_CAST (pad), |
|
706 GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_push)); |
|
707 } |
|
708 |
|
709 static void |
|
710 gst_ghost_pad_dispose (GObject * object) |
|
711 { |
|
712 GstPad *pad; |
|
713 GstPad *internal; |
|
714 GstPad *intpeer; |
|
715 |
|
716 pad = GST_PAD (object); |
|
717 |
|
718 GST_DEBUG_OBJECT (pad, "dispose"); |
|
719 |
|
720 GST_PROXY_LOCK (pad); |
|
721 internal = GST_PROXY_PAD_INTERNAL (pad); |
|
722 |
|
723 gst_pad_set_activatepull_function (internal, NULL); |
|
724 gst_pad_set_activatepush_function (internal, NULL); |
|
725 |
|
726 g_signal_handler_disconnect (internal, GST_GHOST_PAD_CAST (pad)->notify_id); |
|
727 |
|
728 intpeer = gst_pad_get_peer (internal); |
|
729 if (intpeer) { |
|
730 if (GST_PAD_IS_SRC (internal)) |
|
731 gst_pad_unlink (internal, intpeer); |
|
732 else |
|
733 gst_pad_unlink (intpeer, internal); |
|
734 |
|
735 gst_object_unref (intpeer); |
|
736 } |
|
737 |
|
738 GST_PROXY_PAD_INTERNAL (internal) = NULL; |
|
739 |
|
740 /* disposes of the internal pad, since the ghostpad is the only possible object |
|
741 * that has a refcount on the internal pad. */ |
|
742 gst_object_unparent (GST_OBJECT_CAST (internal)); |
|
743 |
|
744 GST_PROXY_UNLOCK (pad); |
|
745 |
|
746 G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object); |
|
747 } |
|
748 |
|
749 static GstPad * |
|
750 gst_ghost_pad_new_full (const gchar * name, GstPadDirection dir, |
|
751 GstPadTemplate * templ) |
|
752 { |
|
753 GstPad *ret; |
|
754 GstPad *internal; |
|
755 GstPadDirection otherdir; |
|
756 |
|
757 g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL); |
|
758 |
|
759 /* OBJECT CREATION */ |
|
760 if (templ) { |
|
761 ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name, |
|
762 "direction", dir, "template", templ, NULL); |
|
763 } else { |
|
764 ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name, |
|
765 "direction", dir, NULL); |
|
766 } |
|
767 |
|
768 /* Set directional padfunctions for ghostpad */ |
|
769 if (dir == GST_PAD_SINK) { |
|
770 gst_pad_set_bufferalloc_function (ret, |
|
771 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc)); |
|
772 gst_pad_set_chain_function (ret, |
|
773 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain)); |
|
774 } else { |
|
775 gst_pad_set_getrange_function (ret, |
|
776 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange)); |
|
777 gst_pad_set_checkgetrange_function (ret, |
|
778 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange)); |
|
779 } |
|
780 |
|
781 /* link/unlink functions */ |
|
782 gst_pad_set_link_function (ret, GST_DEBUG_FUNCPTR (gst_ghost_pad_do_link)); |
|
783 gst_pad_set_unlink_function (ret, |
|
784 GST_DEBUG_FUNCPTR (gst_ghost_pad_do_unlink)); |
|
785 |
|
786 |
|
787 /* INTERNAL PAD, it always exists and is child of the ghostpad */ |
|
788 otherdir = (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC; |
|
789 if (templ) { |
|
790 internal = |
|
791 g_object_new (GST_TYPE_PROXY_PAD, "name", NULL, |
|
792 "direction", otherdir, "template", templ, NULL); |
|
793 } else { |
|
794 internal = |
|
795 g_object_new (GST_TYPE_PROXY_PAD, "name", NULL, |
|
796 "direction", otherdir, NULL); |
|
797 } |
|
798 GST_PAD_UNSET_FLUSHING (internal); |
|
799 |
|
800 /* Set directional padfunctions for internal pad */ |
|
801 if (dir == GST_PAD_SRC) { |
|
802 gst_pad_set_bufferalloc_function (internal, |
|
803 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc)); |
|
804 gst_pad_set_chain_function (internal, |
|
805 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain)); |
|
806 } else { |
|
807 gst_pad_set_getrange_function (internal, |
|
808 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange)); |
|
809 gst_pad_set_checkgetrange_function (internal, |
|
810 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange)); |
|
811 } |
|
812 |
|
813 GST_PROXY_LOCK (ret); |
|
814 |
|
815 /* now make the ghostpad a parent of the internal pad */ |
|
816 if (!gst_object_set_parent (GST_OBJECT_CAST (internal), |
|
817 GST_OBJECT_CAST (ret))) |
|
818 goto parent_failed; |
|
819 |
|
820 /* The ghostpad is the parent of the internal pad and is the only object that |
|
821 * can have a refcount on the internal pad. |
|
822 * At this point, the GstGhostPad has a refcount of 1, and the internal pad has |
|
823 * a refcount of 1. |
|
824 * When the refcount of the GstGhostPad drops to 0, the ghostpad will dispose |
|
825 * it's refcount on the internal pad in the dispose method by un-parenting it. |
|
826 * This is why we don't take extra refcounts in the assignments below |
|
827 */ |
|
828 GST_PROXY_PAD_INTERNAL (ret) = internal; |
|
829 GST_PROXY_PAD_INTERNAL (internal) = ret; |
|
830 |
|
831 /* could be more general here, iterating over all writable properties... |
|
832 * taking the short road for now tho */ |
|
833 GST_GHOST_PAD_CAST (ret)->notify_id = |
|
834 g_signal_connect (internal, "notify::caps", G_CALLBACK (on_int_notify), |
|
835 ret); |
|
836 |
|
837 /* call function to init values of the pad caps */ |
|
838 on_int_notify (internal, NULL, GST_GHOST_PAD_CAST (ret)); |
|
839 |
|
840 /* special activation functions for the internal pad */ |
|
841 gst_pad_set_activatepull_function (internal, |
|
842 GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_pull)); |
|
843 gst_pad_set_activatepush_function (internal, |
|
844 GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_push)); |
|
845 |
|
846 GST_PROXY_UNLOCK (ret); |
|
847 |
|
848 return ret; |
|
849 |
|
850 /* ERRORS */ |
|
851 parent_failed: |
|
852 { |
|
853 GST_WARNING_OBJECT (ret, "Could not set internal pad %s:%s", |
|
854 GST_DEBUG_PAD_NAME (internal)); |
|
855 g_critical ("Could not set internal pad %s:%s", |
|
856 GST_DEBUG_PAD_NAME (internal)); |
|
857 GST_PROXY_UNLOCK (ret); |
|
858 gst_object_unref (ret); |
|
859 gst_object_unref (internal); |
|
860 return NULL; |
|
861 } |
|
862 } |
|
863 |
|
864 /** |
|
865 * gst_ghost_pad_new_no_target: |
|
866 * @name: the name of the new pad, or NULL to assign a default name. |
|
867 * @dir: the direction of the ghostpad |
|
868 * |
|
869 * Create a new ghostpad without a target with the given direction. |
|
870 * A target can be set on the ghostpad later with the |
|
871 * gst_ghost_pad_set_target() function. |
|
872 * |
|
873 * The created ghostpad will not have a padtemplate. |
|
874 * |
|
875 * Returns: a new #GstPad, or NULL in case of an error. |
|
876 */ |
|
877 #ifdef __SYMBIAN32__ |
|
878 EXPORT_C |
|
879 #endif |
|
880 |
|
881 GstPad * |
|
882 gst_ghost_pad_new_no_target (const gchar * name, GstPadDirection dir) |
|
883 { |
|
884 GstPad *ret; |
|
885 |
|
886 g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL); |
|
887 |
|
888 GST_LOG ("name:%s, direction:%d", GST_STR_NULL (name), dir); |
|
889 |
|
890 ret = gst_ghost_pad_new_full (name, dir, NULL); |
|
891 |
|
892 return ret; |
|
893 } |
|
894 |
|
895 /** |
|
896 * gst_ghost_pad_new: |
|
897 * @name: the name of the new pad, or NULL to assign a default name. |
|
898 * @target: the pad to ghost. |
|
899 * |
|
900 * Create a new ghostpad with @target as the target. The direction will be taken |
|
901 * from the target pad. @target must be unlinked. |
|
902 * |
|
903 * Will ref the target. |
|
904 * |
|
905 * Returns: a new #GstPad, or NULL in case of an error. |
|
906 */ |
|
907 #ifdef __SYMBIAN32__ |
|
908 EXPORT_C |
|
909 #endif |
|
910 |
|
911 GstPad * |
|
912 gst_ghost_pad_new (const gchar * name, GstPad * target) |
|
913 { |
|
914 GstPad *ret; |
|
915 |
|
916 g_return_val_if_fail (GST_IS_PAD (target), NULL); |
|
917 g_return_val_if_fail (!gst_pad_is_linked (target), NULL); |
|
918 |
|
919 GST_LOG ("name:%s, target:%s:%s", GST_STR_NULL (name), |
|
920 GST_DEBUG_PAD_NAME (target)); |
|
921 |
|
922 if ((ret = gst_ghost_pad_new_no_target (name, GST_PAD_DIRECTION (target)))) |
|
923 if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target)) |
|
924 goto set_target_failed; |
|
925 |
|
926 return ret; |
|
927 |
|
928 /* ERRORS */ |
|
929 set_target_failed: |
|
930 { |
|
931 GST_WARNING_OBJECT (ret, "failed to set target %s:%s", |
|
932 GST_DEBUG_PAD_NAME (target)); |
|
933 gst_object_unref (ret); |
|
934 return NULL; |
|
935 } |
|
936 } |
|
937 |
|
938 /** |
|
939 * gst_ghost_pad_new_from_template: |
|
940 * @name: the name of the new pad, or NULL to assign a default name. |
|
941 * @target: the pad to ghost. |
|
942 * @templ: the #GstPadTemplate to use on the ghostpad. |
|
943 * |
|
944 * Create a new ghostpad with @target as the target. The direction will be taken |
|
945 * from the target pad. The template used on the ghostpad will be @template. |
|
946 * |
|
947 * Will ref the target. |
|
948 * |
|
949 * Returns: a new #GstPad, or NULL in case of an error. |
|
950 * |
|
951 * Since: 0.10.10 |
|
952 */ |
|
953 #ifdef __SYMBIAN32__ |
|
954 EXPORT_C |
|
955 #endif |
|
956 |
|
957 |
|
958 GstPad * |
|
959 gst_ghost_pad_new_from_template (const gchar * name, GstPad * target, |
|
960 GstPadTemplate * templ) |
|
961 { |
|
962 GstPad *ret; |
|
963 |
|
964 g_return_val_if_fail (GST_IS_PAD (target), NULL); |
|
965 g_return_val_if_fail (!gst_pad_is_linked (target), NULL); |
|
966 g_return_val_if_fail (templ != NULL, NULL); |
|
967 g_return_val_if_fail (GST_PAD_TEMPLATE_DIRECTION (templ) == |
|
968 GST_PAD_DIRECTION (target), NULL); |
|
969 |
|
970 GST_LOG ("name:%s, target:%s:%s, templ:%p", GST_STR_NULL (name), |
|
971 GST_DEBUG_PAD_NAME (target), templ); |
|
972 |
|
973 if ((ret = gst_ghost_pad_new_full (name, GST_PAD_DIRECTION (target), templ))) |
|
974 if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target)) |
|
975 goto set_target_failed; |
|
976 |
|
977 return ret; |
|
978 |
|
979 /* ERRORS */ |
|
980 set_target_failed: |
|
981 { |
|
982 GST_WARNING_OBJECT (ret, "failed to set target %s:%s", |
|
983 GST_DEBUG_PAD_NAME (target)); |
|
984 gst_object_unref (ret); |
|
985 return NULL; |
|
986 } |
|
987 } |
|
988 |
|
989 /** |
|
990 * gst_ghost_pad_new_no_target_from_template: |
|
991 * @name: the name of the new pad, or NULL to assign a default name. |
|
992 * @templ: the #GstPadTemplate to create the ghostpad from. |
|
993 * |
|
994 * Create a new ghostpad based on @templ, without setting a target. The |
|
995 * direction will be taken from the @templ. |
|
996 * |
|
997 * Returns: a new #GstPad, or NULL in case of an error. |
|
998 * |
|
999 * Since: 0.10.10 |
|
1000 */ |
|
1001 #ifdef __SYMBIAN32__ |
|
1002 EXPORT_C |
|
1003 #endif |
|
1004 |
|
1005 GstPad * |
|
1006 gst_ghost_pad_new_no_target_from_template (const gchar * name, |
|
1007 GstPadTemplate * templ) |
|
1008 { |
|
1009 GstPad *ret; |
|
1010 |
|
1011 g_return_val_if_fail (templ != NULL, NULL); |
|
1012 |
|
1013 ret = |
|
1014 gst_ghost_pad_new_full (name, GST_PAD_TEMPLATE_DIRECTION (templ), templ); |
|
1015 |
|
1016 return ret; |
|
1017 } |
|
1018 |
|
1019 /** |
|
1020 * gst_ghost_pad_get_target: |
|
1021 * @gpad: the #GstGhostpad |
|
1022 * |
|
1023 * Get the target pad of #gpad. Unref target pad after usage. |
|
1024 * |
|
1025 * Returns: the target #GstPad, can be NULL if the ghostpad |
|
1026 * has no target set. Unref target pad after usage. |
|
1027 */ |
|
1028 #ifdef __SYMBIAN32__ |
|
1029 EXPORT_C |
|
1030 #endif |
|
1031 |
|
1032 GstPad * |
|
1033 gst_ghost_pad_get_target (GstGhostPad * gpad) |
|
1034 { |
|
1035 GstPad *ret; |
|
1036 |
|
1037 g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), NULL); |
|
1038 |
|
1039 ret = gst_proxy_pad_get_target (GST_PAD_CAST (gpad)); |
|
1040 |
|
1041 GST_DEBUG_OBJECT (gpad, "get target %s:%s", GST_DEBUG_PAD_NAME (ret)); |
|
1042 |
|
1043 return ret; |
|
1044 } |
|
1045 |
|
1046 /** |
|
1047 * gst_ghost_pad_set_target: |
|
1048 * @gpad: the #GstGhostpad |
|
1049 * @newtarget: the new pad target |
|
1050 * |
|
1051 * Set the new target of the ghostpad @gpad. Any existing target |
|
1052 * is unlinked and links to the new target are established. |
|
1053 * |
|
1054 * Returns: TRUE if the new target could be set. This function can return FALSE |
|
1055 * when the internal pads could not be linked. |
|
1056 */ |
|
1057 #ifdef __SYMBIAN32__ |
|
1058 EXPORT_C |
|
1059 #endif |
|
1060 |
|
1061 gboolean |
|
1062 gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget) |
|
1063 { |
|
1064 GstPad *internal; |
|
1065 GstPad *oldtarget; |
|
1066 gboolean result; |
|
1067 GstPadLinkReturn lret; |
|
1068 |
|
1069 g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE); |
|
1070 |
|
1071 GST_PROXY_LOCK (gpad); |
|
1072 internal = GST_PROXY_PAD_INTERNAL (gpad); |
|
1073 |
|
1074 GST_DEBUG_OBJECT (gpad, "set target %s:%s", GST_DEBUG_PAD_NAME (newtarget)); |
|
1075 |
|
1076 /* clear old target */ |
|
1077 if ((oldtarget = GST_PROXY_PAD_TARGET (gpad))) { |
|
1078 /* if we have an internal pad, unlink */ |
|
1079 if (internal) { |
|
1080 if (GST_PAD_IS_SRC (internal)) |
|
1081 gst_pad_unlink (internal, oldtarget); |
|
1082 else |
|
1083 gst_pad_unlink (oldtarget, internal); |
|
1084 } |
|
1085 } |
|
1086 |
|
1087 result = gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), newtarget); |
|
1088 |
|
1089 if (result && newtarget) { |
|
1090 /* and link to internal pad */ |
|
1091 GST_DEBUG_OBJECT (gpad, "connecting internal pad to target"); |
|
1092 |
|
1093 if (GST_PAD_IS_SRC (internal)) |
|
1094 lret = gst_pad_link (internal, newtarget); |
|
1095 else |
|
1096 lret = gst_pad_link (newtarget, internal); |
|
1097 |
|
1098 if (lret != GST_PAD_LINK_OK) |
|
1099 goto link_failed; |
|
1100 } |
|
1101 GST_PROXY_UNLOCK (gpad); |
|
1102 |
|
1103 return result; |
|
1104 |
|
1105 /* ERRORS */ |
|
1106 link_failed: |
|
1107 { |
|
1108 GST_WARNING_OBJECT (gpad, "could not link internal and target, reason:%d", |
|
1109 lret); |
|
1110 /* and unset target again */ |
|
1111 gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), NULL); |
|
1112 GST_PROXY_UNLOCK (gpad); |
|
1113 return FALSE; |
|
1114 } |
|
1115 } |