1 /* GstHarness - A test-harness for GStreamer testing
3 * Copyright (C) 2012-2015 Pexip <pexip.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
23 * @short_description: A test-harness for writing GStreamer unit tests
24 * @see_also: #GstTestClock,\
26 * #GstHarness is ment to make writing unit test for GStreamer much easier.
27 * It can be though of as a way of treating a #GstElement as a black box,
28 * deterministially feeding it data, and controlling what data it outputs.
30 * The basic structure of #GstHarness is two "floating" #GstPads, that connects
31 * to the harnessed #GstElement src and sink #GstPads like so:
34 * __________________________
35 * _____ | _____ _____ | _____
37 * | src |--+-| sink| Element | src |-+--| sink|
38 * |_____| | |_____| |_____| | |_____|
39 * |__________________________|
43 * With this, you can now simulate any environment the #GstElement might find
44 * itself in. By specifying the #GstCaps of the harness #GstPads, using
45 * functions like gst_harness_set_src_caps or gst_harness_set_sink_caps_str,
46 * you can test how the #GstElement interacts with different capssets.
48 * Your harnessed #GstElement can of course also be a bin, and using
49 * gst_harness_new_parse supporting standard gst-launch syntax, you can
50 * easily test a whole pipeline instead of just one element.
52 * You can then go on to push #GstBuffers and #GstEvents on to the srcpad,
53 * using functions like gst_harness_push and gst_harness_push_event, and
54 * then pull them out to examine them with gst_harness_pull and
55 * gst_harness_pull_event.
58 * <title>A simple buffer-in buffer-out example</title>
59 * <programlisting language="c">
60 * #include <gst/gst.h>
61 * #include <gst/check/gstharness.h>
66 * // attach the harness to the src and sink pad of GstQueue
67 * h = gst_harness_new ("queue");
69 * // we must specify a caps before pushing buffers
70 * gst_harness_set_src_caps_str (h, "mycaps");
72 * // create a buffer of size 42
73 * in_buf = gst_harness_create_buffer (h, 42);
75 * // push the buffer into the queue
76 * gst_harness_push (h, in_buf);
78 * // pull the buffer from the queue
79 * out_buf = gst_harness_pull (h);
81 * // validate the buffer in is the same as buffer out
82 * fail_unless (in_buf == out_buf);
85 * gst_buffer_unref (out_buf);
86 * gst_harness_teardown (h);
91 * Another main feature of the #GstHarness is its integration with the
92 * #GstTestClock. Operating the #GstTestClock can be very challenging, but
93 * #GstHarness simplifies some of the most desired actions a lot, like wanting
94 * to manually advance the clock while at the same time releasing a #GstClockID
95 * that is waiting, with functions like gst_harness_crank_single_clock_wait.
97 * #GstHarness also supports sub-harnesses, as a way of generating and
98 * validating data. A sub-harness is another #GstHarness that is managed by
99 * the "parent" harness, and can either be created by using the standard
100 * gst_harness_new type functions directly on the (GstHarness *)->src_harness,
101 * or using the much more convenient gst_harness_add_src or
102 * gst_harness_add_sink_parse. If you have a decoder-element you want to test,
103 * (like vp8dec) it can be very useful to add a src-harness with both a
104 * src-element (videotestsrc) and an encoder (vp8enc) to feed the decoder data
105 * with different configurations, by simply doing:
108 * <programlisting language="c">
109 * GstHarness * h = gst_harness_new (h, "vp8dec");
110 * gst_harness_add_src_parse (h, "videotestsrc is-live=1 ! vp8enc", TRUE);
114 * and then feeding it data with:
117 * <programlisting language="c">
118 * gst_harness_push_from_src (h);
127 /* we have code with side effects in asserts, so make sure they are active */
128 #ifdef G_DISABLE_ASSERT
129 #error "GstHarness must be compiled with G_DISABLE_ASSERT undefined"
132 #include "gstharness.h"
138 static void gst_harness_stress_free (GstHarnessThread * t);
140 #define HARNESS_KEY "harness"
141 #define HARNESS_REF "harness-ref"
143 static GstStaticPadTemplate hsrctemplate = GST_STATIC_PAD_TEMPLATE ("src",
146 GST_STATIC_CAPS_ANY);
147 static GstStaticPadTemplate hsinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
150 GST_STATIC_CAPS_ANY);
152 struct _GstHarnessPrivate
154 gchar *element_sinkpad_name;
155 gchar *element_srcpad_name;
159 GstPad *sink_forward_pad;
161 volatile gint recv_buffers;
162 volatile gint recv_events;
163 volatile gint recv_upstream_events;
165 GAsyncQueue *buffer_queue;
166 GAsyncQueue *src_event_queue;
167 GAsyncQueue *sink_event_queue;
169 GstClockTime latency_min;
170 GstClockTime latency_max;
171 gboolean has_clock_wait;
172 gboolean drop_buffers;
173 GstClockTime last_push_ts;
176 GstAllocator *allocator;
177 GstAllocationParams allocation_params;
178 GstAllocator *propose_allocator;
179 GstAllocationParams propose_allocation_params;
181 gboolean blocking_push_mode;
182 GCond blocking_push_cond;
183 GMutex blocking_push_mutex;
189 gst_harness_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
191 GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
192 GstHarnessPrivate *priv = h->priv;
194 g_assert (h != NULL);
195 g_mutex_lock (&priv->blocking_push_mutex);
196 g_atomic_int_inc (&priv->recv_buffers);
198 if (priv->drop_buffers)
199 gst_buffer_unref (buffer);
201 g_async_queue_push (priv->buffer_queue, buffer);
203 if (priv->blocking_push_mode) {
204 g_cond_wait (&priv->blocking_push_cond, &priv->blocking_push_mutex);
206 g_mutex_unlock (&priv->blocking_push_mutex);
212 gst_harness_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
214 GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
215 GstHarnessPrivate *priv = h->priv;
217 g_assert (h != NULL);
218 g_atomic_int_inc (&priv->recv_upstream_events);
219 g_async_queue_push (priv->src_event_queue, event);
224 gst_harness_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
226 GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
227 GstHarnessPrivate *priv = h->priv;
230 g_assert (h != NULL);
232 g_atomic_int_inc (&priv->recv_events);
234 switch (GST_EVENT_TYPE (event)) {
235 case GST_EVENT_STREAM_START:
237 case GST_EVENT_SEGMENT:
245 if (forward && priv->sink_forward_pad) {
246 gst_pad_push_event (priv->sink_forward_pad, event);
248 g_async_queue_push (priv->sink_event_queue, event);
255 gst_harness_decide_allocation (GstHarness * h, GstCaps * caps)
257 GstHarnessPrivate *priv = h->priv;
259 GstAllocator *allocator;
260 GstAllocationParams params;
261 GstBufferPool *pool = NULL;
262 guint size, min, max;
264 query = gst_query_new_allocation (caps, FALSE);
265 gst_pad_peer_query (h->srcpad, query);
267 if (gst_query_get_n_allocation_params (query) > 0) {
268 gst_query_parse_nth_allocation_param (query, 0, &allocator, ¶ms);
271 gst_allocation_params_init (¶ms);
274 if (gst_query_get_n_allocation_pools (query) > 0) {
275 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
277 /* Most elements create their own pools if pool == NULL. Not sure if we
278 * want to do that in the harness since we may want to test the pool
279 * implementation of the elements. Not creating a pool will however ignore
280 * the returned size. */
282 pool = gst_buffer_pool_new ();
286 size = min = max = 0;
288 gst_query_unref (query);
291 GstStructure *config = gst_buffer_pool_get_config (pool);
292 gst_buffer_pool_config_set_params (config, caps, size, min, max);
293 gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
294 gst_buffer_pool_set_config (pool, config);
297 if (pool != priv->pool) {
298 if (priv->pool != NULL)
299 gst_buffer_pool_set_active (priv->pool, FALSE);
301 gst_buffer_pool_set_active (pool, TRUE);
304 priv->allocation_params = params;
306 gst_object_unref (priv->allocator);
307 priv->allocator = allocator;
309 gst_object_unref (priv->pool);
314 gst_harness_negotiate (GstHarness * h)
318 caps = gst_pad_get_current_caps (h->srcpad);
320 gst_harness_decide_allocation (h, caps);
321 gst_caps_unref (caps);
323 GST_FIXME_OBJECT (h, "Cannot negotiate allocation because caps is not set");
328 gst_harness_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
330 GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
331 GstHarnessPrivate *priv = h->priv;
333 g_assert (h != NULL);
335 // FIXME: forward all queries?
337 switch (GST_QUERY_TYPE (query)) {
338 case GST_QUERY_LATENCY:
339 gst_query_set_latency (query, TRUE, priv->latency_min, priv->latency_max);
343 GstCaps *caps, *filter = NULL;
347 sink_caps ? gst_caps_ref (priv->sink_caps) : gst_caps_new_any ();
349 gst_query_parse_caps (query, &filter);
350 if (filter != NULL) {
351 gst_caps_take (&caps,
352 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST));
355 gst_query_set_caps_result (query, caps);
356 gst_caps_unref (caps);
359 case GST_QUERY_ALLOCATION:
361 if (priv->sink_forward_pad != NULL) {
362 GstPad *peer = gst_pad_get_peer (priv->sink_forward_pad);
363 g_assert (peer != NULL);
364 res = gst_pad_query (peer, query);
365 gst_object_unref (peer);
370 gst_query_parse_allocation (query, &caps, &need_pool);
372 /* FIXME: Can this be removed? */
373 g_assert_cmpuint (0, ==, gst_query_get_n_allocation_params (query));
374 gst_query_add_allocation_param (query,
375 priv->propose_allocator, &priv->propose_allocation_params);
377 GST_DEBUG_OBJECT (pad, "proposing allocation %" GST_PTR_FORMAT,
378 priv->propose_allocator);
383 res = gst_pad_query_default (pad, parent, query);
390 gst_harness_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
392 GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
393 GstHarnessPrivate *priv = h->priv;
395 g_assert (h != NULL);
397 switch (GST_QUERY_TYPE (query)) {
398 case GST_QUERY_LATENCY:
399 gst_query_set_latency (query, TRUE, priv->latency_min, priv->latency_max);
403 GstCaps *caps, *filter = NULL;
406 priv->src_caps ? gst_caps_ref (priv->src_caps) : gst_caps_new_any ();
408 gst_query_parse_caps (query, &filter);
409 if (filter != NULL) {
410 gst_caps_take (&caps,
411 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST));
414 gst_query_set_caps_result (query, caps);
415 gst_caps_unref (caps);
419 res = gst_pad_query_default (pad, parent, query);
425 gst_harness_element_ref (GstHarness * h)
427 guint *data = g_object_get_data (G_OBJECT (h->element), HARNESS_REF);
429 data = g_new0 (guint, 1);
431 g_object_set_data_full (G_OBJECT (h->element), HARNESS_REF, data, g_free);
438 gst_harness_element_unref (GstHarness * h)
440 guint *data = g_object_get_data (G_OBJECT (h->element), HARNESS_REF);
441 g_assert (data != NULL);
447 gst_harness_link_element_srcpad (GstHarness * h,
448 const gchar * element_srcpad_name)
450 GstHarnessPrivate *priv = h->priv;
451 GstPad *srcpad = gst_element_get_static_pad (h->element,
452 element_srcpad_name);
454 srcpad = gst_element_get_request_pad (h->element, element_srcpad_name);
456 g_assert_cmpint (gst_pad_link (srcpad, h->sinkpad), ==, GST_PAD_LINK_OK);
457 g_free (priv->element_srcpad_name);
458 priv->element_srcpad_name = gst_pad_get_name (srcpad);
460 gst_object_unref (srcpad);
464 gst_harness_link_element_sinkpad (GstHarness * h,
465 const gchar * element_sinkpad_name)
467 GstHarnessPrivate *priv = h->priv;
468 GstPad *sinkpad = gst_element_get_static_pad (h->element,
469 element_sinkpad_name);
471 sinkpad = gst_element_get_request_pad (h->element, element_sinkpad_name);
473 g_assert_cmpint (gst_pad_link (h->srcpad, sinkpad), ==, GST_PAD_LINK_OK);
474 g_free (priv->element_sinkpad_name);
475 priv->element_sinkpad_name = gst_pad_get_name (sinkpad);
477 gst_object_unref (sinkpad);
481 gst_harness_setup_src_pad (GstHarness * h,
482 GstStaticPadTemplate * src_tmpl, const gchar * element_sinkpad_name)
484 GstHarnessPrivate *priv = h->priv;
486 g_assert (h->srcpad == NULL);
488 priv->src_event_queue =
489 g_async_queue_new_full ((GDestroyNotify) gst_event_unref);
492 h->srcpad = gst_pad_new_from_static_template (src_tmpl, "src");
493 g_assert (h->srcpad);
494 g_object_set_data (G_OBJECT (h->srcpad), HARNESS_KEY, h);
496 gst_pad_set_query_function (h->srcpad, gst_harness_src_query);
497 gst_pad_set_event_function (h->srcpad, gst_harness_src_event);
499 gst_pad_set_active (h->srcpad, TRUE);
501 if (element_sinkpad_name)
502 gst_harness_link_element_sinkpad (h, element_sinkpad_name);
506 gst_harness_setup_sink_pad (GstHarness * h,
507 GstStaticPadTemplate * sink_tmpl, const gchar * element_srcpad_name)
509 GstHarnessPrivate *priv = h->priv;
510 g_assert (sink_tmpl);
511 g_assert (h->sinkpad == NULL);
513 priv->buffer_queue = g_async_queue_new_full (
514 (GDestroyNotify) gst_buffer_unref);
515 priv->sink_event_queue = g_async_queue_new_full (
516 (GDestroyNotify) gst_event_unref);
519 h->sinkpad = gst_pad_new_from_static_template (sink_tmpl, "sink");
520 g_assert (h->sinkpad);
521 g_object_set_data (G_OBJECT (h->sinkpad), HARNESS_KEY, h);
523 gst_pad_set_chain_function (h->sinkpad, gst_harness_chain);
524 gst_pad_set_query_function (h->sinkpad, gst_harness_sink_query);
525 gst_pad_set_event_function (h->sinkpad, gst_harness_sink_event);
527 gst_pad_set_active (h->sinkpad, TRUE);
529 if (element_srcpad_name)
530 gst_harness_link_element_srcpad (h, element_srcpad_name);
534 check_element_type (GstElement * element, gboolean * has_sinkpad,
535 gboolean * has_srcpad)
537 GstElementFactory *factory;
538 const GList *tmpl_list;
540 *has_srcpad = element->numsrcpads > 0;
541 *has_sinkpad = element->numsinkpads > 0;
543 factory = gst_element_get_factory (element);
544 tmpl_list = gst_element_factory_get_static_pad_templates (factory);
547 GstStaticPadTemplate *pad_tmpl = (GstStaticPadTemplate *) tmpl_list->data;
548 tmpl_list = g_list_next (tmpl_list);
549 if (pad_tmpl->direction == GST_PAD_SRC)
551 if (pad_tmpl->direction == GST_PAD_SINK)
552 *has_sinkpad |= TRUE;
557 turn_async_and_sync_off (GstElement * element)
559 GObjectClass *class = G_OBJECT_GET_CLASS (element);
560 if (g_object_class_find_property (class, "async"))
561 g_object_set (element, "async", FALSE, NULL);
562 if (g_object_class_find_property (class, "sync"))
563 g_object_set (element, "sync", FALSE, NULL);
567 gst_pad_is_request_pad (GstPad * pad)
569 GstPadTemplate *temp;
574 temp = gst_pad_get_pad_template (pad);
577 is_request = GST_PAD_TEMPLATE_PRESENCE (temp) == GST_PAD_REQUEST;
578 gst_object_unref (temp);
583 * gst_harness_new_full: (skip)
584 * @element: a #GstElement to attach the harness to (transfer none)
585 * @hsrc: (allow-none): a #GstStaticPadTemplate describing the harness srcpad.
586 * %NULL will not create a harness srcpad.
587 * @element_sinkpad_name: (allow-none): a #gchar with the name of the element
588 * sinkpad that is then linked to the harness srcpad. Can be a static or request
589 * or a sometimes pad that has been added. %NULL will not get/request a sinkpad
590 * from the element. (Like if the element is a src.)
591 * @hsink: (allow-none): a #GstStaticPadTemplate describing the harness sinkpad.
592 * %NULL will not create a harness sinkpad.
593 * @element_srcpad_name: (allow-none): a #gchar with the name of the element
594 * srcpad that is then linked to the harness sinkpad, similar to the
595 * @element_sinkpad_name.
597 * Creates a new harness.
601 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
607 gst_harness_new_full (GstElement * element,
608 GstStaticPadTemplate * hsrc, const gchar * element_sinkpad_name,
609 GstStaticPadTemplate * hsink, const gchar * element_srcpad_name)
612 GstHarnessPrivate *priv;
613 gboolean has_sinkpad, has_srcpad;
615 g_return_val_if_fail (element != NULL, NULL);
617 h = g_new0 (GstHarness, 1);
618 g_assert (h != NULL);
619 h->priv = g_new0 (GstHarnessPrivate, 1);
622 GST_DEBUG_OBJECT (h, "about to create new harness %p", h);
623 h->element = gst_object_ref (element);
624 priv->last_push_ts = GST_CLOCK_TIME_NONE;
625 priv->latency_min = 0;
626 priv->latency_max = GST_CLOCK_TIME_NONE;
627 priv->drop_buffers = FALSE;
629 priv->propose_allocator = NULL;
630 gst_allocation_params_init (&priv->propose_allocation_params);
632 g_mutex_init (&priv->blocking_push_mutex);
633 g_cond_init (&priv->blocking_push_cond);
635 check_element_type (element, &has_sinkpad, &has_srcpad);
637 /* setup the loose srcpad linked to the element sinkpad */
639 gst_harness_setup_src_pad (h, hsrc, element_sinkpad_name);
641 /* setup the loose sinkpad linked to the element srcpad */
643 gst_harness_setup_sink_pad (h, hsink, element_srcpad_name);
645 /* as a harness sink, we should not need sync and async */
646 if (has_sinkpad && !has_srcpad)
647 turn_async_and_sync_off (h->element);
649 if (h->srcpad != NULL) {
650 gchar *stream_id = g_strdup_printf ("%s-%p",
651 GST_OBJECT_NAME (h->element), h);
652 g_assert (gst_pad_push_event (h->srcpad,
653 gst_event_new_stream_start (stream_id)));
657 /* don't start sources, they start producing data! */
659 gst_harness_play (h);
661 gst_harness_element_ref (h);
663 GST_DEBUG_OBJECT (h, "created new harness %p "
664 "with element_srcpad_name (%p, %s, %s) and element_sinkpad_name (%p, %s, %s)",
665 h, h->srcpad, GST_DEBUG_PAD_NAME (h->srcpad),
666 h->sinkpad, GST_DEBUG_PAD_NAME (h->sinkpad));
668 priv->stress = g_ptr_array_new_with_free_func (
669 (GDestroyNotify) gst_harness_stress_free);
675 * gst_harness_new_with_element: (skip)
676 * @element: a #GstElement to attach the harness to (transfer none)
677 * @element_sinkpad_name: (allow-none): a #gchar with the name of the element
678 * sinkpad that is then linked to the harness srcpad. %NULL does not attach a
680 * @element_srcpad_name: (allow-none): a #gchar with the name of the element
681 * srcpad that is then linked to the harness sinkpad. %NULL does not attach a
684 * Creates a new harness. Works in the same way as gst_harness_new_full, only
685 * that generic padtemplates are used for the harness src and sinkpads, which
686 * will be sufficient in most usecases.
690 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
696 gst_harness_new_with_element (GstElement * element,
697 const gchar * element_sinkpad_name, const gchar * element_srcpad_name)
699 return gst_harness_new_full (element,
700 &hsrctemplate, element_sinkpad_name, &hsinktemplate, element_srcpad_name);
704 * gst_harness_new_with_padnames: (skip)
705 * @element_name: a #gchar describing the #GstElement name
706 * @element_sinkpad_name: (allow-none): a #gchar with the name of the element
707 * sinkpad that is then linked to the harness srcpad. %NULL does not attach a
709 * @element_srcpad_name: (allow-none): a #gchar with the name of the element
710 * srcpad that is then linked to the harness sinkpad. %NULL does not attach a
713 * Creates a new harness. Works in the same way as gst_harness_new_with_element,
714 * except you specify the factoryname of the #GstElement
718 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
724 gst_harness_new_with_padnames (const gchar * element_name,
725 const gchar * element_sinkpad_name, const gchar * element_srcpad_name)
728 GstElement *element = gst_element_factory_make (element_name, NULL);
729 g_assert (element != NULL);
731 h = gst_harness_new_with_element (element, element_sinkpad_name,
732 element_srcpad_name);
733 gst_object_unref (element);
738 * gst_harness_new_with_templates: (skip)
739 * @element_name: a #gchar describing the #GstElement name
740 * @hsrc: (allow-none): a #GstStaticPadTemplate describing the harness srcpad.
741 * %NULL will not create a harness srcpad.
742 * @hsink: (allow-none): a #GstStaticPadTemplate describing the harness sinkpad.
743 * %NULL will not create a harness sinkpad.
745 * Creates a new harness, like gst_harness_new_full, except it
746 * assumes the #GstElement sinkpad is named "sink" and srcpad is named "src"
750 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
756 gst_harness_new_with_templates (const gchar * element_name,
757 GstStaticPadTemplate * hsrc, GstStaticPadTemplate * hsink)
760 GstElement *element = gst_element_factory_make (element_name, NULL);
761 g_assert (element != NULL);
763 h = gst_harness_new_full (element, hsrc, "sink", hsink, "src");
764 gst_object_unref (element);
769 * gst_harness_new: (skip)
770 * @element_name: a #gchar describing the #GstElement name
772 * Creates a new harness. Works like gst_harness_new_with_padnames, except it
773 * assumes the #GstElement sinkpad is named "sink" and srcpad is named "src"
777 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
783 gst_harness_new (const gchar * element_name)
785 return gst_harness_new_with_padnames (element_name, "sink", "src");
789 * gst_harness_new_parse: (skip)
790 * @launchline: a #gchar describing a gst-launch type line
792 * Creates a new harness, parsing the @launchline and putting that in a #GstBin,
793 * and then attches the harness to the bin.
797 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
803 gst_harness_new_parse (const gchar * launchline)
810 gboolean done = FALSE;
812 g_return_val_if_fail (launchline != NULL, NULL);
814 desc = g_strdup_printf ("bin.( %s )", launchline);
816 (GstBin *) gst_parse_launch_full (desc, NULL, GST_PARSE_FLAG_NONE, NULL);
819 if (G_UNLIKELY (bin == NULL))
822 /* find pads and ghost them if necessary */
823 if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SRC)) != NULL) {
824 gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", pad));
825 gst_object_unref (pad);
827 if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SINK)) != NULL) {
828 gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", pad));
829 gst_object_unref (pad);
832 iter = gst_bin_iterate_sinks (bin);
834 GValue item = { 0, };
836 switch (gst_iterator_next (iter, &item)) {
837 case GST_ITERATOR_OK:
838 turn_async_and_sync_off (GST_ELEMENT (g_value_get_object (&item)));
839 g_value_reset (&item);
841 case GST_ITERATOR_DONE:
844 case GST_ITERATOR_RESYNC:
845 gst_iterator_resync (iter);
847 case GST_ITERATOR_ERROR:
848 gst_object_unref (bin);
849 gst_iterator_free (iter);
850 g_return_val_if_reached (NULL);
854 gst_iterator_free (iter);
856 h = gst_harness_new_full (GST_ELEMENT_CAST (bin),
857 &hsrctemplate, "sink", &hsinktemplate, "src");
858 gst_object_unref (bin);
863 * gst_harness_teardown:
866 * Tears down a @GstHarness, freeing all resources allocated using it.
873 gst_harness_teardown (GstHarness * h)
875 GstHarnessPrivate *priv = h->priv;
877 if (priv->blocking_push_mode) {
878 g_mutex_lock (&priv->blocking_push_mutex);
879 priv->blocking_push_mode = FALSE;
880 g_cond_signal (&priv->blocking_push_cond);
881 g_mutex_unlock (&priv->blocking_push_mutex);
884 if (h->src_harness) {
885 gst_harness_teardown (h->src_harness);
888 if (h->sink_harness) {
889 gst_harness_teardown (h->sink_harness);
893 gst_caps_unref (priv->src_caps);
896 gst_caps_unref (priv->sink_caps);
899 if (gst_pad_is_request_pad (GST_PAD_PEER (h->srcpad)))
900 gst_element_release_request_pad (h->element, GST_PAD_PEER (h->srcpad));
901 g_free (priv->element_sinkpad_name);
903 gst_pad_set_active (h->srcpad, FALSE);
904 gst_object_unref (h->srcpad);
906 g_async_queue_unref (priv->src_event_queue);
910 if (gst_pad_is_request_pad (GST_PAD_PEER (h->sinkpad)))
911 gst_element_release_request_pad (h->element, GST_PAD_PEER (h->sinkpad));
912 g_free (priv->element_srcpad_name);
914 gst_pad_set_active (h->sinkpad, FALSE);
915 gst_object_unref (h->sinkpad);
917 g_async_queue_unref (priv->buffer_queue);
918 g_async_queue_unref (priv->sink_event_queue);
921 if (priv->sink_forward_pad)
922 gst_object_unref (priv->sink_forward_pad);
924 gst_object_replace ((GstObject **) & priv->propose_allocator, NULL);
925 gst_object_replace ((GstObject **) & priv->allocator, NULL);
926 gst_object_replace ((GstObject **) & priv->pool, NULL);
928 /* if we hold the last ref, set to NULL */
929 if (gst_harness_element_unref (h) == 0) {
930 GstState state, pending;
931 g_assert (gst_element_set_state (h->element, GST_STATE_NULL) ==
932 GST_STATE_CHANGE_SUCCESS);
933 g_assert (gst_element_get_state (h->element, &state, &pending, 0) ==
934 GST_STATE_CHANGE_SUCCESS);
935 g_assert (state == GST_STATE_NULL);
938 g_cond_clear (&priv->blocking_push_cond);
939 g_mutex_clear (&priv->blocking_push_mutex);
941 g_ptr_array_unref (priv->stress);
943 gst_object_unref (h->element);
949 * gst_harness_add_element_src_pad:
951 * @srcpad: a #GstPad to link to the harness sinkpad
953 * Links the specifed #GstPad the @GstHarness sinkpad. This can be useful if
954 * perhaps the srcpad did not exist at the time of creating the harness,
955 * like a demuxer that provides a sometimes-pad after receiving data.
962 gst_harness_add_element_src_pad (GstHarness * h, GstPad * srcpad)
964 GstHarnessPrivate *priv = h->priv;
965 if (h->sinkpad == NULL)
966 gst_harness_setup_sink_pad (h, &hsinktemplate, NULL);
967 g_assert_cmpint (gst_pad_link (srcpad, h->sinkpad), ==, GST_PAD_LINK_OK);
968 g_free (priv->element_srcpad_name);
969 priv->element_srcpad_name = gst_pad_get_name (srcpad);
973 * gst_harness_add_element_sink_pad:
975 * @sinkpad: a #GstPad to link to the harness srcpad
977 * Links the specifed #GstPad the @GstHarness srcpad.
984 gst_harness_add_element_sink_pad (GstHarness * h, GstPad * sinkpad)
986 GstHarnessPrivate *priv = h->priv;
987 if (h->srcpad == NULL)
988 gst_harness_setup_src_pad (h, &hsrctemplate, NULL);
989 g_assert_cmpint (gst_pad_link (h->srcpad, sinkpad), ==, GST_PAD_LINK_OK);
990 g_free (priv->element_sinkpad_name);
991 priv->element_sinkpad_name = gst_pad_get_name (sinkpad);
995 * gst_harness_set_src_caps:
997 * @caps: (transfer full): a #GstCaps to set on the harness srcpad
999 * Sets the @GstHarness srcpad caps. This must be done before any buffers
1000 * can legally be pushed from the harness to the element.
1007 gst_harness_set_src_caps (GstHarness * h, GstCaps * caps)
1009 GstHarnessPrivate *priv = h->priv;
1012 g_assert (gst_pad_push_event (h->srcpad, gst_event_new_caps (caps)));
1013 gst_caps_take (&priv->src_caps, caps);
1015 gst_segment_init (&segment, GST_FORMAT_TIME);
1016 g_assert (gst_pad_push_event (h->srcpad, gst_event_new_segment (&segment)));
1020 * gst_harness_set_sink_caps:
1022 * @caps: (transfer full): a #GstCaps to set on the harness sinkpad
1024 * Sets the @GstHarness sinkpad caps.
1031 gst_harness_set_sink_caps (GstHarness * h, GstCaps * caps)
1033 GstHarnessPrivate *priv = h->priv;
1035 gst_caps_take (&priv->sink_caps, caps);
1036 gst_pad_push_event (h->sinkpad, gst_event_new_reconfigure ());
1040 * gst_harness_set_caps:
1042 * @in: (transfer full): a #GstCaps to set on the harness srcpad
1043 * @out: (transfer full): a #GstCaps to set on the harness sinkpad
1045 * Sets the @GstHarness srcpad and sinkpad caps.
1052 gst_harness_set_caps (GstHarness * h, GstCaps * in, GstCaps * out)
1054 gst_harness_set_sink_caps (h, out);
1055 gst_harness_set_src_caps (h, in);
1059 * gst_harness_set_src_caps_str:
1061 * @str: a @gchar describing a #GstCaps to set on the harness srcpad
1063 * Sets the @GstHarness srcpad caps using a string. This must be done before
1064 * any buffers can legally be pushed from the harness to the element.
1071 gst_harness_set_src_caps_str (GstHarness * h, const gchar * str)
1073 gst_harness_set_src_caps (h, gst_caps_from_string (str));
1077 * gst_harness_set_sink_caps_str:
1079 * @str: a @gchar describing a #GstCaps to set on the harness sinkpad
1081 * Sets the @GstHarness sinkpad caps using a string.
1088 gst_harness_set_sink_caps_str (GstHarness * h, const gchar * str)
1090 gst_harness_set_sink_caps (h, gst_caps_from_string (str));
1094 * gst_harness_set_caps_str:
1096 * @in: a @gchar describing a #GstCaps to set on the harness srcpad
1097 * @out: a @gchar describing a #GstCaps to set on the harness sinkpad
1099 * Sets the @GstHarness srcpad and sinkpad caps using strings.
1106 gst_harness_set_caps_str (GstHarness * h, const gchar * in, const gchar * out)
1108 gst_harness_set_sink_caps_str (h, out);
1109 gst_harness_set_src_caps_str (h, in);
1113 * gst_harness_use_systemclock:
1116 * Sets the system #GstClock on the @GstHarness #GstElement
1123 gst_harness_use_systemclock (GstHarness * h)
1125 GstClock *clock = gst_system_clock_obtain ();
1126 g_assert (clock != NULL);
1127 gst_element_set_clock (h->element, clock);
1128 gst_object_unref (clock);
1132 * gst_harness_use_testclock:
1135 * Sets the #GstTestClock on the #GstHarness #GstElement
1142 gst_harness_use_testclock (GstHarness * h)
1144 GstClock *clock = gst_test_clock_new ();
1145 g_assert (clock != NULL);
1146 gst_element_set_clock (h->element, clock);
1147 gst_object_unref (clock);
1151 * gst_harness_get_testclock:
1154 * Get the #GstTestClock. Useful if specific operations on the testclock is
1159 * Returns: (transfer full): a #GstTestClock, or %NULL if the testclock is not
1165 gst_harness_get_testclock (GstHarness * h)
1167 GstTestClock *testclock = NULL;
1170 clock = gst_element_get_clock (h->element);
1172 if (GST_IS_TEST_CLOCK (clock))
1173 testclock = GST_TEST_CLOCK (clock);
1175 gst_object_unref (clock);
1181 * gst_harness_set_time:
1183 * @time: a #GstClockTime to advance the clock to
1185 * Advance the #GstTestClock to a specific time.
1189 * Returns: a @gboolean %TRUE if the time could be set. %FALSE if not.
1194 gst_harness_set_time (GstHarness * h, GstClockTime time)
1196 GstTestClock *testclock;
1197 testclock = gst_harness_get_testclock (h);
1198 if (testclock == NULL)
1201 gst_test_clock_set_time (testclock, time);
1202 gst_object_unref (testclock);
1207 * gst_harness_wait_for_clock_id_waits:
1209 * @waits: a #guint describing the numbers of #GstClockID registered with
1211 * @timeout: a #guint describing how many seconds to wait for @waits to be true
1213 * Waits for @timeout seconds until @waits number of #GstClockID waits is
1214 * registered with the #GstTestClock. Useful for writing deterministic tests,
1215 * where you want to make sure that an expected number of waits have been
1220 * Returns: a @gboolean %TRUE if the waits have been registered, %FALSE if not.
1221 * (Could be that it timed out waiting or that more waits then waits was found)
1226 gst_harness_wait_for_clock_id_waits (GstHarness * h, guint waits, guint timeout)
1228 GstTestClock *testclock = gst_harness_get_testclock (h);
1232 if (testclock == NULL)
1235 start_time = g_get_monotonic_time ();
1236 while (gst_test_clock_peek_id_count (testclock) < waits) {
1239 g_usleep (G_USEC_PER_SEC / 1000);
1240 time_spent = g_get_monotonic_time () - start_time;
1241 if ((time_spent / G_USEC_PER_SEC) > timeout)
1245 ret = (waits == gst_test_clock_peek_id_count (testclock));
1247 gst_object_unref (testclock);
1252 * gst_harness_crank_single_clock_wait:
1255 * A "crank" consists of three steps:
1256 * 1: Wait for a #GstClockID to be registered with the #GstTestClock.
1257 * 2: Advance the #GstTestClock to the time the #GstClockID is waiting for.
1258 * 3: Release the #GstClockID wait.
1259 * Together, this provides an easy way to not have to think about the details
1260 * around clocks and time, but still being able to write deterministic tests
1261 * that are dependant on this. A "crank" can be though of as the notion of
1262 * manually driving the clock forward to its next logical step.
1266 * Returns: a @gboolean %TRUE if the "crank" was successful, %FALSE if not.
1271 gst_harness_crank_single_clock_wait (GstHarness * h)
1273 GstTestClock *testclock = gst_harness_get_testclock (h);
1274 GstClockID res, pending;
1275 gboolean ret = FALSE;
1277 if (G_LIKELY (testclock != NULL)) {
1278 gst_test_clock_wait_for_next_pending_id (testclock, &pending);
1280 gst_test_clock_set_time (testclock, gst_clock_id_get_time (pending));
1281 res = gst_test_clock_process_next_clock_id (testclock);
1282 if (res == pending) {
1283 GST_DEBUG ("cranked time %" GST_TIME_FORMAT,
1284 GST_TIME_ARGS (gst_clock_get_time (GST_CLOCK (testclock))));
1287 GST_WARNING ("testclock next id != pending (%p != %p)", res, pending);
1290 gst_clock_id_unref (res);
1291 gst_clock_id_unref (pending);
1293 gst_object_unref (testclock);
1295 GST_WARNING ("No testclock on element %s", GST_ELEMENT_NAME (h->element));
1302 * gst_harness_crank_multiple_clock_waits:
1304 * @waits: a #guint describing the number of #GstClockIDs to crank
1306 * Similar to gst_harness_crank_single_clock_wait, this is the function to use
1307 * if your harnessed element(s) are using more then one gst_clock_id_wait.
1308 * Failing to do so can (and will) make it racy which #GstClockID you actually
1309 * are releasing, where as this function will process all the waits at the
1310 * same time, ensuring that one thread can't register another wait before
1311 * both are released.
1315 * Returns: a @gboolean %TRUE if the "crank" was successful, %FALSE if not.
1320 gst_harness_crank_multiple_clock_waits (GstHarness * h, guint waits)
1322 GstTestClock *testclock;
1326 testclock = gst_harness_get_testclock (h);
1327 if (testclock == NULL)
1330 gst_test_clock_wait_for_multiple_pending_ids (testclock, waits, &pending);
1331 gst_harness_set_time (h, gst_test_clock_id_list_get_latest_time (pending));
1332 processed = gst_test_clock_process_id_list (testclock, pending);
1334 g_list_free_full (pending, gst_clock_id_unref);
1335 gst_object_unref (testclock);
1336 return processed == waits;
1343 * This will set the harnessed #GstElement to %GST_STATE_PLAYING.
1344 * #GstElements without a sink-#GstPad and with the %GST_ELEMENT_FLAG_SOURCE
1345 * flag set is concidered a src #GstElement
1346 * Non-src #GstElements (like sinks and filters) are automatically set to
1347 * playing by the #GstHarness, but src #GstElements are not to avoid them
1348 * starting to produce buffers.
1349 * Hence, for src #GstElement you will need to call gst_harness_play explicitly.
1356 gst_harness_play (GstHarness * h)
1358 GstState state, pending;
1359 g_assert_cmpint (GST_STATE_CHANGE_SUCCESS, ==,
1360 gst_element_set_state (h->element, GST_STATE_PLAYING));
1361 g_assert_cmpint (GST_STATE_CHANGE_SUCCESS, ==,
1362 gst_element_get_state (h->element, &state, &pending, 0));
1363 g_assert_cmpint (GST_STATE_PLAYING, ==, state);
1367 * gst_harness_set_blocking_push_mode:
1370 * Setting this will make the harness block in the chain-function, and
1371 * then release when gst_harness_pull or gst_harness_try_pull is called.
1372 * Can be useful when wanting to control a src-element that is not implementing
1373 * gst_clock_id_wait so it can't be controlled by the #GstTestClock, since
1374 * it otherwise would produce buffers as fast as possible.
1381 gst_harness_set_blocking_push_mode (GstHarness * h)
1383 GstHarnessPrivate *priv = h->priv;
1384 priv->blocking_push_mode = TRUE;
1388 * gst_harness_create_buffer:
1390 * @size: a #gsize specifying the size of the buffer
1392 * Allocates a buffer using a #GstBufferPool if present, or else using the
1393 * configured #GstAllocator and #GstAllocatorParams
1397 * Returns: a #GstBuffer of size @size
1402 gst_harness_create_buffer (GstHarness * h, gsize size)
1404 GstHarnessPrivate *priv = h->priv;
1405 GstBuffer *ret = NULL;
1407 if (gst_pad_check_reconfigure (h->srcpad))
1408 gst_harness_negotiate (h);
1411 g_assert_cmpint (gst_buffer_pool_acquire_buffer (priv->pool, &ret, NULL),
1413 if (gst_buffer_get_size (ret) != size) {
1414 GST_DEBUG_OBJECT (h,
1415 "use fallback, pool is configured with a different size (%zu != %zu)",
1416 size, gst_buffer_get_size (ret));
1417 gst_buffer_unref (ret);
1424 gst_buffer_new_allocate (priv->allocator, size,
1425 &priv->allocation_params);
1427 g_assert (ret != NULL);
1434 * @buffer: a #GstBuffer to push
1436 * Pushes a #GstBuffer on the #GstHarness srcpad. The standard way of
1437 * interacting with an harnessed element.
1441 * Returns: a #GstFlowReturn with the result from the push
1446 gst_harness_push (GstHarness * h, GstBuffer * buffer)
1448 GstHarnessPrivate *priv = h->priv;
1449 g_assert (buffer != NULL);
1450 priv->last_push_ts = GST_BUFFER_TIMESTAMP (buffer);
1451 return gst_pad_push (h->srcpad, buffer);
1458 * Pulls a #GstBuffer from the #GAsyncQueue on the #GstHarness sinkpad. The pull
1459 * will timeout in 60 seconds. This is the standard way of getting a buffer
1460 * from a harnessed #GstElement.
1464 * Returns: a #GstBuffer or %NULL if timed out.
1469 gst_harness_pull (GstHarness * h)
1471 GstHarnessPrivate *priv = h->priv;
1473 if (priv->blocking_push_mode) {
1474 g_mutex_lock (&priv->blocking_push_mutex);
1475 g_cond_signal (&priv->blocking_push_cond);
1476 g_mutex_unlock (&priv->blocking_push_mutex);
1479 return (GstBuffer *) g_async_queue_timeout_pop (priv->buffer_queue,
1480 G_USEC_PER_SEC * 60);
1484 * gst_harness_try_pull:
1487 * Pulls a #GstBuffer from the #GAsyncQueue on the #GstHarness sinkpad. Unlike
1488 * gst_harness_pull this will not wait for any buffers if not any are present,
1489 * and return %NULL straight away.
1493 * Returns: a #GstBuffer or %NULL if no buffers are present in the #GAsyncQueue
1498 gst_harness_try_pull (GstHarness * h)
1500 GstHarnessPrivate *priv = h->priv;
1502 if (priv->blocking_push_mode) {
1503 g_mutex_lock (&priv->blocking_push_mutex);
1504 g_cond_signal (&priv->blocking_push_cond);
1505 g_mutex_unlock (&priv->blocking_push_mutex);
1508 return (GstBuffer *) g_async_queue_try_pop (priv->buffer_queue);
1512 * gst_harness_push_and_pull:
1514 * @buffer: a #GstBuffer to push
1516 * Basically a gst_harness_push and a gst_harness_pull in one line. Reflects
1517 * the fact that you often want to do exactly this in your test: Push one buffer
1518 * in, and inspect the outcome.
1522 * Returns: a #GstBuffer or %NULL if timed out.
1527 gst_harness_push_and_pull (GstHarness * h, GstBuffer * buffer)
1529 gst_harness_push (h, buffer);
1530 return gst_harness_pull (h);
1534 * gst_harness_buffers_received:
1537 * The total number of #GstBuffers that has arrived on the #GstHarness sinkpad.
1538 * This number includes buffers that have been dropped as well as buffers
1539 * that have already been pulled out.
1543 * Returns: a #guint number of buffers received
1548 gst_harness_buffers_received (GstHarness * h)
1550 GstHarnessPrivate *priv = h->priv;
1551 return g_atomic_int_get (&priv->recv_buffers);
1555 * gst_harness_buffers_in_queue:
1558 * The number of #GstBuffers currently in the #GstHarness sinkpad #GAsyncQueue
1562 * Returns: a #guint number of buffers in the queue
1567 gst_harness_buffers_in_queue (GstHarness * h)
1569 GstHarnessPrivate *priv = h->priv;
1570 return g_async_queue_length (priv->buffer_queue);
1574 * gst_harness_set_drop_buffers:
1576 * @drop_buffers: a #gboolean specifying to drop outgoing buffers or not
1578 * When set to %TRUE, instead of placing the buffers arriving from the harnessed
1579 * #GstElement inside the sinkpads #GAsyncQueue, they are instead unreffed.
1586 gst_harness_set_drop_buffers (GstHarness * h, gboolean drop_buffers)
1588 GstHarnessPrivate *priv = h->priv;
1589 priv->drop_buffers = drop_buffers;
1593 * gst_harness_dump_to_file:
1595 * @filename: a #gchar with a the name of a file
1597 * Allows you to dump the #GstBuffers the #GstHarness sinkpad #GAsyncQueue
1605 gst_harness_dump_to_file (GstHarness * h, const gchar * filename)
1607 GstHarnessPrivate *priv = h->priv;
1610 fd = fopen (filename, "wb");
1613 while ((buf = g_async_queue_try_pop (priv->buffer_queue))) {
1615 gst_buffer_map (buf, &info, GST_MAP_READ);
1616 fwrite (info.data, 1, info.size, fd);
1617 gst_buffer_unmap (buf, &info);
1618 gst_buffer_unref (buf);
1626 * gst_harness_get_last_pushed_timestamp:
1629 * Get the timestamp of the last #GstBuffer pushed on the #GstHarness srcpad,
1630 * typically with gst_harness_push or gst_harness_push_from_src.
1634 * Returns: a #GstClockTime with the timestamp or %GST_CLOCK_TIME_NONE if no
1635 * #GstBuffer has been pushed on the #GstHarness srcpad
1640 gst_harness_get_last_pushed_timestamp (GstHarness * h)
1642 GstHarnessPrivate *priv = h->priv;
1643 return priv->last_push_ts;
1647 * gst_harness_push_event:
1649 * @event: a #GstEvent to push
1651 * Pushes an #GstEvent on the #GstHarness srcpad.
1655 * Returns: a #gboolean with the result from the push
1660 gst_harness_push_event (GstHarness * h, GstEvent * event)
1662 return gst_pad_push_event (h->srcpad, event);
1666 * gst_harness_pull_event:
1669 * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness sinkpad.
1670 * Timeouts after 60 seconds similar to gst_harness_pull.
1674 * Returns: a #GstEvent or %NULL if timed out.
1679 gst_harness_pull_event (GstHarness * h)
1681 GstHarnessPrivate *priv = h->priv;
1682 return (GstEvent *) g_async_queue_timeout_pop (priv->sink_event_queue,
1683 G_USEC_PER_SEC * 60);
1687 * gst_harness_try_pull_event:
1690 * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness sinkpad.
1691 * See gst_harness_try_pull for details.
1695 * Returns: a #GstEvent or %NULL if no buffers are present in the #GAsyncQueue
1700 gst_harness_try_pull_event (GstHarness * h)
1702 GstHarnessPrivate *priv = h->priv;
1703 return (GstEvent *) g_async_queue_try_pop (priv->sink_event_queue);
1707 * gst_harness_events_received:
1710 * The total number of #GstEvents that has arrived on the #GstHarness sinkpad
1711 * This number includes events handled by the harness as well as events
1712 * that have already been pulled out.
1716 * Returns: a #guint number of events received
1721 gst_harness_events_received (GstHarness * h)
1723 GstHarnessPrivate *priv = h->priv;
1724 return g_atomic_int_get (&priv->recv_events);
1728 * gst_harness_events_in_queue:
1731 * The number of #GstEvents currently in the #GstHarness sinkpad #GAsyncQueue
1735 * Returns: a #guint number of events in the queue
1740 gst_harness_events_in_queue (GstHarness * h)
1742 GstHarnessPrivate *priv = h->priv;
1743 return g_async_queue_length (priv->sink_event_queue);
1747 * gst_harness_push_upstream_event:
1749 * @event: a #GstEvent to push
1751 * Pushes an #GstEvent on the #GstHarness sinkpad.
1755 * Returns: a #gboolean with the result from the push
1760 gst_harness_push_upstream_event (GstHarness * h, GstEvent * event)
1762 g_return_val_if_fail (event != NULL, FALSE);
1763 g_return_val_if_fail (GST_EVENT_IS_UPSTREAM (event), FALSE);
1765 return gst_pad_push_event (h->sinkpad, event);
1769 * gst_harness_pull_upstream_event:
1772 * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness srcpad.
1773 * Timeouts after 60 seconds similar to gst_harness_pull.
1777 * Returns: a #GstEvent or %NULL if timed out.
1782 gst_harness_pull_upstream_event (GstHarness * h)
1784 GstHarnessPrivate *priv = h->priv;
1785 return (GstEvent *) g_async_queue_timeout_pop (priv->src_event_queue,
1786 G_USEC_PER_SEC * 60);
1790 * gst_harness_try_pull_upstream_event:
1793 * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness srcpad.
1794 * See gst_harness_try_pull for details.
1798 * Returns: a #GstEvent or %NULL if no buffers are present in the #GAsyncQueue
1803 gst_harness_try_pull_upstream_event (GstHarness * h)
1805 GstHarnessPrivate *priv = h->priv;
1806 return (GstEvent *) g_async_queue_try_pop (priv->src_event_queue);
1810 * gst_harness_upstream_events_received:
1813 * The total number of #GstEvents that has arrived on the #GstHarness srcpad
1814 * This number includes events handled by the harness as well as events
1815 * that have already been pulled out.
1819 * Returns: a #guint number of events received
1824 gst_harness_upstream_events_received (GstHarness * h)
1826 GstHarnessPrivate *priv = h->priv;
1827 return g_atomic_int_get (&priv->recv_upstream_events);
1831 * gst_harness_upstream_events_in_queue:
1834 * The number of #GstEvents currently in the #GstHarness srcpad #GAsyncQueue
1838 * Returns: a #guint number of events in the queue
1843 gst_harness_upstream_events_in_queue (GstHarness * h)
1845 GstHarnessPrivate *priv = h->priv;
1846 return g_async_queue_length (priv->src_event_queue);
1850 * gst_harness_query_latency:
1853 * Get the min latency reported by any harnessed #GstElement.
1857 * Returns: a #GstClockTime with min latency
1862 gst_harness_query_latency (GstHarness * h)
1866 GstClockTime min = GST_CLOCK_TIME_NONE;
1869 query = gst_query_new_latency ();
1871 if (gst_pad_peer_query (h->sinkpad, query)) {
1872 gst_query_parse_latency (query, &is_live, &min, &max);
1874 gst_query_unref (query);
1880 * gst_harness_set_upstream_latency:
1882 * @latency: a #GstClockTime specifying the latency
1884 * Sets the min latency reported by #GstHarness when receiving a latency-query
1888 * Returns: a #GstClockTime with min latency
1893 gst_harness_set_upstream_latency (GstHarness * h, GstClockTime latency)
1895 GstHarnessPrivate *priv = h->priv;
1896 priv->latency_min = latency;
1900 * gst_harness_get_allocator:
1902 * @allocator: (out) (allow-none) (transfer none): the #GstAllocator
1904 * @params: (out) (allow-none) (transfer full): the
1905 * #GstAllocatorParams of @allocator
1907 * Gets the @allocator and its @params that has been decided to use after an
1915 gst_harness_get_allocator (GstHarness * h, GstAllocator ** allocator,
1916 GstAllocationParams * params)
1918 GstHarnessPrivate *priv = h->priv;
1920 *allocator = priv->allocator;
1922 *params = priv->allocation_params;
1927 * gst_harness_set_propose_allocator:
1929 * @allocator: (allow-none) (transfer full): a #GstAllocator
1930 * @params: (allow-none) (transfer none): a #GstAllocationParams
1932 * Sets the @allocator and @params to propose when receiving an allocation
1940 gst_harness_set_propose_allocator (GstHarness * h, GstAllocator * allocator,
1941 const GstAllocationParams * params)
1943 GstHarnessPrivate *priv = h->priv;
1945 priv->propose_allocator = allocator;
1947 priv->propose_allocation_params = *params;
1951 * gst_harness_add_src_harness:
1953 * @src_harness: (transfer full): a #GstHarness to be added as a src-harness.
1954 * @has_clock_wait: a #gboolean specifying if the #GstElement uses
1955 * gst_clock_wait_id internally.
1957 * A src-harness is a great way of providing the #GstHarness with data.
1958 * By adding a src-type #GstElement, it is then easy to use functions like
1959 * gst_harness_push_from_src or gst_harness_src_crank_and_push_many
1960 * to provide your harnessed element with input. The @has_clock_wait variable
1961 * is a greate way to control you src-element with, in that you can have it
1962 * produce a buffer for you by simply cranking the clock, and not have it
1963 * spin out of control producing buffers as fast as possible.
1965 * If a src-harness already exists it will be replaced.
1972 gst_harness_add_src_harness (GstHarness * h,
1973 GstHarness * src_harness, gboolean has_clock_wait)
1976 gst_harness_teardown (h->src_harness);
1977 h->src_harness = src_harness;
1979 h->src_harness->priv->sink_forward_pad = gst_object_ref (h->srcpad);
1980 gst_harness_use_testclock (h->src_harness);
1981 h->src_harness->priv->has_clock_wait = has_clock_wait;
1985 * gst_harness_add_src:
1987 * @src_element_name: a #gchar with the name of a #GstElement
1988 * @has_clock_wait: a #gboolean specifying if the #GstElement uses
1989 * gst_clock_wait_id internally.
1991 * Similar to gst_harness_add_src_harness, this is a convenience to
1992 * directly create a src-harness using the @src_element_name name specified.
1999 gst_harness_add_src (GstHarness * h,
2000 const gchar * src_element_name, gboolean has_clock_wait)
2002 GstHarness *src_harness = gst_harness_new (src_element_name);
2003 gst_harness_add_src_harness (h, src_harness, has_clock_wait);
2007 * gst_harness_add_src_parse:
2009 * @launchline: a #gchar describing a gst-launch type line
2010 * @has_clock_wait: a #gboolean specifying if the #GstElement uses
2011 * gst_clock_wait_id internally.
2013 * Similar to gst_harness_add_src, this allows you to specify a launch-line,
2014 * which can be useful for both having more then one #GstElement acting as your
2015 * src (Like a src producing raw buffers, and then an encoder, providing encoded
2016 * data), but also by allowing you to set properties like "is-live" directly on
2024 gst_harness_add_src_parse (GstHarness * h,
2025 const gchar * launchline, gboolean has_clock_wait)
2027 GstHarness *src_harness = gst_harness_new_parse (launchline);
2028 gst_harness_add_src_harness (h, src_harness, has_clock_wait);
2032 * gst_harness_push_from_src:
2035 * Transfer data from the src-#GstHarness to the main-#GstHarness. It consists
2037 * 1: Make sure the src is started. (see: gst_harness_play)
2038 * 2: Crank the clock (see: gst_harness_crank_single_clock_wait)
2039 * 3: Pull a #GstBuffer from the src-#GstHarness (see: gst_harness_pull)
2040 * 4: Push the same #GstBuffer into the main-#GstHarness (see: gst_harness_push)
2044 * Returns: a #GstFlowReturn with the result of the push
2049 gst_harness_push_from_src (GstHarness * h)
2053 g_assert (h->src_harness);
2055 /* FIXME: this *is* the right time to start the src,
2056 but maybe a flag so we don't keep telling it to play? */
2057 gst_harness_play (h->src_harness);
2059 if (h->src_harness->priv->has_clock_wait) {
2060 g_assert (gst_harness_crank_single_clock_wait (h->src_harness));
2063 g_assert ((buf = gst_harness_pull (h->src_harness)) != NULL);
2064 return gst_harness_push (h, buf);
2068 * gst_harness_src_crank_and_push_many:
2070 * @cranks: a #gint with the number of calls to gst_harness_crank_single_clock_wait
2071 * @pushes: a #gint with the number of calls to gst_harness_push
2073 * Transfer data from the src-#GstHarness to the main-#GstHarness. Similar to
2074 * gst_harness_push_from_src, this variant allows you to specify how many cranks
2075 * and how many pushes to perform. This can be useful for both moving a lot
2076 * of data at the same time, as well as cases when one crank does not equal one
2077 * buffer to push and v.v.
2081 * Returns: a #GstFlowReturn with the result of the push
2086 gst_harness_src_crank_and_push_many (GstHarness * h, gint cranks, gint pushes)
2088 GstFlowReturn ret = GST_FLOW_OK;
2090 g_assert (h->src_harness);
2091 gst_harness_play (h->src_harness);
2093 for (int i = 0; i < cranks; i++)
2094 g_assert (gst_harness_crank_single_clock_wait (h->src_harness));
2096 for (int i = 0; i < pushes; i++) {
2098 g_assert ((buf = gst_harness_pull (h->src_harness)) != NULL);
2099 ret = gst_harness_push (h, buf);
2100 if (ret != GST_FLOW_OK)
2108 * gst_harness_src_push_event:
2111 * Similar to what gst_harness_src_push does with #GstBuffers, this transfers
2112 * a #GstEvent from the src-#GstHarness to the main-#GstHarness. Note that
2113 * some #GstEvents are being transferred automagically. Look at sink_forward_pad
2118 * Returns: a #gboolean with the result of the push
2123 gst_harness_src_push_event (GstHarness * h)
2125 return gst_harness_push_event (h, gst_harness_pull_event (h->src_harness));
2130 forward_sticky_events (GstPad * pad, GstEvent ** ev, gpointer user_data)
2132 GstHarness *h = user_data;
2133 return gst_pad_push_event (h->priv->sink_forward_pad, gst_event_ref (*ev));
2137 * gst_harness_add_sink_harness:
2139 * @sink_harness: (transfer full): a #GstHarness to be added as a sink-harness.
2141 * Similar to gst_harness_add_src, this allows you to send the data coming out
2142 * of your harnessed #GstElement to a sink-element, allowing to test different
2143 * responses the element output might create in sink elements. An example might
2144 * be an existing sink providing some analytical data on the input it receives that
2145 * can be useful to your testing. If the goal is to test a sink-element itself,
2146 * this is better acheived using gst_harness_new directly on the sink.
2148 * If a sink-harness already exists it will be replaced.
2155 gst_harness_add_sink_harness (GstHarness * h, GstHarness * sink_harness)
2157 GstHarnessPrivate *priv = h->priv;
2159 if (h->sink_harness) {
2160 gst_harness_teardown (h->sink_harness);
2161 gst_object_unref (priv->sink_forward_pad);
2163 h->sink_harness = sink_harness;
2164 priv->sink_forward_pad = gst_object_ref (h->sink_harness->srcpad);
2165 gst_harness_use_testclock (h->sink_harness);
2166 gst_pad_sticky_events_foreach (h->sinkpad, forward_sticky_events, h);
2170 * gst_harness_add_sink:
2172 * @sink_element_name: a #gchar with the name of a #GstElement
2174 * Similar to gst_harness_add_sink_harness, this is a convenience to
2175 * directly create a sink-harness using the @sink_element_name name specified.
2182 gst_harness_add_sink (GstHarness * h, const gchar * sink_element_name)
2184 GstHarness *sink_harness = gst_harness_new (sink_element_name);
2185 gst_harness_add_sink_harness (h, sink_harness);
2189 * gst_harness_add_sink_parse:
2191 * @launchline: a #gchar with the name of a #GstElement
2193 * Similar to gst_harness_add_sink, this allows you to specify a launch-line
2194 * instead of just an element name. See gst_harness_add_src_parse for details.
2201 gst_harness_add_sink_parse (GstHarness * h, const gchar * launchline)
2203 GstHarness *sink_harness = gst_harness_new_parse (launchline);
2204 gst_harness_add_sink_harness (h, sink_harness);
2208 * gst_harness_push_to_sink:
2211 * Transfer one #GstBuffer from the main-#GstHarness to the sink-#GstHarness.
2212 * See gst_harness_push_from_src for details.
2216 * Returns: a #GstFlowReturn with the result of the push
2221 gst_harness_push_to_sink (GstHarness * h)
2224 g_assert (h->sink_harness);
2225 g_assert ((buf = gst_harness_pull (h)) != NULL);
2226 return gst_harness_push (h->sink_harness, buf);
2230 * gst_harness_sink_push_many:
2232 * @pushes: a #gint with the number of calls to gst_harness_push_to_sink
2234 * Convenience that calls gst_harness_push_to_sink @pushes number of times.
2235 * Will abort the pushing if any one push fails.
2239 * Returns: a #GstFlowReturn with the result of the push
2244 gst_harness_sink_push_many (GstHarness * h, gint pushes)
2246 GstFlowReturn ret = GST_FLOW_OK;
2247 g_assert (h->sink_harness);
2248 for (int i = 0; i < pushes; i++) {
2249 ret = gst_harness_push_to_sink (h);
2250 if (ret != GST_FLOW_OK)
2257 * gst_harness_find_element:
2259 * @element_name: a #gchar with a #GstElementFactory name
2261 * Most useful in conjunction with gst_harness_new_parse, this will scan the
2262 * #GstElements inside the #GstHarness, and check if any of them matches
2263 * @element_name. Typical usecase being that you need to access one of the
2264 * harnessed elements for properties and/or signals.
2268 * Returns: (transfer full) (allow-none): a #GstElement or %NULL if not found
2273 gst_harness_find_element (GstHarness * h, const gchar * element_name)
2275 gboolean done = FALSE;
2277 GValue data = G_VALUE_INIT;
2279 iter = gst_bin_iterate_elements (GST_BIN (h->element));
2283 switch (gst_iterator_next (iter, &data)) {
2284 case GST_ITERATOR_OK:
2286 GstElement *element = g_value_get_object (&data);
2287 GstPluginFeature *feature =
2288 GST_PLUGIN_FEATURE (gst_element_get_factory (element));
2289 if (!strcmp (element_name, gst_plugin_feature_get_name (feature))) {
2290 gst_iterator_free (iter);
2293 g_value_reset (&data);
2296 case GST_ITERATOR_RESYNC:
2297 gst_iterator_resync (iter);
2299 case GST_ITERATOR_ERROR:
2300 case GST_ITERATOR_DONE:
2305 gst_iterator_free (iter);
2313 * @element_name: a #gchar with a #GstElementFactory name
2314 * @first_property_name: a #gchar with the first property name
2315 * @...: value for the first property, followed optionally by more
2316 * name/value pairs, followed by %NULL
2318 * A convenience function to allows you to call g_object_set on a #GstElement
2319 * that are residing inside the #GstHarness, by using normal g_object_set
2327 gst_harness_set (GstHarness * h,
2328 const gchar * element_name, const gchar * first_property_name, ...)
2331 GstElement *element = gst_harness_find_element (h, element_name);
2332 va_start (var_args, first_property_name);
2333 g_object_set_valist (G_OBJECT (element), first_property_name, var_args);
2335 gst_object_unref (element);
2341 * @element_name: a #gchar with a #GstElementFactory name
2342 * @first_property_name: a #gchar with the first property name
2343 * @...: return location for the first property, followed optionally by more
2344 * name/return location pairs, followed by %NULL
2346 * A convenience function to allows you to call g_object_get on a #GstElement
2347 * that are residing inside the #GstHarness, by using normal g_object_get
2355 gst_harness_get (GstHarness * h,
2356 const gchar * element_name, const gchar * first_property_name, ...)
2359 GstElement *element = gst_harness_find_element (h, element_name);
2360 va_start (var_args, first_property_name);
2361 g_object_get_valist (G_OBJECT (element), first_property_name, var_args);
2363 gst_object_unref (element);
2367 * gst_harness_add_probe:
2369 * @element_name: a #gchar with a #GstElementFactory name
2370 * @pad_name: a #gchar with the name of the pad to attach the probe to
2371 * @mask: a #GstPadProbeType (see gst_pad_add_probe)
2372 * @callback: a #GstPadProbeCallback (see gst_pad_add_probe)
2373 * @user_data: a #gpointer (see gst_pad_add_probe)
2374 * @destroy_data: a #GDestroyNotify (see gst_pad_add_probe)
2376 * A convenience function to allows you to call gst_pad_add_probe on a
2377 * #GstPad of a #GstElement that are residing inside the #GstHarness,
2378 * by using normal gst_pad_add_probe syntax
2385 gst_harness_add_probe (GstHarness * h,
2386 const gchar * element_name, const gchar * pad_name, GstPadProbeType mask,
2387 GstPadProbeCallback callback, gpointer user_data,
2388 GDestroyNotify destroy_data)
2390 GstElement *element = gst_harness_find_element (h, element_name);
2391 GstPad *pad = gst_element_get_static_pad (element, pad_name);
2392 gst_pad_add_probe (pad, mask, callback, user_data, destroy_data);
2393 gst_object_unref (pad);
2394 gst_object_unref (element);
2397 /******************************************************************************/
2399 /******************************************************************************/
2400 struct _GstHarnessThread
2408 GDestroyNotify freefunc;
2418 } GstHarnessCustomThread;
2426 GstHarnessPrepareBufferFunc func;
2428 GDestroyNotify notify;
2429 } GstHarnessPushBufferThread;
2436 } GstHarnessPushEventThread;
2444 } GstHarnessPropThread;
2450 GstPadTemplate *templ;
2456 } GstHarnessReqPadThread;
2459 gst_harness_thread_init (GstHarnessThread * t, GDestroyNotify freefunc,
2460 GstHarness * h, gulong sleep)
2462 t->freefunc = freefunc;
2466 g_ptr_array_add (h->priv->stress, t);
2470 gst_harness_thread_free (GstHarnessThread * t)
2472 g_slice_free (GstHarnessThread, t);
2476 gst_harness_custom_thread_free (GstHarnessCustomThread * t)
2478 g_slice_free (GstHarnessCustomThread, t);
2482 gst_harness_push_buffer_thread_free (GstHarnessPushBufferThread * t)
2485 gst_caps_replace (&t->caps, NULL);
2486 if (t->notify != NULL)
2487 t->notify (t->data);
2488 g_slice_free (GstHarnessPushBufferThread, t);
2493 gst_harness_push_event_thread_free (GstHarnessPushEventThread * t)
2496 gst_event_replace (&t->event, NULL);
2497 g_slice_free (GstHarnessPushEventThread, t);
2502 gst_harness_property_thread_free (GstHarnessPropThread * t)
2506 g_value_unset (&t->value);
2507 g_slice_free (GstHarnessPropThread, t);
2512 gst_harness_requestpad_release (GstPad * pad, GstElement * element)
2514 gst_element_release_request_pad (element, pad);
2515 gst_object_unref (pad);
2519 gst_harness_requestpad_release_pads (GstHarnessReqPadThread * rpt)
2521 g_slist_foreach (rpt->pads, (GFunc) gst_harness_requestpad_release,
2523 g_slist_free (rpt->pads);
2528 gst_harness_requestpad_thread_free (GstHarnessReqPadThread * t)
2531 gst_object_replace ((GstObject **) & t->templ, NULL);
2533 gst_caps_replace (&t->caps, NULL);
2535 gst_harness_requestpad_release_pads (t);
2536 g_slice_free (GstHarnessReqPadThread, t);
2540 #define GST_HARNESS_THREAD_START(ID, t) \
2541 (((GstHarnessThread *)t)->running = TRUE, \
2542 ((GstHarnessThread *)t)->thread = g_thread_new ( \
2543 "gst-harness-stress-"G_STRINGIFY(ID), \
2544 (GThreadFunc)gst_harness_stress_##ID##_func, t))
2545 #define GST_HARNESS_THREAD_END(t) \
2546 (t->running = FALSE, \
2547 GPOINTER_TO_UINT (g_thread_join (t->thread)))
2550 gst_harness_stress_free (GstHarnessThread * t)
2552 if (t != NULL && t->freefunc != NULL)
2557 gst_harness_stress_custom_func (GstHarnessThread * t)
2559 GstHarnessCustomThread *ct = (GstHarnessCustomThread *) t;
2562 ct->init (ct, ct->data);
2564 while (t->running) {
2565 ct->callback (ct, ct->data);
2568 g_usleep (t->sleep);
2570 return GUINT_TO_POINTER (count);
2575 gst_harness_stress_statechange_func (GstHarnessThread * t)
2579 while (t->running) {
2580 GstClock *clock = gst_element_get_clock (t->h->element);
2582 gboolean done = FALSE;
2584 g_assert (gst_element_set_state (t->h->element, GST_STATE_NULL) ==
2585 GST_STATE_CHANGE_SUCCESS);
2588 it = gst_element_iterate_sink_pads (t->h->element);
2590 GValue item = G_VALUE_INIT;
2591 switch (gst_iterator_next (it, &item)) {
2592 case GST_ITERATOR_OK:
2594 GstPad *sinkpad = g_value_get_object (&item);
2595 GstPad *srcpad = gst_pad_get_peer (sinkpad);
2596 if (srcpad != NULL) {
2597 gst_pad_unlink (srcpad, sinkpad);
2598 gst_pad_link (srcpad, sinkpad);
2599 gst_object_unref (srcpad);
2601 g_value_reset (&item);
2604 case GST_ITERATOR_RESYNC:
2605 gst_iterator_resync (it);
2607 case GST_ITERATOR_ERROR:
2608 g_assert_not_reached ();
2609 case GST_ITERATOR_DONE:
2613 g_value_unset (&item);
2615 gst_iterator_free (it);
2617 if (clock != NULL) {
2618 gst_element_set_clock (t->h->element, clock);
2619 gst_object_unref (clock);
2621 g_assert (gst_element_set_state (t->h->element, GST_STATE_PLAYING) ==
2622 GST_STATE_CHANGE_SUCCESS);
2625 g_usleep (t->sleep);
2627 return GUINT_TO_POINTER (count);
2631 gst_harness_stress_buffer_func (GstHarnessThread * t)
2633 GstHarnessPushBufferThread *pt = (GstHarnessPushBufferThread *) t;
2637 /* Push stream start, caps and segment events */
2638 sid = g_strdup_printf ("%s-%p", GST_OBJECT_NAME (t->h->element), t->h);
2639 g_assert (gst_pad_push_event (t->h->srcpad,
2640 gst_event_new_stream_start (sid)));
2642 g_assert (gst_pad_push_event (t->h->srcpad, gst_event_new_caps (pt->caps)));
2643 g_assert (gst_pad_push_event (t->h->srcpad,
2644 gst_event_new_segment (&pt->segment)));
2646 while (t->running) {
2647 gst_harness_push (t->h, pt->func (t->h, pt->data));
2650 g_usleep (t->sleep);
2652 return GUINT_TO_POINTER (count);
2656 gst_harness_stress_event_func (GstHarnessThread * t)
2658 GstHarnessPushEventThread *pet = (GstHarnessPushEventThread *) t;
2661 while (t->running) {
2662 gst_harness_push_event (t->h, gst_event_ref (pet->event));
2665 g_usleep (t->sleep);
2667 return GUINT_TO_POINTER (count);
2671 gst_harness_stress_upstream_event_func (GstHarnessThread * t)
2673 GstHarnessPushEventThread *pet = (GstHarnessPushEventThread *) t;
2676 while (t->running) {
2677 gst_harness_push_upstream_event (t->h, gst_event_ref (pet->event));
2680 g_usleep (t->sleep);
2682 return GUINT_TO_POINTER (count);
2686 gst_harness_stress_property_func (GstHarnessThread * t)
2688 GstHarnessPropThread *pt = (GstHarnessPropThread *) t;
2691 while (t->running) {
2692 GValue value = G_VALUE_INIT;
2694 g_object_set_property (G_OBJECT (t->h->element), pt->name, &pt->value);
2696 g_value_init (&value, G_VALUE_TYPE (&pt->value));
2697 g_object_get_property (G_OBJECT (t->h->element), pt->name, &value);
2698 g_value_reset (&value);
2701 g_usleep (t->sleep);
2703 return GUINT_TO_POINTER (count);
2707 gst_harness_stress_requestpad_func (GstHarnessThread * t)
2709 GstHarnessReqPadThread *rpt = (GstHarnessReqPadThread *) t;
2712 while (t->running) {
2716 gst_harness_requestpad_release_pads (rpt);
2720 reqpad = gst_element_request_pad (t->h->element,
2721 rpt->templ, rpt->name, rpt->caps);
2723 g_assert (reqpad != NULL);
2725 rpt->pads = g_slist_prepend (rpt->pads, reqpad);
2728 g_usleep (t->sleep);
2730 return GUINT_TO_POINTER (count);
2734 * gst_harness_stress_thread_stop:
2735 * @t: a #GstHarnessThread
2737 * Stop the running #GstHarnessThread
2744 gst_harness_stress_thread_stop (GstHarnessThread * t)
2748 g_return_val_if_fail (t != NULL, 0);
2750 ret = GST_HARNESS_THREAD_END (t);
2751 g_ptr_array_remove (t->h->priv->stress, t);
2756 * gst_harness_stress_custom_start: (skip)
2758 * @init: a #GFunc that is called initially and only once
2759 * @callback: a #GFunc that is called as often as possible
2760 * @data: a #gpointer with custom data to pass to the @callback function
2761 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
2762 * each call to the @callback
2764 * Start a custom stress-thread that will call your @callback for every
2765 * iteration allowing you to do something nasty.
2769 * Returns: a #GstHarnessThread
2774 gst_harness_stress_custom_start (GstHarness * h,
2775 GFunc init, GFunc callback, gpointer data, gulong sleep)
2777 GstHarnessCustomThread *t = g_slice_new0 (GstHarnessCustomThread);
2778 gst_harness_thread_init (&t->t,
2779 (GDestroyNotify) gst_harness_custom_thread_free, h, sleep);
2782 t->callback = callback;
2785 GST_HARNESS_THREAD_START (custom, t);
2790 * gst_harness_stress_statechange_start_full: (skip)
2792 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
2795 * Change the state of your harnessed #GstElement from NULL to PLAYING and
2796 * back again, only pausing for @sleep microseconds every time.
2800 * Returns: a #GstHarnessThread
2805 gst_harness_stress_statechange_start_full (GstHarness * h, gulong sleep)
2807 GstHarnessThread *t = g_slice_new0 (GstHarnessThread);
2808 gst_harness_thread_init (t,
2809 (GDestroyNotify) gst_harness_thread_free, h, sleep);
2810 GST_HARNESS_THREAD_START (statechange, t);
2815 gst_harness_ref_buffer (GstHarness * h, gpointer data)
2818 return gst_buffer_ref (GST_BUFFER_CAST (data));
2822 * gst_harness_stress_push_buffer_start_full: (skip)
2824 * @caps: a #GstCaps for the #GstBuffer
2825 * @segment: a #GstSegment
2826 * @buf: a #GstBuffer to push
2827 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
2828 * each call to gst_pad_push
2830 * Push a #GstBuffer in intervals of @sleep microseconds.
2834 * Returns: a #GstHarnessThread
2839 gst_harness_stress_push_buffer_start_full (GstHarness * h,
2840 GstCaps * caps, const GstSegment * segment, GstBuffer * buf, gulong sleep)
2842 return gst_harness_stress_push_buffer_with_cb_start_full (h, caps, segment,
2843 gst_harness_ref_buffer, gst_buffer_ref (buf),
2844 (GDestroyNotify) gst_buffer_unref, sleep);
2848 * gst_harness_stress_push_buffer_with_cb_start_full: (skip)
2850 * @caps: a #GstCaps for the #GstBuffer
2851 * @segment: a #GstSegment
2852 * @func: a #GstHarnessPrepareBufferFunc function called before every iteration
2853 * to prepare / create a #GstBuffer for pushing
2854 * @data: a #gpointer with data to the #GstHarnessPrepareBufferFunc function
2855 * @notify: a #GDestroyNotify that is called for every push to allow cleaning
2856 * up the #GstBuffer. (like gst_buffer_unref)
2857 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
2858 * each call to gst_pad_push
2860 * Push a #GstBuffer in intervals of @sleep microseconds.
2864 * Returns: a #GstHarnessThread
2869 gst_harness_stress_push_buffer_with_cb_start_full (GstHarness * h,
2870 GstCaps * caps, const GstSegment * segment,
2871 GstHarnessPrepareBufferFunc func, gpointer data, GDestroyNotify notify,
2874 GstHarnessPushBufferThread *t = g_slice_new0 (GstHarnessPushBufferThread);
2875 gst_harness_thread_init (&t->t,
2876 (GDestroyNotify) gst_harness_push_buffer_thread_free, h, sleep);
2878 gst_caps_replace (&t->caps, caps);
2879 t->segment = *segment;
2884 GST_HARNESS_THREAD_START (buffer, t);
2889 * gst_harness_stress_push_event_start_full: (skip)
2891 * @event: a #GstEvent to push
2892 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
2893 * each gst_event_push with @event
2895 * Push the @event onto the harnessed #GstElement sinkpad in intervals of
2896 * @sleep microseconds
2900 * Returns: a #GstHarnessThread
2905 gst_harness_stress_push_event_start_full (GstHarness * h,
2906 GstEvent * event, gulong sleep)
2908 GstHarnessPushEventThread *t = g_slice_new0 (GstHarnessPushEventThread);
2909 gst_harness_thread_init (&t->t,
2910 (GDestroyNotify) gst_harness_push_event_thread_free, h, sleep);
2912 t->event = gst_event_ref (event);
2913 GST_HARNESS_THREAD_START (event, t);
2918 * gst_harness_stress_push_upstream_event_start_full: (skip)
2920 * @event: a #GstEvent to push
2921 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
2922 * each gst_event_push with @event
2924 * Push the @event onto the harnessed #GstElement srcpad in intervals of
2925 * @sleep microseconds.
2926 * Pushing events should generally be OOB events.
2927 * If you need serialized events, you may use a custom stress thread which
2928 * both pushes buffers and events.
2932 * Returns: a #GstHarnessThread
2937 gst_harness_stress_push_upstream_event_start_full (GstHarness * h,
2938 GstEvent * event, gulong sleep)
2940 GstHarnessPushEventThread *t = g_slice_new0 (GstHarnessPushEventThread);
2941 gst_harness_thread_init (&t->t,
2942 (GDestroyNotify) gst_harness_push_event_thread_free, h, sleep);
2944 t->event = gst_event_ref (event);
2945 GST_HARNESS_THREAD_START (upstream_event, t);
2950 * gst_harness_stress_property_start_full: (skip)
2952 * @name: a #gchar specifying a property name
2953 * @value: a #GValue to set the property to
2954 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
2955 * each g_object_set with @name and @value
2957 * Call g_object_set with @name and @value in intervals of @sleep microseconds
2961 * Returns: a #GstHarnessThread
2966 gst_harness_stress_property_start_full (GstHarness * h,
2967 const gchar * name, const GValue * value, gulong sleep)
2969 GstHarnessPropThread *t = g_slice_new0 (GstHarnessPropThread);
2970 gst_harness_thread_init (&t->t,
2971 (GDestroyNotify) gst_harness_property_thread_free, h, sleep);
2973 t->name = g_strdup (name);
2974 g_value_init (&t->value, G_VALUE_TYPE (value));
2975 g_value_copy (value, &t->value);
2977 GST_HARNESS_THREAD_START (property, t);
2982 * gst_harness_stress_requestpad_start_full: (skip)
2984 * @templ: a #GstPadTemplate
2987 * @release: a #gboolean
2988 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
2989 * each gst_element_request_pad
2991 * Call gst_element_request_pad in intervals of @sleep microseconds
2995 * Returns: a #GstHarnessThread
3000 gst_harness_stress_requestpad_start_full (GstHarness * h,
3001 GstPadTemplate * templ, const gchar * name, GstCaps * caps,
3002 gboolean release, gulong sleep)
3004 GstHarnessReqPadThread *t = g_slice_new0 (GstHarnessReqPadThread);
3005 gst_harness_thread_init (&t->t,
3006 (GDestroyNotify) gst_harness_requestpad_thread_free, h, sleep);
3008 t->templ = gst_object_ref (templ);
3009 t->name = g_strdup (name);
3010 gst_caps_replace (&t->caps, caps);
3011 t->release = release;
3013 GST_HARNESS_THREAD_START (requestpad, t);