Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / tests / check / gst / gstghostpad.c
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., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <gst/check/gstcheck.h>
23
24 /* test if removing a bin also cleans up the ghostpads
25  */
26 GST_START_TEST (test_remove1)
27 {
28   GstElement *b1, *b2, *src, *sink;
29   GstPad *srcpad, *sinkpad;
30   GstPadLinkReturn ret;
31
32   b1 = gst_element_factory_make ("pipeline", NULL);
33   b2 = gst_element_factory_make ("bin", NULL);
34   src = gst_element_factory_make ("fakesrc", NULL);
35   sink = gst_element_factory_make ("fakesink", NULL);
36   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
37   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
38
39   fail_unless (gst_bin_add (GST_BIN (b2), sink));
40   fail_unless (gst_bin_add (GST_BIN (b1), src));
41   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
42   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
43   fail_unless (gst_bin_add (GST_BIN (b1), b2));
44   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
45   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
46
47   sinkpad = gst_element_get_static_pad (sink, "sink");
48   gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
49   gst_object_unref (sinkpad);
50
51   srcpad = gst_element_get_static_pad (src, "src");
52   /* get the ghostpad */
53   sinkpad = gst_element_get_static_pad (b2, "sink");
54
55   ret = gst_pad_link (srcpad, sinkpad);
56   fail_unless (ret == GST_PAD_LINK_OK);
57   gst_object_unref (srcpad);
58   gst_object_unref (sinkpad);
59
60   /* now remove the bin with the ghostpad, b2 is disposed now. */
61   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
62   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
63   gst_bin_remove (GST_BIN (b1), b2);
64
65   srcpad = gst_element_get_static_pad (src, "src");
66   /* pad cannot be linked now */
67   fail_if (gst_pad_is_linked (srcpad));
68   gst_object_unref (srcpad);
69
70   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
71   gst_object_unref (b1);
72 }
73
74 GST_END_TEST;
75
76 /* test if removing a bin also cleans up the ghostpads
77  */
78 GST_START_TEST (test_remove2)
79 {
80   GstElement *b1, *b2, *src, *sink;
81   GstPad *srcpad, *sinkpad;
82   GstPadLinkReturn ret;
83
84   b1 = gst_element_factory_make ("pipeline", NULL);
85   b2 = gst_element_factory_make ("bin", NULL);
86   src = gst_element_factory_make ("fakesrc", NULL);
87   sink = gst_element_factory_make ("fakesink", NULL);
88   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
89
90   fail_unless (gst_bin_add (GST_BIN (b2), sink));
91   fail_unless (gst_bin_add (GST_BIN (b1), src));
92   fail_unless (gst_bin_add (GST_BIN (b1), b2));
93   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
94
95   sinkpad = gst_element_get_static_pad (sink, "sink");
96   gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
97   gst_object_unref (sinkpad);
98
99   srcpad = gst_element_get_static_pad (src, "src");
100   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2); /* since we got one */
101   /* get the ghostpad */
102   sinkpad = gst_element_get_static_pad (b2, "sink");
103   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);       /* since we got one */
104
105   GST_DEBUG ("linking srcpad and sinkpad");
106   ret = gst_pad_link (srcpad, sinkpad);
107   GST_DEBUG ("linked srcpad and sinkpad");
108   fail_unless (ret == GST_PAD_LINK_OK);
109   /* the linking causes a proxypad to be created for srcpad,
110    * to which sinkpad gets linked.  This proxypad has a ref to srcpad */
111   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 3);
112   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
113   gst_object_unref (srcpad);
114   gst_object_unref (sinkpad);
115
116   /* now remove the sink from the bin */
117   gst_bin_remove (GST_BIN (b2), sink);
118
119   srcpad = gst_element_get_static_pad (src, "src");
120   /* pad is still linked to ghostpad */
121   fail_if (!gst_pad_is_linked (srcpad));
122   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
123   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 3);
124   gst_object_unref (srcpad);
125   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
126
127   /* cleanup */
128   /* now unlink the pads */
129   gst_pad_unlink (srcpad, sinkpad);
130   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1); /* proxy has dropped ref */
131   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
132
133   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
134   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
135   /* remove b2 from b1 */
136   gst_bin_remove (GST_BIN (b1), b2);
137
138   /* flush the message, dropping the b1 refcount to 1 */
139   gst_element_set_state (b1, GST_STATE_READY);
140   gst_element_set_state (b1, GST_STATE_NULL);
141   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
142   gst_object_unref (b1);
143 }
144
145 GST_END_TEST;
146
147
148
149 /* test if a ghost pad without a target can be linked and
150  * unlinked. An untargeted ghostpad has a default ANY caps unless there 
151  * is a padtemplate that says something else.
152  */
153 GST_START_TEST (test_ghost_pads_notarget)
154 {
155   GstElement *b1, *b2, *sink;
156   GstPad *srcpad, *sinkpad, *peer;
157   GstPadLinkReturn ret;
158   gboolean bret;
159   GstBus *bus;
160   GstCaps *caps;
161
162   b1 = gst_element_factory_make ("pipeline", NULL);
163
164   /* make sure all messages are discarded */
165   bus = gst_pipeline_get_bus (GST_PIPELINE (b1));
166   gst_bus_set_flushing (bus, TRUE);
167   gst_object_unref (bus);
168
169   b2 = gst_element_factory_make ("bin", NULL);
170   sink = gst_element_factory_make ("fakesink", NULL);
171
172   fail_unless (gst_bin_add (GST_BIN (b1), sink));
173   fail_unless (gst_bin_add (GST_BIN (b1), b2));
174
175   srcpad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC);
176   fail_unless (srcpad != NULL);
177   sinkpad = gst_element_get_static_pad (sink, "sink");
178   fail_unless (sinkpad != NULL);
179
180   ret = gst_pad_link (srcpad, sinkpad);
181   fail_unless (ret == GST_PAD_LINK_OK);
182
183   /* check if the peers are ok */
184   peer = gst_pad_get_peer (srcpad);
185   fail_unless (peer == sinkpad);
186   gst_object_unref (peer);
187
188   peer = gst_pad_get_peer (sinkpad);
189   fail_unless (peer == srcpad);
190   gst_object_unref (peer);
191
192   /* check caps, untargetted pad should return ANY or the padtemplate caps 
193    * when it was created from a template */
194   caps = gst_pad_get_caps (srcpad, NULL);
195   fail_unless (gst_caps_is_any (caps));
196   gst_caps_unref (caps);
197
198   /* unlink */
199   bret = gst_pad_unlink (srcpad, sinkpad);
200   fail_unless (bret == TRUE);
201
202   /* cleanup */
203   gst_object_unref (srcpad);
204   gst_object_unref (sinkpad);
205   gst_object_unref (b1);
206 }
207
208 GST_END_TEST;
209
210 /* Test that removing the target of a ghostpad properly sets the target of the
211  * ghostpad to NULL */
212 GST_START_TEST (test_remove_target)
213 {
214   GstElement *b1, *b2, *src, *sink;
215   GstPad *sinkpad, *ghost, *target;
216
217   b1 = gst_element_factory_make ("pipeline", NULL);
218   b2 = gst_element_factory_make ("bin", NULL);
219   src = gst_element_factory_make ("fakesrc", NULL);
220   sink = gst_element_factory_make ("fakesink", NULL);
221   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
222
223   fail_unless (gst_bin_add (GST_BIN (b2), sink));
224   fail_unless (gst_bin_add (GST_BIN (b1), src));
225   fail_unless (gst_bin_add (GST_BIN (b1), b2));
226   ASSERT_OBJECT_REFCOUNT (src, "src", 1);
227
228   sinkpad = gst_element_get_static_pad (sink, "sink");
229   gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
230
231   ghost = gst_element_get_static_pad (b2, "sink");
232
233   target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost));
234   fail_unless (target == sinkpad);
235   gst_object_unref (target);
236   gst_object_unref (sinkpad);
237
238   gst_bin_remove (GST_BIN (b2), sink);
239
240   target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost));
241   fail_unless (target == NULL);
242
243   gst_object_unref (b1);
244 }
245
246 GST_END_TEST;
247
248
249 /* test if linking fails over different bins using a pipeline
250  * like this:
251  *
252  * fakesrc num_buffers=10 ! ( fakesink )
253  *
254  */
255 GST_START_TEST (test_link)
256 {
257   GstElement *b1, *b2, *src, *sink;
258   GstPad *srcpad, *sinkpad, *gpad, *ppad, *tmp;
259   GstPadLinkReturn ret;
260
261   b1 = gst_element_factory_make ("pipeline", NULL);
262   b2 = gst_element_factory_make ("bin", NULL);
263   src = gst_element_factory_make ("fakesrc", NULL);
264   sink = gst_element_factory_make ("fakesink", NULL);
265
266   fail_unless (gst_bin_add (GST_BIN (b2), sink));
267   fail_unless (gst_bin_add (GST_BIN (b1), src));
268   fail_unless (gst_bin_add (GST_BIN (b1), b2));
269
270   srcpad = gst_element_get_static_pad (src, "src");
271   fail_unless (srcpad != NULL);
272   sinkpad = gst_element_get_static_pad (sink, "sink");
273   fail_unless (sinkpad != NULL);
274
275   /* linking in different hierarchies should fail */
276   ret = gst_pad_link (srcpad, sinkpad);
277   fail_unless (ret == GST_PAD_LINK_WRONG_HIERARCHY);
278
279   /* now setup a ghostpad */
280   gpad = gst_ghost_pad_new ("sink", sinkpad);
281
282   /* Check if the internal pads are set correctly */
283   ppad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (gpad)));
284   fail_unless (ppad == GST_PAD_PEER (sinkpad));
285   tmp = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (ppad)));
286   fail_unless (tmp == gpad);
287   gst_object_unref (tmp);
288   gst_object_unref (ppad);
289   gst_object_unref (sinkpad);
290   /* need to ref as _add_pad takes ownership */
291   gst_object_ref (gpad);
292   gst_element_add_pad (b2, gpad);
293
294   /* our new sinkpad */
295   sinkpad = gpad;
296
297   /* and linking should work now */
298   ret = gst_pad_link (srcpad, sinkpad);
299   fail_unless (ret == GST_PAD_LINK_OK);
300
301   /* flush the message, dropping the b1 refcount to 1 */
302   gst_element_set_state (b1, GST_STATE_READY);
303   gst_element_set_state (b1, GST_STATE_NULL);
304   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
305
306   gst_object_unref (srcpad);
307   gst_object_unref (sinkpad);
308   gst_object_unref (b1);
309 }
310
311 GST_END_TEST;
312
313 /* test if ghostpads are created automagically when using
314  * gst_element_link_pads.
315  *
316  * fakesrc num_buffers=10 ! ( identity ) ! fakesink
317  */
318 GST_START_TEST (test_ghost_pads)
319 {
320   GstElement *b1, *b2, *src, *i1, *sink;
321   GstPad *gsink, *gsrc, *gisrc, *gisink, *isink, *isrc, *fsrc, *fsink;
322   GstStateChangeReturn ret;
323
324   b1 = gst_element_factory_make ("pipeline", NULL);
325   b2 = gst_element_factory_make ("bin", NULL);
326   src = gst_element_factory_make ("fakesrc", NULL);
327   g_object_set (src, "num-buffers", (int) 10, NULL);
328   i1 = gst_element_factory_make ("identity", NULL);
329   sink = gst_element_factory_make ("fakesink", NULL);
330
331   fail_unless (gst_bin_add (GST_BIN (b2), i1));
332   fail_unless (gst_bin_add (GST_BIN (b1), src));
333   fail_unless (gst_bin_add (GST_BIN (b1), b2));
334   fail_unless (gst_bin_add (GST_BIN (b1), sink));
335   fail_unless (gst_element_link_pads (src, NULL, i1, NULL));
336   fail_unless (gst_element_link_pads (i1, NULL, sink, NULL));
337   GST_OBJECT_LOCK (b2);
338   fail_unless (b2->numsinkpads == 1);
339   fail_unless (GST_IS_GHOST_PAD (b2->sinkpads->data));
340   fail_unless (b2->numsrcpads == 1);
341   fail_unless (GST_IS_GHOST_PAD (b2->srcpads->data));
342   GST_OBJECT_UNLOCK (b2);
343
344   fsrc = gst_element_get_static_pad (src, "src");
345   fail_unless (fsrc != NULL);
346   gsink = GST_PAD (gst_object_ref (b2->sinkpads->data));
347   fail_unless (gsink != NULL);
348   gsrc = GST_PAD (gst_object_ref (b2->srcpads->data));
349   fail_unless (gsrc != NULL);
350   fsink = gst_element_get_static_pad (sink, "sink");
351   fail_unless (fsink != NULL);
352
353   isink = gst_element_get_static_pad (i1, "sink");
354   fail_unless (isink != NULL);
355   isrc = gst_element_get_static_pad (i1, "src");
356   fail_unless (isrc != NULL);
357   gisrc = gst_pad_get_peer (isink);
358   fail_unless (gisrc != NULL);
359   gisink = gst_pad_get_peer (isrc);
360   fail_unless (gisink != NULL);
361
362   /* all objects above have one refcount owned by us as well */
363
364   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 3);     /* parent and gisrc */
365   ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 2);   /* parent */
366   ASSERT_OBJECT_REFCOUNT (gsrc, "gsrc", 2);     /* parent */
367   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 3);   /* parent and gisink */
368
369   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2);   /* parent */
370   ASSERT_OBJECT_REFCOUNT (isink, "isink", 3);   /* parent and gsink */
371   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* parent */
372   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 3);     /* parent and gsrc */
373
374   ret = gst_element_set_state (b1, GST_STATE_PLAYING);
375   ret = gst_element_get_state (b1, NULL, NULL, GST_CLOCK_TIME_NONE);
376   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
377
378   ret = gst_element_set_state (b1, GST_STATE_NULL);
379   ret = gst_element_get_state (b1, NULL, NULL, GST_CLOCK_TIME_NONE);
380   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
381
382   gst_object_unref (b1);
383   /* unreffing the bin will unref all elements, which will unlink and unparent
384    * all pads */
385
386   /* wait for thread to settle down */
387   while (GST_OBJECT_REFCOUNT_VALUE (fsrc) > 1)
388     THREAD_SWITCH ();
389
390   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
391   ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 1);
392   ASSERT_OBJECT_REFCOUNT (gsrc, "gsink", 1);
393   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
394
395   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2);   /* gsink */
396   ASSERT_OBJECT_REFCOUNT (isink, "isink", 1);   /* gsink */
397   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* gsrc */
398   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1);     /* gsrc */
399
400   gst_object_unref (gsink);
401   ASSERT_OBJECT_REFCOUNT (isink, "isink", 1);
402   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 1);
403   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
404   gst_object_unref (gisrc);
405   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
406
407   gst_object_unref (gsrc);
408   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1);
409   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 1);
410   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
411   gst_object_unref (gisink);
412   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
413
414   gst_object_unref (fsrc);
415   gst_object_unref (isrc);
416   gst_object_unref (isink);
417   gst_object_unref (fsink);
418 }
419
420 GST_END_TEST;
421
422 GST_START_TEST (test_ghost_pads_bin)
423 {
424   GstBin *pipeline;
425   GstBin *srcbin;
426   GstBin *sinkbin;
427   GstElement *src;
428   GstElement *sink;
429   GstPad *srcpad, *srcghost, *target;
430   GstPad *sinkpad, *sinkghost;
431
432   pipeline = GST_BIN (gst_pipeline_new ("pipe"));
433   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
434
435   srcbin = GST_BIN (gst_bin_new ("srcbin"));
436   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
437   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
438
439   sinkbin = GST_BIN (gst_bin_new ("sinkbin"));
440   gst_bin_add (pipeline, GST_ELEMENT (sinkbin));
441   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
442
443   src = gst_element_factory_make ("fakesrc", "src");
444   gst_bin_add (srcbin, src);
445   srcpad = gst_element_get_static_pad (src, "src");
446   srcghost = gst_ghost_pad_new ("src", srcpad);
447   gst_object_unref (srcpad);
448   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
449
450   sink = gst_element_factory_make ("fakesink", "sink");
451   gst_bin_add (sinkbin, sink);
452   sinkpad = gst_element_get_static_pad (sink, "sink");
453   sinkghost = gst_ghost_pad_new ("sink", sinkpad);
454   gst_object_unref (sinkpad);
455   gst_element_add_pad (GST_ELEMENT (sinkbin), sinkghost);
456
457   gst_element_link (GST_ELEMENT (srcbin), GST_ELEMENT (sinkbin));
458
459   fail_unless (GST_PAD_PEER (srcghost) != NULL);
460   fail_unless (GST_PAD_PEER (sinkghost) != NULL);
461   target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcghost));
462   fail_unless (GST_PAD_PEER (target) != NULL);
463   gst_object_unref (target);
464   target = gst_ghost_pad_get_target (GST_GHOST_PAD (sinkghost));
465   fail_unless (GST_PAD_PEER (target) != NULL);
466   gst_object_unref (target);
467
468   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
469
470   gst_object_unref (pipeline);
471 }
472
473 GST_END_TEST;
474
475 typedef struct
476 {
477   GMutex *mutex;
478   GCond *cond;
479 } BlockData;
480
481 static GstProbeReturn
482 block_callback (GstPad * pad, GstProbeType type, gpointer type_data,
483     gpointer user_data)
484 {
485   BlockData *block_data = (BlockData *) user_data;
486
487   g_mutex_lock (block_data->mutex);
488   GST_DEBUG ("blocked\n");
489   g_cond_signal (block_data->cond);
490   g_mutex_unlock (block_data->mutex);
491
492   return GST_PROBE_OK;
493 }
494
495 GST_START_TEST (test_ghost_pads_block)
496 {
497   GstBin *pipeline;
498   GstBin *srcbin;
499   GstElement *src;
500   GstPad *srcpad;
501   GstPad *srcghost;
502   BlockData block_data;
503
504   pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
505
506   srcbin = GST_BIN (gst_bin_new ("srcbin"));
507   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
508
509   src = gst_element_factory_make ("fakesrc", "src");
510   gst_bin_add (srcbin, src);
511   srcpad = gst_element_get_static_pad (src, "src");
512   srcghost = gst_ghost_pad_new ("src", srcpad);
513   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
514   gst_object_unref (srcpad);
515
516   block_data.mutex = g_mutex_new ();
517   block_data.cond = g_cond_new ();
518
519   g_mutex_lock (block_data.mutex);
520   gst_pad_add_probe (srcghost, GST_PROBE_TYPE_BLOCK, block_callback,
521       &block_data, NULL);
522   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
523   /* and wait now */
524   g_cond_wait (block_data.cond, block_data.mutex);
525   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
526   g_mutex_unlock (block_data.mutex);
527
528   g_mutex_free (block_data.mutex);
529   g_cond_free (block_data.cond);
530
531   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
532   gst_object_unref (pipeline);
533 }
534
535 GST_END_TEST;
536
537 GST_START_TEST (test_ghost_pads_probes)
538 {
539   GstBin *pipeline;
540   GstBin *srcbin;
541   GstElement *src;
542   GstPad *srcpad;
543   GstPad *srcghost;
544   BlockData block_data;
545
546   pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
547
548   srcbin = GST_BIN (gst_bin_new ("srcbin"));
549   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
550
551   src = gst_element_factory_make ("fakesrc", "src");
552   gst_bin_add (srcbin, src);
553   srcpad = gst_element_get_static_pad (src, "src");
554   srcghost = gst_ghost_pad_new ("src", srcpad);
555   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
556   gst_object_unref (srcpad);
557
558   block_data.mutex = g_mutex_new ();
559   block_data.cond = g_cond_new ();
560
561   g_mutex_lock (block_data.mutex);
562   gst_pad_add_probe (srcghost, GST_PROBE_TYPE_BLOCK, block_callback,
563       &block_data, NULL);
564   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
565   /* and wait now */
566   g_cond_wait (block_data.cond, block_data.mutex);
567   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
568   g_mutex_unlock (block_data.mutex);
569
570   g_mutex_free (block_data.mutex);
571   g_cond_free (block_data.cond);
572
573   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
574   gst_object_unref (pipeline);
575 }
576
577 GST_END_TEST;
578
579 GST_START_TEST (test_ghost_pads_new_from_template)
580 {
581   GstPad *sinkpad, *ghostpad;
582   GstPadTemplate *padtempl, *ghosttempl;
583   GstCaps *padcaps, *ghostcaps, *newcaps;
584
585   padcaps = gst_caps_from_string ("some/caps");
586   fail_unless (padcaps != NULL);
587   ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
588   fail_unless (ghostcaps != NULL);
589
590   padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
591       GST_PAD_ALWAYS, padcaps);
592   fail_unless (padtempl != NULL);
593   ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
594       GST_PAD_ALWAYS, ghostcaps);
595
596   sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
597   fail_unless (sinkpad != NULL);
598
599   ghostpad = gst_ghost_pad_new_from_template ("ghostpad", sinkpad, ghosttempl);
600   fail_unless (ghostpad != NULL);
601
602   /* check template is properly set */
603   fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
604
605   /* check ghostpad caps are from the sinkpad */
606   newcaps = gst_pad_get_caps (ghostpad, NULL);
607   fail_unless (newcaps != NULL);
608   fail_unless (gst_caps_is_equal (newcaps, padcaps));
609   gst_caps_unref (newcaps);
610   gst_caps_unref (padcaps);
611   gst_caps_unref (ghostcaps);
612
613   gst_object_unref (sinkpad);
614   gst_object_unref (ghostpad);
615
616   gst_object_unref (padtempl);
617   gst_object_unref (ghosttempl);
618 }
619
620 GST_END_TEST;
621
622 GST_START_TEST (test_ghost_pads_new_no_target_from_template)
623 {
624   GstPad *sinkpad, *ghostpad;
625   GstPadTemplate *padtempl, *ghosttempl;
626   GstCaps *padcaps, *ghostcaps, *newcaps;
627
628   padcaps = gst_caps_from_string ("some/caps");
629   fail_unless (padcaps != NULL);
630   ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
631   fail_unless (ghostcaps != NULL);
632
633   padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
634       GST_PAD_ALWAYS, padcaps);
635   fail_unless (padtempl != NULL);
636   ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
637       GST_PAD_ALWAYS, ghostcaps);
638
639   sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
640   fail_unless (sinkpad != NULL);
641
642   ghostpad = gst_ghost_pad_new_no_target_from_template ("ghostpad", ghosttempl);
643   fail_unless (ghostpad != NULL);
644
645   /* check template is properly set */
646   fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
647
648   /* check ghostpad caps are from the ghostpad template */
649   newcaps = gst_pad_get_caps (ghostpad, NULL);
650   fail_unless (newcaps != NULL);
651   fail_unless (gst_caps_is_equal (newcaps, ghostcaps));
652   gst_caps_unref (newcaps);
653
654   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
655
656   /* check ghostpad caps are now from the target pad */
657   newcaps = gst_pad_get_caps (ghostpad, NULL);
658   fail_unless (newcaps != NULL);
659   fail_unless (gst_caps_is_equal (newcaps, padcaps));
660   gst_caps_unref (newcaps);
661
662   gst_object_unref (sinkpad);
663   gst_object_unref (ghostpad);
664
665   gst_object_unref (padtempl);
666   gst_object_unref (ghosttempl);
667
668   gst_caps_unref (padcaps);
669   gst_caps_unref (ghostcaps);
670 }
671
672 GST_END_TEST;
673
674 static void
675 ghost_notify_caps (GObject * object, GParamSpec * pspec, gpointer * user_data)
676 {
677   GST_DEBUG ("caps notify called");
678   (*(gint *) user_data)++;
679 }
680
681 GST_START_TEST (test_ghost_pads_forward_setcaps)
682 {
683   GstCaps *templ_caps, *caps1, *caps2;
684   GstPadTemplate *src_template, *sink_template;
685   GstPad *src, *ghost, *sink;
686   gint notify_counter = 0;
687
688   templ_caps = gst_caps_from_string ("meh; muh");
689   src_template = gst_pad_template_new ("src", GST_PAD_SRC,
690       GST_PAD_ALWAYS, templ_caps);
691   gst_caps_unref (templ_caps);
692
693   templ_caps = gst_caps_from_string ("muh; meh");
694   sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
695       GST_PAD_ALWAYS, templ_caps);
696   gst_caps_unref (templ_caps);
697
698   src = gst_pad_new_from_template (src_template, "src");
699   sink = gst_pad_new_from_template (sink_template, "sink");
700
701   /* ghost source pad, setting caps on the source influences the caps of the
702    * ghostpad. */
703   ghost = gst_ghost_pad_new ("ghostsrc", src);
704   g_signal_connect (ghost, "notify::caps",
705       G_CALLBACK (ghost_notify_caps), &notify_counter);
706   fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
707
708   /* Activate pads for caps forwarding/setting to work */
709   gst_pad_set_active (src, TRUE);
710   gst_pad_set_active (ghost, TRUE);
711
712   caps1 = gst_caps_from_string ("meh");
713   fail_unless (gst_pad_set_caps (src, caps1));
714   caps2 = gst_pad_get_current_caps (ghost);
715   fail_unless (gst_caps_is_equal (caps1, caps2));
716   fail_unless_equals_int (notify_counter, 1);
717
718   gst_object_unref (ghost);
719   gst_caps_unref (caps1);
720
721   /* source 2, setting the caps on the ghostpad does not influence the caps of
722    * the target */
723   notify_counter = 0;
724   ghost = gst_ghost_pad_new ("ghostsrc", src);
725   g_signal_connect (ghost, "notify::caps",
726       G_CALLBACK (ghost_notify_caps), &notify_counter);
727   fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
728
729   gst_pad_set_active (ghost, TRUE);
730   gst_pad_set_active (sink, TRUE);
731
732   caps1 = gst_caps_from_string ("meh");
733   fail_unless (gst_pad_set_caps (ghost, caps1));
734 #if 0
735   caps2 = gst_pad_get_current_caps (src);
736   fail_unless (caps2 == NULL);
737 #endif
738   fail_unless_equals_int (notify_counter, 1);
739
740   gst_object_unref (ghost);
741   gst_caps_unref (caps1);
742
743
744   /* ghost sink pad. Setting caps on the ghostpad will also set those caps on
745    * the target pad. */
746   notify_counter = 0;
747   ghost = gst_ghost_pad_new ("ghostsink", sink);
748   g_signal_connect (ghost, "notify::caps",
749       G_CALLBACK (ghost_notify_caps), &notify_counter);
750   fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
751
752   gst_pad_set_active (src, TRUE);
753   gst_pad_set_active (ghost, TRUE);
754
755   caps1 = gst_caps_from_string ("muh");
756   fail_unless (gst_pad_set_caps (ghost, caps1));
757   caps2 = gst_pad_get_current_caps (sink);
758   fail_unless (gst_caps_is_equal (caps1, caps2));
759   fail_unless_equals_int (notify_counter, 1);
760
761   gst_object_unref (ghost);
762   gst_caps_unref (caps1);
763
764   /* clear caps on pads */
765   gst_pad_set_active (src, FALSE);
766   gst_pad_set_active (src, TRUE);
767   gst_pad_set_active (sink, FALSE);
768   gst_pad_set_active (sink, TRUE);
769
770   /* sink pad 2, setting caps just on the target pad should not influence the caps
771    * on the ghostpad. */
772   notify_counter = 0;
773   ghost = gst_ghost_pad_new ("ghostsink", sink);
774   fail_unless (gst_pad_get_current_caps (ghost) == NULL);
775   g_signal_connect (ghost, "notify::caps",
776       G_CALLBACK (ghost_notify_caps), &notify_counter);
777   fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
778
779   gst_pad_set_active (ghost, TRUE);
780
781   caps1 = gst_caps_from_string ("muh");
782   fail_unless (gst_pad_set_caps (sink, caps1));
783   caps2 = gst_pad_get_current_caps (ghost);
784   fail_unless (caps2 == NULL);
785   fail_unless_equals_int (notify_counter, 0);
786
787   gst_object_unref (ghost);
788   gst_caps_unref (caps1);
789
790   gst_object_unref (src);
791   gst_object_unref (sink);
792   gst_object_unref (src_template);
793   gst_object_unref (sink_template);
794 }
795
796 GST_END_TEST;
797
798 static gint linked_count1;
799 static gint unlinked_count1;
800 static gint linked_count2;
801 static gint unlinked_count2;
802
803 static GstPadLinkReturn
804 pad_linked1 (GstPad * pad, GstPad * peer)
805 {
806   linked_count1++;
807
808   return GST_PAD_LINK_OK;
809 }
810
811 static void
812 pad_unlinked1 (GstPad * pad)
813 {
814   unlinked_count1++;
815 }
816
817 static GstPadLinkReturn
818 pad_linked2 (GstPad * pad, GstPad * peer)
819 {
820   linked_count2++;
821
822   return GST_PAD_LINK_OK;
823 }
824
825 static void
826 pad_unlinked2 (GstPad * pad)
827 {
828   unlinked_count2++;
829 }
830
831 GST_START_TEST (test_ghost_pads_sink_link_unlink)
832 {
833   GstCaps *padcaps;
834   GstPad *srcpad, *sinkpad, *ghostpad;
835   GstPadTemplate *srctempl, *sinktempl;
836   GstPadLinkReturn ret;
837   gboolean res;
838
839   padcaps = gst_caps_from_string ("some/caps");
840   fail_unless (padcaps != NULL);
841   srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
842       GST_PAD_ALWAYS, padcaps);
843   gst_caps_unref (padcaps);
844
845   padcaps = gst_caps_from_string ("some/caps");
846   fail_unless (padcaps != NULL);
847   sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
848       GST_PAD_ALWAYS, padcaps);
849   gst_caps_unref (padcaps);
850
851   srcpad = gst_pad_new_from_template (srctempl, "src");
852   fail_unless (srcpad != NULL);
853   sinkpad = gst_pad_new_from_template (sinktempl, "sink");
854   fail_unless (sinkpad != NULL);
855
856   /* set up link/unlink functions for the pad */
857   linked_count1 = unlinked_count1 = 0;
858   gst_pad_set_link_function (sinkpad, pad_linked1);
859   gst_pad_set_unlink_function (sinkpad, pad_unlinked1);
860   linked_count2 = unlinked_count2 = 0;
861   gst_pad_set_link_function (srcpad, pad_linked2);
862   gst_pad_set_unlink_function (srcpad, pad_unlinked2);
863
864   /* this should trigger a link from the internal pad to the sinkpad */
865   ghostpad = gst_ghost_pad_new ("ghostpad", sinkpad);
866   fail_unless (ghostpad != NULL);
867   fail_unless (linked_count1 == 1);
868   fail_unless (unlinked_count1 == 0);
869   fail_unless (linked_count2 == 0);
870   fail_unless (unlinked_count2 == 0);
871
872   /* this should not trigger anything because we are not directly
873    * linking/unlinking the sink pad. */
874   ret = gst_pad_link (srcpad, ghostpad);
875   fail_unless (ret == GST_PAD_LINK_OK);
876   fail_unless (linked_count1 == 1);
877   fail_unless (unlinked_count1 == 0);
878   fail_unless (linked_count2 == 1);
879   fail_unless (unlinked_count2 == 0);
880
881   res = gst_pad_unlink (srcpad, ghostpad);
882   fail_unless (res == TRUE);
883   fail_unless (linked_count1 == 1);
884   fail_unless (unlinked_count1 == 0);
885   fail_unless (linked_count2 == 1);
886   fail_unless (unlinked_count2 == 1);
887
888   /* this should trigger the unlink */
889   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
890   fail_unless (res == TRUE);
891   fail_unless (linked_count1 == 1);
892   fail_unless (unlinked_count1 == 1);
893   fail_unless (linked_count2 == 1);
894   fail_unless (unlinked_count2 == 1);
895
896   gst_object_unref (ghostpad);
897   gst_object_unref (sinkpad);
898   gst_object_unref (srcpad);
899   gst_object_unref (srctempl);
900   gst_object_unref (sinktempl);
901 }
902
903 GST_END_TEST;
904
905 GST_START_TEST (test_ghost_pads_src_link_unlink)
906 {
907   GstCaps *padcaps;
908   GstPad *srcpad, *sinkpad, *ghostpad, *dummy;
909   GstPadTemplate *srctempl, *sinktempl;
910   GstPadLinkReturn ret;
911   gboolean res;
912
913   padcaps = gst_caps_from_string ("some/caps");
914   fail_unless (padcaps != NULL);
915   srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
916       GST_PAD_ALWAYS, padcaps);
917   gst_caps_unref (padcaps);
918
919   padcaps = gst_caps_from_string ("some/caps");
920   fail_unless (padcaps != NULL);
921   sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
922       GST_PAD_ALWAYS, padcaps);
923   gst_caps_unref (padcaps);
924
925   srcpad = gst_pad_new_from_template (srctempl, "src");
926   fail_unless (srcpad != NULL);
927   sinkpad = gst_pad_new_from_template (sinktempl, "sink");
928   fail_unless (sinkpad != NULL);
929
930   /* set up link/unlink functions for the pad */
931   linked_count1 = unlinked_count1 = 0;
932   gst_pad_set_link_function (srcpad, pad_linked1);
933   gst_pad_set_unlink_function (srcpad, pad_unlinked1);
934   linked_count2 = unlinked_count2 = 0;
935   gst_pad_set_link_function (sinkpad, pad_linked2);
936   gst_pad_set_unlink_function (sinkpad, pad_unlinked2);
937
938   /* this should trigger a link from the internal pad to the srcpad */
939   ghostpad = gst_ghost_pad_new ("ghostpad", srcpad);
940   fail_unless (ghostpad != NULL);
941   fail_unless (linked_count1 == 1);
942   fail_unless (unlinked_count1 == 0);
943   fail_unless (linked_count2 == 0);
944   fail_unless (unlinked_count2 == 0);
945
946   /* this should fail with a critial */
947   ASSERT_CRITICAL (dummy = gst_ghost_pad_new ("ghostpad", srcpad));
948   fail_unless (dummy == NULL);
949   fail_unless (linked_count1 == 1);
950   fail_unless (unlinked_count1 == 0);
951   fail_unless (linked_count2 == 0);
952   fail_unless (unlinked_count2 == 0);
953
954   /* this should not trigger anything because we are not directly
955    * linking/unlinking the src pad. */
956   ret = gst_pad_link (ghostpad, sinkpad);
957   fail_unless (ret == GST_PAD_LINK_OK);
958   fail_unless (linked_count1 == 1);
959   fail_unless (unlinked_count1 == 0);
960   fail_unless (linked_count2 == 1);
961   fail_unless (unlinked_count2 == 0);
962
963   /* this link should fail because we are already linked. Let's make sure the
964    * link functions are not called */
965   ret = gst_pad_link (ghostpad, sinkpad);
966   fail_unless (ret == GST_PAD_LINK_WAS_LINKED);
967   fail_unless (linked_count1 == 1);
968   fail_unless (unlinked_count1 == 0);
969   fail_unless (linked_count2 == 1);
970   fail_unless (unlinked_count2 == 0);
971
972   res = gst_pad_unlink (ghostpad, sinkpad);
973   fail_unless (res == TRUE);
974   fail_unless (linked_count1 == 1);
975   fail_unless (unlinked_count1 == 0);
976   fail_unless (linked_count2 == 1);
977   fail_unless (unlinked_count2 == 1);
978
979   res = gst_pad_unlink (ghostpad, sinkpad);
980   fail_unless (res == FALSE);
981   fail_unless (linked_count1 == 1);
982   fail_unless (unlinked_count1 == 0);
983   fail_unless (linked_count2 == 1);
984   fail_unless (unlinked_count2 == 1);
985
986   /* this should trigger the unlink function */
987   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
988   fail_unless (res == TRUE);
989   fail_unless (linked_count1 == 1);
990   fail_unless (unlinked_count1 == 1);
991   fail_unless (linked_count2 == 1);
992   fail_unless (unlinked_count2 == 1);
993
994   /* and this the link function again */
995   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), srcpad);
996   fail_unless (res == TRUE);
997   fail_unless (linked_count1 == 2);
998   fail_unless (unlinked_count1 == 1);
999   fail_unless (linked_count2 == 1);
1000   fail_unless (unlinked_count2 == 1);
1001
1002   gst_object_unref (ghostpad);
1003   gst_object_unref (sinkpad);
1004   gst_object_unref (srcpad);
1005   gst_object_unref (srctempl);
1006   gst_object_unref (sinktempl);
1007 }
1008
1009 GST_END_TEST;
1010
1011 GST_START_TEST (test_ghost_pads_change_when_linked)
1012 {
1013   GstElement *b1, *b2, *src, *fmt, *sink1, *sink2;
1014   GstPad *sinkpad, *ghostpad;
1015   GstCaps *caps;
1016
1017   b1 = gst_element_factory_make ("pipeline", NULL);
1018   b2 = gst_element_factory_make ("bin", NULL);
1019   src = gst_element_factory_make ("fakesrc", NULL);
1020   fmt = gst_element_factory_make ("capsfilter", NULL);
1021   sink1 = gst_element_factory_make ("fakesink", NULL);
1022   sink2 = gst_element_factory_make ("fakesink", NULL);
1023
1024   gst_bin_add (GST_BIN (b2), sink1);
1025   gst_bin_add (GST_BIN (b2), sink2);
1026   gst_bin_add (GST_BIN (b1), src);
1027   gst_bin_add (GST_BIN (b1), fmt);
1028   gst_bin_add (GST_BIN (b1), b2);
1029
1030   caps = gst_caps_from_string ("audio/x-raw-int, width=16, channels=1");
1031   g_object_set (fmt, "caps", caps, NULL);
1032   gst_caps_unref (caps);
1033
1034   /* create the ghostpad as a sink-pad for bin 2 */
1035   ghostpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
1036   gst_element_add_pad (b2, ghostpad);
1037
1038   sinkpad = gst_element_get_static_pad (sink1, "sink");
1039   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1040   gst_object_unref (sinkpad);
1041
1042   fail_unless (gst_element_link_many (src, fmt, b2, NULL));
1043
1044   /* set different target after ghostpad is linked */
1045   sinkpad = gst_element_get_static_pad (sink2, "sink");
1046   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1047   gst_object_unref (sinkpad);
1048
1049   /* clean up */
1050   gst_object_unref (b1);
1051 }
1052
1053 GST_END_TEST;
1054
1055
1056 static Suite *
1057 gst_ghost_pad_suite (void)
1058 {
1059   Suite *s = suite_create ("GstGhostPad");
1060
1061   TCase *tc_chain = tcase_create ("ghost pad tests");
1062
1063   suite_add_tcase (s, tc_chain);
1064   tcase_add_test (tc_chain, test_remove1);
1065   tcase_add_test (tc_chain, test_remove2);
1066   tcase_add_test (tc_chain, test_remove_target);
1067   tcase_add_test (tc_chain, test_link);
1068   tcase_add_test (tc_chain, test_ghost_pads);
1069   tcase_add_test (tc_chain, test_ghost_pads_bin);
1070   tcase_add_test (tc_chain, test_ghost_pads_notarget);
1071   tcase_add_test (tc_chain, test_ghost_pads_block);
1072   tcase_add_test (tc_chain, test_ghost_pads_probes);
1073   tcase_add_test (tc_chain, test_ghost_pads_new_from_template);
1074   tcase_add_test (tc_chain, test_ghost_pads_new_no_target_from_template);
1075   tcase_add_test (tc_chain, test_ghost_pads_forward_setcaps);
1076   tcase_add_test (tc_chain, test_ghost_pads_sink_link_unlink);
1077   tcase_add_test (tc_chain, test_ghost_pads_src_link_unlink);
1078   tcase_add_test (tc_chain, test_ghost_pads_change_when_linked);
1079
1080   return s;
1081 }
1082
1083 GST_CHECK_MAIN (gst_ghost_pad);