Merge remote-tracking branch 'origin/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   gst_object_unref (ghost);
245 }
246
247 GST_END_TEST;
248
249
250 /* test if linking fails over different bins using a pipeline
251  * like this:
252  *
253  * fakesrc num_buffers=10 ! ( fakesink )
254  *
255  */
256 GST_START_TEST (test_link)
257 {
258   GstElement *b1, *b2, *src, *sink;
259   GstPad *srcpad, *sinkpad, *gpad, *ppad, *tmp;
260   GstPadLinkReturn ret;
261
262   b1 = gst_element_factory_make ("pipeline", NULL);
263   b2 = gst_element_factory_make ("bin", NULL);
264   src = gst_element_factory_make ("fakesrc", NULL);
265   sink = gst_element_factory_make ("fakesink", NULL);
266
267   fail_unless (gst_bin_add (GST_BIN (b2), sink));
268   fail_unless (gst_bin_add (GST_BIN (b1), src));
269   fail_unless (gst_bin_add (GST_BIN (b1), b2));
270
271   srcpad = gst_element_get_static_pad (src, "src");
272   fail_unless (srcpad != NULL);
273   sinkpad = gst_element_get_static_pad (sink, "sink");
274   fail_unless (sinkpad != NULL);
275
276   /* linking in different hierarchies should fail */
277   ret = gst_pad_link (srcpad, sinkpad);
278   fail_unless (ret == GST_PAD_LINK_WRONG_HIERARCHY);
279
280   /* now setup a ghostpad */
281   gpad = gst_ghost_pad_new ("sink", sinkpad);
282
283   /* Check if the internal pads are set correctly */
284   ppad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (gpad)));
285   fail_unless (ppad == GST_PAD_PEER (sinkpad));
286   tmp = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (ppad)));
287   fail_unless (tmp == gpad);
288   gst_object_unref (tmp);
289   gst_object_unref (ppad);
290   gst_object_unref (sinkpad);
291   /* need to ref as _add_pad takes ownership */
292   gst_object_ref (gpad);
293   gst_element_add_pad (b2, gpad);
294
295   /* our new sinkpad */
296   sinkpad = gpad;
297
298   /* and linking should work now */
299   ret = gst_pad_link (srcpad, sinkpad);
300   fail_unless (ret == GST_PAD_LINK_OK);
301
302   /* flush the message, dropping the b1 refcount to 1 */
303   gst_element_set_state (b1, GST_STATE_READY);
304   gst_element_set_state (b1, GST_STATE_NULL);
305   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
306
307   gst_object_unref (srcpad);
308   gst_object_unref (sinkpad);
309   gst_object_unref (b1);
310 }
311
312 GST_END_TEST;
313
314 /* test if ghostpads are created automagically when using
315  * gst_element_link_pads.
316  *
317  * fakesrc num_buffers=10 ! ( identity ) ! fakesink
318  */
319 GST_START_TEST (test_ghost_pads)
320 {
321   GstElement *b1, *b2, *src, *i1, *sink;
322   GstPad *gsink, *gsrc, *gisrc, *gisink, *isink, *isrc, *fsrc, *fsink;
323   GstStateChangeReturn ret;
324
325   b1 = gst_element_factory_make ("pipeline", NULL);
326   b2 = gst_element_factory_make ("bin", NULL);
327   src = gst_element_factory_make ("fakesrc", NULL);
328   g_object_set (src, "num-buffers", (int) 10, NULL);
329   i1 = gst_element_factory_make ("identity", NULL);
330   sink = gst_element_factory_make ("fakesink", NULL);
331
332   fail_unless (gst_bin_add (GST_BIN (b2), i1));
333   fail_unless (gst_bin_add (GST_BIN (b1), src));
334   fail_unless (gst_bin_add (GST_BIN (b1), b2));
335   fail_unless (gst_bin_add (GST_BIN (b1), sink));
336   fail_unless (gst_element_link_pads (src, NULL, i1, NULL));
337   fail_unless (gst_element_link_pads (i1, NULL, sink, NULL));
338   GST_OBJECT_LOCK (b2);
339   fail_unless (b2->numsinkpads == 1);
340   fail_unless (GST_IS_GHOST_PAD (b2->sinkpads->data));
341   fail_unless (b2->numsrcpads == 1);
342   fail_unless (GST_IS_GHOST_PAD (b2->srcpads->data));
343   GST_OBJECT_UNLOCK (b2);
344
345   fsrc = gst_element_get_static_pad (src, "src");
346   fail_unless (fsrc != NULL);
347   gsink = GST_PAD (gst_object_ref (b2->sinkpads->data));
348   fail_unless (gsink != NULL);
349   gsrc = GST_PAD (gst_object_ref (b2->srcpads->data));
350   fail_unless (gsrc != NULL);
351   fsink = gst_element_get_static_pad (sink, "sink");
352   fail_unless (fsink != NULL);
353
354   isink = gst_element_get_static_pad (i1, "sink");
355   fail_unless (isink != NULL);
356   isrc = gst_element_get_static_pad (i1, "src");
357   fail_unless (isrc != NULL);
358   gisrc = gst_pad_get_peer (isink);
359   fail_unless (gisrc != NULL);
360   gisink = gst_pad_get_peer (isrc);
361   fail_unless (gisink != NULL);
362
363   /* all objects above have one refcount owned by us as well */
364
365   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 3);     /* parent and gisrc */
366   ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 2);   /* parent */
367   ASSERT_OBJECT_REFCOUNT (gsrc, "gsrc", 2);     /* parent */
368   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 3);   /* parent and gisink */
369
370   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2);   /* parent */
371   ASSERT_OBJECT_REFCOUNT (isink, "isink", 3);   /* parent and gsink */
372   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* parent */
373   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 3);     /* parent and gsrc */
374
375   ret = gst_element_set_state (b1, GST_STATE_PLAYING);
376   ret = gst_element_get_state (b1, NULL, NULL, GST_CLOCK_TIME_NONE);
377   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
378
379   ret = gst_element_set_state (b1, GST_STATE_NULL);
380   ret = gst_element_get_state (b1, NULL, NULL, GST_CLOCK_TIME_NONE);
381   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
382
383   gst_object_unref (b1);
384   /* unreffing the bin will unref all elements, which will unlink and unparent
385    * all pads */
386
387   /* wait for thread to settle down */
388   while (GST_OBJECT_REFCOUNT_VALUE (fsrc) > 1)
389     THREAD_SWITCH ();
390
391   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
392   ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 1);
393   ASSERT_OBJECT_REFCOUNT (gsrc, "gsink", 1);
394   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
395
396   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2);   /* gsink */
397   ASSERT_OBJECT_REFCOUNT (isink, "isink", 1);   /* gsink */
398   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* gsrc */
399   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1);     /* gsrc */
400
401   gst_object_unref (gsink);
402   ASSERT_OBJECT_REFCOUNT (isink, "isink", 1);
403   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 1);
404   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
405   gst_object_unref (gisrc);
406   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
407
408   gst_object_unref (gsrc);
409   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1);
410   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 1);
411   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
412   gst_object_unref (gisink);
413   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
414
415   gst_object_unref (fsrc);
416   gst_object_unref (isrc);
417   gst_object_unref (isink);
418   gst_object_unref (fsink);
419 }
420
421 GST_END_TEST;
422
423 GST_START_TEST (test_ghost_pads_bin)
424 {
425   GstBin *pipeline;
426   GstBin *srcbin;
427   GstBin *sinkbin;
428   GstElement *src;
429   GstElement *sink;
430   GstPad *srcpad, *srcghost, *target;
431   GstPad *sinkpad, *sinkghost;
432
433   pipeline = GST_BIN (gst_pipeline_new ("pipe"));
434   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
435
436   srcbin = GST_BIN (gst_bin_new ("srcbin"));
437   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
438   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
439
440   sinkbin = GST_BIN (gst_bin_new ("sinkbin"));
441   gst_bin_add (pipeline, GST_ELEMENT (sinkbin));
442   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
443
444   src = gst_element_factory_make ("fakesrc", "src");
445   gst_bin_add (srcbin, src);
446   srcpad = gst_element_get_static_pad (src, "src");
447   srcghost = gst_ghost_pad_new ("src", srcpad);
448   gst_object_unref (srcpad);
449   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
450
451   sink = gst_element_factory_make ("fakesink", "sink");
452   gst_bin_add (sinkbin, sink);
453   sinkpad = gst_element_get_static_pad (sink, "sink");
454   sinkghost = gst_ghost_pad_new ("sink", sinkpad);
455   gst_object_unref (sinkpad);
456   gst_element_add_pad (GST_ELEMENT (sinkbin), sinkghost);
457
458   gst_element_link (GST_ELEMENT (srcbin), GST_ELEMENT (sinkbin));
459
460   fail_unless (GST_PAD_PEER (srcghost) != NULL);
461   fail_unless (GST_PAD_PEER (sinkghost) != NULL);
462   target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcghost));
463   fail_unless (GST_PAD_PEER (target) != NULL);
464   gst_object_unref (target);
465   target = gst_ghost_pad_get_target (GST_GHOST_PAD (sinkghost));
466   fail_unless (GST_PAD_PEER (target) != NULL);
467   gst_object_unref (target);
468
469   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
470
471   gst_object_unref (pipeline);
472 }
473
474 GST_END_TEST;
475
476 typedef struct
477 {
478   GMutex *mutex;
479   GCond *cond;
480 } BlockData;
481
482 static GstProbeReturn
483 block_callback (GstPad * pad, GstProbeType type, gpointer type_data,
484     gpointer user_data)
485 {
486   BlockData *block_data = (BlockData *) user_data;
487
488   g_mutex_lock (block_data->mutex);
489   GST_DEBUG ("blocked\n");
490   g_cond_signal (block_data->cond);
491   g_mutex_unlock (block_data->mutex);
492
493   return GST_PROBE_OK;
494 }
495
496 GST_START_TEST (test_ghost_pads_block)
497 {
498   GstBin *pipeline;
499   GstBin *srcbin;
500   GstElement *src;
501   GstPad *srcpad;
502   GstPad *srcghost;
503   BlockData block_data;
504
505   pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
506
507   srcbin = GST_BIN (gst_bin_new ("srcbin"));
508   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
509
510   src = gst_element_factory_make ("fakesrc", "src");
511   gst_bin_add (srcbin, src);
512   srcpad = gst_element_get_static_pad (src, "src");
513   srcghost = gst_ghost_pad_new ("src", srcpad);
514   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
515   gst_object_unref (srcpad);
516
517   block_data.mutex = g_mutex_new ();
518   block_data.cond = g_cond_new ();
519
520   g_mutex_lock (block_data.mutex);
521   gst_pad_add_probe (srcghost, GST_PROBE_TYPE_BLOCK, block_callback,
522       &block_data, NULL);
523   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
524   /* and wait now */
525   g_cond_wait (block_data.cond, block_data.mutex);
526   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
527   g_mutex_unlock (block_data.mutex);
528
529   g_mutex_free (block_data.mutex);
530   g_cond_free (block_data.cond);
531
532   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
533   gst_object_unref (pipeline);
534 }
535
536 GST_END_TEST;
537
538 GST_START_TEST (test_ghost_pads_probes)
539 {
540   GstBin *pipeline;
541   GstBin *srcbin;
542   GstElement *src;
543   GstPad *srcpad;
544   GstPad *srcghost;
545   BlockData block_data;
546
547   pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
548
549   srcbin = GST_BIN (gst_bin_new ("srcbin"));
550   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
551
552   src = gst_element_factory_make ("fakesrc", "src");
553   gst_bin_add (srcbin, src);
554   srcpad = gst_element_get_static_pad (src, "src");
555   srcghost = gst_ghost_pad_new ("src", srcpad);
556   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
557   gst_object_unref (srcpad);
558
559   block_data.mutex = g_mutex_new ();
560   block_data.cond = g_cond_new ();
561
562   g_mutex_lock (block_data.mutex);
563   gst_pad_add_probe (srcghost, GST_PROBE_TYPE_BLOCK, block_callback,
564       &block_data, NULL);
565   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
566   /* and wait now */
567   g_cond_wait (block_data.cond, block_data.mutex);
568   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
569   g_mutex_unlock (block_data.mutex);
570
571   g_mutex_free (block_data.mutex);
572   g_cond_free (block_data.cond);
573
574   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
575   gst_object_unref (pipeline);
576 }
577
578 GST_END_TEST;
579
580 GST_START_TEST (test_ghost_pads_new_from_template)
581 {
582   GstPad *sinkpad, *ghostpad;
583   GstPadTemplate *padtempl, *ghosttempl;
584   GstCaps *padcaps, *ghostcaps, *newcaps;
585
586   padcaps = gst_caps_from_string ("some/caps");
587   fail_unless (padcaps != NULL);
588   ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
589   fail_unless (ghostcaps != NULL);
590
591   padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
592       GST_PAD_ALWAYS, padcaps);
593   fail_unless (padtempl != NULL);
594   ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
595       GST_PAD_ALWAYS, ghostcaps);
596
597   sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
598   fail_unless (sinkpad != NULL);
599
600   ghostpad = gst_ghost_pad_new_from_template ("ghostpad", sinkpad, ghosttempl);
601   fail_unless (ghostpad != NULL);
602
603   /* check template is properly set */
604   fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
605
606   /* check ghostpad caps are from the sinkpad */
607   newcaps = gst_pad_get_caps (ghostpad, NULL);
608   fail_unless (newcaps != NULL);
609   fail_unless (gst_caps_is_equal (newcaps, padcaps));
610   gst_caps_unref (newcaps);
611   gst_caps_unref (padcaps);
612   gst_caps_unref (ghostcaps);
613
614   gst_object_unref (sinkpad);
615   gst_object_unref (ghostpad);
616
617   gst_object_unref (padtempl);
618   gst_object_unref (ghosttempl);
619 }
620
621 GST_END_TEST;
622
623 GST_START_TEST (test_ghost_pads_new_no_target_from_template)
624 {
625   GstPad *sinkpad, *ghostpad;
626   GstPadTemplate *padtempl, *ghosttempl;
627   GstCaps *padcaps, *ghostcaps, *newcaps;
628
629   padcaps = gst_caps_from_string ("some/caps");
630   fail_unless (padcaps != NULL);
631   ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
632   fail_unless (ghostcaps != NULL);
633
634   padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
635       GST_PAD_ALWAYS, padcaps);
636   fail_unless (padtempl != NULL);
637   ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
638       GST_PAD_ALWAYS, ghostcaps);
639
640   sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
641   fail_unless (sinkpad != NULL);
642
643   ghostpad = gst_ghost_pad_new_no_target_from_template ("ghostpad", ghosttempl);
644   fail_unless (ghostpad != NULL);
645
646   /* check template is properly set */
647   fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
648
649   /* check ghostpad caps are from the ghostpad template */
650   newcaps = gst_pad_get_caps (ghostpad, NULL);
651   fail_unless (newcaps != NULL);
652   fail_unless (gst_caps_is_equal (newcaps, ghostcaps));
653   gst_caps_unref (newcaps);
654
655   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
656
657   /* check ghostpad caps are now from the target pad */
658   newcaps = gst_pad_get_caps (ghostpad, NULL);
659   fail_unless (newcaps != NULL);
660   fail_unless (gst_caps_is_equal (newcaps, padcaps));
661   gst_caps_unref (newcaps);
662
663   gst_object_unref (sinkpad);
664   gst_object_unref (ghostpad);
665
666   gst_object_unref (padtempl);
667   gst_object_unref (ghosttempl);
668
669   gst_caps_unref (padcaps);
670   gst_caps_unref (ghostcaps);
671 }
672
673 GST_END_TEST;
674
675 static void
676 ghost_notify_caps (GObject * object, GParamSpec * pspec, gpointer * user_data)
677 {
678   GST_DEBUG ("caps notify called");
679   (*(gint *) user_data)++;
680 }
681
682 GST_START_TEST (test_ghost_pads_forward_setcaps)
683 {
684   GstCaps *templ_caps, *caps1, *caps2;
685   GstPadTemplate *src_template, *sink_template;
686   GstPad *src, *ghost, *sink;
687   gint notify_counter = 0;
688
689   templ_caps = gst_caps_from_string ("meh; muh");
690   src_template = gst_pad_template_new ("src", GST_PAD_SRC,
691       GST_PAD_ALWAYS, templ_caps);
692   gst_caps_unref (templ_caps);
693
694   templ_caps = gst_caps_from_string ("muh; meh");
695   sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
696       GST_PAD_ALWAYS, templ_caps);
697   gst_caps_unref (templ_caps);
698
699   src = gst_pad_new_from_template (src_template, "src");
700   sink = gst_pad_new_from_template (sink_template, "sink");
701
702   /* ghost source pad, setting caps on the source influences the caps of the
703    * ghostpad. */
704   ghost = gst_ghost_pad_new ("ghostsrc", src);
705   g_signal_connect (ghost, "notify::caps",
706       G_CALLBACK (ghost_notify_caps), &notify_counter);
707   fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
708
709   /* Activate pads for caps forwarding/setting to work */
710   gst_pad_set_active (src, TRUE);
711   gst_pad_set_active (ghost, TRUE);
712
713   caps1 = gst_caps_from_string ("meh");
714   fail_unless (gst_pad_set_caps (src, caps1));
715   caps2 = gst_pad_get_current_caps (ghost);
716   fail_unless (gst_caps_is_equal (caps1, caps2));
717   fail_unless_equals_int (notify_counter, 1);
718
719   gst_object_unref (ghost);
720   gst_caps_unref (caps1);
721   gst_caps_unref (caps2);
722
723   /* source 2, setting the caps on the ghostpad does not influence the caps of
724    * the target */
725   notify_counter = 0;
726   ghost = gst_ghost_pad_new ("ghostsrc", src);
727   g_signal_connect (ghost, "notify::caps",
728       G_CALLBACK (ghost_notify_caps), &notify_counter);
729   fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
730
731   gst_pad_set_active (ghost, TRUE);
732   gst_pad_set_active (sink, TRUE);
733
734   caps1 = gst_caps_from_string ("meh");
735   fail_unless (gst_pad_set_caps (ghost, caps1));
736 #if 0
737   caps2 = gst_pad_get_current_caps (src);
738   fail_unless (caps2 == NULL);
739 #endif
740   fail_unless_equals_int (notify_counter, 1);
741
742   gst_object_unref (ghost);
743   gst_caps_unref (caps1);
744
745
746   /* ghost sink pad. Setting caps on the ghostpad will also set those caps on
747    * the target pad. */
748   notify_counter = 0;
749   ghost = gst_ghost_pad_new ("ghostsink", sink);
750   g_signal_connect (ghost, "notify::caps",
751       G_CALLBACK (ghost_notify_caps), &notify_counter);
752   fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
753
754   gst_pad_set_active (src, TRUE);
755   gst_pad_set_active (ghost, TRUE);
756
757   caps1 = gst_caps_from_string ("muh");
758   fail_unless (gst_pad_set_caps (ghost, caps1));
759   caps2 = gst_pad_get_current_caps (sink);
760   fail_unless (gst_caps_is_equal (caps1, caps2));
761   fail_unless_equals_int (notify_counter, 1);
762
763   gst_object_unref (ghost);
764   gst_caps_unref (caps1);
765   gst_caps_unref (caps2);
766
767   /* clear caps on pads */
768   gst_pad_set_active (src, FALSE);
769   gst_pad_set_active (src, TRUE);
770   gst_pad_set_active (sink, FALSE);
771   gst_pad_set_active (sink, TRUE);
772
773   /* sink pad 2, setting caps just on the target pad should not influence the caps
774    * on the ghostpad. */
775   notify_counter = 0;
776   ghost = gst_ghost_pad_new ("ghostsink", sink);
777   fail_unless (gst_pad_get_current_caps (ghost) == NULL);
778   g_signal_connect (ghost, "notify::caps",
779       G_CALLBACK (ghost_notify_caps), &notify_counter);
780   fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
781
782   gst_pad_set_active (ghost, TRUE);
783
784   caps1 = gst_caps_from_string ("muh");
785   fail_unless (gst_pad_set_caps (sink, caps1));
786   caps2 = gst_pad_get_current_caps (ghost);
787   fail_unless (caps2 == NULL);
788   fail_unless_equals_int (notify_counter, 0);
789
790   gst_object_unref (ghost);
791   gst_caps_unref (caps1);
792
793   gst_object_unref (src);
794   gst_object_unref (sink);
795   gst_object_unref (src_template);
796   gst_object_unref (sink_template);
797 }
798
799 GST_END_TEST;
800
801 static gint linked_count1;
802 static gint unlinked_count1;
803 static gint linked_count2;
804 static gint unlinked_count2;
805
806 static GstPadLinkReturn
807 pad_linked1 (GstPad * pad, GstPad * peer)
808 {
809   linked_count1++;
810
811   return GST_PAD_LINK_OK;
812 }
813
814 static void
815 pad_unlinked1 (GstPad * pad)
816 {
817   unlinked_count1++;
818 }
819
820 static GstPadLinkReturn
821 pad_linked2 (GstPad * pad, GstPad * peer)
822 {
823   linked_count2++;
824
825   return GST_PAD_LINK_OK;
826 }
827
828 static void
829 pad_unlinked2 (GstPad * pad)
830 {
831   unlinked_count2++;
832 }
833
834 GST_START_TEST (test_ghost_pads_sink_link_unlink)
835 {
836   GstCaps *padcaps;
837   GstPad *srcpad, *sinkpad, *ghostpad;
838   GstPadTemplate *srctempl, *sinktempl;
839   GstPadLinkReturn ret;
840   gboolean res;
841
842   padcaps = gst_caps_from_string ("some/caps");
843   fail_unless (padcaps != NULL);
844   srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
845       GST_PAD_ALWAYS, padcaps);
846   gst_caps_unref (padcaps);
847
848   padcaps = gst_caps_from_string ("some/caps");
849   fail_unless (padcaps != NULL);
850   sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
851       GST_PAD_ALWAYS, padcaps);
852   gst_caps_unref (padcaps);
853
854   srcpad = gst_pad_new_from_template (srctempl, "src");
855   fail_unless (srcpad != NULL);
856   sinkpad = gst_pad_new_from_template (sinktempl, "sink");
857   fail_unless (sinkpad != NULL);
858
859   /* set up link/unlink functions for the pad */
860   linked_count1 = unlinked_count1 = 0;
861   gst_pad_set_link_function (sinkpad, pad_linked1);
862   gst_pad_set_unlink_function (sinkpad, pad_unlinked1);
863   linked_count2 = unlinked_count2 = 0;
864   gst_pad_set_link_function (srcpad, pad_linked2);
865   gst_pad_set_unlink_function (srcpad, pad_unlinked2);
866
867   /* this should trigger a link from the internal pad to the sinkpad */
868   ghostpad = gst_ghost_pad_new ("ghostpad", sinkpad);
869   fail_unless (ghostpad != NULL);
870   fail_unless (linked_count1 == 1);
871   fail_unless (unlinked_count1 == 0);
872   fail_unless (linked_count2 == 0);
873   fail_unless (unlinked_count2 == 0);
874
875   /* this should not trigger anything because we are not directly
876    * linking/unlinking the sink pad. */
877   ret = gst_pad_link (srcpad, ghostpad);
878   fail_unless (ret == GST_PAD_LINK_OK);
879   fail_unless (linked_count1 == 1);
880   fail_unless (unlinked_count1 == 0);
881   fail_unless (linked_count2 == 1);
882   fail_unless (unlinked_count2 == 0);
883
884   res = gst_pad_unlink (srcpad, ghostpad);
885   fail_unless (res == TRUE);
886   fail_unless (linked_count1 == 1);
887   fail_unless (unlinked_count1 == 0);
888   fail_unless (linked_count2 == 1);
889   fail_unless (unlinked_count2 == 1);
890
891   /* this should trigger the unlink */
892   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
893   fail_unless (res == TRUE);
894   fail_unless (linked_count1 == 1);
895   fail_unless (unlinked_count1 == 1);
896   fail_unless (linked_count2 == 1);
897   fail_unless (unlinked_count2 == 1);
898
899   gst_object_unref (ghostpad);
900   gst_object_unref (sinkpad);
901   gst_object_unref (srcpad);
902   gst_object_unref (srctempl);
903   gst_object_unref (sinktempl);
904 }
905
906 GST_END_TEST;
907
908 GST_START_TEST (test_ghost_pads_src_link_unlink)
909 {
910   GstCaps *padcaps;
911   GstPad *srcpad, *sinkpad, *ghostpad, *dummy;
912   GstPadTemplate *srctempl, *sinktempl;
913   GstPadLinkReturn ret;
914   gboolean res;
915
916   padcaps = gst_caps_from_string ("some/caps");
917   fail_unless (padcaps != NULL);
918   srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
919       GST_PAD_ALWAYS, padcaps);
920   gst_caps_unref (padcaps);
921
922   padcaps = gst_caps_from_string ("some/caps");
923   fail_unless (padcaps != NULL);
924   sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
925       GST_PAD_ALWAYS, padcaps);
926   gst_caps_unref (padcaps);
927
928   srcpad = gst_pad_new_from_template (srctempl, "src");
929   fail_unless (srcpad != NULL);
930   sinkpad = gst_pad_new_from_template (sinktempl, "sink");
931   fail_unless (sinkpad != NULL);
932
933   /* set up link/unlink functions for the pad */
934   linked_count1 = unlinked_count1 = 0;
935   gst_pad_set_link_function (srcpad, pad_linked1);
936   gst_pad_set_unlink_function (srcpad, pad_unlinked1);
937   linked_count2 = unlinked_count2 = 0;
938   gst_pad_set_link_function (sinkpad, pad_linked2);
939   gst_pad_set_unlink_function (sinkpad, pad_unlinked2);
940
941   /* this should trigger a link from the internal pad to the srcpad */
942   ghostpad = gst_ghost_pad_new ("ghostpad", srcpad);
943   fail_unless (ghostpad != NULL);
944   fail_unless (linked_count1 == 1);
945   fail_unless (unlinked_count1 == 0);
946   fail_unless (linked_count2 == 0);
947   fail_unless (unlinked_count2 == 0);
948
949   /* this should fail with a critial */
950   ASSERT_CRITICAL (dummy = gst_ghost_pad_new ("ghostpad", srcpad));
951   fail_unless (dummy == NULL);
952   fail_unless (linked_count1 == 1);
953   fail_unless (unlinked_count1 == 0);
954   fail_unless (linked_count2 == 0);
955   fail_unless (unlinked_count2 == 0);
956
957   /* this should not trigger anything because we are not directly
958    * linking/unlinking the src pad. */
959   ret = gst_pad_link (ghostpad, sinkpad);
960   fail_unless (ret == GST_PAD_LINK_OK);
961   fail_unless (linked_count1 == 1);
962   fail_unless (unlinked_count1 == 0);
963   fail_unless (linked_count2 == 1);
964   fail_unless (unlinked_count2 == 0);
965
966   /* this link should fail because we are already linked. Let's make sure the
967    * link functions are not called */
968   ret = gst_pad_link (ghostpad, sinkpad);
969   fail_unless (ret == GST_PAD_LINK_WAS_LINKED);
970   fail_unless (linked_count1 == 1);
971   fail_unless (unlinked_count1 == 0);
972   fail_unless (linked_count2 == 1);
973   fail_unless (unlinked_count2 == 0);
974
975   res = gst_pad_unlink (ghostpad, sinkpad);
976   fail_unless (res == TRUE);
977   fail_unless (linked_count1 == 1);
978   fail_unless (unlinked_count1 == 0);
979   fail_unless (linked_count2 == 1);
980   fail_unless (unlinked_count2 == 1);
981
982   res = gst_pad_unlink (ghostpad, sinkpad);
983   fail_unless (res == FALSE);
984   fail_unless (linked_count1 == 1);
985   fail_unless (unlinked_count1 == 0);
986   fail_unless (linked_count2 == 1);
987   fail_unless (unlinked_count2 == 1);
988
989   /* this should trigger the unlink function */
990   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
991   fail_unless (res == TRUE);
992   fail_unless (linked_count1 == 1);
993   fail_unless (unlinked_count1 == 1);
994   fail_unless (linked_count2 == 1);
995   fail_unless (unlinked_count2 == 1);
996
997   /* and this the link function again */
998   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), srcpad);
999   fail_unless (res == TRUE);
1000   fail_unless (linked_count1 == 2);
1001   fail_unless (unlinked_count1 == 1);
1002   fail_unless (linked_count2 == 1);
1003   fail_unless (unlinked_count2 == 1);
1004
1005   gst_object_unref (ghostpad);
1006   gst_object_unref (sinkpad);
1007   gst_object_unref (srcpad);
1008   gst_object_unref (srctempl);
1009   gst_object_unref (sinktempl);
1010 }
1011
1012 GST_END_TEST;
1013
1014 GST_START_TEST (test_ghost_pads_change_when_linked)
1015 {
1016   GstElement *b1, *b2, *src, *fmt, *sink1, *sink2;
1017   GstPad *sinkpad, *ghostpad;
1018   GstCaps *caps;
1019
1020   b1 = gst_element_factory_make ("pipeline", NULL);
1021   b2 = gst_element_factory_make ("bin", NULL);
1022   src = gst_element_factory_make ("fakesrc", NULL);
1023   fmt = gst_element_factory_make ("capsfilter", NULL);
1024   sink1 = gst_element_factory_make ("fakesink", NULL);
1025   sink2 = gst_element_factory_make ("fakesink", NULL);
1026
1027   gst_bin_add (GST_BIN (b2), sink1);
1028   gst_bin_add (GST_BIN (b2), sink2);
1029   gst_bin_add (GST_BIN (b1), src);
1030   gst_bin_add (GST_BIN (b1), fmt);
1031   gst_bin_add (GST_BIN (b1), b2);
1032
1033   caps = gst_caps_from_string ("audio/x-raw-int, width=16, channels=1");
1034   g_object_set (fmt, "caps", caps, NULL);
1035   gst_caps_unref (caps);
1036
1037   /* create the ghostpad as a sink-pad for bin 2 */
1038   ghostpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
1039   gst_element_add_pad (b2, ghostpad);
1040
1041   sinkpad = gst_element_get_static_pad (sink1, "sink");
1042   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1043   gst_object_unref (sinkpad);
1044
1045   fail_unless (gst_element_link_many (src, fmt, b2, NULL));
1046
1047   /* set different target after ghostpad is linked */
1048   sinkpad = gst_element_get_static_pad (sink2, "sink");
1049   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1050   gst_object_unref (sinkpad);
1051
1052   /* clean up */
1053   gst_object_unref (b1);
1054 }
1055
1056 GST_END_TEST;
1057
1058
1059 static Suite *
1060 gst_ghost_pad_suite (void)
1061 {
1062   Suite *s = suite_create ("GstGhostPad");
1063
1064   TCase *tc_chain = tcase_create ("ghost pad tests");
1065
1066   suite_add_tcase (s, tc_chain);
1067   tcase_add_test (tc_chain, test_remove1);
1068   tcase_add_test (tc_chain, test_remove2);
1069   tcase_add_test (tc_chain, test_remove_target);
1070   tcase_add_test (tc_chain, test_link);
1071   tcase_add_test (tc_chain, test_ghost_pads);
1072   tcase_add_test (tc_chain, test_ghost_pads_bin);
1073   tcase_add_test (tc_chain, test_ghost_pads_notarget);
1074   tcase_add_test (tc_chain, test_ghost_pads_block);
1075   tcase_add_test (tc_chain, test_ghost_pads_probes);
1076   tcase_add_test (tc_chain, test_ghost_pads_new_from_template);
1077   tcase_add_test (tc_chain, test_ghost_pads_new_no_target_from_template);
1078   tcase_add_test (tc_chain, test_ghost_pads_forward_setcaps);
1079   tcase_add_test (tc_chain, test_ghost_pads_sink_link_unlink);
1080   tcase_add_test (tc_chain, test_ghost_pads_src_link_unlink);
1081   tcase_add_test (tc_chain, test_ghost_pads_change_when_linked);
1082
1083   return s;
1084 }
1085
1086 GST_CHECK_MAIN (gst_ghost_pad);