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.
24 * @short_description: A test-harness for writing GStreamer unit tests
25 * @see_also: #GstTestClock
27 * #GstHarness is meant to make writing unit test for GStreamer much easier.
28 * It can be thought of as a way of treating a #GstElement as a black box,
29 * deterministically feeding it data, and controlling what data it outputs.
31 * The basic structure of #GstHarness is two "floating" #GstPads that connect
32 * to the harnessed #GstElement src and sink #GstPads like so:
35 * __________________________
36 * _____ | _____ _____ | _____
38 * | src |--+-| sink| Element | src |-+--| sink|
39 * |_____| | |_____| |_____| | |_____|
40 * |__________________________|
44 * With this, you can now simulate any environment the #GstElement might find
45 * itself in. By specifying the #GstCaps of the harness #GstPads, using
46 * functions like gst_harness_set_src_caps() or gst_harness_set_sink_caps_str(),
47 * you can test how the #GstElement interacts with different caps sets.
49 * Your harnessed #GstElement can of course also be a bin, and using
50 * gst_harness_new_parse() supporting standard gst-launch syntax, you can
51 * easily test a whole pipeline instead of just one element.
53 * You can then go on to push #GstBuffers and #GstEvents on to the srcpad,
54 * using functions like gst_harness_push() and gst_harness_push_event(), and
55 * then pull them out to examine them with gst_harness_pull() and
56 * gst_harness_pull_event().
58 * ## A simple buffer-in buffer-out example
60 * |[<!-- language="C" -->
61 * #include <gst/gst.h>
62 * #include <gst/check/gstharness.h>
67 * // attach the harness to the src and sink pad of GstQueue
68 * h = gst_harness_new ("queue");
70 * // we must specify a caps before pushing buffers
71 * gst_harness_set_src_caps_str (h, "mycaps");
73 * // create a buffer of size 42
74 * in_buf = gst_harness_create_buffer (h, 42);
76 * // push the buffer into the queue
77 * gst_harness_push (h, in_buf);
79 * // pull the buffer from the queue
80 * out_buf = gst_harness_pull (h);
82 * // validate the buffer in is the same as buffer out
83 * fail_unless (in_buf == out_buf);
86 * gst_buffer_unref (out_buf);
87 * 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:
107 * |[<!-- language="C" -->
108 * GstHarness * h = gst_harness_new (h, "vp8dec");
109 * gst_harness_add_src_parse (h, "videotestsrc is-live=1 ! vp8enc", TRUE);
112 * and then feeding it data with:
114 * |[<!-- language="C" -->
115 * gst_harness_push_from_src (h);
123 /* we have code with side effects in asserts, so make sure they are active */
124 #ifdef G_DISABLE_ASSERT
125 #error "GstHarness must be compiled with G_DISABLE_ASSERT undefined"
128 #include "gstharness.h"
134 static void gst_harness_stress_free (GstHarnessThread * t);
136 #define HARNESS_KEY "harness"
137 #define HARNESS_REF "harness-ref"
138 #define HARNESS_LOCK(h) g_mutex_lock (&(h)->priv->priv_mutex)
139 #define HARNESS_UNLOCK(h) g_mutex_unlock (&(h)->priv->priv_mutex)
141 static GstStaticPadTemplate hsrctemplate = GST_STATIC_PAD_TEMPLATE ("src",
144 GST_STATIC_CAPS_ANY);
145 static GstStaticPadTemplate hsinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
148 GST_STATIC_CAPS_ANY);
153 GstStructure *params;
157 propose_meta_clear (ProposeMeta * meta)
160 gst_structure_free (meta->params);
163 struct _GstHarnessPrivate
165 gchar *element_sinkpad_name;
166 gchar *element_srcpad_name;
172 GstPad *sink_forward_pad;
173 GstTestClock *testclock;
177 gint recv_upstream_events;
179 GAsyncQueue *buffer_queue;
180 GAsyncQueue *src_event_queue;
181 GAsyncQueue *sink_event_queue;
183 GstClockTime latency_min;
184 GstClockTime latency_max;
187 gboolean has_clock_wait;
188 gboolean drop_buffers;
189 GstClockTime last_push_ts;
192 GstAllocator *allocator;
193 GstAllocationParams allocation_params;
194 GstAllocator *propose_allocator;
195 GstAllocationParams propose_allocation_params;
197 GArray *propose_allocation_metas;
199 gboolean blocking_push_mode;
200 GCond blocking_push_cond;
201 GMutex blocking_push_mutex;
204 GCond buf_or_eos_cond;
205 GMutex buf_or_eos_mutex;
206 gboolean eos_received;
212 gst_harness_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
214 GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
215 GstHarnessPrivate *priv = h->priv;
217 g_assert (h != NULL);
218 g_mutex_lock (&priv->blocking_push_mutex);
219 g_atomic_int_inc (&priv->recv_buffers);
221 if (priv->drop_buffers) {
222 gst_buffer_unref (buffer);
224 g_mutex_lock (&priv->buf_or_eos_mutex);
225 g_async_queue_push (priv->buffer_queue, buffer);
226 g_cond_signal (&priv->buf_or_eos_cond);
227 g_mutex_unlock (&priv->buf_or_eos_mutex);
231 if (priv->blocking_push_mode) {
232 g_cond_wait (&priv->blocking_push_cond, &priv->blocking_push_mutex);
234 g_mutex_unlock (&priv->blocking_push_mutex);
240 gst_harness_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
242 GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
243 GstHarnessPrivate *priv = h->priv;
245 g_assert (h != NULL);
246 g_atomic_int_inc (&priv->recv_upstream_events);
247 g_async_queue_push (priv->src_event_queue, event);
252 gst_harness_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
254 GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
255 GstHarnessPrivate *priv = h->priv;
259 g_assert (h != NULL);
261 g_atomic_int_inc (&priv->recv_events);
263 switch (GST_EVENT_TYPE (event)) {
264 case GST_EVENT_STREAM_START:
266 case GST_EVENT_SEGMENT:
275 if (priv->forwarding && forward && priv->sink_forward_pad) {
276 GstPad *fwdpad = gst_object_ref (priv->sink_forward_pad);
278 ret = gst_pad_push_event (fwdpad, event);
279 gst_object_unref (fwdpad);
282 if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
283 g_mutex_lock (&priv->buf_or_eos_mutex);
284 priv->eos_received = TRUE;
285 g_cond_signal (&priv->buf_or_eos_cond);
286 g_mutex_unlock (&priv->buf_or_eos_mutex);
288 g_async_queue_push (priv->sink_event_queue, event);
296 gst_harness_decide_allocation (GstHarness * h, GstCaps * caps)
298 GstHarnessPrivate *priv = h->priv;
300 GstAllocator *allocator;
301 GstAllocationParams params;
302 GstBufferPool *pool = NULL;
303 guint size, min, max;
305 query = gst_query_new_allocation (caps, FALSE);
306 gst_pad_peer_query (h->srcpad, query);
308 if (gst_query_get_n_allocation_params (query) > 0) {
309 gst_query_parse_nth_allocation_param (query, 0, &allocator, ¶ms);
312 gst_allocation_params_init (¶ms);
315 if (gst_query_get_n_allocation_pools (query) > 0) {
316 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
318 /* Most elements create their own pools if pool == NULL. Not sure if we
319 * want to do that in the harness since we may want to test the pool
320 * implementation of the elements. Not creating a pool will however ignore
321 * the returned size. */
323 pool = gst_buffer_pool_new ();
327 size = min = max = 0;
329 gst_query_unref (query);
332 GstStructure *config = gst_buffer_pool_get_config (pool);
333 gst_buffer_pool_config_set_params (config, caps, size, min, max);
334 gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
335 gst_buffer_pool_set_config (pool, config);
338 if (pool != priv->pool) {
339 if (priv->pool != NULL)
340 gst_buffer_pool_set_active (priv->pool, FALSE);
342 gst_buffer_pool_set_active (pool, TRUE);
345 priv->allocation_params = params;
347 gst_object_unref (priv->allocator);
348 priv->allocator = allocator;
350 gst_object_unref (priv->pool);
355 gst_harness_negotiate (GstHarness * h)
359 caps = gst_pad_get_current_caps (h->srcpad);
361 gst_harness_decide_allocation (h, caps);
362 gst_caps_unref (caps);
364 GST_FIXME_OBJECT (h->srcpad,
365 "Cannot negotiate allocation because caps is not set");
370 gst_harness_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
372 GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
373 GstHarnessPrivate *priv = h->priv;
375 g_assert (h != NULL);
377 // FIXME: forward all queries?
379 switch (GST_QUERY_TYPE (query)) {
380 case GST_QUERY_LATENCY:
381 gst_query_set_latency (query, priv->is_live, priv->latency_min,
386 GstCaps *caps, *filter = NULL;
388 if (priv->sink_caps) {
389 caps = gst_caps_ref (priv->sink_caps);
391 caps = gst_pad_get_pad_template_caps (pad);
394 gst_query_parse_caps (query, &filter);
395 if (filter != NULL) {
396 gst_caps_take (&caps,
397 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST));
400 gst_query_set_caps_result (query, caps);
401 gst_caps_unref (caps);
404 case GST_QUERY_ALLOCATION:
407 if (priv->forwarding && priv->sink_forward_pad != NULL) {
408 GstPad *peer = gst_pad_get_peer (priv->sink_forward_pad);
409 g_assert (peer != NULL);
411 res = gst_pad_query (peer, query);
412 gst_object_unref (peer);
419 gst_query_parse_allocation (query, &caps, &need_pool);
421 /* FIXME: Can this be removed? */
422 size = gst_query_get_n_allocation_params (query);
423 g_assert_cmpuint (0, ==, size);
424 gst_query_add_allocation_param (query,
425 priv->propose_allocator, &priv->propose_allocation_params);
427 if (priv->propose_allocation_metas) {
429 for (i = 0; i < priv->propose_allocation_metas->len; i++) {
431 &g_array_index (priv->propose_allocation_metas, ProposeMeta, i);
432 gst_query_add_allocation_meta (query, meta->api, meta->params);
436 GST_DEBUG_OBJECT (pad, "proposing allocation %" GST_PTR_FORMAT,
437 priv->propose_allocator);
442 case GST_QUERY_CONTEXT:
444 if (priv->forwarding && priv->sink_forward_pad != NULL) {
445 GstPad *peer = gst_pad_get_peer (priv->sink_forward_pad);
446 g_assert (peer != NULL);
448 res = gst_pad_query (peer, query);
449 gst_object_unref (peer);
452 res = gst_pad_query_default (pad, parent, query);
456 res = gst_pad_query_default (pad, parent, query);
463 gst_harness_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
465 GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
466 GstHarnessPrivate *priv = h->priv;
468 g_assert (h != NULL);
470 switch (GST_QUERY_TYPE (query)) {
471 case GST_QUERY_LATENCY:
472 gst_query_set_latency (query, priv->is_live, priv->latency_min,
477 GstCaps *caps, *filter = NULL;
479 if (priv->src_caps) {
480 caps = gst_caps_ref (priv->src_caps);
482 caps = gst_pad_get_pad_template_caps (pad);
485 gst_query_parse_caps (query, &filter);
486 if (filter != NULL) {
487 gst_caps_take (&caps,
488 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST));
491 gst_query_set_caps_result (query, caps);
492 gst_caps_unref (caps);
496 res = gst_pad_query_default (pad, parent, query);
502 gst_harness_element_ref (GstHarness * h)
506 GST_OBJECT_LOCK (h->element);
507 data = g_object_get_data (G_OBJECT (h->element), HARNESS_REF);
509 data = g_new0 (guint, 1);
511 g_object_set_data_full (G_OBJECT (h->element), HARNESS_REF, data, g_free);
515 GST_OBJECT_UNLOCK (h->element);
519 gst_harness_element_unref (GstHarness * h)
524 GST_OBJECT_LOCK (h->element);
525 data = g_object_get_data (G_OBJECT (h->element), HARNESS_REF);
526 g_assert (data != NULL);
529 GST_OBJECT_UNLOCK (h->element);
535 gst_harness_link_element_srcpad (GstHarness * h,
536 const gchar * element_srcpad_name)
538 GstHarnessPrivate *priv = h->priv;
539 GstPad *srcpad = gst_element_get_static_pad (h->element,
540 element_srcpad_name);
541 GstPadLinkReturn link;
543 srcpad = gst_element_get_request_pad (h->element, element_srcpad_name);
545 link = gst_pad_link (srcpad, h->sinkpad);
546 g_assert_cmpint (link, ==, GST_PAD_LINK_OK);
547 g_free (priv->element_srcpad_name);
548 priv->element_srcpad_name = gst_pad_get_name (srcpad);
550 gst_object_unref (srcpad);
554 gst_harness_link_element_sinkpad (GstHarness * h,
555 const gchar * element_sinkpad_name)
557 GstHarnessPrivate *priv = h->priv;
558 GstPad *sinkpad = gst_element_get_static_pad (h->element,
559 element_sinkpad_name);
560 GstPadLinkReturn link;
562 sinkpad = gst_element_get_request_pad (h->element, element_sinkpad_name);
564 link = gst_pad_link (h->srcpad, sinkpad);
565 g_assert_cmpint (link, ==, GST_PAD_LINK_OK);
566 g_free (priv->element_sinkpad_name);
567 priv->element_sinkpad_name = gst_pad_get_name (sinkpad);
569 gst_object_unref (sinkpad);
573 gst_harness_setup_src_pad (GstHarness * h,
574 GstStaticPadTemplate * src_tmpl, const gchar * element_sinkpad_name)
577 g_assert (h->srcpad == NULL);
580 h->srcpad = gst_pad_new_from_static_template (src_tmpl, "src");
581 g_assert (h->srcpad);
582 g_object_set_data (G_OBJECT (h->srcpad), HARNESS_KEY, h);
584 gst_pad_set_query_function (h->srcpad, gst_harness_src_query);
585 gst_pad_set_event_function (h->srcpad, gst_harness_src_event);
587 gst_pad_set_active (h->srcpad, TRUE);
589 if (element_sinkpad_name)
590 gst_harness_link_element_sinkpad (h, element_sinkpad_name);
594 gst_harness_setup_sink_pad (GstHarness * h,
595 GstStaticPadTemplate * sink_tmpl, const gchar * element_srcpad_name)
597 g_assert (sink_tmpl);
598 g_assert (h->sinkpad == NULL);
601 h->sinkpad = gst_pad_new_from_static_template (sink_tmpl, "sink");
602 g_assert (h->sinkpad);
603 g_object_set_data (G_OBJECT (h->sinkpad), HARNESS_KEY, h);
605 gst_pad_set_chain_function (h->sinkpad, gst_harness_chain);
606 gst_pad_set_query_function (h->sinkpad, gst_harness_sink_query);
607 gst_pad_set_event_function (h->sinkpad, gst_harness_sink_event);
609 gst_pad_set_active (h->sinkpad, TRUE);
611 if (element_srcpad_name)
612 gst_harness_link_element_srcpad (h, element_srcpad_name);
616 check_element_type (GstElement * element, gboolean * has_sinkpad,
617 gboolean * has_srcpad)
619 GstElementClass *element_class = GST_ELEMENT_GET_CLASS (element);
620 const GList *tmpl_list;
622 *has_srcpad = element->numsrcpads > 0;
623 *has_sinkpad = element->numsinkpads > 0;
625 tmpl_list = gst_element_class_get_pad_template_list (element_class);
628 GstPadTemplate *pad_tmpl = (GstPadTemplate *) tmpl_list->data;
629 tmpl_list = g_list_next (tmpl_list);
630 if (GST_PAD_TEMPLATE_DIRECTION (pad_tmpl) == GST_PAD_SRC)
632 if (GST_PAD_TEMPLATE_DIRECTION (pad_tmpl) == GST_PAD_SINK)
633 *has_sinkpad |= TRUE;
638 turn_async_and_sync_off (GstElement * element)
640 GObjectClass *class = G_OBJECT_GET_CLASS (element);
641 if (g_object_class_find_property (class, "async"))
642 g_object_set (element, "async", FALSE, NULL);
643 if (g_object_class_find_property (class, "sync"))
644 g_object_set (element, "sync", FALSE, NULL);
648 gst_pad_is_request_pad (GstPad * pad)
650 GstPadTemplate *temp;
655 temp = gst_pad_get_pad_template (pad);
658 is_request = GST_PAD_TEMPLATE_PRESENCE (temp) == GST_PAD_REQUEST;
659 gst_object_unref (temp);
664 * gst_harness_new_empty: (skip)
666 * Creates a new empty harness. Use gst_harness_add_element_full() to add
667 * an #GstElement to it.
671 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
677 gst_harness_new_empty (void)
680 GstHarnessPrivate *priv;
682 h = g_new0 (GstHarness, 1);
683 g_assert (h != NULL);
684 h->priv = g_new0 (GstHarnessPrivate, 1);
687 GST_DEBUG ("about to create new harness %p", h);
688 priv->last_push_ts = GST_CLOCK_TIME_NONE;
689 priv->latency_min = 0;
690 priv->latency_max = GST_CLOCK_TIME_NONE;
691 priv->is_live = TRUE;
692 priv->drop_buffers = FALSE;
693 priv->testclock = GST_TEST_CLOCK_CAST (gst_test_clock_new ());
695 priv->buffer_queue = g_async_queue_new_full (
696 (GDestroyNotify) gst_buffer_unref);
697 priv->src_event_queue = g_async_queue_new_full (
698 (GDestroyNotify) gst_event_unref);
699 priv->sink_event_queue = g_async_queue_new_full (
700 (GDestroyNotify) gst_event_unref);
702 priv->propose_allocator = NULL;
703 gst_allocation_params_init (&priv->propose_allocation_params);
705 g_mutex_init (&priv->blocking_push_mutex);
706 g_cond_init (&priv->blocking_push_cond);
707 g_mutex_init (&priv->priv_mutex);
709 g_mutex_init (&priv->buf_or_eos_mutex);
710 g_cond_init (&priv->buf_or_eos_cond);
711 priv->eos_received = FALSE;
713 priv->stress = g_ptr_array_new_with_free_func (
714 (GDestroyNotify) gst_harness_stress_free);
716 /* we have forwarding on as a default */
717 gst_harness_set_forwarding (h, TRUE);
723 * gst_harness_add_element_full: (skip)
725 * @element: a #GstElement to add to the harness (transfer none)
726 * @hsrc: (allow-none): a #GstStaticPadTemplate describing the harness srcpad.
727 * %NULL will not create a harness srcpad.
728 * @element_sinkpad_name: (allow-none): a #gchar with the name of the element
729 * sinkpad that is then linked to the harness srcpad. Can be a static or request
730 * or a sometimes pad that has been added. %NULL will not get/request a sinkpad
731 * from the element. (Like if the element is a src.)
732 * @hsink: (allow-none): a #GstStaticPadTemplate describing the harness sinkpad.
733 * %NULL will not create a harness sinkpad.
734 * @element_srcpad_name: (allow-none): a #gchar with the name of the element
735 * srcpad that is then linked to the harness sinkpad, similar to the
736 * @element_sinkpad_name.
738 * Adds a #GstElement to an empty #GstHarness
745 gst_harness_add_element_full (GstHarness * h, GstElement * element,
746 GstStaticPadTemplate * hsrc, const gchar * element_sinkpad_name,
747 GstStaticPadTemplate * hsink, const gchar * element_srcpad_name)
749 GstClock *element_clock;
750 gboolean has_sinkpad, has_srcpad;
752 g_return_if_fail (element != NULL);
753 g_return_if_fail (h->element == NULL);
755 element_clock = GST_ELEMENT_CLOCK (element);
756 h->element = gst_object_ref (element);
757 check_element_type (element, &has_sinkpad, &has_srcpad);
759 /* setup the loose srcpad linked to the element sinkpad */
761 gst_harness_setup_src_pad (h, hsrc, element_sinkpad_name);
763 /* setup the loose sinkpad linked to the element srcpad */
765 gst_harness_setup_sink_pad (h, hsink, element_srcpad_name);
767 /* as a harness sink, we should not need sync and async */
768 if (has_sinkpad && !has_srcpad)
769 turn_async_and_sync_off (h->element);
771 if (h->srcpad != NULL) {
773 gchar *stream_id = g_strdup_printf ("%s-%p",
774 GST_OBJECT_NAME (h->element), h);
775 handled = gst_pad_push_event (h->srcpad,
776 gst_event_new_stream_start (stream_id));
781 /* if the element already has a testclock attached,
782 we replace our own with it, if no clock we attach the testclock */
784 if (GST_IS_TEST_CLOCK (element_clock)) {
785 gst_object_replace ((GstObject **) & h->priv->testclock,
786 (GstObject *) GST_ELEMENT_CLOCK (element));
789 gst_harness_use_testclock (h);
792 /* don't start sources, they start producing data! */
794 gst_harness_play (h);
796 gst_harness_element_ref (h);
798 GST_DEBUG ("added element to harness %p "
799 "with element_srcpad_name (%p, %s, %s) and element_sinkpad_name (%p, %s, %s)",
800 h, h->srcpad, GST_DEBUG_PAD_NAME (h->srcpad),
801 h->sinkpad, GST_DEBUG_PAD_NAME (h->sinkpad));
805 * gst_harness_new_full: (skip)
806 * @element: a #GstElement to attach the harness to (transfer none)
807 * @hsrc: (allow-none): a #GstStaticPadTemplate describing the harness srcpad.
808 * %NULL will not create a harness srcpad.
809 * @element_sinkpad_name: (allow-none): a #gchar with the name of the element
810 * sinkpad that is then linked to the harness srcpad. Can be a static or request
811 * or a sometimes pad that has been added. %NULL will not get/request a sinkpad
812 * from the element. (Like if the element is a src.)
813 * @hsink: (allow-none): a #GstStaticPadTemplate describing the harness sinkpad.
814 * %NULL will not create a harness sinkpad.
815 * @element_srcpad_name: (allow-none): a #gchar with the name of the element
816 * srcpad that is then linked to the harness sinkpad, similar to the
817 * @element_sinkpad_name.
819 * Creates a new harness.
823 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
829 gst_harness_new_full (GstElement * element,
830 GstStaticPadTemplate * hsrc, const gchar * element_sinkpad_name,
831 GstStaticPadTemplate * hsink, const gchar * element_srcpad_name)
834 h = gst_harness_new_empty ();
835 gst_harness_add_element_full (h, element,
836 hsrc, element_sinkpad_name, hsink, element_srcpad_name);
841 * gst_harness_new_with_element: (skip)
842 * @element: a #GstElement to attach the harness to (transfer none)
843 * @element_sinkpad_name: (allow-none): a #gchar with the name of the element
844 * sinkpad that is then linked to the harness srcpad. %NULL does not attach a
846 * @element_srcpad_name: (allow-none): a #gchar with the name of the element
847 * srcpad that is then linked to the harness sinkpad. %NULL does not attach a
850 * Creates a new harness. Works in the same way as gst_harness_new_full(), only
851 * that generic padtemplates are used for the harness src and sinkpads, which
852 * will be sufficient in most usecases.
856 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
862 gst_harness_new_with_element (GstElement * element,
863 const gchar * element_sinkpad_name, const gchar * element_srcpad_name)
865 return gst_harness_new_full (element,
866 &hsrctemplate, element_sinkpad_name, &hsinktemplate, element_srcpad_name);
870 * gst_harness_new_with_padnames: (skip)
871 * @element_name: a #gchar describing the #GstElement name
872 * @element_sinkpad_name: (allow-none): a #gchar with the name of the element
873 * sinkpad that is then linked to the harness srcpad. %NULL does not attach a
875 * @element_srcpad_name: (allow-none): a #gchar with the name of the element
876 * srcpad that is then linked to the harness sinkpad. %NULL does not attach a
879 * Creates a new harness. Works like gst_harness_new_with_element(),
880 * except you specify the factoryname of the #GstElement
884 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
890 gst_harness_new_with_padnames (const gchar * element_name,
891 const gchar * element_sinkpad_name, const gchar * element_srcpad_name)
894 GstElement *element = gst_element_factory_make (element_name, NULL);
895 g_assert (element != NULL);
897 h = gst_harness_new_with_element (element, element_sinkpad_name,
898 element_srcpad_name);
899 gst_object_unref (element);
904 * gst_harness_new_with_templates: (skip)
905 * @element_name: a #gchar describing the #GstElement name
906 * @hsrc: (allow-none): a #GstStaticPadTemplate describing the harness srcpad.
907 * %NULL will not create a harness srcpad.
908 * @hsink: (allow-none): a #GstStaticPadTemplate describing the harness sinkpad.
909 * %NULL will not create a harness sinkpad.
911 * Creates a new harness, like gst_harness_new_full(), except it
912 * assumes the #GstElement sinkpad is named "sink" and srcpad is named "src"
916 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
922 gst_harness_new_with_templates (const gchar * element_name,
923 GstStaticPadTemplate * hsrc, GstStaticPadTemplate * hsink)
926 GstElement *element = gst_element_factory_make (element_name, NULL);
927 g_assert (element != NULL);
929 h = gst_harness_new_full (element, hsrc, "sink", hsink, "src");
930 gst_object_unref (element);
935 * gst_harness_new: (skip)
936 * @element_name: a #gchar describing the #GstElement name
938 * Creates a new harness. Works like gst_harness_new_with_padnames(), except it
939 * assumes the #GstElement sinkpad is named "sink" and srcpad is named "src"
943 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
949 gst_harness_new (const gchar * element_name)
951 return gst_harness_new_with_padnames (element_name, "sink", "src");
955 * gst_harness_add_parse: (skip)
957 * @launchline: a #gchar describing a gst-launch type line
959 * Parses the @launchline and puts that in a #GstBin,
960 * and then attches the supplied #GstHarness to the bin.
967 gst_harness_add_parse (GstHarness * h, const gchar * launchline)
973 gboolean done = FALSE;
974 GError *error = NULL;
976 g_return_if_fail (launchline != NULL);
978 desc = g_strdup_printf ("bin.( %s )", launchline);
980 (GstBin *) gst_parse_launch_full (desc, NULL, GST_PARSE_FLAG_FATAL_ERRORS,
983 if (G_UNLIKELY (error != NULL)) {
984 g_error ("Unable to create pipeline '%s': %s", desc, error->message);
988 /* find pads and ghost them if necessary */
989 if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SRC)) != NULL) {
990 gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", pad));
991 gst_object_unref (pad);
993 if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SINK)) != NULL) {
994 gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", pad));
995 gst_object_unref (pad);
998 iter = gst_bin_iterate_sinks (bin);
1000 GValue item = { 0, };
1002 switch (gst_iterator_next (iter, &item)) {
1003 case GST_ITERATOR_OK:
1004 turn_async_and_sync_off (GST_ELEMENT (g_value_get_object (&item)));
1005 g_value_reset (&item);
1007 case GST_ITERATOR_DONE:
1010 case GST_ITERATOR_RESYNC:
1011 gst_iterator_resync (iter);
1013 case GST_ITERATOR_ERROR:
1014 gst_object_unref (bin);
1015 gst_iterator_free (iter);
1016 g_return_if_reached ();
1020 gst_iterator_free (iter);
1022 gst_harness_add_element_full (h, GST_ELEMENT_CAST (bin),
1023 &hsrctemplate, "sink", &hsinktemplate, "src");
1024 gst_object_unref (bin);
1028 * gst_harness_new_parse: (skip)
1029 * @launchline: a #gchar describing a gst-launch type line
1031 * Creates a new harness, parsing the @launchline and putting that in a #GstBin,
1032 * and then attches the harness to the bin.
1036 * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
1042 gst_harness_new_parse (const gchar * launchline)
1045 h = gst_harness_new_empty ();
1046 gst_harness_add_parse (h, launchline);
1051 * gst_harness_teardown:
1054 * Tears down a @GstHarness, freeing all resources allocated using it.
1061 gst_harness_teardown (GstHarness * h)
1063 GstHarnessPrivate *priv = h->priv;
1065 if (priv->blocking_push_mode) {
1066 g_mutex_lock (&priv->blocking_push_mutex);
1067 priv->blocking_push_mode = FALSE;
1068 g_cond_signal (&priv->blocking_push_cond);
1069 g_mutex_unlock (&priv->blocking_push_mutex);
1073 gst_harness_teardown (h->src_harness);
1074 h->src_harness = NULL;
1077 gst_object_replace ((GstObject **) & priv->sink_forward_pad, NULL);
1080 if (h->sink_harness)
1081 gst_harness_teardown (h->sink_harness);
1082 h->sink_harness = NULL;
1085 if (gst_pad_is_request_pad (GST_PAD_PEER (h->srcpad)))
1086 gst_element_release_request_pad (h->element, GST_PAD_PEER (h->srcpad));
1087 g_free (priv->element_sinkpad_name);
1089 gst_pad_set_active (h->srcpad, FALSE);
1091 /* Make sure our funcs are not called after harness is teared down since
1092 * they try to access this harness through pad data */
1093 GST_PAD_STREAM_LOCK (h->srcpad);
1094 gst_pad_set_event_function (h->srcpad, NULL);
1095 gst_pad_set_query_function (h->srcpad, NULL);
1096 GST_PAD_STREAM_UNLOCK (h->srcpad);
1098 gst_object_unref (h->srcpad);
1103 if (gst_pad_is_request_pad (GST_PAD_PEER (h->sinkpad)))
1104 gst_element_release_request_pad (h->element, GST_PAD_PEER (h->sinkpad));
1105 g_free (priv->element_srcpad_name);
1107 gst_pad_set_active (h->sinkpad, FALSE);
1109 /* Make sure our funcs are not called after harness is teared down since
1110 * they try to access this harness through pad data */
1111 GST_PAD_STREAM_LOCK (h->sinkpad);
1112 gst_pad_set_chain_function (h->sinkpad, NULL);
1113 gst_pad_set_event_function (h->sinkpad, NULL);
1114 gst_pad_set_query_function (h->sinkpad, NULL);
1115 GST_PAD_STREAM_UNLOCK (h->sinkpad);
1117 gst_object_unref (h->sinkpad);
1122 gst_caps_unref (priv->src_caps);
1123 priv->src_caps = NULL;
1125 if (priv->sink_caps)
1126 gst_caps_unref (priv->sink_caps);
1127 priv->sink_caps = NULL;
1129 gst_object_replace ((GstObject **) & priv->propose_allocator, NULL);
1130 gst_object_replace ((GstObject **) & priv->allocator, NULL);
1131 gst_object_replace ((GstObject **) & priv->pool, NULL);
1133 if (priv->propose_allocation_metas)
1134 g_array_unref (priv->propose_allocation_metas);
1135 priv->propose_allocation_metas = NULL;
1137 /* if we hold the last ref, set to NULL */
1138 if (h->element != NULL && gst_harness_element_unref (h) == 0) {
1139 gboolean state_change;
1140 GstState state, pending;
1141 state_change = gst_element_set_state (h->element, GST_STATE_NULL);
1142 g_assert (state_change == GST_STATE_CHANGE_SUCCESS);
1143 state_change = gst_element_get_state (h->element, &state, &pending, 0);
1144 g_assert (state_change == GST_STATE_CHANGE_SUCCESS);
1145 g_assert (state == GST_STATE_NULL);
1148 g_cond_clear (&priv->blocking_push_cond);
1149 g_mutex_clear (&priv->blocking_push_mutex);
1150 g_mutex_clear (&priv->priv_mutex);
1152 g_mutex_clear (&priv->buf_or_eos_mutex);
1153 g_cond_clear (&priv->buf_or_eos_cond);
1154 priv->eos_received = FALSE;
1156 g_async_queue_unref (priv->buffer_queue);
1157 priv->buffer_queue = NULL;
1158 g_async_queue_unref (priv->src_event_queue);
1159 priv->src_event_queue = NULL;
1160 g_async_queue_unref (priv->sink_event_queue);
1161 priv->sink_event_queue = NULL;
1163 g_ptr_array_unref (priv->stress);
1164 priv->stress = NULL;
1167 gst_object_unref (h->element);
1171 gst_object_replace ((GstObject **) & priv->testclock, NULL);
1179 * gst_harness_add_element_src_pad:
1181 * @srcpad: a #GstPad to link to the harness sinkpad
1183 * Links the specified #GstPad the @GstHarness sinkpad. This can be useful if
1184 * perhaps the srcpad did not exist at the time of creating the harness,
1185 * like a demuxer that provides a sometimes-pad after receiving data.
1192 gst_harness_add_element_src_pad (GstHarness * h, GstPad * srcpad)
1194 GstHarnessPrivate *priv = h->priv;
1195 GstPadLinkReturn link;
1196 if (h->sinkpad == NULL)
1197 gst_harness_setup_sink_pad (h, &hsinktemplate, NULL);
1198 link = gst_pad_link (srcpad, h->sinkpad);
1199 g_assert_cmpint (link, ==, GST_PAD_LINK_OK);
1200 g_free (priv->element_srcpad_name);
1201 priv->element_srcpad_name = gst_pad_get_name (srcpad);
1205 * gst_harness_add_element_sink_pad:
1207 * @sinkpad: a #GstPad to link to the harness srcpad
1209 * Links the specified #GstPad the @GstHarness srcpad.
1216 gst_harness_add_element_sink_pad (GstHarness * h, GstPad * sinkpad)
1218 GstHarnessPrivate *priv = h->priv;
1219 GstPadLinkReturn link;
1220 if (h->srcpad == NULL)
1221 gst_harness_setup_src_pad (h, &hsrctemplate, NULL);
1222 link = gst_pad_link (h->srcpad, sinkpad);
1223 g_assert_cmpint (link, ==, GST_PAD_LINK_OK);
1224 g_free (priv->element_sinkpad_name);
1225 priv->element_sinkpad_name = gst_pad_get_name (sinkpad);
1229 * gst_harness_set_src_caps:
1231 * @caps: (transfer full): a #GstCaps to set on the harness srcpad
1233 * Sets the @GstHarness srcpad caps. This must be done before any buffers
1234 * can legally be pushed from the harness to the element.
1241 gst_harness_set_src_caps (GstHarness * h, GstCaps * caps)
1243 GstHarnessPrivate *priv = h->priv;
1247 handled = gst_pad_push_event (h->srcpad, gst_event_new_caps (caps));
1249 gst_caps_take (&priv->src_caps, caps);
1251 gst_segment_init (&segment, GST_FORMAT_TIME);
1252 handled = gst_pad_push_event (h->srcpad, gst_event_new_segment (&segment));
1257 * gst_harness_set_sink_caps:
1259 * @caps: (transfer full): a #GstCaps to set on the harness sinkpad
1261 * Sets the @GstHarness sinkpad caps.
1268 gst_harness_set_sink_caps (GstHarness * h, GstCaps * caps)
1270 GstHarnessPrivate *priv = h->priv;
1272 gst_caps_take (&priv->sink_caps, caps);
1273 gst_pad_push_event (h->sinkpad, gst_event_new_reconfigure ());
1277 * gst_harness_set_caps:
1279 * @in: (transfer full): a #GstCaps to set on the harness srcpad
1280 * @out: (transfer full): a #GstCaps to set on the harness sinkpad
1282 * Sets the @GstHarness srcpad and sinkpad caps.
1289 gst_harness_set_caps (GstHarness * h, GstCaps * in, GstCaps * out)
1291 gst_harness_set_sink_caps (h, out);
1292 gst_harness_set_src_caps (h, in);
1296 * gst_harness_set_src_caps_str:
1298 * @str: a @gchar describing a #GstCaps to set on the harness srcpad
1300 * Sets the @GstHarness srcpad caps using a string. This must be done before
1301 * any buffers can legally be pushed from the harness to the element.
1308 gst_harness_set_src_caps_str (GstHarness * h, const gchar * str)
1310 gst_harness_set_src_caps (h, gst_caps_from_string (str));
1314 * gst_harness_set_sink_caps_str:
1316 * @str: a @gchar describing a #GstCaps to set on the harness sinkpad
1318 * Sets the @GstHarness sinkpad caps using a string.
1325 gst_harness_set_sink_caps_str (GstHarness * h, const gchar * str)
1327 gst_harness_set_sink_caps (h, gst_caps_from_string (str));
1331 * gst_harness_set_caps_str:
1333 * @in: a @gchar describing a #GstCaps to set on the harness srcpad
1334 * @out: a @gchar describing a #GstCaps to set on the harness sinkpad
1336 * Sets the @GstHarness srcpad and sinkpad caps using strings.
1343 gst_harness_set_caps_str (GstHarness * h, const gchar * in, const gchar * out)
1345 gst_harness_set_sink_caps_str (h, out);
1346 gst_harness_set_src_caps_str (h, in);
1350 * gst_harness_use_systemclock:
1353 * Sets the system #GstClock on the @GstHarness #GstElement
1360 gst_harness_use_systemclock (GstHarness * h)
1362 GstClock *clock = gst_system_clock_obtain ();
1363 g_assert (clock != NULL);
1364 gst_element_set_clock (h->element, clock);
1365 gst_object_unref (clock);
1369 * gst_harness_use_testclock:
1372 * Sets the #GstTestClock on the #GstHarness #GstElement
1379 gst_harness_use_testclock (GstHarness * h)
1381 gst_element_set_clock (h->element, GST_CLOCK_CAST (h->priv->testclock));
1385 * gst_harness_get_testclock:
1388 * Get the #GstTestClock. Useful if specific operations on the testclock is
1393 * Returns: (transfer full): a #GstTestClock, or %NULL if the testclock is not
1399 gst_harness_get_testclock (GstHarness * h)
1401 return gst_object_ref (h->priv->testclock);
1405 * gst_harness_set_time:
1407 * @time: a #GstClockTime to advance the clock to
1409 * Advance the #GstTestClock to a specific time.
1413 * Returns: a @gboolean %TRUE if the time could be set. %FALSE if not.
1418 gst_harness_set_time (GstHarness * h, GstClockTime time)
1420 gst_test_clock_set_time (h->priv->testclock, time);
1425 * gst_harness_wait_for_clock_id_waits:
1427 * @waits: a #guint describing the numbers of #GstClockID registered with
1429 * @timeout: a #guint describing how many seconds to wait for @waits to be true
1431 * Waits for @timeout seconds until @waits number of #GstClockID waits is
1432 * registered with the #GstTestClock. Useful for writing deterministic tests,
1433 * where you want to make sure that an expected number of waits have been
1438 * Returns: a @gboolean %TRUE if the waits have been registered, %FALSE if not.
1439 * (Could be that it timed out waiting or that more waits than waits was found)
1444 gst_harness_wait_for_clock_id_waits (GstHarness * h, guint waits, guint timeout)
1446 return gst_test_clock_timed_wait_for_multiple_pending_ids (h->priv->testclock,
1447 waits, timeout * 1000, NULL);
1451 * gst_harness_crank_single_clock_wait:
1454 * A "crank" consists of three steps:
1455 * 1: Wait for a #GstClockID to be registered with the #GstTestClock.
1456 * 2: Advance the #GstTestClock to the time the #GstClockID is waiting for.
1457 * 3: Release the #GstClockID wait.
1458 * Together, this provides an easy way to not have to think about the details
1459 * around clocks and time, but still being able to write deterministic tests
1460 * that are dependent on this. A "crank" can be though of as the notion of
1461 * manually driving the clock forward to its next logical step.
1465 * Returns: a @gboolean %TRUE if the "crank" was successful, %FALSE if not.
1470 gst_harness_crank_single_clock_wait (GstHarness * h)
1472 return gst_test_clock_crank (h->priv->testclock);
1476 * gst_harness_crank_multiple_clock_waits:
1478 * @waits: a #guint describing the number of #GstClockIDs to crank
1480 * Similar to gst_harness_crank_single_clock_wait(), this is the function to use
1481 * if your harnessed element(s) are using more then one gst_clock_id_wait.
1482 * Failing to do so can (and will) make it racy which #GstClockID you actually
1483 * are releasing, where as this function will process all the waits at the
1484 * same time, ensuring that one thread can't register another wait before
1485 * both are released.
1489 * Returns: a @gboolean %TRUE if the "crank" was successful, %FALSE if not.
1494 gst_harness_crank_multiple_clock_waits (GstHarness * h, guint waits)
1496 GstTestClock *testclock = h->priv->testclock;
1500 gst_test_clock_wait_for_multiple_pending_ids (testclock, waits, &pending);
1501 gst_harness_set_time (h, gst_test_clock_id_list_get_latest_time (pending));
1502 processed = gst_test_clock_process_id_list (testclock, pending);
1504 g_list_free_full (pending, gst_clock_id_unref);
1505 return processed == waits;
1512 * This will set the harnessed #GstElement to %GST_STATE_PLAYING.
1513 * #GstElements without a sink-#GstPad and with the %GST_ELEMENT_FLAG_SOURCE
1514 * flag set is considered a src #GstElement
1515 * Non-src #GstElements (like sinks and filters) are automatically set to
1516 * playing by the #GstHarness, but src #GstElements are not to avoid them
1517 * starting to produce buffers.
1518 * Hence, for src #GstElement you must call gst_harness_play() explicitly.
1525 gst_harness_play (GstHarness * h)
1527 GstState state, pending;
1528 gboolean state_change;
1529 state_change = gst_element_set_state (h->element, GST_STATE_PLAYING);
1530 g_assert_cmpint (GST_STATE_CHANGE_SUCCESS, ==, state_change);
1531 state_change = gst_element_get_state (h->element, &state, &pending, 0);
1532 g_assert_cmpint (GST_STATE_CHANGE_SUCCESS, ==, state_change);
1533 g_assert_cmpint (GST_STATE_PLAYING, ==, state);
1537 * gst_harness_set_blocking_push_mode:
1540 * Setting this will make the harness block in the chain-function, and
1541 * then release when gst_harness_pull() or gst_harness_try_pull() is called.
1542 * Can be useful when wanting to control a src-element that is not implementing
1543 * gst_clock_id_wait() so it can't be controlled by the #GstTestClock, since
1544 * it otherwise would produce buffers as fast as possible.
1551 gst_harness_set_blocking_push_mode (GstHarness * h)
1553 GstHarnessPrivate *priv = h->priv;
1554 priv->blocking_push_mode = TRUE;
1558 * gst_harness_set_forwarding:
1560 * @forwarding: a #gboolean to enable/disable forwarding
1562 * As a convenience, a src-harness will forward %GST_EVENT_STREAM_START,
1563 * %GST_EVENT_CAPS and %GST_EVENT_SEGMENT to the main-harness if forwarding
1564 * is enabled, and forward any sticky-events from the main-harness to
1565 * the sink-harness. It will also forward the %GST_QUERY_ALLOCATION.
1567 * If forwarding is disabled, the user will have to either manually push
1568 * these events from the src-harness using gst_harness_src_push_event(), or
1569 * create and push them manually. While this will allow full control and
1570 * inspection of these events, for the most cases having forwarding enabled
1571 * will be sufficient when writing a test where the src-harness' main function
1572 * is providing data for the main-harness.
1574 * Forwarding is enabled by default.
1581 gst_harness_set_forwarding (GstHarness * h, gboolean forwarding)
1583 GstHarnessPrivate *priv = h->priv;
1584 priv->forwarding = forwarding;
1586 gst_harness_set_forwarding (h->src_harness, forwarding);
1587 if (h->sink_harness)
1588 gst_harness_set_forwarding (h->sink_harness, forwarding);
1592 * Call with HARNESS_LOCK
1595 gst_harness_set_forward_pad (GstHarness * h, GstPad * fwdpad)
1597 gst_object_replace ((GstObject **) & h->priv->sink_forward_pad,
1598 (GstObject *) fwdpad);
1602 * gst_harness_create_buffer:
1604 * @size: a #gsize specifying the size of the buffer
1606 * Allocates a buffer using a #GstBufferPool if present, or else using the
1607 * configured #GstAllocator and #GstAllocationParams
1611 * Returns: a #GstBuffer of size @size
1616 gst_harness_create_buffer (GstHarness * h, gsize size)
1618 GstHarnessPrivate *priv = h->priv;
1619 GstBuffer *ret = NULL;
1622 if (gst_pad_check_reconfigure (h->srcpad))
1623 gst_harness_negotiate (h);
1626 flow = gst_buffer_pool_acquire_buffer (priv->pool, &ret, NULL);
1627 g_assert_cmpint (flow, ==, GST_FLOW_OK);
1628 if (gst_buffer_get_size (ret) != size) {
1629 GST_DEBUG ("use fallback, pool is configured with a different size (%"
1630 G_GSIZE_FORMAT " != %" G_GSIZE_FORMAT ")",
1631 size, gst_buffer_get_size (ret));
1632 gst_buffer_unref (ret);
1639 gst_buffer_new_allocate (priv->allocator, size,
1640 &priv->allocation_params);
1642 g_assert (ret != NULL);
1649 * @buffer: (transfer full): a #GstBuffer to push
1651 * Pushes a #GstBuffer on the #GstHarness srcpad. The standard way of
1652 * interacting with an harnessed element.
1656 * Returns: a #GstFlowReturn with the result from the push
1661 gst_harness_push (GstHarness * h, GstBuffer * buffer)
1663 GstHarnessPrivate *priv = h->priv;
1664 g_assert (buffer != NULL);
1665 priv->last_push_ts = GST_BUFFER_TIMESTAMP (buffer);
1666 return gst_pad_push (h->srcpad, buffer);
1673 * Pulls a #GstBuffer from the #GAsyncQueue on the #GstHarness sinkpad. The pull
1674 * will timeout in 60 seconds. This is the standard way of getting a buffer
1675 * from a harnessed #GstElement.
1679 * Returns: (transfer full): a #GstBuffer or %NULL if timed out.
1684 gst_harness_pull (GstHarness * h)
1686 GstHarnessPrivate *priv = h->priv;
1687 GstBuffer *buf = (GstBuffer *) g_async_queue_timeout_pop (priv->buffer_queue,
1688 G_USEC_PER_SEC * 60);
1690 if (priv->blocking_push_mode) {
1691 g_mutex_lock (&priv->blocking_push_mutex);
1692 g_cond_signal (&priv->blocking_push_cond);
1693 g_mutex_unlock (&priv->blocking_push_mutex);
1700 * gst_harness_pull_until_eos:
1702 * @buf: (out) (transfer full): A #GstBuffer, or %NULL if EOS or timeout occures
1705 * Pulls a #GstBuffer from the #GAsyncQueue on the #GstHarness sinkpad. The pull
1706 * will block until an EOS event is received, or timeout in 60 seconds.
1709 * Returns: %TRUE on success, %FALSE on timeout.
1714 gst_harness_pull_until_eos (GstHarness * h, GstBuffer ** buf)
1716 GstHarnessPrivate *priv = h->priv;
1717 gboolean success = TRUE;
1718 gint64 end_time = g_get_monotonic_time () + 60 * G_TIME_SPAN_SECOND;
1720 g_mutex_lock (&priv->buf_or_eos_mutex);
1722 *buf = g_async_queue_try_pop (priv->buffer_queue);
1723 if (*buf || priv->eos_received)
1725 success = g_cond_wait_until (&priv->buf_or_eos_cond,
1726 &priv->buf_or_eos_mutex, end_time);
1728 g_mutex_unlock (&priv->buf_or_eos_mutex);
1734 * gst_harness_try_pull:
1737 * Pulls a #GstBuffer from the #GAsyncQueue on the #GstHarness sinkpad. Unlike
1738 * gst_harness_pull this will not wait for any buffers if not any are present,
1739 * and return %NULL straight away.
1743 * Returns: (transfer full): a #GstBuffer or %NULL if no buffers are present in the #GAsyncQueue
1748 gst_harness_try_pull (GstHarness * h)
1750 GstHarnessPrivate *priv = h->priv;
1751 GstBuffer *buf = (GstBuffer *) g_async_queue_try_pop (priv->buffer_queue);
1753 if (priv->blocking_push_mode) {
1754 g_mutex_lock (&priv->blocking_push_mutex);
1755 g_cond_signal (&priv->blocking_push_cond);
1756 g_mutex_unlock (&priv->blocking_push_mutex);
1763 * gst_harness_push_and_pull:
1765 * @buffer: (transfer full): a #GstBuffer to push
1767 * Basically a gst_harness_push and a gst_harness_pull in one line. Reflects
1768 * the fact that you often want to do exactly this in your test: Push one buffer
1769 * in, and inspect the outcome.
1773 * Returns: (transfer full): a #GstBuffer or %NULL if timed out.
1778 gst_harness_push_and_pull (GstHarness * h, GstBuffer * buffer)
1780 gst_harness_push (h, buffer);
1781 return gst_harness_pull (h);
1785 * gst_harness_buffers_received:
1788 * The total number of #GstBuffers that has arrived on the #GstHarness sinkpad.
1789 * This number includes buffers that have been dropped as well as buffers
1790 * that have already been pulled out.
1794 * Returns: a #guint number of buffers received
1799 gst_harness_buffers_received (GstHarness * h)
1801 GstHarnessPrivate *priv = h->priv;
1802 return g_atomic_int_get (&priv->recv_buffers);
1806 * gst_harness_buffers_in_queue:
1809 * The number of #GstBuffers currently in the #GstHarness sinkpad #GAsyncQueue
1813 * Returns: a #guint number of buffers in the queue
1818 gst_harness_buffers_in_queue (GstHarness * h)
1820 GstHarnessPrivate *priv = h->priv;
1821 return g_async_queue_length (priv->buffer_queue);
1825 * gst_harness_set_drop_buffers:
1827 * @drop_buffers: a #gboolean specifying to drop outgoing buffers or not
1829 * When set to %TRUE, instead of placing the buffers arriving from the harnessed
1830 * #GstElement inside the sinkpads #GAsyncQueue, they are instead unreffed.
1837 gst_harness_set_drop_buffers (GstHarness * h, gboolean drop_buffers)
1839 GstHarnessPrivate *priv = h->priv;
1840 priv->drop_buffers = drop_buffers;
1844 * gst_harness_take_all_data_as_buffer:
1847 * Pulls all pending data from the harness and returns it as a single buffer.
1849 * Returns: (transfer full): the data as a buffer. Unref with gst_buffer_unref()
1850 * when no longer needed.
1855 gst_harness_take_all_data_as_buffer (GstHarness * h)
1857 GstHarnessPrivate *priv;
1858 GstBuffer *ret, *buf;
1860 g_return_val_if_fail (h != NULL, NULL);
1864 g_async_queue_lock (priv->buffer_queue);
1866 ret = g_async_queue_try_pop_unlocked (priv->buffer_queue);
1869 ret = gst_buffer_new ();
1871 /* buffer appending isn't very efficient for larger numbers of buffers
1872 * or lots of memories, but this function is not performance critical and
1873 * we can still improve it if and when the need arises. For now KISS. */
1874 while ((buf = g_async_queue_try_pop_unlocked (priv->buffer_queue)))
1875 ret = gst_buffer_append (ret, buf);
1878 g_async_queue_unlock (priv->buffer_queue);
1884 * gst_harness_take_all_data: (skip)
1886 * @size: (out): the size of the data in bytes
1888 * Pulls all pending data from the harness and returns it as a single
1891 * Returns: (transfer full): a pointer to the data, newly allocated. Free
1892 * with g_free() when no longer needed. Will return %NULL if there is no
1898 gst_harness_take_all_data (GstHarness * h, gsize * size)
1901 guint8 *data = NULL;
1903 g_return_val_if_fail (h != NULL, NULL);
1904 g_return_val_if_fail (size != NULL, NULL);
1906 buf = gst_harness_take_all_data_as_buffer (h);
1907 gst_buffer_extract_dup (buf, 0, -1, (gpointer *) & data, size);
1908 gst_buffer_unref (buf);
1913 * gst_harness_take_all_data_as_bytes: (rename-to gst_harness_take_all_data)
1916 * Pulls all pending data from the harness and returns it as a single #GBytes.
1918 * Returns: (transfer full): a pointer to the data, newly allocated. Free
1919 * with g_free() when no longer needed.
1924 gst_harness_take_all_data_as_bytes (GstHarness * h)
1929 g_return_val_if_fail (h != NULL, NULL);
1931 data = gst_harness_take_all_data (h, &size);
1932 return g_bytes_new_take (data, size);
1937 * gst_harness_dump_to_file:
1939 * @filename: a #gchar with a the name of a file
1941 * Allows you to dump the #GstBuffers the #GstHarness sinkpad #GAsyncQueue
1949 gst_harness_dump_to_file (GstHarness * h, const gchar * filename)
1955 data = gst_harness_take_all_data (h, &size);
1956 if (!g_file_set_contents (filename, data ? data : "", size, &err)) {
1957 g_error ("GstHarness: Failed to write data to file: %s", err->message);
1958 g_clear_error (&err);
1964 * gst_harness_get_last_pushed_timestamp:
1967 * Get the timestamp of the last #GstBuffer pushed on the #GstHarness srcpad,
1968 * typically with gst_harness_push or gst_harness_push_from_src.
1972 * Returns: a #GstClockTime with the timestamp or %GST_CLOCK_TIME_NONE if no
1973 * #GstBuffer has been pushed on the #GstHarness srcpad
1978 gst_harness_get_last_pushed_timestamp (GstHarness * h)
1980 GstHarnessPrivate *priv = h->priv;
1981 return priv->last_push_ts;
1985 * gst_harness_push_event:
1987 * @event: a #GstEvent to push
1989 * Pushes an #GstEvent on the #GstHarness srcpad.
1993 * Returns: a #gboolean with the result from the push
1998 gst_harness_push_event (GstHarness * h, GstEvent * event)
2000 return gst_pad_push_event (h->srcpad, event);
2004 * gst_harness_pull_event:
2007 * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness sinkpad.
2008 * Timeouts after 60 seconds similar to gst_harness_pull.
2012 * Returns: a #GstEvent or %NULL if timed out.
2017 gst_harness_pull_event (GstHarness * h)
2019 GstHarnessPrivate *priv = h->priv;
2020 return (GstEvent *) g_async_queue_timeout_pop (priv->sink_event_queue,
2021 G_USEC_PER_SEC * 60);
2025 * gst_harness_try_pull_event:
2028 * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness sinkpad.
2029 * See gst_harness_try_pull for details.
2033 * Returns: a #GstEvent or %NULL if no buffers are present in the #GAsyncQueue
2038 gst_harness_try_pull_event (GstHarness * h)
2040 GstHarnessPrivate *priv = h->priv;
2041 return (GstEvent *) g_async_queue_try_pop (priv->sink_event_queue);
2045 * gst_harness_events_received:
2048 * The total number of #GstEvents that has arrived on the #GstHarness sinkpad
2049 * This number includes events handled by the harness as well as events
2050 * that have already been pulled out.
2054 * Returns: a #guint number of events received
2059 gst_harness_events_received (GstHarness * h)
2061 GstHarnessPrivate *priv = h->priv;
2062 return g_atomic_int_get (&priv->recv_events);
2066 * gst_harness_events_in_queue:
2069 * The number of #GstEvents currently in the #GstHarness sinkpad #GAsyncQueue
2073 * Returns: a #guint number of events in the queue
2078 gst_harness_events_in_queue (GstHarness * h)
2080 GstHarnessPrivate *priv = h->priv;
2081 return g_async_queue_length (priv->sink_event_queue);
2085 * gst_harness_push_upstream_event:
2087 * @event: a #GstEvent to push
2089 * Pushes an #GstEvent on the #GstHarness sinkpad.
2093 * Returns: a #gboolean with the result from the push
2098 gst_harness_push_upstream_event (GstHarness * h, GstEvent * event)
2100 g_return_val_if_fail (event != NULL, FALSE);
2101 g_return_val_if_fail (GST_EVENT_IS_UPSTREAM (event), FALSE);
2103 return gst_pad_push_event (h->sinkpad, event);
2107 * gst_harness_pull_upstream_event:
2110 * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness srcpad.
2111 * Timeouts after 60 seconds similar to gst_harness_pull.
2115 * Returns: a #GstEvent or %NULL if timed out.
2120 gst_harness_pull_upstream_event (GstHarness * h)
2122 GstHarnessPrivate *priv = h->priv;
2123 return (GstEvent *) g_async_queue_timeout_pop (priv->src_event_queue,
2124 G_USEC_PER_SEC * 60);
2128 * gst_harness_try_pull_upstream_event:
2131 * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness srcpad.
2132 * See gst_harness_try_pull for details.
2136 * Returns: a #GstEvent or %NULL if no buffers are present in the #GAsyncQueue
2141 gst_harness_try_pull_upstream_event (GstHarness * h)
2143 GstHarnessPrivate *priv = h->priv;
2144 return (GstEvent *) g_async_queue_try_pop (priv->src_event_queue);
2148 * gst_harness_upstream_events_received:
2151 * The total number of #GstEvents that has arrived on the #GstHarness srcpad
2152 * This number includes events handled by the harness as well as events
2153 * that have already been pulled out.
2157 * Returns: a #guint number of events received
2162 gst_harness_upstream_events_received (GstHarness * h)
2164 GstHarnessPrivate *priv = h->priv;
2165 return g_atomic_int_get (&priv->recv_upstream_events);
2169 * gst_harness_upstream_events_in_queue:
2172 * The number of #GstEvents currently in the #GstHarness srcpad #GAsyncQueue
2176 * Returns: a #guint number of events in the queue
2181 gst_harness_upstream_events_in_queue (GstHarness * h)
2183 GstHarnessPrivate *priv = h->priv;
2184 return g_async_queue_length (priv->src_event_queue);
2188 * gst_harness_query_latency:
2191 * Get the min latency reported by any harnessed #GstElement.
2195 * Returns: a #GstClockTime with min latency
2200 gst_harness_query_latency (GstHarness * h)
2204 GstClockTime min = GST_CLOCK_TIME_NONE;
2207 query = gst_query_new_latency ();
2209 if (gst_pad_peer_query (h->sinkpad, query)) {
2210 gst_query_parse_latency (query, &is_live, &min, &max);
2212 gst_query_unref (query);
2218 * gst_harness_set_upstream_latency:
2220 * @latency: a #GstClockTime specifying the latency
2222 * Sets the min latency reported by #GstHarness when receiving a latency-query
2227 gst_harness_set_upstream_latency (GstHarness * h, GstClockTime latency)
2229 GstHarnessPrivate *priv = h->priv;
2230 priv->latency_min = latency;
2234 * gst_harness_set_live:
2236 * @is_live: %TRUE for live, %FALSE for non-live
2238 * Sets the liveness reported by #GstHarness when receiving a latency-query.
2239 * The default is %TRUE.
2244 gst_harness_set_live (GstHarness * h, gboolean is_live)
2246 GstHarnessPrivate *priv = h->priv;
2247 priv->is_live = is_live;
2251 * gst_harness_get_allocator:
2253 * @allocator: (out) (allow-none) (transfer none): the #GstAllocator used
2254 * @params: (out) (allow-none) (transfer full): the #GstAllocationParams of
2257 * Gets the @allocator and its @params that has been decided to use after an
2265 gst_harness_get_allocator (GstHarness * h, GstAllocator ** allocator,
2266 GstAllocationParams * params)
2268 GstHarnessPrivate *priv = h->priv;
2270 *allocator = priv->allocator;
2272 *params = priv->allocation_params;
2277 * gst_harness_set_propose_allocator:
2279 * @allocator: (allow-none) (transfer full): a #GstAllocator
2280 * @params: (allow-none) (transfer none): a #GstAllocationParams
2282 * Sets the @allocator and @params to propose when receiving an allocation
2290 gst_harness_set_propose_allocator (GstHarness * h, GstAllocator * allocator,
2291 const GstAllocationParams * params)
2293 GstHarnessPrivate *priv = h->priv;
2295 priv->propose_allocator = allocator;
2297 priv->propose_allocation_params = *params;
2301 * gst_harness_add_propose_allocation_meta:
2303 * @api: a metadata API
2304 * @params: (allow-none) (transfer none): API specific parameters
2306 * Add api with params as one of the supported metadata API to propose when
2307 * receiving an allocation query.
2314 gst_harness_add_propose_allocation_meta (GstHarness * h, GType api,
2315 const GstStructure * params)
2317 GstHarnessPrivate *priv = h->priv;
2321 meta.params = params ? gst_structure_copy (params) : NULL;
2323 if (!priv->propose_allocation_metas) {
2324 priv->propose_allocation_metas =
2325 g_array_new (FALSE, FALSE, sizeof (ProposeMeta));
2326 g_array_set_clear_func (priv->propose_allocation_metas,
2327 (GDestroyNotify) propose_meta_clear);
2329 g_array_append_val (priv->propose_allocation_metas, meta);
2333 * gst_harness_add_src_harness:
2335 * @src_harness: (transfer full): a #GstHarness to be added as a src-harness.
2336 * @has_clock_wait: a #gboolean specifying if the #GstElement uses
2337 * gst_clock_wait_id internally.
2339 * A src-harness is a great way of providing the #GstHarness with data.
2340 * By adding a src-type #GstElement, it is then easy to use functions like
2341 * gst_harness_push_from_src or gst_harness_src_crank_and_push_many
2342 * to provide your harnessed element with input. The @has_clock_wait variable
2343 * is a great way to control you src-element with, in that you can have it
2344 * produce a buffer for you by simply cranking the clock, and not have it
2345 * spin out of control producing buffers as fast as possible.
2347 * If a src-harness already exists it will be replaced.
2354 gst_harness_add_src_harness (GstHarness * h,
2355 GstHarness * src_harness, gboolean has_clock_wait)
2358 gst_harness_teardown (h->src_harness);
2359 h->src_harness = src_harness;
2361 HARNESS_LOCK (h->src_harness);
2362 gst_harness_set_forward_pad (h->src_harness, h->srcpad);
2363 HARNESS_UNLOCK (h->src_harness);
2365 h->src_harness->priv->has_clock_wait = has_clock_wait;
2366 gst_harness_set_forwarding (h->src_harness, h->priv->forwarding);
2370 * gst_harness_add_src:
2372 * @src_element_name: a #gchar with the name of a #GstElement
2373 * @has_clock_wait: a #gboolean specifying if the #GstElement uses
2374 * gst_clock_wait_id internally.
2376 * Similar to gst_harness_add_src_harness, this is a convenience to
2377 * directly create a src-harness using the @src_element_name name specified.
2384 gst_harness_add_src (GstHarness * h,
2385 const gchar * src_element_name, gboolean has_clock_wait)
2387 GstHarness *src_harness = gst_harness_new (src_element_name);
2388 gst_harness_add_src_harness (h, src_harness, has_clock_wait);
2392 * gst_harness_add_src_parse:
2394 * @launchline: a #gchar describing a gst-launch type line
2395 * @has_clock_wait: a #gboolean specifying if the #GstElement uses
2396 * gst_clock_wait_id internally.
2398 * Similar to gst_harness_add_src, this allows you to specify a launch-line,
2399 * which can be useful for both having more then one #GstElement acting as your
2400 * src (Like a src producing raw buffers, and then an encoder, providing encoded
2401 * data), but also by allowing you to set properties like "is-live" directly on
2409 gst_harness_add_src_parse (GstHarness * h,
2410 const gchar * launchline, gboolean has_clock_wait)
2412 GstHarness *src_harness = gst_harness_new_parse (launchline);
2413 gst_harness_add_src_harness (h, src_harness, has_clock_wait);
2417 * gst_harness_push_from_src:
2420 * Transfer data from the src-#GstHarness to the main-#GstHarness. It consists
2422 * 1: Make sure the src is started. (see: gst_harness_play)
2423 * 2: Crank the clock (see: gst_harness_crank_single_clock_wait)
2424 * 3: Pull a #GstBuffer from the src-#GstHarness (see: gst_harness_pull)
2425 * 4: Push the same #GstBuffer into the main-#GstHarness (see: gst_harness_push)
2429 * Returns: a #GstFlowReturn with the result of the push
2434 gst_harness_push_from_src (GstHarness * h)
2439 g_assert (h->src_harness);
2441 /* FIXME: this *is* the right time to start the src,
2442 but maybe a flag so we don't keep telling it to play? */
2443 gst_harness_play (h->src_harness);
2445 if (h->src_harness->priv->has_clock_wait) {
2446 crank = gst_harness_crank_single_clock_wait (h->src_harness);
2450 buf = gst_harness_pull (h->src_harness);
2451 g_assert (buf != NULL);
2452 return gst_harness_push (h, buf);
2456 * gst_harness_src_crank_and_push_many:
2458 * @cranks: a #gint with the number of calls to gst_harness_crank_single_clock_wait
2459 * @pushes: a #gint with the number of calls to gst_harness_push
2461 * Transfer data from the src-#GstHarness to the main-#GstHarness. Similar to
2462 * gst_harness_push_from_src, this variant allows you to specify how many cranks
2463 * and how many pushes to perform. This can be useful for both moving a lot
2464 * of data at the same time, as well as cases when one crank does not equal one
2465 * buffer to push and v.v.
2469 * Returns: a #GstFlowReturn with the result of the push
2474 gst_harness_src_crank_and_push_many (GstHarness * h, gint cranks, gint pushes)
2476 GstFlowReturn ret = GST_FLOW_OK;
2480 g_assert (h->src_harness);
2481 gst_harness_play (h->src_harness);
2483 for (i = 0; i < cranks; i++) {
2484 crank = gst_harness_crank_single_clock_wait (h->src_harness);
2488 for (i = 0; i < pushes; i++) {
2490 buf = gst_harness_pull (h->src_harness);
2491 g_assert (buf != NULL);
2492 ret = gst_harness_push (h, buf);
2493 if (ret != GST_FLOW_OK)
2501 * gst_harness_src_push_event:
2504 * Similar to what gst_harness_src_push does with #GstBuffers, this transfers
2505 * a #GstEvent from the src-#GstHarness to the main-#GstHarness. Note that
2506 * some #GstEvents are being transferred automagically. Look at sink_forward_pad
2511 * Returns: a #gboolean with the result of the push
2516 gst_harness_src_push_event (GstHarness * h)
2518 return gst_harness_push_event (h, gst_harness_pull_event (h->src_harness));
2523 forward_sticky_events (GstPad * pad, GstEvent ** ev, gpointer user_data)
2525 GstPad *fwdpad = user_data;
2526 return gst_pad_push_event (fwdpad, gst_event_ref (*ev));
2530 * gst_harness_add_sink_harness:
2532 * @sink_harness: (transfer full): a #GstHarness to be added as a sink-harness.
2534 * Similar to gst_harness_add_src, this allows you to send the data coming out
2535 * of your harnessed #GstElement to a sink-element, allowing to test different
2536 * responses the element output might create in sink elements. An example might
2537 * be an existing sink providing some analytical data on the input it receives that
2538 * can be useful to your testing. If the goal is to test a sink-element itself,
2539 * this is better achieved using gst_harness_new directly on the sink.
2541 * If a sink-harness already exists it will be replaced.
2548 gst_harness_add_sink_harness (GstHarness * h, GstHarness * sink_harness)
2550 GstHarnessPrivate *priv;
2556 if (h->sink_harness) {
2557 gst_harness_set_forward_pad (h, NULL);
2558 gst_harness_teardown (h->sink_harness);
2560 h->sink_harness = sink_harness;
2562 fwdpad = h->sink_harness->srcpad;
2564 gst_object_ref (fwdpad);
2566 if (priv->forwarding && h->sinkpad && fwdpad) {
2568 gst_pad_sticky_events_foreach (h->sinkpad, forward_sticky_events, fwdpad);
2572 gst_harness_set_forward_pad (h, fwdpad);
2574 gst_object_unref (fwdpad);
2576 gst_harness_set_forwarding (h->sink_harness, priv->forwarding);
2582 * gst_harness_add_sink:
2584 * @sink_element_name: a #gchar with the name of a #GstElement
2586 * Similar to gst_harness_add_sink_harness, this is a convenience to
2587 * directly create a sink-harness using the @sink_element_name name specified.
2594 gst_harness_add_sink (GstHarness * h, const gchar * sink_element_name)
2596 GstHarness *sink_harness = gst_harness_new (sink_element_name);
2597 gst_harness_add_sink_harness (h, sink_harness);
2601 * gst_harness_add_sink_parse:
2603 * @launchline: a #gchar with the name of a #GstElement
2605 * Similar to gst_harness_add_sink, this allows you to specify a launch-line
2606 * instead of just an element name. See gst_harness_add_src_parse for details.
2613 gst_harness_add_sink_parse (GstHarness * h, const gchar * launchline)
2615 GstHarness *sink_harness = gst_harness_new_parse (launchline);
2616 gst_harness_add_sink_harness (h, sink_harness);
2620 * gst_harness_push_to_sink:
2623 * Transfer one #GstBuffer from the main-#GstHarness to the sink-#GstHarness.
2624 * See gst_harness_push_from_src for details.
2628 * Returns: a #GstFlowReturn with the result of the push
2633 gst_harness_push_to_sink (GstHarness * h)
2636 g_assert (h->sink_harness);
2637 buf = gst_harness_pull (h);
2638 g_assert (buf != NULL);
2639 return gst_harness_push (h->sink_harness, buf);
2643 * gst_harness_sink_push_many:
2645 * @pushes: a #gint with the number of calls to gst_harness_push_to_sink
2647 * Convenience that calls gst_harness_push_to_sink @pushes number of times.
2648 * Will abort the pushing if any one push fails.
2652 * Returns: a #GstFlowReturn with the result of the push
2657 gst_harness_sink_push_many (GstHarness * h, gint pushes)
2659 GstFlowReturn ret = GST_FLOW_OK;
2661 g_assert (h->sink_harness);
2662 for (i = 0; i < pushes; i++) {
2663 ret = gst_harness_push_to_sink (h);
2664 if (ret != GST_FLOW_OK)
2671 * gst_harness_find_element:
2673 * @element_name: a #gchar with a #GstElementFactory name
2675 * Most useful in conjunction with gst_harness_new_parse, this will scan the
2676 * #GstElements inside the #GstHarness, and check if any of them matches
2677 * @element_name. Typical usecase being that you need to access one of the
2678 * harnessed elements for properties and/or signals.
2682 * Returns: (transfer full) (allow-none): a #GstElement or %NULL if not found
2687 gst_harness_find_element (GstHarness * h, const gchar * element_name)
2689 gboolean done = FALSE;
2691 GValue data = G_VALUE_INIT;
2693 if (!GST_IS_BIN (h->element)) {
2694 GstPluginFeature *feature;
2696 g_return_val_if_fail (GST_IS_ELEMENT (h->element), NULL);
2698 feature = GST_PLUGIN_FEATURE (gst_element_get_factory (h->element));
2699 if (!strcmp (element_name, gst_plugin_feature_get_name (feature)))
2700 return gst_object_ref (h->element);
2705 iter = gst_bin_iterate_elements (GST_BIN (h->element));
2709 switch (gst_iterator_next (iter, &data)) {
2710 case GST_ITERATOR_OK:
2712 GstElement *element = g_value_get_object (&data);
2713 GstPluginFeature *feature =
2714 GST_PLUGIN_FEATURE (gst_element_get_factory (element));
2715 if (!strcmp (element_name, gst_plugin_feature_get_name (feature))) {
2716 gst_iterator_free (iter);
2719 g_value_reset (&data);
2722 case GST_ITERATOR_RESYNC:
2723 gst_iterator_resync (iter);
2725 case GST_ITERATOR_ERROR:
2726 case GST_ITERATOR_DONE:
2731 gst_iterator_free (iter);
2739 * @element_name: a #gchar with a #GstElementFactory name
2740 * @first_property_name: a #gchar with the first property name
2741 * @...: value for the first property, followed optionally by more
2742 * name/value pairs, followed by %NULL
2744 * A convenience function to allows you to call g_object_set on a #GstElement
2745 * that are residing inside the #GstHarness, by using normal g_object_set
2753 gst_harness_set (GstHarness * h,
2754 const gchar * element_name, const gchar * first_property_name, ...)
2757 GstElement *element = gst_harness_find_element (h, element_name);
2758 va_start (var_args, first_property_name);
2759 g_object_set_valist (G_OBJECT (element), first_property_name, var_args);
2761 gst_object_unref (element);
2767 * @element_name: a #gchar with a #GstElementFactory name
2768 * @first_property_name: a #gchar with the first property name
2769 * @...: return location for the first property, followed optionally by more
2770 * name/return location pairs, followed by %NULL
2772 * A convenience function to allows you to call g_object_get on a #GstElement
2773 * that are residing inside the #GstHarness, by using normal g_object_get
2781 gst_harness_get (GstHarness * h,
2782 const gchar * element_name, const gchar * first_property_name, ...)
2785 GstElement *element = gst_harness_find_element (h, element_name);
2786 va_start (var_args, first_property_name);
2787 g_object_get_valist (G_OBJECT (element), first_property_name, var_args);
2789 gst_object_unref (element);
2793 * gst_harness_add_probe:
2795 * @element_name: a #gchar with a #GstElementFactory name
2796 * @pad_name: a #gchar with the name of the pad to attach the probe to
2797 * @mask: a #GstPadProbeType (see gst_pad_add_probe)
2798 * @callback: a #GstPadProbeCallback (see gst_pad_add_probe)
2799 * @user_data: a #gpointer (see gst_pad_add_probe)
2800 * @destroy_data: a #GDestroyNotify (see gst_pad_add_probe)
2802 * A convenience function to allows you to call gst_pad_add_probe on a
2803 * #GstPad of a #GstElement that are residing inside the #GstHarness,
2804 * by using normal gst_pad_add_probe syntax
2811 gst_harness_add_probe (GstHarness * h,
2812 const gchar * element_name, const gchar * pad_name, GstPadProbeType mask,
2813 GstPadProbeCallback callback, gpointer user_data,
2814 GDestroyNotify destroy_data)
2816 GstElement *element = gst_harness_find_element (h, element_name);
2817 GstPad *pad = gst_element_get_static_pad (element, pad_name);
2818 gst_pad_add_probe (pad, mask, callback, user_data, destroy_data);
2819 gst_object_unref (pad);
2820 gst_object_unref (element);
2823 /******************************************************************************/
2825 /******************************************************************************/
2826 struct _GstHarnessThread
2834 GDestroyNotify freefunc;
2844 } GstHarnessCustomThread;
2852 GstHarnessPrepareBufferFunc func;
2854 GDestroyNotify notify;
2855 } GstHarnessPushBufferThread;
2861 GstHarnessPrepareEventFunc func;
2863 GDestroyNotify notify;
2864 } GstHarnessPushEventThread;
2872 } GstHarnessPropThread;
2878 GstPadTemplate *templ;
2884 } GstHarnessReqPadThread;
2887 gst_harness_thread_init (GstHarnessThread * t, GDestroyNotify freefunc,
2888 GstHarness * h, gulong sleep)
2890 t->freefunc = freefunc;
2894 g_ptr_array_add (h->priv->stress, t);
2898 gst_harness_thread_free (GstHarnessThread * t)
2900 g_slice_free (GstHarnessThread, t);
2904 gst_harness_custom_thread_free (GstHarnessCustomThread * t)
2906 g_slice_free (GstHarnessCustomThread, t);
2910 gst_harness_push_buffer_thread_free (GstHarnessPushBufferThread * t)
2913 gst_caps_replace (&t->caps, NULL);
2914 if (t->notify != NULL)
2915 t->notify (t->data);
2916 g_slice_free (GstHarnessPushBufferThread, t);
2921 gst_harness_push_event_thread_free (GstHarnessPushEventThread * t)
2924 if (t->notify != NULL)
2925 t->notify (t->data);
2926 g_slice_free (GstHarnessPushEventThread, t);
2931 gst_harness_property_thread_free (GstHarnessPropThread * t)
2935 g_value_unset (&t->value);
2936 g_slice_free (GstHarnessPropThread, t);
2941 gst_harness_requestpad_release (GstPad * pad, GstElement * element)
2943 gst_element_release_request_pad (element, pad);
2944 gst_object_unref (pad);
2948 gst_harness_requestpad_release_pads (GstHarnessReqPadThread * rpt)
2950 g_slist_foreach (rpt->pads, (GFunc) gst_harness_requestpad_release,
2952 g_slist_free (rpt->pads);
2957 gst_harness_requestpad_thread_free (GstHarnessReqPadThread * t)
2960 gst_object_replace ((GstObject **) & t->templ, NULL);
2962 gst_caps_replace (&t->caps, NULL);
2964 gst_harness_requestpad_release_pads (t);
2965 g_slice_free (GstHarnessReqPadThread, t);
2969 #define GST_HARNESS_THREAD_START(ID, t) \
2970 (((GstHarnessThread *)t)->running = TRUE, \
2971 ((GstHarnessThread *)t)->thread = g_thread_new ( \
2972 "gst-harness-stress-"G_STRINGIFY(ID), \
2973 (GThreadFunc)gst_harness_stress_##ID##_func, t))
2974 #define GST_HARNESS_THREAD_END(t) \
2975 (t->running = FALSE, \
2976 GPOINTER_TO_UINT (g_thread_join (t->thread)))
2979 gst_harness_stress_free (GstHarnessThread * t)
2981 if (t != NULL && t->freefunc != NULL)
2986 gst_harness_stress_custom_func (GstHarnessThread * t)
2988 GstHarnessCustomThread *ct = (GstHarnessCustomThread *) t;
2991 if (ct->init != NULL)
2992 ct->init (ct, ct->data);
2994 while (t->running) {
2995 ct->callback (ct, ct->data);
2998 g_usleep (t->sleep);
3000 return GUINT_TO_POINTER (count);
3005 gst_harness_stress_statechange_func (GstHarnessThread * t)
3009 while (t->running) {
3010 GstClock *clock = gst_element_get_clock (t->h->element);
3012 gboolean done = FALSE;
3015 change = gst_element_set_state (t->h->element, GST_STATE_NULL);
3016 g_assert (change == GST_STATE_CHANGE_SUCCESS);
3019 it = gst_element_iterate_sink_pads (t->h->element);
3021 GValue item = G_VALUE_INIT;
3022 switch (gst_iterator_next (it, &item)) {
3023 case GST_ITERATOR_OK:
3025 GstPad *sinkpad = g_value_get_object (&item);
3026 GstPad *srcpad = gst_pad_get_peer (sinkpad);
3027 if (srcpad != NULL) {
3028 gst_pad_unlink (srcpad, sinkpad);
3029 gst_pad_link (srcpad, sinkpad);
3030 gst_object_unref (srcpad);
3032 g_value_reset (&item);
3035 case GST_ITERATOR_RESYNC:
3036 gst_iterator_resync (it);
3038 case GST_ITERATOR_ERROR:
3039 g_assert_not_reached ();
3040 case GST_ITERATOR_DONE:
3044 g_value_unset (&item);
3046 gst_iterator_free (it);
3048 if (clock != NULL) {
3049 gst_element_set_clock (t->h->element, clock);
3050 gst_object_unref (clock);
3052 change = gst_element_set_state (t->h->element, GST_STATE_PLAYING);
3053 g_assert (change == GST_STATE_CHANGE_SUCCESS);
3056 g_usleep (t->sleep);
3058 return GUINT_TO_POINTER (count);
3062 gst_harness_stress_buffer_func (GstHarnessThread * t)
3064 GstHarnessPushBufferThread *pt = (GstHarnessPushBufferThread *) t;
3069 /* Push stream start, caps and segment events */
3070 sid = g_strdup_printf ("%s-%p", GST_OBJECT_NAME (t->h->element), t->h);
3071 handled = gst_pad_push_event (t->h->srcpad, gst_event_new_stream_start (sid));
3074 handled = gst_pad_push_event (t->h->srcpad, gst_event_new_caps (pt->caps));
3076 handled = gst_pad_push_event (t->h->srcpad,
3077 gst_event_new_segment (&pt->segment));
3080 while (t->running) {
3081 gst_harness_push (t->h, pt->func (t->h, pt->data));
3084 g_usleep (t->sleep);
3086 return GUINT_TO_POINTER (count);
3090 gst_harness_stress_event_func (GstHarnessThread * t)
3092 GstHarnessPushEventThread *pet = (GstHarnessPushEventThread *) t;
3095 while (t->running) {
3096 gst_harness_push_event (t->h, pet->func (t->h, pet->data));
3099 g_usleep (t->sleep);
3101 return GUINT_TO_POINTER (count);
3105 gst_harness_stress_upstream_event_func (GstHarnessThread * t)
3107 GstHarnessPushEventThread *pet = (GstHarnessPushEventThread *) t;
3110 while (t->running) {
3111 gst_harness_push_upstream_event (t->h, pet->func (t->h, pet->data));
3114 g_usleep (t->sleep);
3116 return GUINT_TO_POINTER (count);
3120 gst_harness_stress_property_func (GstHarnessThread * t)
3122 GstHarnessPropThread *pt = (GstHarnessPropThread *) t;
3125 while (t->running) {
3126 GValue value = G_VALUE_INIT;
3128 g_object_set_property (G_OBJECT (t->h->element), pt->name, &pt->value);
3130 g_value_init (&value, G_VALUE_TYPE (&pt->value));
3131 g_object_get_property (G_OBJECT (t->h->element), pt->name, &value);
3132 g_value_reset (&value);
3135 g_usleep (t->sleep);
3137 return GUINT_TO_POINTER (count);
3141 gst_harness_stress_requestpad_func (GstHarnessThread * t)
3143 GstHarnessReqPadThread *rpt = (GstHarnessReqPadThread *) t;
3146 while (t->running) {
3150 gst_harness_requestpad_release_pads (rpt);
3154 reqpad = gst_element_request_pad (t->h->element,
3155 rpt->templ, rpt->name, rpt->caps);
3157 g_assert (reqpad != NULL);
3159 rpt->pads = g_slist_prepend (rpt->pads, reqpad);
3162 g_usleep (t->sleep);
3164 return GUINT_TO_POINTER (count);
3168 * gst_harness_stress_thread_stop:
3169 * @t: a #GstHarnessThread
3171 * Stop the running #GstHarnessThread
3178 gst_harness_stress_thread_stop (GstHarnessThread * t)
3182 g_return_val_if_fail (t != NULL, 0);
3184 ret = GST_HARNESS_THREAD_END (t);
3185 g_ptr_array_remove (t->h->priv->stress, t);
3190 * gst_harness_stress_custom_start: (skip)
3192 * @init: (allow-none): a #GFunc that is called initially and only once
3193 * @callback: a #GFunc that is called as often as possible
3194 * @data: a #gpointer with custom data to pass to the @callback function
3195 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3196 * each call to the @callback
3198 * Start a custom stress-thread that will call your @callback for every
3199 * iteration allowing you to do something nasty.
3203 * Returns: a #GstHarnessThread
3208 gst_harness_stress_custom_start (GstHarness * h,
3209 GFunc init, GFunc callback, gpointer data, gulong sleep)
3211 GstHarnessCustomThread *t = g_slice_new0 (GstHarnessCustomThread);
3212 gst_harness_thread_init (&t->t,
3213 (GDestroyNotify) gst_harness_custom_thread_free, h, sleep);
3216 t->callback = callback;
3219 GST_HARNESS_THREAD_START (custom, t);
3224 * gst_harness_stress_statechange_start_full: (skip)
3226 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3229 * Change the state of your harnessed #GstElement from NULL to PLAYING and
3230 * back again, only pausing for @sleep microseconds every time.
3234 * Returns: a #GstHarnessThread
3239 gst_harness_stress_statechange_start_full (GstHarness * h, gulong sleep)
3241 GstHarnessThread *t = g_slice_new0 (GstHarnessThread);
3242 gst_harness_thread_init (t,
3243 (GDestroyNotify) gst_harness_thread_free, h, sleep);
3244 GST_HARNESS_THREAD_START (statechange, t);
3249 gst_harness_ref_buffer (GstHarness * h, gpointer data)
3252 return gst_buffer_ref (GST_BUFFER_CAST (data));
3256 gst_harness_ref_event (GstHarness * h, gpointer data)
3259 return gst_event_ref (GST_EVENT_CAST (data));
3263 * gst_harness_stress_push_buffer_start_full: (skip)
3265 * @caps: a #GstCaps for the #GstBuffer
3266 * @segment: a #GstSegment
3267 * @buf: a #GstBuffer to push
3268 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3269 * each call to gst_pad_push
3271 * Push a #GstBuffer in intervals of @sleep microseconds.
3275 * Returns: a #GstHarnessThread
3280 gst_harness_stress_push_buffer_start_full (GstHarness * h,
3281 GstCaps * caps, const GstSegment * segment, GstBuffer * buf, gulong sleep)
3283 return gst_harness_stress_push_buffer_with_cb_start_full (h, caps, segment,
3284 gst_harness_ref_buffer, gst_buffer_ref (buf),
3285 (GDestroyNotify) gst_buffer_unref, sleep);
3289 * gst_harness_stress_push_buffer_with_cb_start_full: (skip)
3291 * @caps: a #GstCaps for the #GstBuffer
3292 * @segment: a #GstSegment
3293 * @func: a #GstHarnessPrepareBufferFunc function called before every iteration
3294 * to prepare / create a #GstBuffer for pushing
3295 * @data: a #gpointer with data to the #GstHarnessPrepareBufferFunc function
3296 * @notify: a #GDestroyNotify that is called when thread is stopped
3297 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3298 * each call to gst_pad_push
3300 * Push a #GstBuffer returned by @func in intervals of @sleep microseconds.
3304 * Returns: a #GstHarnessThread
3309 gst_harness_stress_push_buffer_with_cb_start_full (GstHarness * h,
3310 GstCaps * caps, const GstSegment * segment,
3311 GstHarnessPrepareBufferFunc func, gpointer data, GDestroyNotify notify,
3314 GstHarnessPushBufferThread *t = g_slice_new0 (GstHarnessPushBufferThread);
3315 gst_harness_thread_init (&t->t,
3316 (GDestroyNotify) gst_harness_push_buffer_thread_free, h, sleep);
3318 gst_caps_replace (&t->caps, caps);
3319 t->segment = *segment;
3324 GST_HARNESS_THREAD_START (buffer, t);
3329 * gst_harness_stress_push_event_start_full: (skip)
3331 * @event: a #GstEvent to push
3332 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3333 * each gst_event_push with @event
3335 * Push the @event onto the harnessed #GstElement sinkpad in intervals of
3336 * @sleep microseconds
3340 * Returns: a #GstHarnessThread
3345 gst_harness_stress_push_event_start_full (GstHarness * h,
3346 GstEvent * event, gulong sleep)
3348 return gst_harness_stress_push_event_with_cb_start_full (h,
3349 gst_harness_ref_event, gst_event_ref (event),
3350 (GDestroyNotify) gst_event_unref, sleep);
3354 * gst_harness_stress_push_event_with_cb_start_full: (skip)
3356 * @func: a #GstHarnessPrepareEventFunc function called before every iteration
3357 * to prepare / create a #GstEvent for pushing
3358 * @data: a #gpointer with data to the #GstHarnessPrepareEventFunc function
3359 * @notify: a #GDestroyNotify that is called when thread is stopped
3360 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3361 * each call to gst_pad_push
3363 * Push a #GstEvent returned by @func onto the harnessed #GstElement sinkpad
3364 * in intervals of @sleep microseconds.
3368 * Returns: a #GstHarnessThread
3373 gst_harness_stress_push_event_with_cb_start_full (GstHarness * h,
3374 GstHarnessPrepareEventFunc func, gpointer data, GDestroyNotify notify,
3377 GstHarnessPushEventThread *t = g_slice_new0 (GstHarnessPushEventThread);
3378 gst_harness_thread_init (&t->t,
3379 (GDestroyNotify) gst_harness_push_event_thread_free, h, sleep);
3385 GST_HARNESS_THREAD_START (event, t);
3390 * gst_harness_stress_push_upstream_event_start_full: (skip)
3392 * @event: a #GstEvent to push
3393 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3394 * each gst_event_push with @event
3396 * Push the @event onto the harnessed #GstElement srcpad in intervals of
3397 * @sleep microseconds.
3401 * Returns: a #GstHarnessThread
3406 gst_harness_stress_push_upstream_event_start_full (GstHarness * h,
3407 GstEvent * event, gulong sleep)
3409 return gst_harness_stress_push_upstream_event_with_cb_start_full (h,
3410 gst_harness_ref_event, gst_event_ref (event),
3411 (GDestroyNotify) gst_event_unref, sleep);
3415 * gst_harness_stress_push_upstream_event_with_cb_start_full: (skip)
3417 * @func: a #GstHarnessPrepareEventFunc function called before every iteration
3418 * to prepare / create a #GstEvent for pushing
3419 * @data: a #gpointer with data to the #GstHarnessPrepareEventFunc function
3420 * @notify: a #GDestroyNotify that is called when thread is stopped
3421 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3422 * each call to gst_pad_push
3424 * Push a #GstEvent returned by @func onto the harnessed #GstElement srcpad
3425 * in intervals of @sleep microseconds.
3429 * Returns: a #GstHarnessThread
3434 gst_harness_stress_push_upstream_event_with_cb_start_full (GstHarness * h,
3435 GstHarnessPrepareEventFunc func, gpointer data, GDestroyNotify notify,
3438 GstHarnessPushEventThread *t = g_slice_new0 (GstHarnessPushEventThread);
3439 gst_harness_thread_init (&t->t,
3440 (GDestroyNotify) gst_harness_push_event_thread_free, h, sleep);
3446 GST_HARNESS_THREAD_START (upstream_event, t);
3451 * gst_harness_stress_property_start_full: (skip)
3453 * @name: a #gchar specifying a property name
3454 * @value: a #GValue to set the property to
3455 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3456 * each g_object_set with @name and @value
3458 * Call g_object_set with @name and @value in intervals of @sleep microseconds
3462 * Returns: a #GstHarnessThread
3467 gst_harness_stress_property_start_full (GstHarness * h,
3468 const gchar * name, const GValue * value, gulong sleep)
3470 GstHarnessPropThread *t = g_slice_new0 (GstHarnessPropThread);
3471 gst_harness_thread_init (&t->t,
3472 (GDestroyNotify) gst_harness_property_thread_free, h, sleep);
3474 t->name = g_strdup (name);
3475 g_value_init (&t->value, G_VALUE_TYPE (value));
3476 g_value_copy (value, &t->value);
3478 GST_HARNESS_THREAD_START (property, t);
3483 * gst_harness_stress_requestpad_start_full: (skip)
3485 * @templ: a #GstPadTemplate
3488 * @release: a #gboolean
3489 * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3490 * each gst_element_request_pad
3492 * Call gst_element_request_pad in intervals of @sleep microseconds
3496 * Returns: a #GstHarnessThread
3501 gst_harness_stress_requestpad_start_full (GstHarness * h,
3502 GstPadTemplate * templ, const gchar * name, GstCaps * caps,
3503 gboolean release, gulong sleep)
3505 GstHarnessReqPadThread *t = g_slice_new0 (GstHarnessReqPadThread);
3506 gst_harness_thread_init (&t->t,
3507 (GDestroyNotify) gst_harness_requestpad_thread_free, h, sleep);
3509 t->templ = gst_object_ref (templ);
3510 t->name = g_strdup (name);
3511 gst_caps_replace (&t->caps, caps);
3512 t->release = release;
3514 GST_HARNESS_THREAD_START (requestpad, t);