• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
3  *
4  * gstghostpad.c: Unit test for GstGhostPad
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <gst/check/gstcheck.h>
26 #include <gst/check/gstharness.h>
27 
28 /* test if removing a bin also cleans up the ghostpads
29  */
GST_START_TEST(test_remove1)30 GST_START_TEST (test_remove1)
31 {
32   GstElement *b1, *b2, *src, *sink;
33   GstPad *srcpad, *sinkpad;
34   GstPadLinkReturn ret;
35 
36   b1 = gst_element_factory_make ("pipeline", NULL);
37   b2 = gst_element_factory_make ("bin", NULL);
38   src = gst_element_factory_make ("fakesrc", NULL);
39   sink = gst_element_factory_make ("fakesink", NULL);
40   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
41   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
42 
43   fail_unless (gst_bin_add (GST_BIN (b2), sink));
44   fail_unless (gst_bin_add (GST_BIN (b1), src));
45   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
46   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
47   fail_unless (gst_bin_add (GST_BIN (b1), b2));
48   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
49   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
50 
51   sinkpad = gst_element_get_static_pad (sink, "sink");
52   gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
53   gst_object_unref (sinkpad);
54 
55   srcpad = gst_element_get_static_pad (src, "src");
56   /* get the ghostpad */
57   sinkpad = gst_element_get_static_pad (b2, "sink");
58 
59   ret = gst_pad_link (srcpad, sinkpad);
60   fail_unless (ret == GST_PAD_LINK_OK);
61   gst_object_unref (srcpad);
62   gst_object_unref (sinkpad);
63 
64   /* now remove the bin with the ghostpad, b2 is disposed now. */
65   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
66   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
67   gst_bin_remove (GST_BIN (b1), b2);
68 
69   srcpad = gst_element_get_static_pad (src, "src");
70   /* pad cannot be linked now */
71   fail_if (gst_pad_is_linked (srcpad));
72   gst_object_unref (srcpad);
73 
74   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
75   gst_object_unref (b1);
76 }
77 
78 GST_END_TEST;
79 
80 /* test if removing a bin also cleans up the ghostpads
81  */
GST_START_TEST(test_remove2)82 GST_START_TEST (test_remove2)
83 {
84   GstElement *b1, *b2, *src, *sink;
85   GstPad *srcpad, *sinkpad;
86   GstPadLinkReturn ret;
87 
88   b1 = gst_element_factory_make ("pipeline", NULL);
89   b2 = gst_element_factory_make ("bin", NULL);
90   src = gst_element_factory_make ("fakesrc", NULL);
91   sink = gst_element_factory_make ("fakesink", NULL);
92   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
93 
94   fail_unless (gst_bin_add (GST_BIN (b2), sink));
95   fail_unless (gst_bin_add (GST_BIN (b1), src));
96   fail_unless (gst_bin_add (GST_BIN (b1), b2));
97   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
98 
99   sinkpad = gst_element_get_static_pad (sink, "sink");
100   gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
101   gst_object_unref (sinkpad);
102 
103   srcpad = gst_element_get_static_pad (src, "src");
104   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2); /* since we got one */
105   /* get the ghostpad */
106   sinkpad = gst_element_get_static_pad (b2, "sink");
107   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);       /* since we got one */
108 
109   GST_DEBUG ("linking srcpad and sinkpad");
110   ret = gst_pad_link (srcpad, sinkpad);
111   GST_DEBUG ("linked srcpad and sinkpad");
112   fail_unless (ret == GST_PAD_LINK_OK);
113   /* Refcount should be unchanged, targets are now decuced using peer pad */
114   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2);
115   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
116   gst_object_unref (srcpad);
117   gst_object_unref (sinkpad);
118 
119   /* now remove the sink from the bin */
120   gst_bin_remove (GST_BIN (b2), sink);
121 
122   srcpad = gst_element_get_static_pad (src, "src");
123   /* pad is still linked to ghostpad */
124   fail_if (!gst_pad_is_linked (srcpad));
125   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
126   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2);
127   gst_object_unref (srcpad);
128   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
129 
130   /* cleanup */
131   /* now unlink the pads */
132   gst_pad_unlink (srcpad, sinkpad);
133   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1); /* we dropped our ref */
134   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
135 
136   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
137   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
138   /* remove b2 from b1 */
139   gst_bin_remove (GST_BIN (b1), b2);
140 
141   /* flush the message, dropping the b1 refcount to 1 */
142   gst_element_set_state (b1, GST_STATE_READY);
143   gst_element_set_state (b1, GST_STATE_NULL);
144   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
145   gst_object_unref (b1);
146 }
147 
148 GST_END_TEST;
149 
150 
151 
152 /* test if a ghost pad without a target can be linked and
153  * unlinked. An untargeted ghostpad has a default ANY caps unless there
154  * is a padtemplate that says something else.
155  */
GST_START_TEST(test_ghost_pads_notarget)156 GST_START_TEST (test_ghost_pads_notarget)
157 {
158   GstElement *b1, *b2, *sink;
159   GstPad *srcpad, *sinkpad, *peer;
160   GstPadLinkReturn ret;
161   gboolean bret;
162   GstBus *bus;
163   GstCaps *caps;
164 
165   b1 = gst_element_factory_make ("pipeline", NULL);
166 
167   /* make sure all messages are discarded */
168   bus = gst_pipeline_get_bus (GST_PIPELINE (b1));
169   gst_bus_set_flushing (bus, TRUE);
170   gst_object_unref (bus);
171 
172   b2 = gst_element_factory_make ("bin", NULL);
173   sink = gst_element_factory_make ("fakesink", NULL);
174 
175   fail_unless (gst_bin_add (GST_BIN (b1), sink));
176   fail_unless (gst_bin_add (GST_BIN (b1), b2));
177 
178   srcpad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC);
179   fail_unless (srcpad != NULL);
180   sinkpad = gst_element_get_static_pad (sink, "sink");
181   fail_unless (sinkpad != NULL);
182 
183   ret = gst_pad_link (srcpad, sinkpad);
184   fail_unless (ret == GST_PAD_LINK_OK);
185 
186   /* check if the peers are ok */
187   peer = gst_pad_get_peer (srcpad);
188   fail_unless (peer == sinkpad);
189   gst_object_unref (peer);
190 
191   peer = gst_pad_get_peer (sinkpad);
192   fail_unless (peer == srcpad);
193   gst_object_unref (peer);
194 
195   /* check caps, untargetted pad should return ANY or the padtemplate caps
196    * when it was created from a template */
197   caps = gst_pad_query_caps (srcpad, NULL);
198   fail_unless (gst_caps_is_any (caps));
199   gst_caps_unref (caps);
200 
201   /* unlink */
202   bret = gst_pad_unlink (srcpad, sinkpad);
203   fail_unless (bret == TRUE);
204 
205   /* cleanup */
206   gst_object_unref (srcpad);
207   gst_object_unref (sinkpad);
208   gst_object_unref (b1);
209 }
210 
211 GST_END_TEST;
212 
213 /* Test that removing the target of a ghostpad properly sets the target of the
214  * ghostpad to NULL */
GST_START_TEST(test_remove_target)215 GST_START_TEST (test_remove_target)
216 {
217   GstElement *b1, *b2, *src, *sink;
218   GstPad *sinkpad, *ghost, *target;
219 
220   b1 = gst_element_factory_make ("pipeline", NULL);
221   b2 = gst_element_factory_make ("bin", NULL);
222   src = gst_element_factory_make ("fakesrc", NULL);
223   sink = gst_element_factory_make ("fakesink", NULL);
224   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
225 
226   fail_unless (gst_bin_add (GST_BIN (b2), sink));
227   fail_unless (gst_bin_add (GST_BIN (b1), src));
228   fail_unless (gst_bin_add (GST_BIN (b1), b2));
229   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
230 
231   sinkpad = gst_element_get_static_pad (sink, "sink");
232   gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
233 
234   ghost = gst_element_get_static_pad (b2, "sink");
235 
236   target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost));
237   fail_unless (target == sinkpad);
238   gst_object_unref (target);
239   gst_object_unref (sinkpad);
240 
241   gst_bin_remove (GST_BIN (b2), sink);
242 
243   target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost));
244   fail_unless (target == NULL);
245 
246   gst_object_unref (b1);
247   gst_object_unref (ghost);
248 }
249 
250 GST_END_TEST;
251 
252 
253 /* test if linking fails over different bins using a pipeline
254  * like this:
255  *
256  * fakesrc num_buffers=10 ! ( fakesink )
257  *
258  */
GST_START_TEST(test_link)259 GST_START_TEST (test_link)
260 {
261   GstElement *b1, *b2, *src, *sink;
262   GstPad *srcpad, *sinkpad, *gpad, *ppad, *tmp;
263   GstPadLinkReturn ret;
264 
265   b1 = gst_element_factory_make ("pipeline", NULL);
266   b2 = gst_element_factory_make ("bin", NULL);
267   src = gst_element_factory_make ("fakesrc", NULL);
268   sink = gst_element_factory_make ("fakesink", NULL);
269 
270   fail_unless (gst_bin_add (GST_BIN (b2), sink));
271   fail_unless (gst_bin_add (GST_BIN (b1), src));
272   fail_unless (gst_bin_add (GST_BIN (b1), b2));
273 
274   srcpad = gst_element_get_static_pad (src, "src");
275   fail_unless (srcpad != NULL);
276   sinkpad = gst_element_get_static_pad (sink, "sink");
277   fail_unless (sinkpad != NULL);
278 
279   /* linking in different hierarchies should fail */
280   ret = gst_pad_link (srcpad, sinkpad);
281   fail_unless (ret == GST_PAD_LINK_WRONG_HIERARCHY);
282 
283   /* now setup a ghostpad */
284   gpad = gst_ghost_pad_new ("sink", sinkpad);
285 
286   /* Check if the internal pads are set correctly */
287   ppad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (gpad)));
288   fail_unless (ppad == GST_PAD_PEER (sinkpad));
289   tmp = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (ppad)));
290   fail_unless (tmp == gpad);
291   gst_object_unref (tmp);
292   gst_object_unref (ppad);
293   gst_object_unref (sinkpad);
294   /* need to ref as _add_pad takes ownership */
295   gst_object_ref (gpad);
296   gst_element_add_pad (b2, gpad);
297 
298   /* our new sinkpad */
299   sinkpad = gpad;
300 
301   /* and linking should work now */
302   ret = gst_pad_link (srcpad, sinkpad);
303   fail_unless (ret == GST_PAD_LINK_OK);
304 
305   /* flush the message, dropping the b1 refcount to 1 */
306   gst_element_set_state (b1, GST_STATE_READY);
307   gst_element_set_state (b1, GST_STATE_NULL);
308   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
309 
310   gst_object_unref (srcpad);
311   gst_object_unref (sinkpad);
312   gst_object_unref (b1);
313 }
314 
315 GST_END_TEST;
316 
317 /* test if ghostpads are created automagically when using
318  * gst_element_link_pads.
319  *
320  * fakesrc num_buffers=10 ! ( identity ) ! fakesink
321  */
GST_START_TEST(test_ghost_pads)322 GST_START_TEST (test_ghost_pads)
323 {
324   GstElement *b1, *b2, *src, *i1, *sink;
325   GstPad *gsink, *gsrc, *gisrc, *gisink, *isink, *isrc, *fsrc, *fsink;
326   GstStateChangeReturn ret;
327 
328   b1 = gst_element_factory_make ("pipeline", NULL);
329   b2 = gst_element_factory_make ("bin", NULL);
330   src = gst_element_factory_make ("fakesrc", NULL);
331   g_object_set (src, "num-buffers", (int) 10, NULL);
332   i1 = gst_element_factory_make ("identity", NULL);
333   sink = gst_element_factory_make ("fakesink", NULL);
334 
335   fail_unless (gst_bin_add (GST_BIN (b2), i1));
336   fail_unless (gst_bin_add (GST_BIN (b1), src));
337   fail_unless (gst_bin_add (GST_BIN (b1), b2));
338   fail_unless (gst_bin_add (GST_BIN (b1), sink));
339   fail_unless (gst_element_link_pads (src, NULL, i1, NULL));
340   fail_unless (gst_element_link_pads (i1, NULL, sink, NULL));
341   GST_OBJECT_LOCK (b2);
342   fail_unless (b2->numsinkpads == 1);
343   fail_unless (GST_IS_GHOST_PAD (b2->sinkpads->data));
344   fail_unless (b2->numsrcpads == 1);
345   fail_unless (GST_IS_GHOST_PAD (b2->srcpads->data));
346   GST_OBJECT_UNLOCK (b2);
347 
348   fsrc = gst_element_get_static_pad (src, "src");
349   fail_unless (fsrc != NULL);
350   gsink = GST_PAD (gst_object_ref (b2->sinkpads->data));
351   fail_unless (gsink != NULL);
352   gsrc = GST_PAD (gst_object_ref (b2->srcpads->data));
353   fail_unless (gsrc != NULL);
354   fsink = gst_element_get_static_pad (sink, "sink");
355   fail_unless (fsink != NULL);
356 
357   isink = gst_element_get_static_pad (i1, "sink");
358   fail_unless (isink != NULL);
359   isrc = gst_element_get_static_pad (i1, "src");
360   fail_unless (isrc != NULL);
361   gisrc = gst_pad_get_peer (isink);
362   fail_unless (gisrc != NULL);
363   gisink = gst_pad_get_peer (isrc);
364   fail_unless (gisink != NULL);
365 
366   /* all objects above have one refcount owned by us as well */
367 
368   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 2);     /* parent */
369   ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 2);   /* parent */
370   ASSERT_OBJECT_REFCOUNT (gsrc, "gsrc", 2);     /* parent */
371   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 2);   /* parent */
372 
373   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2);   /* parent */
374   ASSERT_OBJECT_REFCOUNT (isink, "isink", 2);   /* parent */
375   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* parent */
376   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 2);     /* parent */
377 
378   ret = gst_element_set_state (b1, GST_STATE_PLAYING);
379   ret = gst_element_get_state (b1, NULL, NULL, GST_CLOCK_TIME_NONE);
380   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
381 
382   ret = gst_element_set_state (b1, GST_STATE_NULL);
383   ret = gst_element_get_state (b1, NULL, NULL, GST_CLOCK_TIME_NONE);
384   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
385 
386   gst_object_unref (b1);
387   /* unreffing the bin will unref all elements, which will unlink and unparent
388    * all pads */
389 
390   /* wait for thread to settle down */
391   while (GST_OBJECT_REFCOUNT_VALUE (fsrc) > 1)
392     THREAD_SWITCH ();
393 
394   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
395   ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 1);
396   ASSERT_OBJECT_REFCOUNT (gsrc, "gsink", 1);
397   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
398 
399   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2);   /* gsink */
400   ASSERT_OBJECT_REFCOUNT (isink, "isink", 1);   /* gsink */
401   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* gsrc */
402   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1);     /* gsrc */
403 
404   gst_object_unref (gsink);
405   ASSERT_OBJECT_REFCOUNT (isink, "isink", 1);
406   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 1);
407   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
408   gst_object_unref (gisrc);
409   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
410 
411   gst_object_unref (gsrc);
412   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1);
413   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 1);
414   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
415   gst_object_unref (gisink);
416   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
417 
418   gst_object_unref (fsrc);
419   gst_object_unref (isrc);
420   gst_object_unref (isink);
421   gst_object_unref (fsink);
422 }
423 
424 GST_END_TEST;
425 
GST_START_TEST(test_ghost_pads_bin)426 GST_START_TEST (test_ghost_pads_bin)
427 {
428   GstBin *pipeline;
429   GstBin *srcbin;
430   GstBin *sinkbin;
431   GstElement *src;
432   GstElement *sink;
433   GstPad *srcpad, *srcghost, *target;
434   GstPad *sinkpad, *sinkghost;
435 
436   pipeline = GST_BIN (gst_pipeline_new ("pipe"));
437   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
438 
439   srcbin = GST_BIN (gst_bin_new ("srcbin"));
440   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
441   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
442 
443   sinkbin = GST_BIN (gst_bin_new ("sinkbin"));
444   gst_bin_add (pipeline, GST_ELEMENT (sinkbin));
445   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
446 
447   src = gst_element_factory_make ("fakesrc", "src");
448   gst_bin_add (srcbin, src);
449   srcpad = gst_element_get_static_pad (src, "src");
450   srcghost = gst_ghost_pad_new ("src", srcpad);
451   gst_object_unref (srcpad);
452   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
453 
454   sink = gst_element_factory_make ("fakesink", "sink");
455   gst_bin_add (sinkbin, sink);
456   sinkpad = gst_element_get_static_pad (sink, "sink");
457   sinkghost = gst_ghost_pad_new ("sink", sinkpad);
458   gst_object_unref (sinkpad);
459   gst_element_add_pad (GST_ELEMENT (sinkbin), sinkghost);
460 
461   gst_element_link (GST_ELEMENT (srcbin), GST_ELEMENT (sinkbin));
462 
463   fail_unless (GST_PAD_PEER (srcghost) != NULL);
464   fail_unless (GST_PAD_PEER (sinkghost) != NULL);
465   target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcghost));
466   fail_unless (GST_PAD_PEER (target) != NULL);
467   gst_object_unref (target);
468   target = gst_ghost_pad_get_target (GST_GHOST_PAD (sinkghost));
469   fail_unless (GST_PAD_PEER (target) != NULL);
470   gst_object_unref (target);
471 
472   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
473 
474   gst_object_unref (pipeline);
475 }
476 
477 GST_END_TEST;
478 
479 typedef struct
480 {
481   GMutex mutex;
482   GCond cond;
483 } BlockData;
484 
485 static GstPadProbeReturn
block_callback(GstPad * pad,GstPadProbeInfo * info,gpointer user_data)486 block_callback (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
487 {
488   BlockData *block_data = (BlockData *) user_data;
489 
490   g_mutex_lock (&block_data->mutex);
491   GST_DEBUG ("blocked\n");
492   g_cond_signal (&block_data->cond);
493   g_mutex_unlock (&block_data->mutex);
494 
495   return GST_PAD_PROBE_OK;
496 }
497 
GST_START_TEST(test_ghost_pads_block)498 GST_START_TEST (test_ghost_pads_block)
499 {
500   GstBin *pipeline;
501   GstBin *srcbin;
502   GstElement *src;
503   GstPad *srcpad;
504   GstPad *srcghost;
505   BlockData block_data;
506 
507   pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
508 
509   srcbin = GST_BIN (gst_bin_new ("srcbin"));
510   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
511 
512   src = gst_element_factory_make ("fakesrc", "src");
513   gst_bin_add (srcbin, src);
514   srcpad = gst_element_get_static_pad (src, "src");
515   srcghost = gst_ghost_pad_new ("src", srcpad);
516   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
517   gst_object_unref (srcpad);
518 
519   g_mutex_init (&block_data.mutex);
520   g_cond_init (&block_data.cond);
521 
522   g_mutex_lock (&block_data.mutex);
523   gst_pad_add_probe (srcghost, GST_PAD_PROBE_TYPE_BLOCK, block_callback,
524       &block_data, NULL);
525   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
526   /* and wait now */
527   g_cond_wait (&block_data.cond, &block_data.mutex);
528   g_mutex_unlock (&block_data.mutex);
529   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
530 
531   g_mutex_clear (&block_data.mutex);
532   g_cond_clear (&block_data.cond);
533 
534   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
535   gst_object_unref (pipeline);
536 }
537 
538 GST_END_TEST;
539 
GST_START_TEST(test_ghost_pads_probes)540 GST_START_TEST (test_ghost_pads_probes)
541 {
542   GstBin *pipeline;
543   GstBin *srcbin;
544   GstElement *src;
545   GstPad *srcpad;
546   GstPad *srcghost;
547   BlockData block_data;
548 
549   pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
550 
551   srcbin = GST_BIN (gst_bin_new ("srcbin"));
552   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
553 
554   src = gst_element_factory_make ("fakesrc", "src");
555   gst_bin_add (srcbin, src);
556   srcpad = gst_element_get_static_pad (src, "src");
557   srcghost = gst_ghost_pad_new ("src", srcpad);
558   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
559   gst_object_unref (srcpad);
560 
561   g_mutex_init (&block_data.mutex);
562   g_cond_init (&block_data.cond);
563 
564   g_mutex_lock (&block_data.mutex);
565   gst_pad_add_probe (srcghost, GST_PAD_PROBE_TYPE_BLOCK, block_callback,
566       &block_data, NULL);
567   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
568   /* and wait now */
569   g_cond_wait (&block_data.cond, &block_data.mutex);
570   g_mutex_unlock (&block_data.mutex);
571   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
572 
573   g_mutex_clear (&block_data.mutex);
574   g_cond_clear (&block_data.cond);
575 
576   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
577   gst_object_unref (pipeline);
578 }
579 
580 GST_END_TEST;
581 
GST_START_TEST(test_ghost_pads_new_from_template)582 GST_START_TEST (test_ghost_pads_new_from_template)
583 {
584   GstPad *sinkpad, *ghostpad;
585   GstPadTemplate *padtempl, *ghosttempl;
586   GstCaps *padcaps, *ghostcaps, *newcaps;
587 
588   padcaps = gst_caps_from_string ("some/caps");
589   fail_unless (padcaps != NULL);
590   ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
591   fail_unless (ghostcaps != NULL);
592 
593   padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
594       GST_PAD_ALWAYS, padcaps);
595   fail_unless (padtempl != NULL);
596   ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
597       GST_PAD_ALWAYS, ghostcaps);
598 
599   sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
600   fail_unless (sinkpad != NULL);
601 
602   ghostpad = gst_ghost_pad_new_from_template ("ghostpad", sinkpad, ghosttempl);
603   fail_unless (ghostpad != NULL);
604 
605   /* check template is properly set */
606   fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
607 
608   /* check ghostpad caps are from the sinkpad */
609   newcaps = gst_pad_query_caps (ghostpad, NULL);
610   fail_unless (newcaps != NULL);
611   fail_unless (gst_caps_is_equal (newcaps, padcaps));
612   gst_caps_unref (newcaps);
613   gst_caps_unref (padcaps);
614   gst_caps_unref (ghostcaps);
615 
616   gst_object_unref (sinkpad);
617   gst_object_unref (ghostpad);
618 
619   gst_object_unref (padtempl);
620   gst_object_unref (ghosttempl);
621 }
622 
623 GST_END_TEST;
624 
GST_START_TEST(test_ghost_pads_new_no_target_from_template)625 GST_START_TEST (test_ghost_pads_new_no_target_from_template)
626 {
627   GstPad *sinkpad, *ghostpad;
628   GstPadTemplate *padtempl, *ghosttempl;
629   GstCaps *padcaps, *ghostcaps, *newcaps;
630 
631   padcaps = gst_caps_from_string ("some/caps");
632   fail_unless (padcaps != NULL);
633   ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
634   fail_unless (ghostcaps != NULL);
635 
636   padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
637       GST_PAD_ALWAYS, padcaps);
638   fail_unless (padtempl != NULL);
639   ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
640       GST_PAD_ALWAYS, ghostcaps);
641 
642   sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
643   fail_unless (sinkpad != NULL);
644 
645   ghostpad = gst_ghost_pad_new_no_target_from_template ("ghostpad", ghosttempl);
646   fail_unless (ghostpad != NULL);
647 
648   /* check template is properly set */
649   fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
650 
651   /* check ghostpad caps are from the ghostpad template */
652   newcaps = gst_pad_query_caps (ghostpad, NULL);
653   fail_unless (newcaps != NULL);
654   fail_unless (gst_caps_is_equal (newcaps, ghostcaps));
655   gst_caps_unref (newcaps);
656 
657   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
658 
659   /* check ghostpad caps are now from the target pad */
660   newcaps = gst_pad_query_caps (ghostpad, NULL);
661   fail_unless (newcaps != NULL);
662   fail_unless (gst_caps_is_equal (newcaps, padcaps));
663   gst_caps_unref (newcaps);
664 
665   gst_object_unref (sinkpad);
666   gst_object_unref (ghostpad);
667 
668   gst_object_unref (padtempl);
669   gst_object_unref (ghosttempl);
670 
671   gst_caps_unref (padcaps);
672   gst_caps_unref (ghostcaps);
673 }
674 
675 GST_END_TEST;
676 
677 static void
ghost_notify_caps(GObject * object,GParamSpec * pspec,gpointer * user_data)678 ghost_notify_caps (GObject * object, GParamSpec * pspec, gpointer * user_data)
679 {
680   GST_DEBUG ("caps notify called");
681   (*(gint *) user_data)++;
682 }
683 
GST_START_TEST(test_ghost_pads_forward_setcaps)684 GST_START_TEST (test_ghost_pads_forward_setcaps)
685 {
686   GstCaps *templ_caps, *caps1, *caps2;
687   GstPadTemplate *src_template, *sink_template;
688   GstPad *src, *ghost, *sink;
689   gint notify_counter = 0;
690 
691   templ_caps = gst_caps_from_string ("meh; muh");
692   src_template = gst_pad_template_new ("src", GST_PAD_SRC,
693       GST_PAD_ALWAYS, templ_caps);
694   gst_caps_unref (templ_caps);
695 
696   templ_caps = gst_caps_from_string ("muh; meh");
697   sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
698       GST_PAD_ALWAYS, templ_caps);
699   gst_caps_unref (templ_caps);
700 
701   src = gst_pad_new_from_template (src_template, "src");
702   sink = gst_pad_new_from_template (sink_template, "sink");
703 
704   /* ghost source pad, setting caps on the source influences the caps of the
705    * ghostpad. */
706   ghost = gst_ghost_pad_new ("ghostsrc", src);
707   g_signal_connect (ghost, "notify::caps",
708       G_CALLBACK (ghost_notify_caps), &notify_counter);
709   fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
710 
711   /* Activate pads for caps forwarding/setting to work */
712   gst_pad_set_active (src, TRUE);
713   gst_pad_set_active (ghost, TRUE);
714 
715   caps1 = gst_caps_from_string ("meh");
716   fail_unless (gst_pad_set_caps (src, caps1));
717   caps2 = gst_pad_get_current_caps (ghost);
718   fail_unless (gst_caps_is_equal (caps1, caps2));
719   fail_unless_equals_int (notify_counter, 1);
720 
721   gst_object_unref (ghost);
722   gst_caps_unref (caps1);
723   gst_caps_unref (caps2);
724 
725   /* source 2, setting the caps on the ghostpad does not influence the caps of
726    * the target */
727   notify_counter = 0;
728   ghost = gst_ghost_pad_new ("ghostsrc", src);
729   g_signal_connect (ghost, "notify::caps",
730       G_CALLBACK (ghost_notify_caps), &notify_counter);
731   fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
732 
733   gst_pad_set_active (ghost, TRUE);
734   gst_pad_set_active (sink, TRUE);
735 
736   caps1 = gst_caps_from_string ("meh");
737   fail_unless (gst_pad_set_caps (ghost, caps1));
738 #if 0
739   caps2 = gst_pad_get_current_caps (src);
740   fail_unless (caps2 == NULL);
741 #endif
742   fail_unless_equals_int (notify_counter, 1);
743 
744   gst_object_unref (ghost);
745   gst_caps_unref (caps1);
746 
747 
748   /* ghost sink pad. Setting caps on the ghostpad will also set those caps on
749    * the target pad. */
750   notify_counter = 0;
751   ghost = gst_ghost_pad_new ("ghostsink", sink);
752   g_signal_connect (ghost, "notify::caps",
753       G_CALLBACK (ghost_notify_caps), &notify_counter);
754   fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
755 
756   gst_pad_set_active (src, TRUE);
757   gst_pad_set_active (ghost, TRUE);
758 
759   caps1 = gst_caps_from_string ("muh");
760   fail_unless (gst_pad_set_caps (ghost, caps1));
761   caps2 = gst_pad_get_current_caps (sink);
762   fail_unless (gst_caps_is_equal (caps1, caps2));
763   fail_unless_equals_int (notify_counter, 1);
764 
765   gst_object_unref (ghost);
766   gst_caps_unref (caps1);
767   gst_caps_unref (caps2);
768 
769   /* clear caps on pads */
770   gst_pad_set_active (src, FALSE);
771   gst_pad_set_active (src, TRUE);
772   gst_pad_set_active (sink, FALSE);
773   gst_pad_set_active (sink, TRUE);
774 
775   /* sink pad 2, setting caps just on the target pad should not influence the caps
776    * on the ghostpad. */
777   notify_counter = 0;
778   ghost = gst_ghost_pad_new ("ghostsink", sink);
779   fail_unless (gst_pad_get_current_caps (ghost) == NULL);
780   g_signal_connect (ghost, "notify::caps",
781       G_CALLBACK (ghost_notify_caps), &notify_counter);
782   fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
783 
784   gst_pad_set_active (ghost, TRUE);
785 
786   caps1 = gst_caps_from_string ("muh");
787   fail_unless (gst_pad_set_caps (sink, caps1));
788   caps2 = gst_pad_get_current_caps (ghost);
789   fail_unless (caps2 == NULL);
790   fail_unless_equals_int (notify_counter, 0);
791 
792   gst_object_unref (ghost);
793   gst_caps_unref (caps1);
794 
795   gst_object_unref (src);
796   gst_object_unref (sink);
797   gst_object_unref (src_template);
798   gst_object_unref (sink_template);
799 }
800 
801 GST_END_TEST;
802 
803 static gint linked_count1;
804 static gint unlinked_count1;
805 static gint linked_count2;
806 static gint unlinked_count2;
807 
808 static GstPadLinkReturn
pad_linked1(GstPad * pad,GstObject * parent,GstPad * peer)809 pad_linked1 (GstPad * pad, GstObject * parent, GstPad * peer)
810 {
811   linked_count1++;
812 
813   return GST_PAD_LINK_OK;
814 }
815 
816 static void
pad_unlinked1(GstPad * pad,GstObject * parent)817 pad_unlinked1 (GstPad * pad, GstObject * parent)
818 {
819   unlinked_count1++;
820 }
821 
822 static GstPadLinkReturn
pad_linked2(GstPad * pad,GstObject * parent,GstPad * peer)823 pad_linked2 (GstPad * pad, GstObject * parent, GstPad * peer)
824 {
825   linked_count2++;
826 
827   return GST_PAD_LINK_OK;
828 }
829 
830 static void
pad_unlinked2(GstPad * pad,GstObject * parent)831 pad_unlinked2 (GstPad * pad, GstObject * parent)
832 {
833   unlinked_count2++;
834 }
835 
GST_START_TEST(test_ghost_pads_sink_link_unlink)836 GST_START_TEST (test_ghost_pads_sink_link_unlink)
837 {
838   GstCaps *padcaps;
839   GstPad *srcpad, *sinkpad, *ghostpad;
840   GstPadTemplate *srctempl, *sinktempl;
841   GstPadLinkReturn ret;
842   gboolean res;
843 
844   padcaps = gst_caps_from_string ("some/caps");
845   fail_unless (padcaps != NULL);
846   srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
847       GST_PAD_ALWAYS, padcaps);
848   gst_caps_unref (padcaps);
849 
850   padcaps = gst_caps_from_string ("some/caps");
851   fail_unless (padcaps != NULL);
852   sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
853       GST_PAD_ALWAYS, padcaps);
854   gst_caps_unref (padcaps);
855 
856   srcpad = gst_pad_new_from_template (srctempl, "src");
857   fail_unless (srcpad != NULL);
858   sinkpad = gst_pad_new_from_template (sinktempl, "sink");
859   fail_unless (sinkpad != NULL);
860 
861   /* set up link/unlink functions for the pad */
862   linked_count1 = unlinked_count1 = 0;
863   gst_pad_set_link_function (sinkpad, pad_linked1);
864   gst_pad_set_unlink_function (sinkpad, pad_unlinked1);
865   linked_count2 = unlinked_count2 = 0;
866   gst_pad_set_link_function (srcpad, pad_linked2);
867   gst_pad_set_unlink_function (srcpad, pad_unlinked2);
868 
869   /* this should trigger a link from the internal pad to the sinkpad */
870   ghostpad = gst_ghost_pad_new ("ghostpad", sinkpad);
871   fail_unless (ghostpad != NULL);
872   fail_unless (linked_count1 == 1);
873   fail_unless (unlinked_count1 == 0);
874   fail_unless (linked_count2 == 0);
875   fail_unless (unlinked_count2 == 0);
876 
877   /* this should not trigger anything because we are not directly
878    * linking/unlinking the sink pad. */
879   ret = gst_pad_link (srcpad, ghostpad);
880   fail_unless (ret == GST_PAD_LINK_OK);
881   fail_unless (linked_count1 == 1);
882   fail_unless (unlinked_count1 == 0);
883   fail_unless (linked_count2 == 1);
884   fail_unless (unlinked_count2 == 0);
885 
886   res = gst_pad_unlink (srcpad, ghostpad);
887   fail_unless (res == TRUE);
888   fail_unless (linked_count1 == 1);
889   fail_unless (unlinked_count1 == 0);
890   fail_unless (linked_count2 == 1);
891   fail_unless (unlinked_count2 == 1);
892 
893   /* this should trigger the unlink */
894   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
895   fail_unless (res == TRUE);
896   fail_unless (linked_count1 == 1);
897   fail_unless (unlinked_count1 == 1);
898   fail_unless (linked_count2 == 1);
899   fail_unless (unlinked_count2 == 1);
900 
901   gst_object_unref (ghostpad);
902   gst_object_unref (sinkpad);
903   gst_object_unref (srcpad);
904   gst_object_unref (srctempl);
905   gst_object_unref (sinktempl);
906 }
907 
908 GST_END_TEST;
909 
GST_START_TEST(test_ghost_pads_src_link_unlink)910 GST_START_TEST (test_ghost_pads_src_link_unlink)
911 {
912   GstCaps *padcaps;
913   GstPad *srcpad, *sinkpad, *ghostpad, *dummy;
914   GstPadTemplate *srctempl, *sinktempl;
915   GstPadLinkReturn ret;
916   gboolean res;
917 
918   padcaps = gst_caps_from_string ("some/caps");
919   fail_unless (padcaps != NULL);
920   srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
921       GST_PAD_ALWAYS, padcaps);
922   gst_caps_unref (padcaps);
923 
924   padcaps = gst_caps_from_string ("some/caps");
925   fail_unless (padcaps != NULL);
926   sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
927       GST_PAD_ALWAYS, padcaps);
928   gst_caps_unref (padcaps);
929 
930   srcpad = gst_pad_new_from_template (srctempl, "src");
931   fail_unless (srcpad != NULL);
932   sinkpad = gst_pad_new_from_template (sinktempl, "sink");
933   fail_unless (sinkpad != NULL);
934 
935   /* set up link/unlink functions for the pad */
936   linked_count1 = unlinked_count1 = 0;
937   gst_pad_set_link_function (srcpad, pad_linked1);
938   gst_pad_set_unlink_function (srcpad, pad_unlinked1);
939   linked_count2 = unlinked_count2 = 0;
940   gst_pad_set_link_function (sinkpad, pad_linked2);
941   gst_pad_set_unlink_function (sinkpad, pad_unlinked2);
942 
943   /* this should trigger a link from the internal pad to the srcpad */
944   ghostpad = gst_ghost_pad_new ("ghostpad", srcpad);
945   fail_unless (ghostpad != NULL);
946   fail_unless (linked_count1 == 1);
947   fail_unless (unlinked_count1 == 0);
948   fail_unless (linked_count2 == 0);
949   fail_unless (unlinked_count2 == 0);
950 
951   /* this should fail with a critial */
952   dummy = NULL;
953   ASSERT_CRITICAL (dummy = gst_ghost_pad_new ("ghostpad", srcpad));
954   fail_unless (dummy == NULL);
955   fail_unless (linked_count1 == 1);
956   fail_unless (unlinked_count1 == 0);
957   fail_unless (linked_count2 == 0);
958   fail_unless (unlinked_count2 == 0);
959 
960   /* this should not trigger anything because we are not directly
961    * linking/unlinking the src pad. */
962   ret = gst_pad_link (ghostpad, sinkpad);
963   fail_unless (ret == GST_PAD_LINK_OK);
964   fail_unless (linked_count1 == 1);
965   fail_unless (unlinked_count1 == 0);
966   fail_unless (linked_count2 == 1);
967   fail_unless (unlinked_count2 == 0);
968 
969   /* this link should fail because we are already linked. Let's make sure the
970    * link functions are not called */
971   ret = gst_pad_link (ghostpad, sinkpad);
972   fail_unless (ret == GST_PAD_LINK_WAS_LINKED);
973   fail_unless (linked_count1 == 1);
974   fail_unless (unlinked_count1 == 0);
975   fail_unless (linked_count2 == 1);
976   fail_unless (unlinked_count2 == 0);
977 
978   res = gst_pad_unlink (ghostpad, sinkpad);
979   fail_unless (res == TRUE);
980   fail_unless (linked_count1 == 1);
981   fail_unless (unlinked_count1 == 0);
982   fail_unless (linked_count2 == 1);
983   fail_unless (unlinked_count2 == 1);
984 
985   res = gst_pad_unlink (ghostpad, sinkpad);
986   fail_unless (res == FALSE);
987   fail_unless (linked_count1 == 1);
988   fail_unless (unlinked_count1 == 0);
989   fail_unless (linked_count2 == 1);
990   fail_unless (unlinked_count2 == 1);
991 
992   /* this should trigger the unlink function */
993   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
994   fail_unless (res == TRUE);
995   fail_unless (linked_count1 == 1);
996   fail_unless (unlinked_count1 == 1);
997   fail_unless (linked_count2 == 1);
998   fail_unless (unlinked_count2 == 1);
999 
1000   /* and this the link function again */
1001   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), srcpad);
1002   fail_unless (res == TRUE);
1003   fail_unless (linked_count1 == 2);
1004   fail_unless (unlinked_count1 == 1);
1005   fail_unless (linked_count2 == 1);
1006   fail_unless (unlinked_count2 == 1);
1007 
1008   gst_object_unref (ghostpad);
1009   gst_object_unref (sinkpad);
1010   gst_object_unref (srcpad);
1011   gst_object_unref (srctempl);
1012   gst_object_unref (sinktempl);
1013 }
1014 
1015 GST_END_TEST;
1016 
GST_START_TEST(test_ghost_pads_change_when_linked)1017 GST_START_TEST (test_ghost_pads_change_when_linked)
1018 {
1019   GstElement *b1, *b2, *src, *fmt, *sink1, *sink2;
1020   GstPad *sinkpad, *ghostpad;
1021   GstCaps *caps;
1022 
1023   b1 = gst_element_factory_make ("pipeline", NULL);
1024   b2 = gst_element_factory_make ("bin", NULL);
1025   src = gst_element_factory_make ("fakesrc", NULL);
1026   fmt = gst_element_factory_make ("capsfilter", NULL);
1027   sink1 = gst_element_factory_make ("fakesink", NULL);
1028   sink2 = gst_element_factory_make ("fakesink", NULL);
1029 
1030   gst_bin_add (GST_BIN (b2), sink1);
1031   gst_bin_add (GST_BIN (b2), sink2);
1032   gst_bin_add (GST_BIN (b1), src);
1033   gst_bin_add (GST_BIN (b1), fmt);
1034   gst_bin_add (GST_BIN (b1), b2);
1035 
1036   caps = gst_caps_from_string ("audio/x-raw, format=S16LE, channels=1");
1037   g_object_set (fmt, "caps", caps, NULL);
1038   gst_caps_unref (caps);
1039 
1040   /* create the ghostpad as a sink-pad for bin 2 */
1041   ghostpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
1042   gst_element_add_pad (b2, ghostpad);
1043 
1044   sinkpad = gst_element_get_static_pad (sink1, "sink");
1045   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1046   gst_object_unref (sinkpad);
1047 
1048   fail_unless (gst_element_link_many (src, fmt, b2, NULL));
1049 
1050   /* set different target after ghostpad is linked */
1051   sinkpad = gst_element_get_static_pad (sink2, "sink");
1052   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1053   gst_object_unref (sinkpad);
1054 
1055   /* clean up */
1056   gst_object_unref (b1);
1057 }
1058 
1059 GST_END_TEST;
1060 
1061 /* test that setting a ghostpad proxy pad as ghostpad target automatically set
1062  * both ghostpad targets.
1063  *
1064  * fakesrc ! ( ) ! fakesink
1065  */
1066 
GST_START_TEST(test_ghost_pads_internal_link)1067 GST_START_TEST (test_ghost_pads_internal_link)
1068 {
1069   GstElement *pipeline, *src, *bin, *sink;
1070   GstPad *sinkpad, *srcpad, *target;
1071   GstProxyPad *proxypad;
1072 
1073   pipeline = gst_element_factory_make ("pipeline", NULL);
1074   bin = gst_element_factory_make ("bin", NULL);
1075   src = gst_element_factory_make ("fakesrc", NULL);
1076   sink = gst_element_factory_make ("fakesink", NULL);
1077 
1078   gst_bin_add (GST_BIN (pipeline), src);
1079   gst_bin_add (GST_BIN (pipeline), bin);
1080   gst_bin_add (GST_BIN (pipeline), sink);
1081 
1082   /* create the sink ghostpad */
1083   sinkpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
1084   proxypad = gst_proxy_pad_get_internal (GST_PROXY_PAD (sinkpad));
1085   gst_element_add_pad (bin, sinkpad);
1086 
1087   /* create the src ghostpad and link it to sink proxypad */
1088   srcpad = gst_ghost_pad_new ("src", GST_PAD (proxypad));
1089   gst_object_unref (proxypad);
1090   gst_element_add_pad (bin, srcpad);
1091 
1092   fail_unless (gst_element_link_many (src, bin, sink, NULL));
1093 
1094   /* Check that both targets are set, and point to each other */
1095   target = gst_ghost_pad_get_target (GST_GHOST_PAD (sinkpad));
1096   fail_if (target == NULL);
1097   proxypad = gst_proxy_pad_get_internal (GST_PROXY_PAD (srcpad));
1098   fail_unless (target == GST_PAD (proxypad));
1099   gst_object_unref (target);
1100   gst_object_unref (proxypad);
1101 
1102   target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcpad));
1103   fail_if (target == NULL);
1104   proxypad = gst_proxy_pad_get_internal (GST_PROXY_PAD (sinkpad));
1105   fail_unless (target == GST_PAD (proxypad));
1106   gst_object_unref (target);
1107   gst_object_unref (proxypad);
1108 
1109   /* clean up */
1110   gst_object_unref (pipeline);
1111 }
1112 
1113 GST_END_TEST;
1114 
1115 /* Test that remove a ghostpad that has something flowing through it does not
1116  * crash the program
1117  */
1118 
1119 GstElement *bin;
1120 GstPad *ghostsink;
1121 GstPad *ghostsrc;
1122 
1123 static GstPadProbeReturn
remove_ghostpad_probe_cb(GstPad * pad,GstPadProbeInfo * info,gpointer data)1124 remove_ghostpad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer data)
1125 {
1126   gst_pad_set_active (ghostsrc, FALSE);
1127   gst_pad_set_active (ghostsink, FALSE);
1128   gst_element_remove_pad (bin, ghostsrc);
1129   gst_element_remove_pad (bin, ghostsink);
1130 
1131   return GST_PAD_PROBE_DROP;
1132 }
1133 
GST_START_TEST(test_ghost_pads_remove_while_playing)1134 GST_START_TEST (test_ghost_pads_remove_while_playing)
1135 {
1136   GstPad *sinkpad;
1137   GstPad *srcpad;
1138   GstSegment segment;
1139 
1140   bin = gst_bin_new (NULL);
1141   gst_element_set_state (bin, GST_STATE_PLAYING);
1142 
1143   ghostsrc = gst_ghost_pad_new_no_target ("ghostsrc", GST_PAD_SRC);
1144   sinkpad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (ghostsrc)));
1145   ghostsink = gst_ghost_pad_new ("ghostsink", sinkpad);
1146   gst_object_unref (sinkpad);
1147   gst_pad_set_active (ghostsrc, TRUE);
1148   gst_pad_set_active (ghostsink, TRUE);
1149   gst_element_add_pad (bin, ghostsrc);
1150   gst_element_add_pad (bin, ghostsink);
1151 
1152   srcpad = gst_pad_new ("srcpad", GST_PAD_SRC);
1153   gst_pad_set_active (srcpad, TRUE);
1154   gst_pad_link (srcpad, ghostsink);
1155 
1156   gst_segment_init (&segment, GST_FORMAT_BYTES);
1157   fail_unless (gst_pad_push_event (srcpad,
1158           gst_event_new_stream_start ("test")) == TRUE);
1159   fail_unless (gst_pad_push_event (srcpad,
1160           gst_event_new_segment (&segment)) == TRUE);
1161 
1162   gst_pad_add_probe (ghostsrc, GST_PAD_PROBE_TYPE_BUFFER,
1163       remove_ghostpad_probe_cb, NULL, NULL);
1164 
1165   g_assert (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_OK);
1166 
1167   gst_pad_set_active (srcpad, FALSE);
1168   gst_element_set_state (bin, GST_STATE_NULL);
1169   gst_object_unref (bin);
1170   gst_object_unref (srcpad);
1171 }
1172 
1173 GST_END_TEST;
1174 
1175 
GST_START_TEST(test_activate_src)1176 GST_START_TEST (test_activate_src)
1177 {
1178   GstHarness *h;
1179   GstElement *b;
1180   GstElement *src;
1181   GstPad *srcpad;
1182 
1183   b = gst_bin_new (NULL);
1184   src = gst_element_factory_make ("fakesrc", NULL);
1185   g_object_set (src, "sync", TRUE, NULL);
1186   gst_bin_add (GST_BIN (b), src);
1187 
1188   srcpad = gst_element_get_static_pad (src, "src");
1189   gst_element_add_pad (b, gst_ghost_pad_new ("src", srcpad));
1190   gst_object_unref (srcpad);
1191 
1192   h = gst_harness_new_with_element (b, NULL, "src");
1193   gst_harness_play (h);
1194 
1195   gst_harness_crank_single_clock_wait (h);
1196   gst_buffer_unref (gst_harness_pull (h));
1197 
1198   gst_object_unref (b);
1199   gst_harness_teardown (h);
1200 }
1201 
1202 GST_END_TEST;
1203 
GST_START_TEST(test_activate_sink_and_src)1204 GST_START_TEST (test_activate_sink_and_src)
1205 {
1206   GstHarness *h;
1207   GstElement *b;
1208   GstElement *element;
1209   GstPad *sinkpad;
1210   GstPad *srcpad;
1211 
1212   b = gst_bin_new (NULL);
1213   element = gst_element_factory_make ("identity", NULL);
1214   gst_bin_add (GST_BIN (b), element);
1215 
1216   sinkpad = gst_element_get_static_pad (element, "sink");
1217   gst_element_add_pad (b, gst_ghost_pad_new ("sink", sinkpad));
1218   gst_object_unref (sinkpad);
1219 
1220   srcpad = gst_element_get_static_pad (element, "src");
1221   gst_element_add_pad (b, gst_ghost_pad_new ("src", srcpad));
1222   gst_object_unref (srcpad);
1223 
1224   h = gst_harness_new_with_element (b, "sink", "src");
1225   gst_harness_set_src_caps_str (h, "mycaps");
1226 
1227   gst_harness_push (h, gst_buffer_new ());
1228   gst_buffer_unref (gst_harness_pull (h));
1229 
1230   gst_object_unref (b);
1231   gst_harness_teardown (h);
1232 }
1233 
1234 GST_END_TEST;
1235 
GST_START_TEST(test_activate_src_pull_mode)1236 GST_START_TEST (test_activate_src_pull_mode)
1237 {
1238   GstElement *b;
1239   GstElement *src;
1240   GstPad *srcpad;
1241   GstPad *internalpad;
1242   GstPad *ghost;
1243 
1244   b = gst_bin_new (NULL);
1245   src = gst_element_factory_make ("fakesrc", NULL);
1246   gst_bin_add (GST_BIN (b), src);
1247 
1248   srcpad = gst_element_get_static_pad (src, "src");
1249   ghost = gst_ghost_pad_new ("src", srcpad);
1250   gst_element_add_pad (b, ghost);
1251 
1252   internalpad = (GstPad *) gst_proxy_pad_get_internal ((GstProxyPad *) ghost);
1253 
1254   fail_if (GST_PAD_IS_ACTIVE (ghost));
1255   fail_if (GST_PAD_IS_ACTIVE (internalpad));
1256   fail_if (GST_PAD_IS_ACTIVE (srcpad));
1257   fail_unless (gst_pad_activate_mode (ghost, GST_PAD_MODE_PULL, TRUE));
1258   fail_unless (GST_PAD_IS_ACTIVE (ghost));
1259   fail_unless (GST_PAD_IS_ACTIVE (internalpad));
1260   fail_unless (GST_PAD_IS_ACTIVE (srcpad));
1261 
1262   gst_object_unref (internalpad);
1263   gst_object_unref (srcpad);
1264   gst_object_unref (b);
1265 }
1266 
1267 GST_END_TEST;
1268 
GST_START_TEST(test_activate_sink_switch_mode)1269 GST_START_TEST (test_activate_sink_switch_mode)
1270 {
1271   GstElement *pipeline;
1272   GstElement *b, *src, *identity;
1273   GstPad *srcpad, *sinkpad, *internalpad, *ghost;
1274 
1275   pipeline = gst_pipeline_new (NULL);
1276   b = gst_bin_new (NULL);
1277   gst_bin_add (GST_BIN (pipeline), b);
1278   src = gst_element_factory_make ("fakesrc", NULL);
1279   gst_bin_add (GST_BIN (pipeline), src);
1280   identity = gst_element_factory_make ("identity", NULL);
1281   gst_bin_add (GST_BIN (b), identity);
1282 
1283   sinkpad = gst_element_get_static_pad (identity, "sink");
1284   ghost = gst_ghost_pad_new ("sink", sinkpad);
1285   gst_element_add_pad (b, ghost);
1286   srcpad = gst_element_get_static_pad (src, "src");
1287   gst_pad_link (srcpad, ghost);
1288 
1289   internalpad = (GstPad *) gst_proxy_pad_get_internal ((GstProxyPad *) ghost);
1290 
1291   /* We start with no active pads */
1292   fail_if (GST_PAD_IS_ACTIVE (ghost));
1293   fail_if (GST_PAD_IS_ACTIVE (internalpad));
1294   fail_if (GST_PAD_IS_ACTIVE (sinkpad));
1295   fail_if (GST_PAD_IS_ACTIVE (srcpad));
1296 
1297   GST_DEBUG ("Activating pads in push mode");
1298   /* Let's first try to activate everything in push-mode, for this we need
1299    * to go on every exposed pad */
1300   fail_unless (gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE));
1301   fail_unless (gst_pad_activate_mode (ghost, GST_PAD_MODE_PUSH, TRUE));
1302   fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE));
1303 
1304   GST_DEBUG ("Checking pads are all activated properly");
1305   /* Let's check all pads are now active, including internal ones */
1306   fail_unless (GST_PAD_MODE (ghost) == GST_PAD_MODE_PUSH);
1307   fail_unless (GST_PAD_MODE (internalpad) == GST_PAD_MODE_PUSH);
1308   fail_unless (GST_PAD_MODE (srcpad) == GST_PAD_MODE_PUSH);
1309   fail_unless (GST_PAD_MODE (sinkpad) == GST_PAD_MODE_PUSH);
1310 
1311   /* Now simulate a scheduling reconfiguration (PUSH=>PULL) */
1312   fail_unless (gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE));
1313 
1314   /* All pads should have switched modes */
1315   fail_unless (GST_PAD_MODE (ghost) == GST_PAD_MODE_PULL);
1316   fail_unless (GST_PAD_MODE (srcpad) == GST_PAD_MODE_PULL);
1317   fail_unless (GST_PAD_MODE (sinkpad) == GST_PAD_MODE_PULL);
1318   fail_unless (GST_PAD_MODE (internalpad) == GST_PAD_MODE_PULL);
1319 
1320   gst_object_unref (internalpad);
1321   gst_object_unref (srcpad);
1322   gst_object_unref (sinkpad);
1323   gst_object_unref (pipeline);
1324 }
1325 
1326 GST_END_TEST;
1327 
1328 static gboolean thread_running;
1329 
1330 static gpointer
send_query_to_pad_func(GstPad * pad)1331 send_query_to_pad_func (GstPad * pad)
1332 {
1333   GstQuery *query = gst_query_new_latency ();
1334 
1335   while (thread_running) {
1336     gst_pad_peer_query (pad, query);
1337     g_thread_yield ();
1338   }
1339 
1340   gst_query_unref (query);
1341   return NULL;
1342 }
1343 
GST_START_TEST(test_stress_upstream_queries_while_tearing_down)1344 GST_START_TEST (test_stress_upstream_queries_while_tearing_down)
1345 {
1346   GThread *query_thread;
1347   gint i;
1348   GstPad *pad = gst_pad_new ("sink", GST_PAD_SINK);
1349   gst_pad_set_active (pad, TRUE);
1350 
1351   thread_running = TRUE;
1352   query_thread = g_thread_new ("queries",
1353       (GThreadFunc) send_query_to_pad_func, pad);
1354 
1355   for (i = 0; i < 1000; i++) {
1356     GstPad *ghostpad = gst_ghost_pad_new ("ghost-sink", pad);
1357     gst_pad_set_active (ghostpad, TRUE);
1358 
1359     g_thread_yield ();
1360 
1361     gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
1362     gst_pad_set_active (pad, FALSE);
1363     gst_object_unref (ghostpad);
1364   }
1365 
1366   thread_running = FALSE;
1367   g_thread_join (query_thread);
1368 
1369   gst_object_unref (pad);
1370 }
1371 
1372 GST_END_TEST;
1373 
GST_START_TEST(test_deactivate_already_deactive_with_no_parent)1374 GST_START_TEST (test_deactivate_already_deactive_with_no_parent)
1375 {
1376   /* This simulates the behavior where a ghostpad is released while
1377    * deactivating (for instance because of a state change).
1378    * gst_pad_activate_mode() may be be called from
1379    * gst_ghost_pad_internal_activate_push_default() on a pad that is already
1380    * deactivate and unparented. The call chain is really like somethink like
1381    * this:
1382    *   gst_pad_activate_mode(ghostpad)
1383    *    -> ...
1384    *    -> gst_pad_activate_mode(proxypad)
1385    *    -> ...
1386    *    -> gst_pad_activate_mode(ghostpad)
1387    */
1388   GstElement *bin = gst_bin_new ("testbin");
1389   GstPad *pad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC);
1390   gst_object_ref (pad);
1391 
1392   /* We need to add/remove pad because that will update the pad's flags */
1393   fail_unless (gst_element_add_pad (bin, pad));
1394   fail_unless (gst_element_remove_pad (bin, pad));
1395 
1396   /* Setting a pad that's already deactive to deactive should not fail. */
1397   fail_if (gst_pad_is_active (pad));
1398   fail_unless (gst_pad_activate_mode (pad, GST_PAD_MODE_PUSH, FALSE));
1399 
1400   gst_object_unref (bin);
1401   gst_object_unref (pad);
1402 }
1403 
1404 GST_END_TEST;
1405 
1406 static Suite *
gst_ghost_pad_suite(void)1407 gst_ghost_pad_suite (void)
1408 {
1409   Suite *s = suite_create ("GstGhostPad");
1410 
1411   TCase *tc_chain = tcase_create ("ghost pad tests");
1412 
1413   suite_add_tcase (s, tc_chain);
1414   tcase_add_test (tc_chain, test_remove1);
1415   tcase_add_test (tc_chain, test_remove2);
1416   tcase_add_test (tc_chain, test_remove_target);
1417   tcase_add_test (tc_chain, test_link);
1418   tcase_add_test (tc_chain, test_ghost_pads);
1419   tcase_add_test (tc_chain, test_ghost_pads_bin);
1420   tcase_add_test (tc_chain, test_ghost_pads_notarget);
1421   tcase_add_test (tc_chain, test_ghost_pads_block);
1422   tcase_add_test (tc_chain, test_ghost_pads_probes);
1423   tcase_add_test (tc_chain, test_ghost_pads_new_from_template);
1424   tcase_add_test (tc_chain, test_ghost_pads_new_no_target_from_template);
1425   tcase_add_test (tc_chain, test_ghost_pads_forward_setcaps);
1426   tcase_add_test (tc_chain, test_ghost_pads_sink_link_unlink);
1427   tcase_add_test (tc_chain, test_ghost_pads_src_link_unlink);
1428   tcase_add_test (tc_chain, test_ghost_pads_change_when_linked);
1429   tcase_add_test (tc_chain, test_ghost_pads_internal_link);
1430   tcase_add_test (tc_chain, test_ghost_pads_remove_while_playing);
1431 
1432   tcase_add_test (tc_chain, test_activate_src);
1433   tcase_add_test (tc_chain, test_activate_sink_and_src);
1434   tcase_add_test (tc_chain, test_activate_src_pull_mode);
1435   tcase_add_test (tc_chain, test_activate_sink_switch_mode);
1436   tcase_add_test (tc_chain, test_deactivate_already_deactive_with_no_parent);
1437   tcase_add_test (tc_chain, test_stress_upstream_queries_while_tearing_down);
1438 
1439   return s;
1440 }
1441 
1442 GST_CHECK_MAIN (gst_ghost_pad);
1443