ghostpad: API: Expose gst_proxy_pad_get_internal()
[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);
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 void
482 block_callback (GstPad * pad, gboolean blocked, gpointer user_data)
483 {
484   BlockData *block_data = (BlockData *) user_data;
485
486   g_mutex_lock (block_data->mutex);
487   GST_DEBUG ("blocked\n");
488   g_cond_signal (block_data->cond);
489   g_mutex_unlock (block_data->mutex);
490 }
491
492 GST_START_TEST (test_ghost_pads_block)
493 {
494   GstBin *pipeline;
495   GstBin *srcbin;
496   GstElement *src;
497   GstPad *srcpad;
498   GstPad *srcghost;
499   BlockData block_data;
500
501   pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
502
503   srcbin = GST_BIN (gst_bin_new ("srcbin"));
504   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
505
506   src = gst_element_factory_make ("fakesrc", "src");
507   gst_bin_add (srcbin, src);
508   srcpad = gst_element_get_static_pad (src, "src");
509   srcghost = gst_ghost_pad_new ("src", srcpad);
510   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
511   gst_object_unref (srcpad);
512
513   block_data.mutex = g_mutex_new ();
514   block_data.cond = g_cond_new ();
515
516   g_mutex_lock (block_data.mutex);
517   gst_pad_set_blocked_async (srcghost, TRUE, block_callback, &block_data);
518   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
519   /* and wait now */
520   g_cond_wait (block_data.cond, block_data.mutex);
521   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
522   g_mutex_unlock (block_data.mutex);
523
524   g_mutex_free (block_data.mutex);
525   g_cond_free (block_data.cond);
526
527   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
528   gst_object_unref (pipeline);
529 }
530
531 GST_END_TEST;
532
533 GST_START_TEST (test_ghost_pads_probes)
534 {
535   GstBin *pipeline;
536   GstBin *srcbin;
537   GstElement *src;
538   GstPad *srcpad;
539   GstPad *srcghost;
540   BlockData block_data;
541
542   pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
543
544   srcbin = GST_BIN (gst_bin_new ("srcbin"));
545   gst_bin_add (pipeline, GST_ELEMENT (srcbin));
546
547   src = gst_element_factory_make ("fakesrc", "src");
548   gst_bin_add (srcbin, src);
549   srcpad = gst_element_get_static_pad (src, "src");
550   srcghost = gst_ghost_pad_new ("src", srcpad);
551   gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
552   gst_object_unref (srcpad);
553
554   block_data.mutex = g_mutex_new ();
555   block_data.cond = g_cond_new ();
556
557   g_mutex_lock (block_data.mutex);
558   gst_pad_set_blocked_async (srcghost, TRUE, block_callback, &block_data);
559   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
560   /* and wait now */
561   g_cond_wait (block_data.cond, block_data.mutex);
562   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
563   g_mutex_unlock (block_data.mutex);
564
565   g_mutex_free (block_data.mutex);
566   g_cond_free (block_data.cond);
567
568   ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
569   gst_object_unref (pipeline);
570 }
571
572 GST_END_TEST;
573
574 GST_START_TEST (test_ghost_pads_new_from_template)
575 {
576   GstPad *sinkpad, *ghostpad;
577   GstPadTemplate *padtempl, *ghosttempl;
578   GstCaps *padcaps, *ghostcaps, *newcaps;
579   GstCaps *copypadcaps;
580
581   padcaps = gst_caps_from_string ("some/caps");
582   fail_unless (padcaps != NULL);
583   ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
584   fail_unless (ghostcaps != NULL);
585
586   copypadcaps = gst_caps_copy (padcaps);
587   padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
588       GST_PAD_ALWAYS, copypadcaps);
589   fail_unless (padtempl != NULL);
590   ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
591       GST_PAD_ALWAYS, ghostcaps);
592
593   sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
594   fail_unless (sinkpad != NULL);
595
596   ghostpad = gst_ghost_pad_new_from_template ("ghostpad", sinkpad, ghosttempl);
597   fail_unless (ghostpad != NULL);
598
599   /* check template is properly set */
600   fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
601
602   /* check ghostpad caps are from the sinkpad */
603   newcaps = gst_pad_get_caps (ghostpad);
604   fail_unless (newcaps != NULL);
605   fail_unless (gst_caps_is_equal (newcaps, padcaps));
606   gst_caps_unref (newcaps);
607   gst_caps_unref (padcaps);
608
609   gst_object_unref (sinkpad);
610   gst_object_unref (ghostpad);
611
612   gst_object_unref (padtempl);
613   gst_object_unref (ghosttempl);
614 }
615
616 GST_END_TEST;
617
618 GST_START_TEST (test_ghost_pads_new_no_target_from_template)
619 {
620   GstPad *sinkpad, *ghostpad;
621   GstPadTemplate *padtempl, *ghosttempl;
622   GstCaps *padcaps, *ghostcaps, *newcaps;
623   GstCaps *copypadcaps, *copyghostcaps;
624
625   padcaps = gst_caps_from_string ("some/caps");
626   fail_unless (padcaps != NULL);
627   ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
628   fail_unless (ghostcaps != NULL);
629
630   copypadcaps = gst_caps_copy (padcaps);
631   copyghostcaps = gst_caps_copy (ghostcaps);
632
633   padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
634       GST_PAD_ALWAYS, copypadcaps);
635   fail_unless (padtempl != NULL);
636   ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
637       GST_PAD_ALWAYS, copyghostcaps);
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);
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);
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
692   templ_caps = gst_caps_from_string ("muh; meh");
693   sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
694       GST_PAD_ALWAYS, templ_caps);
695
696   src = gst_pad_new_from_template (src_template, "src");
697   sink = gst_pad_new_from_template (sink_template, "sink");
698
699   /* ghost source pad, setting caps on the source influences the caps of the
700    * ghostpad. */
701   ghost = gst_ghost_pad_new ("ghostsrc", src);
702   g_signal_connect (ghost, "notify::caps",
703       G_CALLBACK (ghost_notify_caps), &notify_counter);
704   fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
705
706   caps1 = gst_caps_from_string ("meh");
707   fail_unless (gst_pad_set_caps (src, caps1));
708   caps2 = GST_PAD_CAPS (ghost);
709   fail_unless (gst_caps_is_equal (caps1, caps2));
710   fail_unless_equals_int (notify_counter, 1);
711
712   gst_object_unref (ghost);
713   gst_caps_unref (caps1);
714
715   fail_unless (gst_pad_set_caps (src, NULL));
716
717   /* source 2, setting the caps on the ghostpad does not influence the caps of
718    * the target */
719   notify_counter = 0;
720   ghost = gst_ghost_pad_new ("ghostsrc", src);
721   g_signal_connect (ghost, "notify::caps",
722       G_CALLBACK (ghost_notify_caps), &notify_counter);
723   fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
724
725   caps1 = gst_caps_from_string ("meh");
726   fail_unless (gst_pad_set_caps (ghost, caps1));
727   caps2 = GST_PAD_CAPS (src);
728   fail_unless (caps2 == NULL);
729   fail_unless_equals_int (notify_counter, 1);
730
731   gst_object_unref (ghost);
732   gst_caps_unref (caps1);
733
734
735   /* ghost sink pad. Setting caps on the ghostpad will also set those caps on
736    * the target pad. */
737   notify_counter = 0;
738   ghost = gst_ghost_pad_new ("ghostsink", sink);
739   g_signal_connect (ghost, "notify::caps",
740       G_CALLBACK (ghost_notify_caps), &notify_counter);
741   fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
742
743   caps1 = gst_caps_from_string ("muh");
744   fail_unless (gst_pad_set_caps (ghost, caps1));
745   caps2 = GST_PAD_CAPS (sink);
746   fail_unless (gst_caps_is_equal (caps1, caps2));
747   fail_unless_equals_int (notify_counter, 1);
748
749   gst_object_unref (ghost);
750   gst_caps_unref (caps1);
751
752   /* sink pad 2, setting caps just on the target pad should not influence the caps
753    * on the ghostpad. */
754   notify_counter = 0;
755   ghost = gst_ghost_pad_new ("ghostsink", sink);
756   g_signal_connect (ghost, "notify::caps",
757       G_CALLBACK (ghost_notify_caps), &notify_counter);
758   fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
759
760   caps1 = gst_caps_from_string ("muh");
761   fail_unless (gst_pad_set_caps (sink, caps1));
762   caps2 = GST_PAD_CAPS (ghost);
763   fail_unless (caps2 == NULL);
764   fail_unless_equals_int (notify_counter, 0);
765
766   gst_object_unref (ghost);
767   gst_caps_unref (caps1);
768
769   gst_object_unref (src);
770   gst_object_unref (sink);
771   gst_object_unref (src_template);
772   gst_object_unref (sink_template);
773 }
774
775 GST_END_TEST;
776
777 static gint linked_count1;
778 static gint unlinked_count1;
779 static gint linked_count2;
780 static gint unlinked_count2;
781
782 static GstPadLinkReturn
783 pad_linked1 (GstPad * pad, GstPad * peer)
784 {
785   linked_count1++;
786
787   return GST_PAD_LINK_OK;
788 }
789
790 static void
791 pad_unlinked1 (GstPad * pad)
792 {
793   unlinked_count1++;
794 }
795
796 static GstPadLinkReturn
797 pad_linked2 (GstPad * pad, GstPad * peer)
798 {
799   linked_count2++;
800
801   return GST_PAD_LINK_OK;
802 }
803
804 static void
805 pad_unlinked2 (GstPad * pad)
806 {
807   unlinked_count2++;
808 }
809
810 GST_START_TEST (test_ghost_pads_sink_link_unlink)
811 {
812   GstCaps *padcaps;
813   GstPad *srcpad, *sinkpad, *ghostpad;
814   GstPadTemplate *srctempl, *sinktempl;
815   GstPadLinkReturn ret;
816   gboolean res;
817
818   padcaps = gst_caps_from_string ("some/caps");
819   fail_unless (padcaps != NULL);
820   srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
821       GST_PAD_ALWAYS, padcaps);
822
823   padcaps = gst_caps_from_string ("some/caps");
824   fail_unless (padcaps != NULL);
825   sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
826       GST_PAD_ALWAYS, padcaps);
827
828   srcpad = gst_pad_new_from_template (srctempl, "src");
829   fail_unless (srcpad != NULL);
830   sinkpad = gst_pad_new_from_template (sinktempl, "sink");
831   fail_unless (sinkpad != NULL);
832
833   /* set up link/unlink functions for the pad */
834   linked_count1 = unlinked_count1 = 0;
835   gst_pad_set_link_function (sinkpad, pad_linked1);
836   gst_pad_set_unlink_function (sinkpad, pad_unlinked1);
837   linked_count2 = unlinked_count2 = 0;
838   gst_pad_set_link_function (srcpad, pad_linked2);
839   gst_pad_set_unlink_function (srcpad, pad_unlinked2);
840
841   /* this should trigger a link from the internal pad to the sinkpad */
842   ghostpad = gst_ghost_pad_new ("ghostpad", sinkpad);
843   fail_unless (ghostpad != NULL);
844   fail_unless (linked_count1 == 1);
845   fail_unless (unlinked_count1 == 0);
846   fail_unless (linked_count2 == 0);
847   fail_unless (unlinked_count2 == 0);
848
849   /* this should not trigger anything because we are not directly
850    * linking/unlinking the sink pad. */
851   ret = gst_pad_link (srcpad, ghostpad);
852   fail_unless (ret == GST_PAD_LINK_OK);
853   fail_unless (linked_count1 == 1);
854   fail_unless (unlinked_count1 == 0);
855   fail_unless (linked_count2 == 1);
856   fail_unless (unlinked_count2 == 0);
857
858   res = gst_pad_unlink (srcpad, ghostpad);
859   fail_unless (res == TRUE);
860   fail_unless (linked_count1 == 1);
861   fail_unless (unlinked_count1 == 0);
862   fail_unless (linked_count2 == 1);
863   fail_unless (unlinked_count2 == 1);
864
865   /* this should trigger the unlink */
866   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
867   fail_unless (res == TRUE);
868   fail_unless (linked_count1 == 1);
869   fail_unless (unlinked_count1 == 1);
870   fail_unless (linked_count2 == 1);
871   fail_unless (unlinked_count2 == 1);
872
873   gst_object_unref (ghostpad);
874   gst_object_unref (sinkpad);
875   gst_object_unref (srcpad);
876   gst_object_unref (srctempl);
877   gst_object_unref (sinktempl);
878 }
879
880 GST_END_TEST;
881
882 GST_START_TEST (test_ghost_pads_src_link_unlink)
883 {
884   GstCaps *padcaps;
885   GstPad *srcpad, *sinkpad, *ghostpad, *dummy;
886   GstPadTemplate *srctempl, *sinktempl;
887   GstPadLinkReturn ret;
888   gboolean res;
889
890   padcaps = gst_caps_from_string ("some/caps");
891   fail_unless (padcaps != NULL);
892   srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
893       GST_PAD_ALWAYS, padcaps);
894
895   padcaps = gst_caps_from_string ("some/caps");
896   fail_unless (padcaps != NULL);
897   sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
898       GST_PAD_ALWAYS, padcaps);
899
900   srcpad = gst_pad_new_from_template (srctempl, "src");
901   fail_unless (srcpad != NULL);
902   sinkpad = gst_pad_new_from_template (sinktempl, "sink");
903   fail_unless (sinkpad != NULL);
904
905   /* set up link/unlink functions for the pad */
906   linked_count1 = unlinked_count1 = 0;
907   gst_pad_set_link_function (srcpad, pad_linked1);
908   gst_pad_set_unlink_function (srcpad, pad_unlinked1);
909   linked_count2 = unlinked_count2 = 0;
910   gst_pad_set_link_function (sinkpad, pad_linked2);
911   gst_pad_set_unlink_function (sinkpad, pad_unlinked2);
912
913   /* this should trigger a link from the internal pad to the srcpad */
914   ghostpad = gst_ghost_pad_new ("ghostpad", srcpad);
915   fail_unless (ghostpad != NULL);
916   fail_unless (linked_count1 == 1);
917   fail_unless (unlinked_count1 == 0);
918   fail_unless (linked_count2 == 0);
919   fail_unless (unlinked_count2 == 0);
920
921   /* this should fail with a critial */
922   ASSERT_CRITICAL (dummy = gst_ghost_pad_new ("ghostpad", srcpad));
923   fail_unless (dummy == NULL);
924   fail_unless (linked_count1 == 1);
925   fail_unless (unlinked_count1 == 0);
926   fail_unless (linked_count2 == 0);
927   fail_unless (unlinked_count2 == 0);
928
929   /* this should not trigger anything because we are not directly
930    * linking/unlinking the src pad. */
931   ret = gst_pad_link (ghostpad, sinkpad);
932   fail_unless (ret == GST_PAD_LINK_OK);
933   fail_unless (linked_count1 == 1);
934   fail_unless (unlinked_count1 == 0);
935   fail_unless (linked_count2 == 1);
936   fail_unless (unlinked_count2 == 0);
937
938   /* this link should fail because we are already linked. Let's make sure the
939    * link functions are not called */
940   ret = gst_pad_link (ghostpad, sinkpad);
941   fail_unless (ret == GST_PAD_LINK_WAS_LINKED);
942   fail_unless (linked_count1 == 1);
943   fail_unless (unlinked_count1 == 0);
944   fail_unless (linked_count2 == 1);
945   fail_unless (unlinked_count2 == 0);
946
947   res = gst_pad_unlink (ghostpad, sinkpad);
948   fail_unless (res == TRUE);
949   fail_unless (linked_count1 == 1);
950   fail_unless (unlinked_count1 == 0);
951   fail_unless (linked_count2 == 1);
952   fail_unless (unlinked_count2 == 1);
953
954   res = gst_pad_unlink (ghostpad, sinkpad);
955   fail_unless (res == FALSE);
956   fail_unless (linked_count1 == 1);
957   fail_unless (unlinked_count1 == 0);
958   fail_unless (linked_count2 == 1);
959   fail_unless (unlinked_count2 == 1);
960
961   /* this should trigger the unlink function */
962   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
963   fail_unless (res == TRUE);
964   fail_unless (linked_count1 == 1);
965   fail_unless (unlinked_count1 == 1);
966   fail_unless (linked_count2 == 1);
967   fail_unless (unlinked_count2 == 1);
968
969   /* and this the link function again */
970   res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), srcpad);
971   fail_unless (res == TRUE);
972   fail_unless (linked_count1 == 2);
973   fail_unless (unlinked_count1 == 1);
974   fail_unless (linked_count2 == 1);
975   fail_unless (unlinked_count2 == 1);
976
977   gst_object_unref (ghostpad);
978   gst_object_unref (sinkpad);
979   gst_object_unref (srcpad);
980   gst_object_unref (srctempl);
981   gst_object_unref (sinktempl);
982 }
983
984 GST_END_TEST;
985
986 GST_START_TEST (test_ghost_pads_change_when_linked)
987 {
988   GstElement *b1, *b2, *src, *fmt, *sink1, *sink2;
989   GstPad *sinkpad, *ghostpad;
990   GstCaps *caps;
991
992   b1 = gst_element_factory_make ("pipeline", NULL);
993   b2 = gst_element_factory_make ("bin", NULL);
994   src = gst_element_factory_make ("fakesrc", NULL);
995   fmt = gst_element_factory_make ("capsfilter", NULL);
996   sink1 = gst_element_factory_make ("fakesink", NULL);
997   sink2 = gst_element_factory_make ("fakesink", NULL);
998
999   gst_bin_add (GST_BIN (b2), sink1);
1000   gst_bin_add (GST_BIN (b2), sink2);
1001   gst_bin_add (GST_BIN (b1), src);
1002   gst_bin_add (GST_BIN (b1), fmt);
1003   gst_bin_add (GST_BIN (b1), b2);
1004
1005   caps = gst_caps_from_string ("audio/x-raw-int, width=16, channels=1");
1006   g_object_set (fmt, "caps", caps, NULL);
1007   gst_caps_unref (caps);
1008
1009   /* create the ghostpad as a sink-pad for bin 2 */
1010   ghostpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
1011   gst_element_add_pad (b2, ghostpad);
1012
1013   sinkpad = gst_element_get_static_pad (sink1, "sink");
1014   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1015   gst_object_unref (sinkpad);
1016
1017   fail_unless (gst_element_link_many (src, fmt, b2, NULL));
1018
1019   /* set different target after ghostpad is linked */
1020   sinkpad = gst_element_get_static_pad (sink2, "sink");
1021   fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1022   gst_object_unref (sinkpad);
1023
1024   /* clean up */
1025   gst_object_unref (b1);
1026 }
1027
1028 GST_END_TEST;
1029
1030
1031 static Suite *
1032 gst_ghost_pad_suite (void)
1033 {
1034   Suite *s = suite_create ("GstGhostPad");
1035
1036   TCase *tc_chain = tcase_create ("ghost pad tests");
1037
1038   suite_add_tcase (s, tc_chain);
1039   tcase_add_test (tc_chain, test_remove1);
1040   tcase_add_test (tc_chain, test_remove2);
1041   tcase_add_test (tc_chain, test_remove_target);
1042   tcase_add_test (tc_chain, test_link);
1043   tcase_add_test (tc_chain, test_ghost_pads);
1044   tcase_add_test (tc_chain, test_ghost_pads_bin);
1045   tcase_add_test (tc_chain, test_ghost_pads_notarget);
1046   tcase_add_test (tc_chain, test_ghost_pads_block);
1047   tcase_add_test (tc_chain, test_ghost_pads_probes);
1048   tcase_add_test (tc_chain, test_ghost_pads_new_from_template);
1049   tcase_add_test (tc_chain, test_ghost_pads_new_no_target_from_template);
1050   tcase_add_test (tc_chain, test_ghost_pads_forward_setcaps);
1051   tcase_add_test (tc_chain, test_ghost_pads_sink_link_unlink);
1052   tcase_add_test (tc_chain, test_ghost_pads_src_link_unlink);
1053   tcase_add_test (tc_chain, test_ghost_pads_change_when_linked);
1054
1055   return s;
1056 }
1057
1058 GST_CHECK_MAIN (gst_ghost_pad);