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