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;
161 GstPad *sink_forward_pad;
163 volatile gint recv_buffers;
164 volatile gint recv_events;
165 volatile gint recv_upstream_events;
167 GAsyncQueue *buffer_queue;
168 GAsyncQueue *src_event_queue;
169 GAsyncQueue *sink_event_queue;
171 GstClockTime latency_min;
172 GstClockTime latency_max;
173 gboolean has_clock_wait;
174 gboolean drop_buffers;
175 GstClockTime last_push_ts;
178 GstAllocator *allocator;
179 GstAllocationParams allocation_params;
180 GstAllocator *propose_allocator;
181 GstAllocationParams propose_allocation_params;
183 gboolean blocking_push_mode;
184 GCond blocking_push_cond;
185 GMutex blocking_push_mutex;
191 gst_harness_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
193 GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
194 GstHarnessPrivate *priv = h->priv;
196 g_assert (h != NULL);
197 g_mutex_lock (&priv->blocking_push_mutex);
198 g_atomic_int_inc (&priv->recv_buffers);
200 if (priv->drop_buffers)
201 gst_buffer_unref (buffer);
203 g_async_queue_push (priv->buffer_queue, buffer);
205 if (priv->blocking_push_mode) {
206 g_cond_wait (&priv->blocking_push_cond, &priv->blocking_push_mutex);
208 g_mutex_unlock (&priv->blocking_push_mutex);
214 gst_harness_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
216 GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
217 GstHarnessPrivate *priv = h->priv;
219 g_assert (h != NULL);
220 g_atomic_int_inc (&priv->recv_upstream_events);
221 g_async_queue_push (priv->src_event_queue, event);
226 gst_harness_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
228 GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
229 GstHarnessPrivate *priv = h->priv;
232 g_assert (h != NULL);
234 g_atomic_int_inc (&priv->recv_events);
236 switch (GST_EVENT_TYPE (event)) {
237 case GST_EVENT_STREAM_START:
239 case GST_EVENT_SEGMENT:
247 if (priv->forwarding && forward && priv->sink_forward_pad) {
248 gst_pad_push_event (priv->sink_forward_pad, event);
250 g_async_queue_push (priv->sink_event_queue, event);
257 gst_harness_decide_allocation (GstHarness * h, GstCaps * caps)
259 GstHarnessPrivate *priv = h->priv;
261 GstAllocator *allocator;
262 GstAllocationParams params;
263 GstBufferPool *pool = NULL;
264 guint size, min, max;
266 query = gst_query_new_allocation (caps, FALSE);
267 gst_pad_peer_query (h->srcpad, query);
269 if (gst_query_get_n_allocation_params (query) > 0) {
270 gst_query_parse_nth_allocation_param (query, 0, &allocator, ¶ms);
273 gst_allocation_params_init (¶ms);
276 if (gst_query_get_n_allocation_pools (query) > 0) {
277 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
279 /* Most elements create their own pools if pool == NULL. Not sure if we
280 * want to do that in the harness since we may want to test the pool
281 * implementation of the elements. Not creating a pool will however ignore
282 * the returned size. */
284 pool = gst_buffer_pool_new ();
288 size = min = max = 0;
290 gst_query_unref (query);
293 GstStructure *config = gst_buffer_pool_get_config (pool);
294 gst_buffer_pool_config_set_params (config, caps, size, min, max);
295 gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
296 gst_buffer_pool_set_config (pool, config);
299 if (pool != priv->pool) {
300 if (priv->pool != NULL)
301 gst_buffer_pool_set_active (priv->pool, FALSE);
303 gst_buffer_pool_set_active (pool, TRUE);
306 priv->allocation_params = params;
308 gst_object_unref (priv->allocator);
309 priv->allocator = allocator;
311 gst_object_unref (priv->pool);
316 gst_harness_negotiate (GstHarness * h)
320 caps = gst_pad_get_current_caps (h->srcpad);
322 gst_harness_decide_allocation (h, caps);
323 gst_caps_unref (caps);
325 GST_FIXME_OBJECT (h, "Cannot negotiate allocation because caps is not set");
330 gst_harness_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
332 GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
333 GstHarnessPrivate *priv = h->priv;
335 g_assert (h != NULL);
337 // FIXME: forward all queries?
339 switch (GST_QUERY_TYPE (query)) {
340 case GST_QUERY_LATENCY:
341 gst_query_set_latency (query, TRUE, priv->latency_min, priv->latency_max);
345 GstCaps *caps, *filter = NULL;
347 if (priv->sink_caps) {
348 caps = gst_caps_ref (priv->sink_caps);
350 caps = gst_pad_get_pad_template_caps (pad);
353 gst_query_parse_caps (query, &filter);
354 if (filter != NULL) {
355 gst_caps_take (&caps,
356 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST));
359 gst_query_set_caps_result (query, caps);
360 gst_caps_unref (caps);
363 case GST_QUERY_ALLOCATION:
365 if (priv->forwarding && priv->sink_forward_pad != NULL) {
366 GstPad *peer = gst_pad_get_peer (priv->sink_forward_pad);
367 g_assert (peer != NULL);
368 res = gst_pad_query (peer, query);
369 gst_object_unref (peer);
375 gst_query_parse_allocation (query, &caps, &need_pool);
377 /* FIXME: Can this be removed? */
378 size = gst_query_get_n_allocation_params (query);
379 g_assert_cmpuint (0, ==, size);
380 gst_query_add_allocation_param (query,
381 priv->propose_allocator, &priv->propose_allocation_params);
383 GST_DEBUG_OBJECT (pad, "proposing allocation %" GST_PTR_FORMAT,
384 priv->propose_allocator);
389 res = gst_pad_query_default (pad, parent, query);
396 gst_harness_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
398 GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
399 GstHarnessPrivate *priv = h->priv;
401 g_assert (h != NULL);
403 switch (GST_QUERY_TYPE (query)) {
404 case GST_QUERY_LATENCY:
405 gst_query_set_latency (query, TRUE, priv->latency_min, priv->latency_max);
409 GstCaps *caps, *filter = NULL;
411 if (priv->src_caps) {
412 caps = gst_caps_ref (priv->src_caps);
414 caps = gst_pad_get_pad_template_caps (pad);
417 gst_query_parse_caps (query, &filter);
418 if (filter != NULL) {
419 gst_caps_take (&caps,
420 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST));
423 gst_query_set_caps_result (query, caps);
424 gst_caps_unref (caps);
428 res = gst_pad_query_default (pad, parent, query);
434 gst_harness_element_ref (GstHarness * h)
436 guint *data = g_object_get_data (G_OBJECT (h->element), HARNESS_REF);
438 data = g_new0 (guint, 1);
440 g_object_set_data_full (G_OBJECT (h->element), HARNESS_REF, data, g_free);
447 gst_harness_element_unref (GstHarness * h)
449 guint *data = g_object_get_data (G_OBJECT (h->element), HARNESS_REF);
450 g_assert (data != NULL);
456 gst_harness_link_element_srcpad (GstHarness * h,
457 const gchar * element_srcpad_name)
459 GstHarnessPrivate *priv = h->priv;
460 GstPad *srcpad = gst_element_get_static_pad (h->element,
461 element_srcpad_name);
462 GstPadLinkReturn link;
464 srcpad = gst_element_get_request_pad (h->element, element_srcpad_name);
466 link = gst_pad_link (srcpad, h->sinkpad);
467 g_assert_cmpint (link, ==, GST_PAD_LINK_OK);
468 g_free (priv->element_srcpad_name);
469 priv->element_srcpad_name = gst_pad_get_name (srcpad);
471 gst_object_unref (srcpad);
475 gst_harness_link_element_sinkpad (GstHarness * h,
476 const gchar * element_sinkpad_name)
478 GstHarnessPrivate *priv = h->priv;
479 GstPad *sinkpad = gst_element_get_static_pad (h->element,
480 element_sinkpad_name);
481 GstPadLinkReturn link;
483 sinkpad = gst_element_get_request_pad (h->element, element_sinkpad_name);
485 link = gst_pad_link (h->srcpad, sinkpad);
486 g_assert_cmpint (link, ==, GST_PAD_LINK_OK);
487 g_free (priv->element_sinkpad_name);
488 priv->element_sinkpad_name = gst_pad_get_name (sinkpad);
490 gst_object_unref (sinkpad);
494 gst_harness_setup_src_pad (GstHarness * h,
495 GstStaticPadTemplate * src_tmpl, const gchar * element_sinkpad_name)
497 GstHarnessPrivate *priv = h->priv;
499 g_assert (h->srcpad == NULL);
501 priv->src_event_queue =
502 g_async_queue_new_full ((GDestroyNotify) gst_event_unref);
505 h->srcpad = gst_pad_new_from_static_template (src_tmpl, "src");
506 g_assert (h->srcpad);
507 g_object_set_data (G_OBJECT (h->srcpad), HARNESS_KEY, h);
509 gst_pad_set_query_function (h->srcpad, gst_harness_src_query);
510 gst_pad_set_event_function (h->srcpad, gst_harness_src_event);
512 gst_pad_set_active (h->srcpad, TRUE);
514 if (element_sinkpad_name)
515 gst_harness_link_element_sinkpad (h, element_sinkpad_name);
519 gst_harness_setup_sink_pad (GstHarness * h,
520 GstStaticPadTemplate * sink_tmpl, const gchar * element_srcpad_name)
522 GstHarnessPrivate *priv = h->priv;
523 g_assert (sink_tmpl);
524 g_assert (h->sinkpad == NULL);
526 priv->buffer_queue = g_async_queue_new_full (
527 (GDestroyNotify) gst_buffer_unref);
528 priv->sink_event_queue = g_async_queue_new_full (
529 (GDestroyNotify) gst_event_unref);
532 h->sinkpad = gst_pad_new_from_static_template (sink_tmpl, "sink");
533 g_assert (h->sinkpad);
534 g_object_set_data (G_OBJECT (h->sinkpad), HARNESS_KEY, h);
536 gst_pad_set_chain_function (h->sinkpad, gst_harness_chain);
537 gst_pad_set_query_function (h->sinkpad, gst_harness_sink_query);
538 gst_pad_set_event_function (h->sinkpad, gst_harness_sink_event);
540 gst_pad_set_active (h->sinkpad, TRUE);
542 if (element_srcpad_name)
543 gst_harness_link_element_srcpad (h, element_srcpad_name);
547 check_element_type (GstElement * element, gboolean * has_sinkpad,
548 gboolean * has_srcpad)
550 GstElementClass *element_class = GST_ELEMENT_GET_CLASS (element);
551 const GList *tmpl_list;
553 *has_srcpad = element->numsrcpads > 0;
554 *has_sinkpad = element->numsinkpads > 0;
556 tmpl_list = gst_element_class_get_pad_template_list (element_class);
559 GstPadTemplate *pad_tmpl = (GstPadTemplate *) tmpl_list->data;
560 tmpl_list = g_list_next (tmpl_list);
561 if (GST_PAD_TEMPLATE_DIRECTION (pad_tmpl) == GST_PAD_SRC)
563 if (GST_PAD_TEMPLATE_DIRECTION (pad_tmpl) == GST_PAD_SINK)
564 *has_sinkpad |= TRUE;
569 turn_async_and_sync_off (GstElement * element)
571 GObjectClass *class = G_OBJECT_GET_CLASS (element);
572 if (g_object_class_find_property (class, "async"))
573 g_object_set (element, "async", FALSE, NULL);
574 if (g_object_class_find_property (class, "sync"))
575 g_object_set (element, "sync", FALSE, NULL);
579 gst_pad_is_request_pad (GstPad * pad)
581 GstPadTemplate *temp;
586 temp = gst_pad_get_pad_template (pad);
589 is_request = GST_PAD_TEMPLATE_PRESENCE (temp) == GST_PAD_REQUEST;
590 gst_object_unref (temp);
595 * gst_harness_new_full: (skip)
596 * @element: a #GstElement to attach the harness to (transfer none)
597 * @hsrc: (allow-none): a #GstStaticPadTemplate describing the harness srcpad.
598 * %NULL will not create a harness srcpad.
599 * @element_sinkpad_name: (allow-none): a #gchar with the name of the element
600 * sinkpad that is then linked to the harness srcpad. Can be a static or request
601 * or a sometimes pad that has been added. %NULL will not get/request a sinkpad
602 * from the element. (Like if the element is a src.)
603 * @hsink: (allow-none): a #GstStaticPadTemplate describing the harness sinkpad.
604 * %NULL will not create a harness sinkpad.
605 * @element_srcpad_name: (allow-none): a #gchar with the name of the element
606 * srcpad that is then linked to the harness sinkpad, similar to the
607 * @element_sinkpad_name.
609 * Creates a new harness.
613 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
619 gst_harness_new_full (GstElement * element,
620 GstStaticPadTemplate * hsrc, const gchar * element_sinkpad_name,
621 GstStaticPadTemplate * hsink, const gchar * element_srcpad_name)
624 GstHarnessPrivate *priv;
625 gboolean has_sinkpad, has_srcpad;
627 g_return_val_if_fail (element != NULL, NULL);
629 h = g_new0 (GstHarness, 1);
630 g_assert (h != NULL);
631 h->priv = g_new0 (GstHarnessPrivate, 1);
634 GST_DEBUG_OBJECT (h, "about to create new harness %p", h);
635 h->element = gst_object_ref (element);
636 priv->last_push_ts = GST_CLOCK_TIME_NONE;
637 priv->latency_min = 0;
638 priv->latency_max = GST_CLOCK_TIME_NONE;
639 priv->drop_buffers = FALSE;
641 priv->propose_allocator = NULL;
642 gst_allocation_params_init (&priv->propose_allocation_params);
644 g_mutex_init (&priv->blocking_push_mutex);
645 g_cond_init (&priv->blocking_push_cond);
647 check_element_type (element, &has_sinkpad, &has_srcpad);
649 /* setup the loose srcpad linked to the element sinkpad */
651 gst_harness_setup_src_pad (h, hsrc, element_sinkpad_name);
653 /* setup the loose sinkpad linked to the element srcpad */
655 gst_harness_setup_sink_pad (h, hsink, element_srcpad_name);
657 /* as a harness sink, we should not need sync and async */
658 if (has_sinkpad && !has_srcpad)
659 turn_async_and_sync_off (h->element);
661 if (h->srcpad != NULL) {
663 gchar *stream_id = g_strdup_printf ("%s-%p",
664 GST_OBJECT_NAME (h->element), h);
665 handled = gst_pad_push_event (h->srcpad,
666 gst_event_new_stream_start (stream_id));
671 /* don't start sources, they start producing data! */
673 gst_harness_play (h);
675 gst_harness_element_ref (h);
677 GST_DEBUG_OBJECT (h, "created new harness %p "
678 "with element_srcpad_name (%p, %s, %s) and element_sinkpad_name (%p, %s, %s)",
679 h, h->srcpad, GST_DEBUG_PAD_NAME (h->srcpad),
680 h->sinkpad, GST_DEBUG_PAD_NAME (h->sinkpad));
682 priv->stress = g_ptr_array_new_with_free_func (
683 (GDestroyNotify) gst_harness_stress_free);
685 /* we have forwarding on as a default */
686 gst_harness_set_forwarding (h, TRUE);
692 * gst_harness_new_with_element: (skip)
693 * @element: a #GstElement to attach the harness to (transfer none)
694 * @element_sinkpad_name: (allow-none): a #gchar with the name of the element
695 * sinkpad that is then linked to the harness srcpad. %NULL does not attach a
697 * @element_srcpad_name: (allow-none): a #gchar with the name of the element
698 * srcpad that is then linked to the harness sinkpad. %NULL does not attach a
701 * Creates a new harness. Works in the same way as gst_harness_new_full, only
702 * that generic padtemplates are used for the harness src and sinkpads, which
703 * will be sufficient in most usecases.
707 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
713 gst_harness_new_with_element (GstElement * element,
714 const gchar * element_sinkpad_name, const gchar * element_srcpad_name)
716 return gst_harness_new_full (element,
717 &hsrctemplate, element_sinkpad_name, &hsinktemplate, element_srcpad_name);
721 * gst_harness_new_with_padnames: (skip)
722 * @element_name: a #gchar describing the #GstElement name
723 * @element_sinkpad_name: (allow-none): a #gchar with the name of the element
724 * sinkpad that is then linked to the harness srcpad. %NULL does not attach a
726 * @element_srcpad_name: (allow-none): a #gchar with the name of the element
727 * srcpad that is then linked to the harness sinkpad. %NULL does not attach a
730 * Creates a new harness. Works in the same way as gst_harness_new_with_element,
731 * except you specify the factoryname of the #GstElement
735 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
741 gst_harness_new_with_padnames (const gchar * element_name,
742 const gchar * element_sinkpad_name, const gchar * element_srcpad_name)
745 GstElement *element = gst_element_factory_make (element_name, NULL);
746 g_assert (element != NULL);
748 h = gst_harness_new_with_element (element, element_sinkpad_name,
749 element_srcpad_name);
750 gst_object_unref (element);
755 * gst_harness_new_with_templates: (skip)
756 * @element_name: a #gchar describing the #GstElement name
757 * @hsrc: (allow-none): a #GstStaticPadTemplate describing the harness srcpad.
758 * %NULL will not create a harness srcpad.
759 * @hsink: (allow-none): a #GstStaticPadTemplate describing the harness sinkpad.
760 * %NULL will not create a harness sinkpad.
762 * Creates a new harness, like gst_harness_new_full, except it
763 * assumes the #GstElement sinkpad is named "sink" and srcpad is named "src"
767 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
773 gst_harness_new_with_templates (const gchar * element_name,
774 GstStaticPadTemplate * hsrc, GstStaticPadTemplate * hsink)
777 GstElement *element = gst_element_factory_make (element_name, NULL);
778 g_assert (element != NULL);
780 h = gst_harness_new_full (element, hsrc, "sink", hsink, "src");
781 gst_object_unref (element);
786 * gst_harness_new: (skip)
787 * @element_name: a #gchar describing the #GstElement name
789 * Creates a new harness. Works like gst_harness_new_with_padnames, except it
790 * assumes the #GstElement sinkpad is named "sink" and srcpad is named "src"
794 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
800 gst_harness_new (const gchar * element_name)
802 return gst_harness_new_with_padnames (element_name, "sink", "src");
806 * gst_harness_new_parse: (skip)
807 * @launchline: a #gchar describing a gst-launch type line
809 * Creates a new harness, parsing the @launchline and putting that in a #GstBin,
810 * and then attches the harness to the bin.
814 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
820 gst_harness_new_parse (const gchar * launchline)
827 gboolean done = FALSE;
829 g_return_val_if_fail (launchline != NULL, NULL);
831 desc = g_strdup_printf ("bin.( %s )", launchline);
833 (GstBin *) gst_parse_launch_full (desc, NULL, GST_PARSE_FLAG_NONE, NULL);
836 if (G_UNLIKELY (bin == NULL))
839 /* find pads and ghost them if necessary */
840 if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SRC)) != NULL) {
841 gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", pad));
842 gst_object_unref (pad);
844 if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SINK)) != NULL) {
845 gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", pad));
846 gst_object_unref (pad);
849 iter = gst_bin_iterate_sinks (bin);
851 GValue item = { 0, };
853 switch (gst_iterator_next (iter, &item)) {
854 case GST_ITERATOR_OK:
855 turn_async_and_sync_off (GST_ELEMENT (g_value_get_object (&item)));
856 g_value_reset (&item);
858 case GST_ITERATOR_DONE:
861 case GST_ITERATOR_RESYNC:
862 gst_iterator_resync (iter);
864 case GST_ITERATOR_ERROR:
865 gst_object_unref (bin);
866 gst_iterator_free (iter);
867 g_return_val_if_reached (NULL);
871 gst_iterator_free (iter);
873 h = gst_harness_new_full (GST_ELEMENT_CAST (bin),
874 &hsrctemplate, "sink", &hsinktemplate, "src");
875 gst_object_unref (bin);
880 * gst_harness_teardown:
883 * Tears down a @GstHarness, freeing all resources allocated using it.
890 gst_harness_teardown (GstHarness * h)
892 GstHarnessPrivate *priv = h->priv;
894 if (priv->blocking_push_mode) {
895 g_mutex_lock (&priv->blocking_push_mutex);
896 priv->blocking_push_mode = FALSE;
897 g_cond_signal (&priv->blocking_push_cond);
898 g_mutex_unlock (&priv->blocking_push_mutex);
901 if (h->src_harness) {
902 gst_harness_teardown (h->src_harness);
905 if (h->sink_harness) {
906 gst_harness_teardown (h->sink_harness);
910 gst_caps_unref (priv->src_caps);
913 gst_caps_unref (priv->sink_caps);
916 if (gst_pad_is_request_pad (GST_PAD_PEER (h->srcpad)))
917 gst_element_release_request_pad (h->element, GST_PAD_PEER (h->srcpad));
918 g_free (priv->element_sinkpad_name);
920 gst_pad_set_active (h->srcpad, FALSE);
921 gst_object_unref (h->srcpad);
923 g_async_queue_unref (priv->src_event_queue);
927 if (gst_pad_is_request_pad (GST_PAD_PEER (h->sinkpad)))
928 gst_element_release_request_pad (h->element, GST_PAD_PEER (h->sinkpad));
929 g_free (priv->element_srcpad_name);
931 gst_pad_set_active (h->sinkpad, FALSE);
932 gst_object_unref (h->sinkpad);
934 g_async_queue_unref (priv->buffer_queue);
935 g_async_queue_unref (priv->sink_event_queue);
938 if (priv->sink_forward_pad)
939 gst_object_unref (priv->sink_forward_pad);
941 gst_object_replace ((GstObject **) & priv->propose_allocator, NULL);
942 gst_object_replace ((GstObject **) & priv->allocator, NULL);
943 gst_object_replace ((GstObject **) & priv->pool, NULL);
945 /* if we hold the last ref, set to NULL */
946 if (gst_harness_element_unref (h) == 0) {
947 gboolean state_change;
948 GstState state, pending;
949 state_change = gst_element_set_state (h->element, GST_STATE_NULL);
950 g_assert (state_change == GST_STATE_CHANGE_SUCCESS);
951 state_change = gst_element_get_state (h->element, &state, &pending, 0);
952 g_assert (state_change == GST_STATE_CHANGE_SUCCESS);
953 g_assert (state == GST_STATE_NULL);
956 g_cond_clear (&priv->blocking_push_cond);
957 g_mutex_clear (&priv->blocking_push_mutex);
959 g_ptr_array_unref (priv->stress);
961 gst_object_unref (h->element);
967 * gst_harness_add_element_src_pad:
969 * @srcpad: a #GstPad to link to the harness sinkpad
971 * Links the specifed #GstPad the @GstHarness sinkpad. This can be useful if
972 * perhaps the srcpad did not exist at the time of creating the harness,
973 * like a demuxer that provides a sometimes-pad after receiving data.
980 gst_harness_add_element_src_pad (GstHarness * h, GstPad * srcpad)
982 GstHarnessPrivate *priv = h->priv;
983 GstPadLinkReturn link;
984 if (h->sinkpad == NULL)
985 gst_harness_setup_sink_pad (h, &hsinktemplate, NULL);
986 link = gst_pad_link (srcpad, h->sinkpad);
987 g_assert_cmpint (link, ==, GST_PAD_LINK_OK);
988 g_free (priv->element_srcpad_name);
989 priv->element_srcpad_name = gst_pad_get_name (srcpad);
993 * gst_harness_add_element_sink_pad:
995 * @sinkpad: a #GstPad to link to the harness srcpad
997 * Links the specifed #GstPad the @GstHarness srcpad.
1004 gst_harness_add_element_sink_pad (GstHarness * h, GstPad * sinkpad)
1006 GstHarnessPrivate *priv = h->priv;
1007 GstPadLinkReturn link;
1008 if (h->srcpad == NULL)
1009 gst_harness_setup_src_pad (h, &hsrctemplate, NULL);
1010 link = gst_pad_link (h->srcpad, sinkpad);
1011 g_assert_cmpint (link, ==, GST_PAD_LINK_OK);
1012 g_free (priv->element_sinkpad_name);
1013 priv->element_sinkpad_name = gst_pad_get_name (sinkpad);
1017 * gst_harness_set_src_caps:
1019 * @caps: (transfer full): a #GstCaps to set on the harness srcpad
1021 * Sets the @GstHarness srcpad caps. This must be done before any buffers
1022 * can legally be pushed from the harness to the element.
1029 gst_harness_set_src_caps (GstHarness * h, GstCaps * caps)
1031 GstHarnessPrivate *priv = h->priv;
1035 handled = gst_pad_push_event (h->srcpad, gst_event_new_caps (caps));
1037 gst_caps_take (&priv->src_caps, caps);
1039 gst_segment_init (&segment, GST_FORMAT_TIME);
1040 handled = gst_pad_push_event (h->srcpad, gst_event_new_segment (&segment));
1044 * gst_harness_set_sink_caps:
1046 * @caps: (transfer full): a #GstCaps to set on the harness sinkpad
1048 * Sets the @GstHarness sinkpad caps.
1055 gst_harness_set_sink_caps (GstHarness * h, GstCaps * caps)
1057 GstHarnessPrivate *priv = h->priv;
1059 gst_caps_take (&priv->sink_caps, caps);
1060 gst_pad_push_event (h->sinkpad, gst_event_new_reconfigure ());
1064 * gst_harness_set_caps:
1066 * @in: (transfer full): a #GstCaps to set on the harness srcpad
1067 * @out: (transfer full): a #GstCaps to set on the harness sinkpad
1069 * Sets the @GstHarness srcpad and sinkpad caps.
1076 gst_harness_set_caps (GstHarness * h, GstCaps * in, GstCaps * out)
1078 gst_harness_set_sink_caps (h, out);
1079 gst_harness_set_src_caps (h, in);
1083 * gst_harness_set_src_caps_str:
1085 * @str: a @gchar describing a #GstCaps to set on the harness srcpad
1087 * Sets the @GstHarness srcpad caps using a string. This must be done before
1088 * any buffers can legally be pushed from the harness to the element.
1095 gst_harness_set_src_caps_str (GstHarness * h, const gchar * str)
1097 gst_harness_set_src_caps (h, gst_caps_from_string (str));
1101 * gst_harness_set_sink_caps_str:
1103 * @str: a @gchar describing a #GstCaps to set on the harness sinkpad
1105 * Sets the @GstHarness sinkpad caps using a string.
1112 gst_harness_set_sink_caps_str (GstHarness * h, const gchar * str)
1114 gst_harness_set_sink_caps (h, gst_caps_from_string (str));
1118 * gst_harness_set_caps_str:
1120 * @in: a @gchar describing a #GstCaps to set on the harness srcpad
1121 * @out: a @gchar describing a #GstCaps to set on the harness sinkpad
1123 * Sets the @GstHarness srcpad and sinkpad caps using strings.
1130 gst_harness_set_caps_str (GstHarness * h, const gchar * in, const gchar * out)
1132 gst_harness_set_sink_caps_str (h, out);
1133 gst_harness_set_src_caps_str (h, in);
1137 * gst_harness_use_systemclock:
1140 * Sets the system #GstClock on the @GstHarness #GstElement
1147 gst_harness_use_systemclock (GstHarness * h)
1149 GstClock *clock = gst_system_clock_obtain ();
1150 g_assert (clock != NULL);
1151 gst_element_set_clock (h->element, clock);
1152 gst_object_unref (clock);
1156 * gst_harness_use_testclock:
1159 * Sets the #GstTestClock on the #GstHarness #GstElement
1166 gst_harness_use_testclock (GstHarness * h)
1168 GstClock *clock = gst_test_clock_new ();
1169 g_assert (clock != NULL);
1170 gst_element_set_clock (h->element, clock);
1171 gst_object_unref (clock);
1175 * gst_harness_get_testclock:
1178 * Get the #GstTestClock. Useful if specific operations on the testclock is
1183 * Returns: (transfer full): a #GstTestClock, or %NULL if the testclock is not
1189 gst_harness_get_testclock (GstHarness * h)
1191 GstTestClock *testclock = NULL;
1194 clock = gst_element_get_clock (h->element);
1196 if (GST_IS_TEST_CLOCK (clock))
1197 testclock = GST_TEST_CLOCK (clock);
1199 gst_object_unref (clock);
1205 * gst_harness_set_time:
1207 * @time: a #GstClockTime to advance the clock to
1209 * Advance the #GstTestClock to a specific time.
1213 * Returns: a @gboolean %TRUE if the time could be set. %FALSE if not.
1218 gst_harness_set_time (GstHarness * h, GstClockTime time)
1220 GstTestClock *testclock;
1221 testclock = gst_harness_get_testclock (h);
1222 if (testclock == NULL)
1225 gst_test_clock_set_time (testclock, time);
1226 gst_object_unref (testclock);
1231 * gst_harness_wait_for_clock_id_waits:
1233 * @waits: a #guint describing the numbers of #GstClockID registered with
1235 * @timeout: a #guint describing how many seconds to wait for @waits to be true
1237 * Waits for @timeout seconds until @waits number of #GstClockID waits is
1238 * registered with the #GstTestClock. Useful for writing deterministic tests,
1239 * where you want to make sure that an expected number of waits have been
1244 * Returns: a @gboolean %TRUE if the waits have been registered, %FALSE if not.
1245 * (Could be that it timed out waiting or that more waits then waits was found)
1250 gst_harness_wait_for_clock_id_waits (GstHarness * h, guint waits, guint timeout)
1252 GstTestClock *testclock = gst_harness_get_testclock (h);
1256 if (testclock == NULL)
1259 start_time = g_get_monotonic_time ();
1260 while (gst_test_clock_peek_id_count (testclock) < waits) {
1263 g_usleep (G_USEC_PER_SEC / 1000);
1264 time_spent = g_get_monotonic_time () - start_time;
1265 if ((time_spent / G_USEC_PER_SEC) > timeout)
1269 ret = (waits == gst_test_clock_peek_id_count (testclock));
1271 gst_object_unref (testclock);
1276 * gst_harness_crank_single_clock_wait:
1279 * A "crank" consists of three steps:
1280 * 1: Wait for a #GstClockID to be registered with the #GstTestClock.
1281 * 2: Advance the #GstTestClock to the time the #GstClockID is waiting for.
1282 * 3: Release the #GstClockID wait.
1283 * Together, this provides an easy way to not have to think about the details
1284 * around clocks and time, but still being able to write deterministic tests
1285 * that are dependant on this. A "crank" can be though of as the notion of
1286 * manually driving the clock forward to its next logical step.
1290 * Returns: a @gboolean %TRUE if the "crank" was successful, %FALSE if not.
1295 gst_harness_crank_single_clock_wait (GstHarness * h)
1297 GstTestClock *testclock = gst_harness_get_testclock (h);
1298 GstClockID res, pending;
1299 gboolean ret = FALSE;
1301 if (G_LIKELY (testclock != NULL)) {
1302 gst_test_clock_wait_for_next_pending_id (testclock, &pending);
1304 gst_test_clock_set_time (testclock, gst_clock_id_get_time (pending));
1305 res = gst_test_clock_process_next_clock_id (testclock);
1306 if (res == pending) {
1307 GST_DEBUG ("cranked time %" GST_TIME_FORMAT,
1308 GST_TIME_ARGS (gst_clock_get_time (GST_CLOCK (testclock))));
1311 GST_WARNING ("testclock next id != pending (%p != %p)", res, pending);
1314 gst_clock_id_unref (res);
1315 gst_clock_id_unref (pending);
1317 gst_object_unref (testclock);
1319 GST_WARNING ("No testclock on element %s", GST_ELEMENT_NAME (h->element));
1326 * gst_harness_crank_multiple_clock_waits:
1328 * @waits: a #guint describing the number of #GstClockIDs to crank
1330 * Similar to gst_harness_crank_single_clock_wait, this is the function to use
1331 * if your harnessed element(s) are using more then one gst_clock_id_wait.
1332 * Failing to do so can (and will) make it racy which #GstClockID you actually
1333 * are releasing, where as this function will process all the waits at the
1334 * same time, ensuring that one thread can't register another wait before
1335 * both are released.
1339 * Returns: a @gboolean %TRUE if the "crank" was successful, %FALSE if not.
1344 gst_harness_crank_multiple_clock_waits (GstHarness * h, guint waits)
1346 GstTestClock *testclock;
1350 testclock = gst_harness_get_testclock (h);
1351 if (testclock == NULL)
1354 gst_test_clock_wait_for_multiple_pending_ids (testclock, waits, &pending);
1355 gst_harness_set_time (h, gst_test_clock_id_list_get_latest_time (pending));
1356 processed = gst_test_clock_process_id_list (testclock, pending);
1358 g_list_free_full (pending, gst_clock_id_unref);
1359 gst_object_unref (testclock);
1360 return processed == waits;
1367 * This will set the harnessed #GstElement to %GST_STATE_PLAYING.
1368 * #GstElements without a sink-#GstPad and with the %GST_ELEMENT_FLAG_SOURCE
1369 * flag set is concidered a src #GstElement
1370 * Non-src #GstElements (like sinks and filters) are automatically set to
1371 * playing by the #GstHarness, but src #GstElements are not to avoid them
1372 * starting to produce buffers.
1373 * Hence, for src #GstElement you will need to call gst_harness_play explicitly.
1380 gst_harness_play (GstHarness * h)
1382 GstState state, pending;
1383 gboolean state_change;
1384 state_change = gst_element_set_state (h->element, GST_STATE_PLAYING);
1385 g_assert_cmpint (GST_STATE_CHANGE_SUCCESS, ==, state_change);
1386 state_change = gst_element_get_state (h->element, &state, &pending, 0);
1387 g_assert_cmpint (GST_STATE_CHANGE_SUCCESS, ==, state_change);
1388 g_assert_cmpint (GST_STATE_PLAYING, ==, state);
1392 * gst_harness_set_blocking_push_mode:
1395 * Setting this will make the harness block in the chain-function, and
1396 * then release when gst_harness_pull or gst_harness_try_pull is called.
1397 * Can be useful when wanting to control a src-element that is not implementing
1398 * gst_clock_id_wait so it can't be controlled by the #GstTestClock, since
1399 * it otherwise would produce buffers as fast as possible.
1406 gst_harness_set_blocking_push_mode (GstHarness * h)
1408 GstHarnessPrivate *priv = h->priv;
1409 priv->blocking_push_mode = TRUE;
1413 * gst_harness_set_forwarding:
1415 * @forwarding: a #gboolean to enable/disable forwarding
1417 * As a convenience, a src-harness will forward %GST_EVENT_STREAM_START,
1418 * %GST_EVENT_CAPS and %GST_EVENT_SEGMENT to the main-harness if forwarding
1419 * is enabled, and forward any sticky-events from the main-harness to
1420 * the sink-harness. It will also forward the %GST_QUERY_ALLOCATION.
1422 * If forwarding is disabled, the user will have to either manually push
1423 * these events from the src-harness using gst_harness_src_push_event, or
1424 * create and push them manually. While this will allow full control and
1425 * inspection of these events, for the most cases having forwarding enabled
1426 * will be sufficient when writing a test where the src-harness' main function
1427 * is providing data for the main-harness.
1429 * Forwarding is enabled by default.
1436 gst_harness_set_forwarding (GstHarness * h, gboolean forwarding)
1438 GstHarnessPrivate *priv = h->priv;
1439 priv->forwarding = forwarding;
1441 gst_harness_set_forwarding (h->src_harness, forwarding);
1442 if (h->sink_harness)
1443 gst_harness_set_forwarding (h->sink_harness, forwarding);
1447 * gst_harness_create_buffer:
1449 * @size: a #gsize specifying the size of the buffer
1451 * Allocates a buffer using a #GstBufferPool if present, or else using the
1452 * configured #GstAllocator and #GstAllocationParams
1456 * Returns: a #GstBuffer of size @size
1461 gst_harness_create_buffer (GstHarness * h, gsize size)
1463 GstHarnessPrivate *priv = h->priv;
1464 GstBuffer *ret = NULL;
1467 if (gst_pad_check_reconfigure (h->srcpad))
1468 gst_harness_negotiate (h);
1471 flow = gst_buffer_pool_acquire_buffer (priv->pool, &ret, NULL);
1472 g_assert_cmpint (flow, ==, GST_FLOW_OK);
1473 if (gst_buffer_get_size (ret) != size) {
1474 GST_DEBUG_OBJECT (h,
1475 "use fallback, pool is configured with a different size (%zu != %zu)",
1476 size, gst_buffer_get_size (ret));
1477 gst_buffer_unref (ret);
1484 gst_buffer_new_allocate (priv->allocator, size,
1485 &priv->allocation_params);
1487 g_assert (ret != NULL);
1494 * @buffer: a #GstBuffer to push
1496 * Pushes a #GstBuffer on the #GstHarness srcpad. The standard way of
1497 * interacting with an harnessed element.
1501 * Returns: a #GstFlowReturn with the result from the push
1506 gst_harness_push (GstHarness * h, GstBuffer * buffer)
1508 GstHarnessPrivate *priv = h->priv;
1509 g_assert (buffer != NULL);
1510 priv->last_push_ts = GST_BUFFER_TIMESTAMP (buffer);
1511 return gst_pad_push (h->srcpad, buffer);
1518 * Pulls a #GstBuffer from the #GAsyncQueue on the #GstHarness sinkpad. The pull
1519 * will timeout in 60 seconds. This is the standard way of getting a buffer
1520 * from a harnessed #GstElement.
1524 * Returns: a #GstBuffer or %NULL if timed out.
1529 gst_harness_pull (GstHarness * h)
1531 GstHarnessPrivate *priv = h->priv;
1533 if (priv->blocking_push_mode) {
1534 g_mutex_lock (&priv->blocking_push_mutex);
1535 g_cond_signal (&priv->blocking_push_cond);
1536 g_mutex_unlock (&priv->blocking_push_mutex);
1539 return (GstBuffer *) g_async_queue_timeout_pop (priv->buffer_queue,
1540 G_USEC_PER_SEC * 60);
1544 * gst_harness_try_pull:
1547 * Pulls a #GstBuffer from the #GAsyncQueue on the #GstHarness sinkpad. Unlike
1548 * gst_harness_pull this will not wait for any buffers if not any are present,
1549 * and return %NULL straight away.
1553 * Returns: a #GstBuffer or %NULL if no buffers are present in the #GAsyncQueue
1558 gst_harness_try_pull (GstHarness * h)
1560 GstHarnessPrivate *priv = h->priv;
1562 if (priv->blocking_push_mode) {
1563 g_mutex_lock (&priv->blocking_push_mutex);
1564 g_cond_signal (&priv->blocking_push_cond);
1565 g_mutex_unlock (&priv->blocking_push_mutex);
1568 return (GstBuffer *) g_async_queue_try_pop (priv->buffer_queue);
1572 * gst_harness_push_and_pull:
1574 * @buffer: a #GstBuffer to push
1576 * Basically a gst_harness_push and a gst_harness_pull in one line. Reflects
1577 * the fact that you often want to do exactly this in your test: Push one buffer
1578 * in, and inspect the outcome.
1582 * Returns: a #GstBuffer or %NULL if timed out.
1587 gst_harness_push_and_pull (GstHarness * h, GstBuffer * buffer)
1589 gst_harness_push (h, buffer);
1590 return gst_harness_pull (h);
1594 * gst_harness_buffers_received:
1597 * The total number of #GstBuffers that has arrived on the #GstHarness sinkpad.
1598 * This number includes buffers that have been dropped as well as buffers
1599 * that have already been pulled out.
1603 * Returns: a #guint number of buffers received
1608 gst_harness_buffers_received (GstHarness * h)
1610 GstHarnessPrivate *priv = h->priv;
1611 return g_atomic_int_get (&priv->recv_buffers);
1615 * gst_harness_buffers_in_queue:
1618 * The number of #GstBuffers currently in the #GstHarness sinkpad #GAsyncQueue
1622 * Returns: a #guint number of buffers in the queue
1627 gst_harness_buffers_in_queue (GstHarness * h)
1629 GstHarnessPrivate *priv = h->priv;
1630 return g_async_queue_length (priv->buffer_queue);
1634 * gst_harness_set_drop_buffers:
1636 * @drop_buffers: a #gboolean specifying to drop outgoing buffers or not
1638 * When set to %TRUE, instead of placing the buffers arriving from the harnessed
1639 * #GstElement inside the sinkpads #GAsyncQueue, they are instead unreffed.
1646 gst_harness_set_drop_buffers (GstHarness * h, gboolean drop_buffers)
1648 GstHarnessPrivate *priv = h->priv;
1649 priv->drop_buffers = drop_buffers;
1653 * gst_harness_dump_to_file:
1655 * @filename: a #gchar with a the name of a file
1657 * Allows you to dump the #GstBuffers the #GstHarness sinkpad #GAsyncQueue
1665 gst_harness_dump_to_file (GstHarness * h, const gchar * filename)
1667 GstHarnessPrivate *priv = h->priv;
1670 fd = fopen (filename, "wb");
1673 while ((buf = g_async_queue_try_pop (priv->buffer_queue))) {
1675 gst_buffer_map (buf, &info, GST_MAP_READ);
1676 fwrite (info.data, 1, info.size, fd);
1677 gst_buffer_unmap (buf, &info);
1678 gst_buffer_unref (buf);
1686 * gst_harness_get_last_pushed_timestamp:
1689 * Get the timestamp of the last #GstBuffer pushed on the #GstHarness srcpad,
1690 * typically with gst_harness_push or gst_harness_push_from_src.
1694 * Returns: a #GstClockTime with the timestamp or %GST_CLOCK_TIME_NONE if no
1695 * #GstBuffer has been pushed on the #GstHarness srcpad
1700 gst_harness_get_last_pushed_timestamp (GstHarness * h)
1702 GstHarnessPrivate *priv = h->priv;
1703 return priv->last_push_ts;
1707 * gst_harness_push_event:
1709 * @event: a #GstEvent to push
1711 * Pushes an #GstEvent on the #GstHarness srcpad.
1715 * Returns: a #gboolean with the result from the push
1720 gst_harness_push_event (GstHarness * h, GstEvent * event)
1722 return gst_pad_push_event (h->srcpad, event);
1726 * gst_harness_pull_event:
1729 * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness sinkpad.
1730 * Timeouts after 60 seconds similar to gst_harness_pull.
1734 * Returns: a #GstEvent or %NULL if timed out.
1739 gst_harness_pull_event (GstHarness * h)
1741 GstHarnessPrivate *priv = h->priv;
1742 return (GstEvent *) g_async_queue_timeout_pop (priv->sink_event_queue,
1743 G_USEC_PER_SEC * 60);
1747 * gst_harness_try_pull_event:
1750 * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness sinkpad.
1751 * See gst_harness_try_pull for details.
1755 * Returns: a #GstEvent or %NULL if no buffers are present in the #GAsyncQueue
1760 gst_harness_try_pull_event (GstHarness * h)
1762 GstHarnessPrivate *priv = h->priv;
1763 return (GstEvent *) g_async_queue_try_pop (priv->sink_event_queue);
1767 * gst_harness_events_received:
1770 * The total number of #GstEvents that has arrived on the #GstHarness sinkpad
1771 * This number includes events handled by the harness as well as events
1772 * that have already been pulled out.
1776 * Returns: a #guint number of events received
1781 gst_harness_events_received (GstHarness * h)
1783 GstHarnessPrivate *priv = h->priv;
1784 return g_atomic_int_get (&priv->recv_events);
1788 * gst_harness_events_in_queue:
1791 * The number of #GstEvents currently in the #GstHarness sinkpad #GAsyncQueue
1795 * Returns: a #guint number of events in the queue
1800 gst_harness_events_in_queue (GstHarness * h)
1802 GstHarnessPrivate *priv = h->priv;
1803 return g_async_queue_length (priv->sink_event_queue);
1807 * gst_harness_push_upstream_event:
1809 * @event: a #GstEvent to push
1811 * Pushes an #GstEvent on the #GstHarness sinkpad.
1815 * Returns: a #gboolean with the result from the push
1820 gst_harness_push_upstream_event (GstHarness * h, GstEvent * event)
1822 g_return_val_if_fail (event != NULL, FALSE);
1823 g_return_val_if_fail (GST_EVENT_IS_UPSTREAM (event), FALSE);
1825 return gst_pad_push_event (h->sinkpad, event);
1829 * gst_harness_pull_upstream_event:
1832 * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness srcpad.
1833 * Timeouts after 60 seconds similar to gst_harness_pull.
1837 * Returns: a #GstEvent or %NULL if timed out.
1842 gst_harness_pull_upstream_event (GstHarness * h)
1844 GstHarnessPrivate *priv = h->priv;
1845 return (GstEvent *) g_async_queue_timeout_pop (priv->src_event_queue,
1846 G_USEC_PER_SEC * 60);
1850 * gst_harness_try_pull_upstream_event:
1853 * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness srcpad.
1854 * See gst_harness_try_pull for details.
1858 * Returns: a #GstEvent or %NULL if no buffers are present in the #GAsyncQueue
1863 gst_harness_try_pull_upstream_event (GstHarness * h)
1865 GstHarnessPrivate *priv = h->priv;
1866 return (GstEvent *) g_async_queue_try_pop (priv->src_event_queue);
1870 * gst_harness_upstream_events_received:
1873 * The total number of #GstEvents that has arrived on the #GstHarness srcpad
1874 * This number includes events handled by the harness as well as events
1875 * that have already been pulled out.
1879 * Returns: a #guint number of events received
1884 gst_harness_upstream_events_received (GstHarness * h)
1886 GstHarnessPrivate *priv = h->priv;
1887 return g_atomic_int_get (&priv->recv_upstream_events);
1891 * gst_harness_upstream_events_in_queue:
1894 * The number of #GstEvents currently in the #GstHarness srcpad #GAsyncQueue
1898 * Returns: a #guint number of events in the queue
1903 gst_harness_upstream_events_in_queue (GstHarness * h)
1905 GstHarnessPrivate *priv = h->priv;
1906 return g_async_queue_length (priv->src_event_queue);
1910 * gst_harness_query_latency:
1913 * Get the min latency reported by any harnessed #GstElement.
1917 * Returns: a #GstClockTime with min latency
1922 gst_harness_query_latency (GstHarness * h)
1926 GstClockTime min = GST_CLOCK_TIME_NONE;
1929 query = gst_query_new_latency ();
1931 if (gst_pad_peer_query (h->sinkpad, query)) {
1932 gst_query_parse_latency (query, &is_live, &min, &max);
1934 gst_query_unref (query);
1940 * gst_harness_set_upstream_latency:
1942 * @latency: a #GstClockTime specifying the latency
1944 * Sets the min latency reported by #GstHarness when receiving a latency-query
1948 * Returns: a #GstClockTime with min latency
1953 gst_harness_set_upstream_latency (GstHarness * h, GstClockTime latency)
1955 GstHarnessPrivate *priv = h->priv;
1956 priv->latency_min = latency;
1960 * gst_harness_get_allocator:
1962 * @allocator: (out) (allow-none) (transfer none): the #GstAllocator used
1963 * @params: (out) (allow-none) (transfer full): the #GstAllocationParams of
1966 * Gets the @allocator and its @params that has been decided to use after an
1974 gst_harness_get_allocator (GstHarness * h, GstAllocator ** allocator,
1975 GstAllocationParams * params)
1977 GstHarnessPrivate *priv = h->priv;
1979 *allocator = priv->allocator;
1981 *params = priv->allocation_params;
1986 * gst_harness_set_propose_allocator:
1988 * @allocator: (allow-none) (transfer full): a #GstAllocator
1989 * @params: (allow-none) (transfer none): a #GstAllocationParams
1991 * Sets the @allocator and @params to propose when receiving an allocation
1999 gst_harness_set_propose_allocator (GstHarness * h, GstAllocator * allocator,
2000 const GstAllocationParams * params)
2002 GstHarnessPrivate *priv = h->priv;
2004 priv->propose_allocator = allocator;
2006 priv->propose_allocation_params = *params;
2010 * gst_harness_add_src_harness:
2012 * @src_harness: (transfer full): a #GstHarness to be added as a src-harness.
2013 * @has_clock_wait: a #gboolean specifying if the #GstElement uses
2014 * gst_clock_wait_id internally.
2016 * A src-harness is a great way of providing the #GstHarness with data.
2017 * By adding a src-type #GstElement, it is then easy to use functions like
2018 * gst_harness_push_from_src or gst_harness_src_crank_and_push_many
2019 * to provide your harnessed element with input. The @has_clock_wait variable
2020 * is a greate way to control you src-element with, in that you can have it
2021 * produce a buffer for you by simply cranking the clock, and not have it
2022 * spin out of control producing buffers as fast as possible.
2024 * If a src-harness already exists it will be replaced.
2031 gst_harness_add_src_harness (GstHarness * h,
2032 GstHarness * src_harness, gboolean has_clock_wait)
2035 gst_harness_teardown (h->src_harness);
2036 h->src_harness = src_harness;
2038 h->src_harness->priv->sink_forward_pad = gst_object_ref (h->srcpad);
2039 gst_harness_use_testclock (h->src_harness);
2040 h->src_harness->priv->has_clock_wait = has_clock_wait;
2041 gst_harness_set_forwarding (h->src_harness, h->priv->forwarding);
2045 * gst_harness_add_src:
2047 * @src_element_name: a #gchar with the name of a #GstElement
2048 * @has_clock_wait: a #gboolean specifying if the #GstElement uses
2049 * gst_clock_wait_id internally.
2051 * Similar to gst_harness_add_src_harness, this is a convenience to
2052 * directly create a src-harness using the @src_element_name name specified.
2059 gst_harness_add_src (GstHarness * h,
2060 const gchar * src_element_name, gboolean has_clock_wait)
2062 GstHarness *src_harness = gst_harness_new (src_element_name);
2063 gst_harness_add_src_harness (h, src_harness, has_clock_wait);
2067 * gst_harness_add_src_parse:
2069 * @launchline: a #gchar describing a gst-launch type line
2070 * @has_clock_wait: a #gboolean specifying if the #GstElement uses
2071 * gst_clock_wait_id internally.
2073 * Similar to gst_harness_add_src, this allows you to specify a launch-line,
2074 * which can be useful for both having more then one #GstElement acting as your
2075 * src (Like a src producing raw buffers, and then an encoder, providing encoded
2076 * data), but also by allowing you to set properties like "is-live" directly on
2084 gst_harness_add_src_parse (GstHarness * h,
2085 const gchar * launchline, gboolean has_clock_wait)
2087 GstHarness *src_harness = gst_harness_new_parse (launchline);
2088 gst_harness_add_src_harness (h, src_harness, has_clock_wait);
2092 * gst_harness_push_from_src:
2095 * Transfer data from the src-#GstHarness to the main-#GstHarness. It consists
2097 * 1: Make sure the src is started. (see: gst_harness_play)
2098 * 2: Crank the clock (see: gst_harness_crank_single_clock_wait)
2099 * 3: Pull a #GstBuffer from the src-#GstHarness (see: gst_harness_pull)
2100 * 4: Push the same #GstBuffer into the main-#GstHarness (see: gst_harness_push)
2104 * Returns: a #GstFlowReturn with the result of the push
2109 gst_harness_push_from_src (GstHarness * h)
2114 g_assert (h->src_harness);
2116 /* FIXME: this *is* the right time to start the src,
2117 but maybe a flag so we don't keep telling it to play? */
2118 gst_harness_play (h->src_harness);
2120 if (h->src_harness->priv->has_clock_wait) {
2121 crank = gst_harness_crank_single_clock_wait (h->src_harness);
2125 buf = gst_harness_pull (h->src_harness);
2126 g_assert (buf != NULL);
2127 return gst_harness_push (h, buf);
2131 * gst_harness_src_crank_and_push_many:
2133 * @cranks: a #gint with the number of calls to gst_harness_crank_single_clock_wait
2134 * @pushes: a #gint with the number of calls to gst_harness_push
2136 * Transfer data from the src-#GstHarness to the main-#GstHarness. Similar to
2137 * gst_harness_push_from_src, this variant allows you to specify how many cranks
2138 * and how many pushes to perform. This can be useful for both moving a lot
2139 * of data at the same time, as well as cases when one crank does not equal one
2140 * buffer to push and v.v.
2144 * Returns: a #GstFlowReturn with the result of the push
2149 gst_harness_src_crank_and_push_many (GstHarness * h, gint cranks, gint pushes)
2151 GstFlowReturn ret = GST_FLOW_OK;
2154 g_assert (h->src_harness);
2155 gst_harness_play (h->src_harness);
2157 for (int i = 0; i < cranks; i++) {
2158 crank = gst_harness_crank_single_clock_wait (h->src_harness);
2162 for (int i = 0; i < pushes; i++) {
2164 buf = gst_harness_pull (h->src_harness);
2165 g_assert (buf != NULL);
2166 ret = gst_harness_push (h, buf);
2167 if (ret != GST_FLOW_OK)
2175 * gst_harness_src_push_event:
2178 * Similar to what gst_harness_src_push does with #GstBuffers, this transfers
2179 * a #GstEvent from the src-#GstHarness to the main-#GstHarness. Note that
2180 * some #GstEvents are being transferred automagically. Look at sink_forward_pad
2185 * Returns: a #gboolean with the result of the push
2190 gst_harness_src_push_event (GstHarness * h)
2192 return gst_harness_push_event (h, gst_harness_pull_event (h->src_harness));
2197 forward_sticky_events (GstPad * pad, GstEvent ** ev, gpointer user_data)
2199 GstHarness *h = user_data;
2200 return gst_pad_push_event (h->priv->sink_forward_pad, gst_event_ref (*ev));
2204 * gst_harness_add_sink_harness:
2206 * @sink_harness: (transfer full): a #GstHarness to be added as a sink-harness.
2208 * Similar to gst_harness_add_src, this allows you to send the data coming out
2209 * of your harnessed #GstElement to a sink-element, allowing to test different
2210 * responses the element output might create in sink elements. An example might
2211 * be an existing sink providing some analytical data on the input it receives that
2212 * can be useful to your testing. If the goal is to test a sink-element itself,
2213 * this is better acheived using gst_harness_new directly on the sink.
2215 * If a sink-harness already exists it will be replaced.
2222 gst_harness_add_sink_harness (GstHarness * h, GstHarness * sink_harness)
2224 GstHarnessPrivate *priv = h->priv;
2226 if (h->sink_harness) {
2227 gst_harness_teardown (h->sink_harness);
2228 gst_object_unref (priv->sink_forward_pad);
2230 h->sink_harness = sink_harness;
2231 priv->sink_forward_pad = gst_object_ref (h->sink_harness->srcpad);
2232 gst_harness_use_testclock (h->sink_harness);
2233 if (priv->forwarding)
2234 gst_pad_sticky_events_foreach (h->sinkpad, forward_sticky_events, h);
2235 gst_harness_set_forwarding (h->sink_harness, priv->forwarding);
2239 * gst_harness_add_sink:
2241 * @sink_element_name: a #gchar with the name of a #GstElement
2243 * Similar to gst_harness_add_sink_harness, this is a convenience to
2244 * directly create a sink-harness using the @sink_element_name name specified.
2251 gst_harness_add_sink (GstHarness * h, const gchar * sink_element_name)
2253 GstHarness *sink_harness = gst_harness_new (sink_element_name);
2254 gst_harness_add_sink_harness (h, sink_harness);
2258 * gst_harness_add_sink_parse:
2260 * @launchline: a #gchar with the name of a #GstElement
2262 * Similar to gst_harness_add_sink, this allows you to specify a launch-line
2263 * instead of just an element name. See gst_harness_add_src_parse for details.
2270 gst_harness_add_sink_parse (GstHarness * h, const gchar * launchline)
2272 GstHarness *sink_harness = gst_harness_new_parse (launchline);
2273 gst_harness_add_sink_harness (h, sink_harness);
2277 * gst_harness_push_to_sink:
2280 * Transfer one #GstBuffer from the main-#GstHarness to the sink-#GstHarness.
2281 * See gst_harness_push_from_src for details.
2285 * Returns: a #GstFlowReturn with the result of the push
2290 gst_harness_push_to_sink (GstHarness * h)
2293 g_assert (h->sink_harness);
2294 buf = gst_harness_pull (h);
2295 g_assert (buf != NULL);
2296 return gst_harness_push (h->sink_harness, buf);
2300 * gst_harness_sink_push_many:
2302 * @pushes: a #gint with the number of calls to gst_harness_push_to_sink
2304 * Convenience that calls gst_harness_push_to_sink @pushes number of times.
2305 * Will abort the pushing if any one push fails.
2309 * Returns: a #GstFlowReturn with the result of the push
2314 gst_harness_sink_push_many (GstHarness * h, gint pushes)
2316 GstFlowReturn ret = GST_FLOW_OK;
2317 g_assert (h->sink_harness);
2318 for (int i = 0; i < pushes; i++) {
2319 ret = gst_harness_push_to_sink (h);
2320 if (ret != GST_FLOW_OK)
2327 * gst_harness_find_element:
2329 * @element_name: a #gchar with a #GstElementFactory name
2331 * Most useful in conjunction with gst_harness_new_parse, this will scan the
2332 * #GstElements inside the #GstHarness, and check if any of them matches
2333 * @element_name. Typical usecase being that you need to access one of the
2334 * harnessed elements for properties and/or signals.
2338 * Returns: (transfer full) (allow-none): a #GstElement or %NULL if not found
2343 gst_harness_find_element (GstHarness * h, const gchar * element_name)
2345 gboolean done = FALSE;
2347 GValue data = G_VALUE_INIT;
2349 iter = gst_bin_iterate_elements (GST_BIN (h->element));
2353 switch (gst_iterator_next (iter, &data)) {
2354 case GST_ITERATOR_OK:
2356 GstElement *element = g_value_get_object (&data);
2357 GstPluginFeature *feature =
2358 GST_PLUGIN_FEATURE (gst_element_get_factory (element));
2359 if (!strcmp (element_name, gst_plugin_feature_get_name (feature))) {
2360 gst_iterator_free (iter);
2363 g_value_reset (&data);
2366 case GST_ITERATOR_RESYNC:
2367 gst_iterator_resync (iter);
2369 case GST_ITERATOR_ERROR:
2370 case GST_ITERATOR_DONE:
2375 gst_iterator_free (iter);
2383 * @element_name: a #gchar with a #GstElementFactory name
2384 * @first_property_name: a #gchar with the first property name
2385 * @...: value for the first property, followed optionally by more
2386 * name/value pairs, followed by %NULL
2388 * A convenience function to allows you to call g_object_set on a #GstElement
2389 * that are residing inside the #GstHarness, by using normal g_object_set
2397 gst_harness_set (GstHarness * h,
2398 const gchar * element_name, const gchar * first_property_name, ...)
2401 GstElement *element = gst_harness_find_element (h, element_name);
2402 va_start (var_args, first_property_name);
2403 g_object_set_valist (G_OBJECT (element), first_property_name, var_args);
2405 gst_object_unref (element);
2411 * @element_name: a #gchar with a #GstElementFactory name
2412 * @first_property_name: a #gchar with the first property name
2413 * @...: return location for the first property, followed optionally by more
2414 * name/return location pairs, followed by %NULL
2416 * A convenience function to allows you to call g_object_get on a #GstElement
2417 * that are residing inside the #GstHarness, by using normal g_object_get
2425 gst_harness_get (GstHarness * h,
2426 const gchar * element_name, const gchar * first_property_name, ...)
2429 GstElement *element = gst_harness_find_element (h, element_name);
2430 va_start (var_args, first_property_name);
2431 g_object_get_valist (G_OBJECT (element), first_property_name, var_args);
2433 gst_object_unref (element);
2437 * gst_harness_add_probe:
2439 * @element_name: a #gchar with a #GstElementFactory name
2440 * @pad_name: a #gchar with the name of the pad to attach the probe to
2441 * @mask: a #GstPadProbeType (see gst_pad_add_probe)
2442 * @callback: a #GstPadProbeCallback (see gst_pad_add_probe)
2443 * @user_data: a #gpointer (see gst_pad_add_probe)
2444 * @destroy_data: a #GDestroyNotify (see gst_pad_add_probe)
2446 * A convenience function to allows you to call gst_pad_add_probe on a
2447 * #GstPad of a #GstElement that are residing inside the #GstHarness,
2448 * by using normal gst_pad_add_probe syntax
2455 gst_harness_add_probe (GstHarness * h,
2456 const gchar * element_name, const gchar * pad_name, GstPadProbeType mask,
2457 GstPadProbeCallback callback, gpointer user_data,
2458 GDestroyNotify destroy_data)
2460 GstElement *element = gst_harness_find_element (h, element_name);
2461 GstPad *pad = gst_element_get_static_pad (element, pad_name);
2462 gst_pad_add_probe (pad, mask, callback, user_data, destroy_data);
2463 gst_object_unref (pad);
2464 gst_object_unref (element);
2467 /******************************************************************************/
2469 /******************************************************************************/
2470 struct _GstHarnessThread
2478 GDestroyNotify freefunc;
2488 } GstHarnessCustomThread;
2496 GstHarnessPrepareBufferFunc func;
2498 GDestroyNotify notify;
2499 } GstHarnessPushBufferThread;
2506 } GstHarnessPushEventThread;
2514 } GstHarnessPropThread;
2520 GstPadTemplate *templ;
2526 } GstHarnessReqPadThread;
2529 gst_harness_thread_init (GstHarnessThread * t, GDestroyNotify freefunc,
2530 GstHarness * h, gulong sleep)
2532 t->freefunc = freefunc;
2536 g_ptr_array_add (h->priv->stress, t);
2540 gst_harness_thread_free (GstHarnessThread * t)
2542 g_slice_free (GstHarnessThread, t);
2546 gst_harness_custom_thread_free (GstHarnessCustomThread * t)
2548 g_slice_free (GstHarnessCustomThread, t);
2552 gst_harness_push_buffer_thread_free (GstHarnessPushBufferThread * t)
2555 gst_caps_replace (&t->caps, NULL);
2556 if (t->notify != NULL)
2557 t->notify (t->data);
2558 g_slice_free (GstHarnessPushBufferThread, t);
2563 gst_harness_push_event_thread_free (GstHarnessPushEventThread * t)
2566 gst_event_replace (&t->event, NULL);
2567 g_slice_free (GstHarnessPushEventThread, t);
2572 gst_harness_property_thread_free (GstHarnessPropThread * t)
2576 g_value_unset (&t->value);
2577 g_slice_free (GstHarnessPropThread, t);
2582 gst_harness_requestpad_release (GstPad * pad, GstElement * element)
2584 gst_element_release_request_pad (element, pad);
2585 gst_object_unref (pad);
2589 gst_harness_requestpad_release_pads (GstHarnessReqPadThread * rpt)
2591 g_slist_foreach (rpt->pads, (GFunc) gst_harness_requestpad_release,
2593 g_slist_free (rpt->pads);
2598 gst_harness_requestpad_thread_free (GstHarnessReqPadThread * t)
2601 gst_object_replace ((GstObject **) & t->templ, NULL);
2603 gst_caps_replace (&t->caps, NULL);
2605 gst_harness_requestpad_release_pads (t);
2606 g_slice_free (GstHarnessReqPadThread, t);
2610 #define GST_HARNESS_THREAD_START(ID, t) \
2611 (((GstHarnessThread *)t)->running = TRUE, \
2612 ((GstHarnessThread *)t)->thread = g_thread_new ( \
2613 "gst-harness-stress-"G_STRINGIFY(ID), \
2614 (GThreadFunc)gst_harness_stress_##ID##_func, t))
2615 #define GST_HARNESS_THREAD_END(t) \
2616 (t->running = FALSE, \
2617 GPOINTER_TO_UINT (g_thread_join (t->thread)))
2620 gst_harness_stress_free (GstHarnessThread * t)
2622 if (t != NULL && t->freefunc != NULL)
2627 gst_harness_stress_custom_func (GstHarnessThread * t)
2629 GstHarnessCustomThread *ct = (GstHarnessCustomThread *) t;
2632 ct->init (ct, ct->data);
2634 while (t->running) {
2635 ct->callback (ct, ct->data);
2638 g_usleep (t->sleep);
2640 return GUINT_TO_POINTER (count);
2645 gst_harness_stress_statechange_func (GstHarnessThread * t)
2649 while (t->running) {
2650 GstClock *clock = gst_element_get_clock (t->h->element);
2652 gboolean done = FALSE;
2655 change = gst_element_set_state (t->h->element, GST_STATE_NULL);
2656 g_assert (change == GST_STATE_CHANGE_SUCCESS);
2659 it = gst_element_iterate_sink_pads (t->h->element);
2661 GValue item = G_VALUE_INIT;
2662 switch (gst_iterator_next (it, &item)) {
2663 case GST_ITERATOR_OK:
2665 GstPad *sinkpad = g_value_get_object (&item);
2666 GstPad *srcpad = gst_pad_get_peer (sinkpad);
2667 if (srcpad != NULL) {
2668 gst_pad_unlink (srcpad, sinkpad);
2669 gst_pad_link (srcpad, sinkpad);
2670 gst_object_unref (srcpad);
2672 g_value_reset (&item);
2675 case GST_ITERATOR_RESYNC:
2676 gst_iterator_resync (it);
2678 case GST_ITERATOR_ERROR:
2679 g_assert_not_reached ();
2680 case GST_ITERATOR_DONE:
2684 g_value_unset (&item);
2686 gst_iterator_free (it);
2688 if (clock != NULL) {
2689 gst_element_set_clock (t->h->element, clock);
2690 gst_object_unref (clock);
2692 change = gst_element_set_state (t->h->element, GST_STATE_PLAYING);
2693 g_assert (change == GST_STATE_CHANGE_SUCCESS);
2696 g_usleep (t->sleep);
2698 return GUINT_TO_POINTER (count);
2702 gst_harness_stress_buffer_func (GstHarnessThread * t)
2704 GstHarnessPushBufferThread *pt = (GstHarnessPushBufferThread *) t;
2709 /* Push stream start, caps and segment events */
2710 sid = g_strdup_printf ("%s-%p", GST_OBJECT_NAME (t->h->element), t->h);
2711 handled = gst_pad_push_event (t->h->srcpad, gst_event_new_stream_start (sid));
2714 handled = gst_pad_push_event (t->h->srcpad, gst_event_new_caps (pt->caps));
2716 handled = gst_pad_push_event (t->h->srcpad,
2717 gst_event_new_segment (&pt->segment));
2720 while (t->running) {
2721 gst_harness_push (t->h, pt->func (t->h, pt->data));
2724 g_usleep (t->sleep);
2726 return GUINT_TO_POINTER (count);
2730 gst_harness_stress_event_func (GstHarnessThread * t)
2732 GstHarnessPushEventThread *pet = (GstHarnessPushEventThread *) t;
2735 while (t->running) {
2736 gst_harness_push_event (t->h, gst_event_ref (pet->event));
2739 g_usleep (t->sleep);
2741 return GUINT_TO_POINTER (count);
2745 gst_harness_stress_upstream_event_func (GstHarnessThread * t)
2747 GstHarnessPushEventThread *pet = (GstHarnessPushEventThread *) t;
2750 while (t->running) {
2751 gst_harness_push_upstream_event (t->h, gst_event_ref (pet->event));
2754 g_usleep (t->sleep);
2756 return GUINT_TO_POINTER (count);
2760 gst_harness_stress_property_func (GstHarnessThread * t)
2762 GstHarnessPropThread *pt = (GstHarnessPropThread *) t;
2765 while (t->running) {
2766 GValue value = G_VALUE_INIT;
2768 g_object_set_property (G_OBJECT (t->h->element), pt->name, &pt->value);
2770 g_value_init (&value, G_VALUE_TYPE (&pt->value));
2771 g_object_get_property (G_OBJECT (t->h->element), pt->name, &value);
2772 g_value_reset (&value);
2775 g_usleep (t->sleep);
2777 return GUINT_TO_POINTER (count);
2781 gst_harness_stress_requestpad_func (GstHarnessThread * t)
2783 GstHarnessReqPadThread *rpt = (GstHarnessReqPadThread *) t;
2786 while (t->running) {
2790 gst_harness_requestpad_release_pads (rpt);
2794 reqpad = gst_element_request_pad (t->h->element,
2795 rpt->templ, rpt->name, rpt->caps);
2797 g_assert (reqpad != NULL);
2799 rpt->pads = g_slist_prepend (rpt->pads, reqpad);
2802 g_usleep (t->sleep);
2804 return GUINT_TO_POINTER (count);
2808 * gst_harness_stress_thread_stop:
2809 * @t: a #GstHarnessThread
2811 * Stop the running #GstHarnessThread
2818 gst_harness_stress_thread_stop (GstHarnessThread * t)
2822 g_return_val_if_fail (t != NULL, 0);
2824 ret = GST_HARNESS_THREAD_END (t);
2825 g_ptr_array_remove (t->h->priv->stress, t);
2830 * gst_harness_stress_custom_start: (skip)
2832 * @init: a #GFunc that is called initially and only once
2833 * @callback: a #GFunc that is called as often as possible
2834 * @data: a #gpointer with custom data to pass to the @callback function
2835 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
2836 * each call to the @callback
2838 * Start a custom stress-thread that will call your @callback for every
2839 * iteration allowing you to do something nasty.
2843 * Returns: a #GstHarnessThread
2848 gst_harness_stress_custom_start (GstHarness * h,
2849 GFunc init, GFunc callback, gpointer data, gulong sleep)
2851 GstHarnessCustomThread *t = g_slice_new0 (GstHarnessCustomThread);
2852 gst_harness_thread_init (&t->t,
2853 (GDestroyNotify) gst_harness_custom_thread_free, h, sleep);
2856 t->callback = callback;
2859 GST_HARNESS_THREAD_START (custom, t);
2864 * gst_harness_stress_statechange_start_full: (skip)
2866 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
2869 * Change the state of your harnessed #GstElement from NULL to PLAYING and
2870 * back again, only pausing for @sleep microseconds every time.
2874 * Returns: a #GstHarnessThread
2879 gst_harness_stress_statechange_start_full (GstHarness * h, gulong sleep)
2881 GstHarnessThread *t = g_slice_new0 (GstHarnessThread);
2882 gst_harness_thread_init (t,
2883 (GDestroyNotify) gst_harness_thread_free, h, sleep);
2884 GST_HARNESS_THREAD_START (statechange, t);
2889 gst_harness_ref_buffer (GstHarness * h, gpointer data)
2892 return gst_buffer_ref (GST_BUFFER_CAST (data));
2896 * gst_harness_stress_push_buffer_start_full: (skip)
2898 * @caps: a #GstCaps for the #GstBuffer
2899 * @segment: a #GstSegment
2900 * @buf: a #GstBuffer to push
2901 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
2902 * each call to gst_pad_push
2904 * Push a #GstBuffer in intervals of @sleep microseconds.
2908 * Returns: a #GstHarnessThread
2913 gst_harness_stress_push_buffer_start_full (GstHarness * h,
2914 GstCaps * caps, const GstSegment * segment, GstBuffer * buf, gulong sleep)
2916 return gst_harness_stress_push_buffer_with_cb_start_full (h, caps, segment,
2917 gst_harness_ref_buffer, gst_buffer_ref (buf),
2918 (GDestroyNotify) gst_buffer_unref, sleep);
2922 * gst_harness_stress_push_buffer_with_cb_start_full: (skip)
2924 * @caps: a #GstCaps for the #GstBuffer
2925 * @segment: a #GstSegment
2926 * @func: a #GstHarnessPrepareBufferFunc function called before every iteration
2927 * to prepare / create a #GstBuffer for pushing
2928 * @data: a #gpointer with data to the #GstHarnessPrepareBufferFunc function
2929 * @notify: a #GDestroyNotify that is called for every push to allow cleaning
2930 * up the #GstBuffer. (like gst_buffer_unref)
2931 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
2932 * each call to gst_pad_push
2934 * Push a #GstBuffer in intervals of @sleep microseconds.
2938 * Returns: a #GstHarnessThread
2943 gst_harness_stress_push_buffer_with_cb_start_full (GstHarness * h,
2944 GstCaps * caps, const GstSegment * segment,
2945 GstHarnessPrepareBufferFunc func, gpointer data, GDestroyNotify notify,
2948 GstHarnessPushBufferThread *t = g_slice_new0 (GstHarnessPushBufferThread);
2949 gst_harness_thread_init (&t->t,
2950 (GDestroyNotify) gst_harness_push_buffer_thread_free, h, sleep);
2952 gst_caps_replace (&t->caps, caps);
2953 t->segment = *segment;
2958 GST_HARNESS_THREAD_START (buffer, t);
2963 * gst_harness_stress_push_event_start_full: (skip)
2965 * @event: a #GstEvent to push
2966 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
2967 * each gst_event_push with @event
2969 * Push the @event onto the harnessed #GstElement sinkpad in intervals of
2970 * @sleep microseconds
2974 * Returns: a #GstHarnessThread
2979 gst_harness_stress_push_event_start_full (GstHarness * h,
2980 GstEvent * event, gulong sleep)
2982 GstHarnessPushEventThread *t = g_slice_new0 (GstHarnessPushEventThread);
2983 gst_harness_thread_init (&t->t,
2984 (GDestroyNotify) gst_harness_push_event_thread_free, h, sleep);
2986 t->event = gst_event_ref (event);
2987 GST_HARNESS_THREAD_START (event, t);
2992 * gst_harness_stress_push_upstream_event_start_full: (skip)
2994 * @event: a #GstEvent to push
2995 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
2996 * each gst_event_push with @event
2998 * Push the @event onto the harnessed #GstElement srcpad in intervals of
2999 * @sleep microseconds.
3000 * Pushing events should generally be OOB events.
3001 * If you need serialized events, you may use a custom stress thread which
3002 * both pushes buffers and events.
3006 * Returns: a #GstHarnessThread
3011 gst_harness_stress_push_upstream_event_start_full (GstHarness * h,
3012 GstEvent * event, gulong sleep)
3014 GstHarnessPushEventThread *t = g_slice_new0 (GstHarnessPushEventThread);
3015 gst_harness_thread_init (&t->t,
3016 (GDestroyNotify) gst_harness_push_event_thread_free, h, sleep);
3018 t->event = gst_event_ref (event);
3019 GST_HARNESS_THREAD_START (upstream_event, t);
3024 * gst_harness_stress_property_start_full: (skip)
3026 * @name: a #gchar specifying a property name
3027 * @value: a #GValue to set the property to
3028 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3029 * each g_object_set with @name and @value
3031 * Call g_object_set with @name and @value in intervals of @sleep microseconds
3035 * Returns: a #GstHarnessThread
3040 gst_harness_stress_property_start_full (GstHarness * h,
3041 const gchar * name, const GValue * value, gulong sleep)
3043 GstHarnessPropThread *t = g_slice_new0 (GstHarnessPropThread);
3044 gst_harness_thread_init (&t->t,
3045 (GDestroyNotify) gst_harness_property_thread_free, h, sleep);
3047 t->name = g_strdup (name);
3048 g_value_init (&t->value, G_VALUE_TYPE (value));
3049 g_value_copy (value, &t->value);
3051 GST_HARNESS_THREAD_START (property, t);
3056 * gst_harness_stress_requestpad_start_full: (skip)
3058 * @templ: a #GstPadTemplate
3061 * @release: a #gboolean
3062 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3063 * each gst_element_request_pad
3065 * Call gst_element_request_pad in intervals of @sleep microseconds
3069 * Returns: a #GstHarnessThread
3074 gst_harness_stress_requestpad_start_full (GstHarness * h,
3075 GstPadTemplate * templ, const gchar * name, GstCaps * caps,
3076 gboolean release, gulong sleep)
3078 GstHarnessReqPadThread *t = g_slice_new0 (GstHarnessReqPadThread);
3079 gst_harness_thread_init (&t->t,
3080 (GDestroyNotify) gst_harness_requestpad_thread_free, h, sleep);
3082 t->templ = gst_object_ref (templ);
3083 t->name = g_strdup (name);
3084 gst_caps_replace (&t->caps, caps);
3085 t->release = release;
3087 GST_HARNESS_THREAD_START (requestpad, t);