1 /* GstHarness - A test-harness for GStreamer testing
2  *
3  * Copyright (C) 2012-2015 Pexip <pexip.com>
4  *
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.
9  *
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.
14  *
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.
19  */
20 
21 /**
22  * SECTION:gstharness
23  * @title: GstHarness
24  * @short_description: A test-harness for writing GStreamer unit tests
25  * @see_also: #GstTestClock
26  *
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.
30  *
31  * The basic structure of #GstHarness is two "floating" #GstPads that connect
32  * to the harnessed #GstElement src and sink #GstPads like so:
33  *
34  * |[
35  *           __________________________
36  *  _____   |  _____            _____  |   _____
37  * |     |  | |     |          |     | |  |     |
38  * | src |--+-| sink|  Element | src |-+--| sink|
39  * |_____|  | |_____|          |_____| |  |_____|
40  *          |__________________________|
41  *
42  * ]|
43  *
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.
48  *
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.
52  *
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().
57  *
58  * ## A simple buffer-in buffer-out example
59  *
60  * |[<!-- language="C" -->
61  *   #include <gst/gst.h>
62  *   #include <gst/check/gstharness.h>
63  *   GstHarness *h;
64  *   GstBuffer *in_buf;
65  *   GstBuffer *out_buf;
66  *
67  *   // attach the harness to the src and sink pad of GstQueue
68  *   h = gst_harness_new ("queue");
69  *
70  *   // we must specify a caps before pushing buffers
71  *   gst_harness_set_src_caps_str (h, "mycaps");
72  *
73  *   // create a buffer of size 42
74  *   in_buf = gst_harness_create_buffer (h, 42);
75  *
76  *   // push the buffer into the queue
77  *   gst_harness_push (h, in_buf);
78  *
79  *   // pull the buffer from the queue
80  *   out_buf = gst_harness_pull (h);
81  *
82  *   // validate the buffer in is the same as buffer out
83  *   fail_unless (in_buf == out_buf);
84  *
85  *   // cleanup
86  *   gst_buffer_unref (out_buf);
87  *   gst_harness_teardown (h);
88  *
89  *   ]|
90  *
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().
96  *
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:
106  *
107  * |[<!-- language="C" -->
108  *   GstHarness * h = gst_harness_new (h, "vp8dec");
109  *   gst_harness_add_src_parse (h, "videotestsrc is-live=1 ! vp8enc", TRUE);
110  * ]|
111  *
112  * and then feeding it data with:
113  *
114  * |[<!-- language="C" -->
115  * gst_harness_push_from_src (h);
116  * ]|
117  *
118  */
119 #ifdef HAVE_CONFIG_H
120 #include "config.h"
121 #endif
122 
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"
126 #endif
127 
128 #include "gstharness.h"
129 
130 #include <stdio.h>
131 #include <string.h>
132 #include <math.h>
133 
134 static void gst_harness_stress_free (GstHarnessThread * t);
135 
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)
140 
141 static GstStaticPadTemplate hsrctemplate = GST_STATIC_PAD_TEMPLATE ("src",
142     GST_PAD_SRC,
143     GST_PAD_ALWAYS,
144     GST_STATIC_CAPS_ANY);
145 static GstStaticPadTemplate hsinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
146     GST_PAD_SINK,
147     GST_PAD_ALWAYS,
148     GST_STATIC_CAPS_ANY);
149 
150 typedef struct
151 {
152   GType api;
153   GstStructure *params;
154 } ProposeMeta;
155 
156 static void
propose_meta_clear(ProposeMeta * meta)157 propose_meta_clear (ProposeMeta * meta)
158 {
159   if (meta->params)
160     gst_structure_free (meta->params);
161 }
162 
163 struct _GstHarnessPrivate
164 {
165   gchar *element_sinkpad_name;
166   gchar *element_srcpad_name;
167 
168   GstCaps *src_caps;
169   GstCaps *sink_caps;
170 
171   gboolean forwarding;
172   GstPad *sink_forward_pad;
173   GstTestClock *testclock;
174 
175   volatile gint recv_buffers;
176   volatile gint recv_events;
177   volatile gint recv_upstream_events;
178 
179   GAsyncQueue *buffer_queue;
180   GAsyncQueue *src_event_queue;
181   GAsyncQueue *sink_event_queue;
182 
183   GstClockTime latency_min;
184   GstClockTime latency_max;
185   gboolean has_clock_wait;
186   gboolean drop_buffers;
187   GstClockTime last_push_ts;
188 
189   GstBufferPool *pool;
190   GstAllocator *allocator;
191   GstAllocationParams allocation_params;
192   GstAllocator *propose_allocator;
193   GstAllocationParams propose_allocation_params;
194 
195   GArray *propose_allocation_metas;
196 
197   gboolean blocking_push_mode;
198   GCond blocking_push_cond;
199   GMutex blocking_push_mutex;
200   GMutex priv_mutex;
201 
202   GPtrArray *stress;
203 };
204 
205 static GstFlowReturn
gst_harness_chain(GstPad * pad,GstObject * parent,GstBuffer * buffer)206 gst_harness_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
207 {
208   GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
209   GstHarnessPrivate *priv = h->priv;
210   (void) parent;
211   g_assert (h != NULL);
212   g_mutex_lock (&priv->blocking_push_mutex);
213   g_atomic_int_inc (&priv->recv_buffers);
214 
215   if (priv->drop_buffers)
216     gst_buffer_unref (buffer);
217   else
218     g_async_queue_push (priv->buffer_queue, buffer);
219 
220   if (priv->blocking_push_mode) {
221     g_cond_wait (&priv->blocking_push_cond, &priv->blocking_push_mutex);
222   }
223   g_mutex_unlock (&priv->blocking_push_mutex);
224 
225   return GST_FLOW_OK;
226 }
227 
228 static gboolean
gst_harness_src_event(GstPad * pad,GstObject * parent,GstEvent * event)229 gst_harness_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
230 {
231   GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
232   GstHarnessPrivate *priv = h->priv;
233   (void) parent;
234   g_assert (h != NULL);
235   g_atomic_int_inc (&priv->recv_upstream_events);
236   g_async_queue_push (priv->src_event_queue, event);
237   return TRUE;
238 }
239 
240 static gboolean
gst_harness_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)241 gst_harness_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
242 {
243   GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
244   GstHarnessPrivate *priv = h->priv;
245   gboolean ret = TRUE;
246   gboolean forward;
247 
248   g_assert (h != NULL);
249   (void) parent;
250   g_atomic_int_inc (&priv->recv_events);
251 
252   switch (GST_EVENT_TYPE (event)) {
253     case GST_EVENT_STREAM_START:
254     case GST_EVENT_CAPS:
255     case GST_EVENT_SEGMENT:
256       forward = TRUE;
257       break;
258     default:
259       forward = FALSE;
260       break;
261   }
262 
263   HARNESS_LOCK (h);
264   if (priv->forwarding && forward && priv->sink_forward_pad) {
265     GstPad *fwdpad = gst_object_ref (priv->sink_forward_pad);
266     HARNESS_UNLOCK (h);
267     ret = gst_pad_push_event (fwdpad, event);
268     gst_object_unref (fwdpad);
269     HARNESS_LOCK (h);
270   } else {
271     g_async_queue_push (priv->sink_event_queue, event);
272   }
273   HARNESS_UNLOCK (h);
274 
275   return ret;
276 }
277 
278 static void
gst_harness_decide_allocation(GstHarness * h,GstCaps * caps)279 gst_harness_decide_allocation (GstHarness * h, GstCaps * caps)
280 {
281   GstHarnessPrivate *priv = h->priv;
282   GstQuery *query;
283   GstAllocator *allocator;
284   GstAllocationParams params;
285   GstBufferPool *pool = NULL;
286   guint size, min, max;
287 
288   query = gst_query_new_allocation (caps, FALSE);
289   gst_pad_peer_query (h->srcpad, query);
290 
291   if (gst_query_get_n_allocation_params (query) > 0) {
292     gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
293   } else {
294     allocator = NULL;
295     gst_allocation_params_init (&params);
296   }
297 
298   if (gst_query_get_n_allocation_pools (query) > 0) {
299     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
300 #if 0
301     /* Most elements create their own pools if pool == NULL. Not sure if we
302      * want to do that in the harness since we may want to test the pool
303      * implementation of the elements. Not creating a pool will however ignore
304      * the returned size. */
305     if (pool == NULL)
306       pool = gst_buffer_pool_new ();
307 #endif
308   } else {
309     pool = NULL;
310     size = min = max = 0;
311   }
312   gst_query_unref (query);
313 
314   if (pool) {
315     GstStructure *config = gst_buffer_pool_get_config (pool);
316     gst_buffer_pool_config_set_params (config, caps, size, min, max);
317     gst_buffer_pool_config_set_allocator (config, allocator, &params);
318     gst_buffer_pool_set_config (pool, config);
319   }
320 
321   if (pool != priv->pool) {
322     if (priv->pool != NULL)
323       gst_buffer_pool_set_active (priv->pool, FALSE);
324     if (pool)
325       gst_buffer_pool_set_active (pool, TRUE);
326   }
327 
328   priv->allocation_params = params;
329   if (priv->allocator)
330     gst_object_unref (priv->allocator);
331   priv->allocator = allocator;
332   if (priv->pool)
333     gst_object_unref (priv->pool);
334   priv->pool = pool;
335 }
336 
337 static void
gst_harness_negotiate(GstHarness * h)338 gst_harness_negotiate (GstHarness * h)
339 {
340   GstCaps *caps;
341 
342   caps = gst_pad_get_current_caps (h->srcpad);
343   if (caps != NULL) {
344     gst_harness_decide_allocation (h, caps);
345     gst_caps_unref (caps);
346   } else {
347     GST_FIXME_OBJECT (h, "Cannot negotiate allocation because caps is not set");
348   }
349 }
350 
351 static gboolean
gst_harness_sink_query(GstPad * pad,GstObject * parent,GstQuery * query)352 gst_harness_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
353 {
354   GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
355   GstHarnessPrivate *priv = h->priv;
356   gboolean res = TRUE;
357   g_assert (h != NULL);
358 
359   // FIXME: forward all queries?
360 
361   switch (GST_QUERY_TYPE (query)) {
362     case GST_QUERY_LATENCY:
363       gst_query_set_latency (query, TRUE, priv->latency_min, priv->latency_max);
364       break;
365     case GST_QUERY_CAPS:
366     {
367       GstCaps *caps, *filter = NULL;
368 
369       if (priv->sink_caps) {
370         caps = gst_caps_ref (priv->sink_caps);
371       } else {
372         caps = gst_pad_get_pad_template_caps (pad);
373       }
374 
375       gst_query_parse_caps (query, &filter);
376       if (filter != NULL) {
377         gst_caps_take (&caps,
378             gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST));
379       }
380 
381       gst_query_set_caps_result (query, caps);
382       gst_caps_unref (caps);
383     }
384       break;
385     case GST_QUERY_ALLOCATION:
386     {
387       HARNESS_LOCK (h);
388       if (priv->forwarding && priv->sink_forward_pad != NULL) {
389         GstPad *peer = gst_pad_get_peer (priv->sink_forward_pad);
390         g_assert (peer != NULL);
391         HARNESS_UNLOCK (h);
392         res = gst_pad_query (peer, query);
393         gst_object_unref (peer);
394         HARNESS_LOCK (h);
395       } else {
396         GstCaps *caps;
397         gboolean need_pool;
398         guint size;
399 
400         gst_query_parse_allocation (query, &caps, &need_pool);
401 
402         /* FIXME: Can this be removed? */
403         size = gst_query_get_n_allocation_params (query);
404         g_assert_cmpuint (0, ==, size);
405         gst_query_add_allocation_param (query,
406             priv->propose_allocator, &priv->propose_allocation_params);
407 
408         if (priv->propose_allocation_metas) {
409           guint i;
410           for (i = 0; i < priv->propose_allocation_metas->len; i++) {
411             ProposeMeta *meta =
412                 &g_array_index (priv->propose_allocation_metas, ProposeMeta, i);
413             gst_query_add_allocation_meta (query, meta->api, meta->params);
414           }
415         }
416 
417         GST_DEBUG_OBJECT (pad, "proposing allocation %" GST_PTR_FORMAT,
418             priv->propose_allocator);
419       }
420       HARNESS_UNLOCK (h);
421       break;
422     }
423     default:
424       res = gst_pad_query_default (pad, parent, query);
425   }
426 
427   return res;
428 }
429 
430 static gboolean
gst_harness_src_query(GstPad * pad,GstObject * parent,GstQuery * query)431 gst_harness_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
432 {
433   GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
434   GstHarnessPrivate *priv = h->priv;
435   gboolean res = TRUE;
436   g_assert (h != NULL);
437 
438   switch (GST_QUERY_TYPE (query)) {
439     case GST_QUERY_LATENCY:
440       gst_query_set_latency (query, TRUE, priv->latency_min, priv->latency_max);
441       break;
442     case GST_QUERY_CAPS:
443     {
444       GstCaps *caps, *filter = NULL;
445 
446       if (priv->src_caps) {
447         caps = gst_caps_ref (priv->src_caps);
448       } else {
449         caps = gst_pad_get_pad_template_caps (pad);
450       }
451 
452       gst_query_parse_caps (query, &filter);
453       if (filter != NULL) {
454         gst_caps_take (&caps,
455             gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST));
456       }
457 
458       gst_query_set_caps_result (query, caps);
459       gst_caps_unref (caps);
460     }
461       break;
462     default:
463       res = gst_pad_query_default (pad, parent, query);
464   }
465   return res;
466 }
467 
468 static void
gst_harness_element_ref(GstHarness * h)469 gst_harness_element_ref (GstHarness * h)
470 {
471   guint *data;
472 
473   GST_OBJECT_LOCK (h->element);
474   data = g_object_get_data (G_OBJECT (h->element), HARNESS_REF);
475   if (data == NULL) {
476     data = g_new0 (guint, 1);
477     *data = 1;
478     g_object_set_data_full (G_OBJECT (h->element), HARNESS_REF, data, g_free);
479   } else {
480     (*data)++;
481   }
482   GST_OBJECT_UNLOCK (h->element);
483 }
484 
485 static guint
gst_harness_element_unref(GstHarness * h)486 gst_harness_element_unref (GstHarness * h)
487 {
488   guint *data;
489   guint ret;
490 
491   GST_OBJECT_LOCK (h->element);
492   data = g_object_get_data (G_OBJECT (h->element), HARNESS_REF);
493   g_assert (data != NULL);
494   (*data)--;
495   ret = *data;
496   GST_OBJECT_UNLOCK (h->element);
497 
498   return ret;
499 }
500 
501 static void
gst_harness_link_element_srcpad(GstHarness * h,const gchar * element_srcpad_name)502 gst_harness_link_element_srcpad (GstHarness * h,
503     const gchar * element_srcpad_name)
504 {
505   GstHarnessPrivate *priv = h->priv;
506   GstPad *srcpad = gst_element_get_static_pad (h->element,
507       element_srcpad_name);
508   GstPadLinkReturn link;
509   if (srcpad == NULL)
510     srcpad = gst_element_get_request_pad (h->element, element_srcpad_name);
511   g_assert (srcpad);
512   link = gst_pad_link (srcpad, h->sinkpad);
513   g_assert_cmpint (link, ==, GST_PAD_LINK_OK);
514   g_free (priv->element_srcpad_name);
515   priv->element_srcpad_name = gst_pad_get_name (srcpad);
516 
517   gst_object_unref (srcpad);
518 }
519 
520 static void
gst_harness_link_element_sinkpad(GstHarness * h,const gchar * element_sinkpad_name)521 gst_harness_link_element_sinkpad (GstHarness * h,
522     const gchar * element_sinkpad_name)
523 {
524   GstHarnessPrivate *priv = h->priv;
525   GstPad *sinkpad = gst_element_get_static_pad (h->element,
526       element_sinkpad_name);
527   GstPadLinkReturn link;
528   if (sinkpad == NULL)
529     sinkpad = gst_element_get_request_pad (h->element, element_sinkpad_name);
530   g_assert (sinkpad);
531   link = gst_pad_link (h->srcpad, sinkpad);
532   g_assert_cmpint (link, ==, GST_PAD_LINK_OK);
533   g_free (priv->element_sinkpad_name);
534   priv->element_sinkpad_name = gst_pad_get_name (sinkpad);
535 
536   gst_object_unref (sinkpad);
537 }
538 
539 static void
gst_harness_setup_src_pad(GstHarness * h,GstStaticPadTemplate * src_tmpl,const gchar * element_sinkpad_name)540 gst_harness_setup_src_pad (GstHarness * h,
541     GstStaticPadTemplate * src_tmpl, const gchar * element_sinkpad_name)
542 {
543   GstHarnessPrivate *priv = h->priv;
544   g_assert (src_tmpl);
545   g_assert (h->srcpad == NULL);
546 
547   priv->src_event_queue =
548       g_async_queue_new_full ((GDestroyNotify) gst_event_unref);
549 
550   /* sending pad */
551   h->srcpad = gst_pad_new_from_static_template (src_tmpl, "src");
552   g_assert (h->srcpad);
553   g_object_set_data (G_OBJECT (h->srcpad), HARNESS_KEY, h);
554 
555   gst_pad_set_query_function (h->srcpad, gst_harness_src_query);
556   gst_pad_set_event_function (h->srcpad, gst_harness_src_event);
557 
558   gst_pad_set_active (h->srcpad, TRUE);
559 
560   if (element_sinkpad_name)
561     gst_harness_link_element_sinkpad (h, element_sinkpad_name);
562 }
563 
564 static void
gst_harness_setup_sink_pad(GstHarness * h,GstStaticPadTemplate * sink_tmpl,const gchar * element_srcpad_name)565 gst_harness_setup_sink_pad (GstHarness * h,
566     GstStaticPadTemplate * sink_tmpl, const gchar * element_srcpad_name)
567 {
568   GstHarnessPrivate *priv = h->priv;
569   g_assert (sink_tmpl);
570   g_assert (h->sinkpad == NULL);
571 
572   priv->buffer_queue = g_async_queue_new_full (
573       (GDestroyNotify) gst_buffer_unref);
574   priv->sink_event_queue = g_async_queue_new_full (
575       (GDestroyNotify) gst_event_unref);
576 
577   /* receiving pad */
578   h->sinkpad = gst_pad_new_from_static_template (sink_tmpl, "sink");
579   g_assert (h->sinkpad);
580   g_object_set_data (G_OBJECT (h->sinkpad), HARNESS_KEY, h);
581 
582   gst_pad_set_chain_function (h->sinkpad, gst_harness_chain);
583   gst_pad_set_query_function (h->sinkpad, gst_harness_sink_query);
584   gst_pad_set_event_function (h->sinkpad, gst_harness_sink_event);
585 
586   gst_pad_set_active (h->sinkpad, TRUE);
587 
588   if (element_srcpad_name)
589     gst_harness_link_element_srcpad (h, element_srcpad_name);
590 }
591 
592 static void
check_element_type(GstElement * element,gboolean * has_sinkpad,gboolean * has_srcpad)593 check_element_type (GstElement * element, gboolean * has_sinkpad,
594     gboolean * has_srcpad)
595 {
596   GstElementClass *element_class = GST_ELEMENT_GET_CLASS (element);
597   const GList *tmpl_list;
598 
599   *has_srcpad = element->numsrcpads > 0;
600   *has_sinkpad = element->numsinkpads > 0;
601 
602   tmpl_list = gst_element_class_get_pad_template_list (element_class);
603 
604   while (tmpl_list) {
605     GstPadTemplate *pad_tmpl = (GstPadTemplate *) tmpl_list->data;
606     tmpl_list = g_list_next (tmpl_list);
607     if (GST_PAD_TEMPLATE_DIRECTION (pad_tmpl) == GST_PAD_SRC)
608       *has_srcpad |= TRUE;
609     if (GST_PAD_TEMPLATE_DIRECTION (pad_tmpl) == GST_PAD_SINK)
610       *has_sinkpad |= TRUE;
611   }
612 }
613 
614 static void
turn_async_and_sync_off(GstElement * element)615 turn_async_and_sync_off (GstElement * element)
616 {
617   GObjectClass *class = G_OBJECT_GET_CLASS (element);
618   if (g_object_class_find_property (class, "async"))
619     g_object_set (element, "async", FALSE, NULL);
620   if (g_object_class_find_property (class, "sync"))
621     g_object_set (element, "sync", FALSE, NULL);
622 }
623 
624 static gboolean
gst_pad_is_request_pad(GstPad * pad)625 gst_pad_is_request_pad (GstPad * pad)
626 {
627   GstPadTemplate *temp;
628   gboolean is_request;
629 
630   if (pad == NULL)
631     return FALSE;
632   temp = gst_pad_get_pad_template (pad);
633   if (temp == NULL)
634     return FALSE;
635   is_request = GST_PAD_TEMPLATE_PRESENCE (temp) == GST_PAD_REQUEST;
636   gst_object_unref (temp);
637   return is_request;
638 }
639 
640 /**
641  * gst_harness_new_empty: (skip)
642  *
643  * Creates a new empty harness. Use gst_harness_add_element_full() to add
644  * an #GstElement to it.
645  *
646  * MT safe.
647  *
648  * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
649  * not be created
650  *
651  * Since: 1.8
652  */
653 GstHarness *
gst_harness_new_empty(void)654 gst_harness_new_empty (void)
655 {
656   GstHarness *h;
657   GstHarnessPrivate *priv;
658 
659   h = g_new0 (GstHarness, 1);
660   g_assert (h != NULL);
661   h->priv = g_new0 (GstHarnessPrivate, 1);
662   priv = h->priv;
663 
664   GST_DEBUG_OBJECT (h, "about to create new harness %p", h);
665   priv->last_push_ts = GST_CLOCK_TIME_NONE;
666   priv->latency_min = 0;
667   priv->latency_max = GST_CLOCK_TIME_NONE;
668   priv->drop_buffers = FALSE;
669   priv->testclock = GST_TEST_CLOCK_CAST (gst_test_clock_new ());
670 
671   priv->propose_allocator = NULL;
672   gst_allocation_params_init (&priv->propose_allocation_params);
673 
674   g_mutex_init (&priv->blocking_push_mutex);
675   g_cond_init (&priv->blocking_push_cond);
676   g_mutex_init (&priv->priv_mutex);
677 
678   priv->stress = g_ptr_array_new_with_free_func (
679       (GDestroyNotify) gst_harness_stress_free);
680 
681   /* we have forwarding on as a default */
682   gst_harness_set_forwarding (h, TRUE);
683 
684   return h;
685 }
686 
687 /**
688  * gst_harness_add_element_full: (skip)
689  * @h: a #GstHarness
690  * @element: a #GstElement to add to the harness (transfer none)
691  * @hsrc: (allow-none): a #GstStaticPadTemplate describing the harness srcpad.
692  * %NULL will not create a harness srcpad.
693  * @element_sinkpad_name: (allow-none): a #gchar with the name of the element
694  * sinkpad that is then linked to the harness srcpad. Can be a static or request
695  * or a sometimes pad that has been added. %NULL will not get/request a sinkpad
696  * from the element. (Like if the element is a src.)
697  * @hsink: (allow-none): a #GstStaticPadTemplate describing the harness sinkpad.
698  * %NULL will not create a harness sinkpad.
699  * @element_srcpad_name: (allow-none): a #gchar with the name of the element
700  * srcpad that is then linked to the harness sinkpad, similar to the
701  * @element_sinkpad_name.
702  *
703  * Adds a #GstElement to an empty #GstHarness
704  *
705  * MT safe.
706  *
707  * Since: 1.6
708  */
709 void
gst_harness_add_element_full(GstHarness * h,GstElement * element,GstStaticPadTemplate * hsrc,const gchar * element_sinkpad_name,GstStaticPadTemplate * hsink,const gchar * element_srcpad_name)710 gst_harness_add_element_full (GstHarness * h, GstElement * element,
711     GstStaticPadTemplate * hsrc, const gchar * element_sinkpad_name,
712     GstStaticPadTemplate * hsink, const gchar * element_srcpad_name)
713 {
714   GstClock *element_clock;
715   gboolean has_sinkpad, has_srcpad;
716 
717   g_return_if_fail (element != NULL);
718   g_return_if_fail (h->element == NULL);
719 
720   element_clock = GST_ELEMENT_CLOCK (element);
721   h->element = gst_object_ref (element);
722   check_element_type (element, &has_sinkpad, &has_srcpad);
723 
724   /* setup the loose srcpad linked to the element sinkpad */
725   if (has_sinkpad)
726     gst_harness_setup_src_pad (h, hsrc, element_sinkpad_name);
727 
728   /* setup the loose sinkpad linked to the element srcpad */
729   if (has_srcpad)
730     gst_harness_setup_sink_pad (h, hsink, element_srcpad_name);
731 
732   /* as a harness sink, we should not need sync and async */
733   if (has_sinkpad && !has_srcpad)
734     turn_async_and_sync_off (h->element);
735 
736   if (h->srcpad != NULL) {
737     gboolean handled;
738     gchar *stream_id = g_strdup_printf ("%s-%p",
739         GST_OBJECT_NAME (h->element), h);
740     handled = gst_pad_push_event (h->srcpad,
741         gst_event_new_stream_start (stream_id));
742     g_assert (handled);
743     g_free (stream_id);
744   }
745 
746   /* if the element already has a testclock attached,
747      we replace our own with it, if no clock we attach the testclock */
748   if (element_clock) {
749     if (GST_IS_TEST_CLOCK (element_clock)) {
750       gst_object_replace ((GstObject **) & h->priv->testclock,
751           (GstObject *) GST_ELEMENT_CLOCK (element));
752     }
753   } else {
754     gst_harness_use_testclock (h);
755   }
756 
757   /* don't start sources, they start producing data! */
758   if (has_sinkpad)
759     gst_harness_play (h);
760 
761   gst_harness_element_ref (h);
762 
763   GST_DEBUG_OBJECT (h, "added element to harness %p "
764       "with element_srcpad_name (%p, %s, %s) and element_sinkpad_name (%p, %s, %s)",
765       h, h->srcpad, GST_DEBUG_PAD_NAME (h->srcpad),
766       h->sinkpad, GST_DEBUG_PAD_NAME (h->sinkpad));
767 }
768 
769 /**
770  * gst_harness_new_full: (skip)
771  * @element: a #GstElement to attach the harness to (transfer none)
772  * @hsrc: (allow-none): a #GstStaticPadTemplate describing the harness srcpad.
773  * %NULL will not create a harness srcpad.
774  * @element_sinkpad_name: (allow-none): a #gchar with the name of the element
775  * sinkpad that is then linked to the harness srcpad. Can be a static or request
776  * or a sometimes pad that has been added. %NULL will not get/request a sinkpad
777  * from the element. (Like if the element is a src.)
778  * @hsink: (allow-none): a #GstStaticPadTemplate describing the harness sinkpad.
779  * %NULL will not create a harness sinkpad.
780  * @element_srcpad_name: (allow-none): a #gchar with the name of the element
781  * srcpad that is then linked to the harness sinkpad, similar to the
782  * @element_sinkpad_name.
783  *
784  * Creates a new harness.
785  *
786  * MT safe.
787  *
788  * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
789  * not be created
790  *
791  * Since: 1.6
792  */
793 GstHarness *
gst_harness_new_full(GstElement * element,GstStaticPadTemplate * hsrc,const gchar * element_sinkpad_name,GstStaticPadTemplate * hsink,const gchar * element_srcpad_name)794 gst_harness_new_full (GstElement * element,
795     GstStaticPadTemplate * hsrc, const gchar * element_sinkpad_name,
796     GstStaticPadTemplate * hsink, const gchar * element_srcpad_name)
797 {
798   GstHarness *h;
799   h = gst_harness_new_empty ();
800   gst_harness_add_element_full (h, element,
801       hsrc, element_sinkpad_name, hsink, element_srcpad_name);
802   return h;
803 }
804 
805 /**
806  * gst_harness_new_with_element: (skip)
807  * @element: a #GstElement to attach the harness to (transfer none)
808  * @element_sinkpad_name: (allow-none): a #gchar with the name of the element
809  * sinkpad that is then linked to the harness srcpad. %NULL does not attach a
810  * sinkpad
811  * @element_srcpad_name: (allow-none): a #gchar with the name of the element
812  * srcpad that is then linked to the harness sinkpad. %NULL does not attach a
813  * srcpad
814  *
815  * Creates a new harness. Works in the same way as gst_harness_new_full(), only
816  * that generic padtemplates are used for the harness src and sinkpads, which
817  * will be sufficient in most usecases.
818  *
819  * MT safe.
820  *
821  * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
822  * not be created
823  *
824  * Since: 1.6
825  */
826 GstHarness *
gst_harness_new_with_element(GstElement * element,const gchar * element_sinkpad_name,const gchar * element_srcpad_name)827 gst_harness_new_with_element (GstElement * element,
828     const gchar * element_sinkpad_name, const gchar * element_srcpad_name)
829 {
830   return gst_harness_new_full (element,
831       &hsrctemplate, element_sinkpad_name, &hsinktemplate, element_srcpad_name);
832 }
833 
834 /**
835  * gst_harness_new_with_padnames: (skip)
836  * @element_name: a #gchar describing the #GstElement name
837  * @element_sinkpad_name: (allow-none): a #gchar with the name of the element
838  * sinkpad that is then linked to the harness srcpad. %NULL does not attach a
839  * sinkpad
840  * @element_srcpad_name: (allow-none): a #gchar with the name of the element
841  * srcpad that is then linked to the harness sinkpad. %NULL does not attach a
842  * srcpad
843  *
844  * Creates a new harness. Works like gst_harness_new_with_element(),
845  * except you specify the factoryname of the #GstElement
846  *
847  * MT safe.
848  *
849  * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
850  * not be created
851  *
852  * Since: 1.6
853  */
854 GstHarness *
gst_harness_new_with_padnames(const gchar * element_name,const gchar * element_sinkpad_name,const gchar * element_srcpad_name)855 gst_harness_new_with_padnames (const gchar * element_name,
856     const gchar * element_sinkpad_name, const gchar * element_srcpad_name)
857 {
858   GstHarness *h;
859   GstElement *element = gst_element_factory_make (element_name, NULL);
860   g_assert (element != NULL);
861 
862   h = gst_harness_new_with_element (element, element_sinkpad_name,
863       element_srcpad_name);
864   gst_object_unref (element);
865   return h;
866 }
867 
868 /**
869  * gst_harness_new_with_templates: (skip)
870  * @element_name: a #gchar describing the #GstElement name
871  * @hsrc: (allow-none): a #GstStaticPadTemplate describing the harness srcpad.
872  * %NULL will not create a harness srcpad.
873  * @hsink: (allow-none): a #GstStaticPadTemplate describing the harness sinkpad.
874  * %NULL will not create a harness sinkpad.
875  *
876  * Creates a new harness, like gst_harness_new_full(), except it
877  * assumes the #GstElement sinkpad is named "sink" and srcpad is named "src"
878  *
879  * MT safe.
880  *
881  * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
882  * not be created
883  *
884  * Since: 1.6
885  */
886 GstHarness *
gst_harness_new_with_templates(const gchar * element_name,GstStaticPadTemplate * hsrc,GstStaticPadTemplate * hsink)887 gst_harness_new_with_templates (const gchar * element_name,
888     GstStaticPadTemplate * hsrc, GstStaticPadTemplate * hsink)
889 {
890   GstHarness *h;
891   GstElement *element = gst_element_factory_make (element_name, NULL);
892   g_assert (element != NULL);
893 
894   h = gst_harness_new_full (element, hsrc, "sink", hsink, "src");
895   gst_object_unref (element);
896   return h;
897 }
898 
899 /**
900  * gst_harness_new: (skip)
901  * @element_name: a #gchar describing the #GstElement name
902  *
903  * Creates a new harness. Works like gst_harness_new_with_padnames(), except it
904  * assumes the #GstElement sinkpad is named "sink" and srcpad is named "src"
905  *
906  * MT safe.
907  *
908  * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
909  * not be created
910  *
911  * Since: 1.6
912  */
913 GstHarness *
gst_harness_new(const gchar * element_name)914 gst_harness_new (const gchar * element_name)
915 {
916   return gst_harness_new_with_padnames (element_name, "sink", "src");
917 }
918 
919 /**
920  * gst_harness_add_parse: (skip)
921  * @h: a #GstHarness
922  * @launchline: a #gchar describing a gst-launch type line
923  *
924  * Parses the @launchline and puts that in a #GstBin,
925  * and then attches the supplied #GstHarness to the bin.
926  *
927  * MT safe.
928  *
929  * Since: 1.6
930  */
931 void
gst_harness_add_parse(GstHarness * h,const gchar * launchline)932 gst_harness_add_parse (GstHarness * h, const gchar * launchline)
933 {
934   GstBin *bin;
935   gchar *desc;
936   GstPad *pad;
937   GstIterator *iter;
938   gboolean done = FALSE;
939   GError *error = NULL;
940 
941   g_return_if_fail (launchline != NULL);
942 
943   desc = g_strdup_printf ("bin.( %s )", launchline);
944   bin =
945       (GstBin *) gst_parse_launch_full (desc, NULL, GST_PARSE_FLAG_FATAL_ERRORS,
946       &error);
947 
948   if (G_UNLIKELY (error != NULL)) {
949     g_error ("Unable to create pipeline '%s': %s", desc, error->message);
950   }
951   g_free (desc);
952 
953   /* find pads and ghost them if necessary */
954   if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SRC)) != NULL) {
955     gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", pad));
956     gst_object_unref (pad);
957   }
958   if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SINK)) != NULL) {
959     gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", pad));
960     gst_object_unref (pad);
961   }
962 
963   iter = gst_bin_iterate_sinks (bin);
964   while (!done) {
965     GValue item = { 0, };
966 
967     switch (gst_iterator_next (iter, &item)) {
968       case GST_ITERATOR_OK:
969         turn_async_and_sync_off (GST_ELEMENT (g_value_get_object (&item)));
970         g_value_reset (&item);
971         break;
972       case GST_ITERATOR_DONE:
973         done = TRUE;
974         break;
975       case GST_ITERATOR_RESYNC:
976         gst_iterator_resync (iter);
977         break;
978       case GST_ITERATOR_ERROR:
979         gst_object_unref (bin);
980         gst_iterator_free (iter);
981         g_return_if_reached ();
982         break;
983     }
984   }
985   gst_iterator_free (iter);
986 
987   gst_harness_add_element_full (h, GST_ELEMENT_CAST (bin),
988       &hsrctemplate, "sink", &hsinktemplate, "src");
989   gst_object_unref (bin);
990 }
991 
992 /**
993  * gst_harness_new_parse: (skip)
994  * @launchline: a #gchar describing a gst-launch type line
995  *
996  * Creates a new harness, parsing the @launchline and putting that in a #GstBin,
997  * and then attches the harness to the bin.
998  *
999  * MT safe.
1000  *
1001  * Returns: (transfer full): a #GstHarness, or %NULL if the harness could
1002  * not be created
1003  *
1004  * Since: 1.6
1005  */
1006 GstHarness *
gst_harness_new_parse(const gchar * launchline)1007 gst_harness_new_parse (const gchar * launchline)
1008 {
1009   GstHarness *h;
1010   h = gst_harness_new_empty ();
1011   gst_harness_add_parse (h, launchline);
1012   return h;
1013 }
1014 
1015 /**
1016  * gst_harness_teardown:
1017  * @h: a #GstHarness
1018  *
1019  * Tears down a @GstHarness, freeing all resources allocated using it.
1020  *
1021  * MT safe.
1022  *
1023  * Since: 1.6
1024  */
1025 void
gst_harness_teardown(GstHarness * h)1026 gst_harness_teardown (GstHarness * h)
1027 {
1028   GstHarnessPrivate *priv = h->priv;
1029 
1030   if (priv->blocking_push_mode) {
1031     g_mutex_lock (&priv->blocking_push_mutex);
1032     priv->blocking_push_mode = FALSE;
1033     g_cond_signal (&priv->blocking_push_cond);
1034     g_mutex_unlock (&priv->blocking_push_mutex);
1035   }
1036 
1037   if (h->src_harness) {
1038     gst_harness_teardown (h->src_harness);
1039   }
1040 
1041   gst_object_replace ((GstObject **) & priv->sink_forward_pad, NULL);
1042   if (h->sink_harness) {
1043     gst_harness_teardown (h->sink_harness);
1044   }
1045 
1046   if (priv->src_caps)
1047     gst_caps_unref (priv->src_caps);
1048 
1049   if (priv->sink_caps)
1050     gst_caps_unref (priv->sink_caps);
1051 
1052   if (h->srcpad) {
1053     if (gst_pad_is_request_pad (GST_PAD_PEER (h->srcpad)))
1054       gst_element_release_request_pad (h->element, GST_PAD_PEER (h->srcpad));
1055     g_free (priv->element_sinkpad_name);
1056 
1057     gst_pad_set_active (h->srcpad, FALSE);
1058     gst_object_unref (h->srcpad);
1059 
1060     g_async_queue_unref (priv->src_event_queue);
1061   }
1062 
1063   if (h->sinkpad) {
1064     if (gst_pad_is_request_pad (GST_PAD_PEER (h->sinkpad)))
1065       gst_element_release_request_pad (h->element, GST_PAD_PEER (h->sinkpad));
1066     g_free (priv->element_srcpad_name);
1067 
1068     gst_pad_set_active (h->sinkpad, FALSE);
1069     gst_object_unref (h->sinkpad);
1070 
1071     g_async_queue_unref (priv->buffer_queue);
1072     g_async_queue_unref (priv->sink_event_queue);
1073   }
1074 
1075   gst_object_replace ((GstObject **) & priv->propose_allocator, NULL);
1076   gst_object_replace ((GstObject **) & priv->allocator, NULL);
1077   gst_object_replace ((GstObject **) & priv->pool, NULL);
1078 
1079   if (priv->propose_allocation_metas)
1080     g_array_unref (priv->propose_allocation_metas);
1081 
1082   /* if we hold the last ref, set to NULL */
1083   if (gst_harness_element_unref (h) == 0) {
1084     gboolean state_change;
1085     GstState state, pending;
1086     state_change = gst_element_set_state (h->element, GST_STATE_NULL);
1087     g_assert (state_change == GST_STATE_CHANGE_SUCCESS);
1088     state_change = gst_element_get_state (h->element, &state, &pending, 0);
1089     g_assert (state_change == GST_STATE_CHANGE_SUCCESS);
1090     g_assert (state == GST_STATE_NULL);
1091   }
1092 
1093   g_cond_clear (&priv->blocking_push_cond);
1094   g_mutex_clear (&priv->blocking_push_mutex);
1095   g_mutex_clear (&priv->priv_mutex);
1096 
1097   g_ptr_array_unref (priv->stress);
1098 
1099   gst_object_unref (h->element);
1100 
1101   gst_object_replace ((GstObject **) & priv->testclock, NULL);
1102 
1103   g_free (h->priv);
1104   g_free (h);
1105 }
1106 
1107 /**
1108  * gst_harness_add_element_src_pad:
1109  * @h: a #GstHarness
1110  * @srcpad: a #GstPad to link to the harness sinkpad
1111  *
1112  * Links the specified #GstPad the @GstHarness sinkpad. This can be useful if
1113  * perhaps the srcpad did not exist at the time of creating the harness,
1114  * like a demuxer that provides a sometimes-pad after receiving data.
1115  *
1116  * MT safe.
1117  *
1118  * Since: 1.6
1119  */
1120 void
gst_harness_add_element_src_pad(GstHarness * h,GstPad * srcpad)1121 gst_harness_add_element_src_pad (GstHarness * h, GstPad * srcpad)
1122 {
1123   GstHarnessPrivate *priv = h->priv;
1124   GstPadLinkReturn link;
1125   if (h->sinkpad == NULL)
1126     gst_harness_setup_sink_pad (h, &hsinktemplate, NULL);
1127   link = gst_pad_link (srcpad, h->sinkpad);
1128   g_assert_cmpint (link, ==, GST_PAD_LINK_OK);
1129   g_free (priv->element_srcpad_name);
1130   priv->element_srcpad_name = gst_pad_get_name (srcpad);
1131 }
1132 
1133 /**
1134  * gst_harness_add_element_sink_pad:
1135  * @h: a #GstHarness
1136  * @sinkpad: a #GstPad to link to the harness srcpad
1137  *
1138  * Links the specified #GstPad the @GstHarness srcpad.
1139  *
1140  * MT safe.
1141  *
1142  * Since: 1.6
1143  */
1144 void
gst_harness_add_element_sink_pad(GstHarness * h,GstPad * sinkpad)1145 gst_harness_add_element_sink_pad (GstHarness * h, GstPad * sinkpad)
1146 {
1147   GstHarnessPrivate *priv = h->priv;
1148   GstPadLinkReturn link;
1149   if (h->srcpad == NULL)
1150     gst_harness_setup_src_pad (h, &hsrctemplate, NULL);
1151   link = gst_pad_link (h->srcpad, sinkpad);
1152   g_assert_cmpint (link, ==, GST_PAD_LINK_OK);
1153   g_free (priv->element_sinkpad_name);
1154   priv->element_sinkpad_name = gst_pad_get_name (sinkpad);
1155 }
1156 
1157 /**
1158  * gst_harness_set_src_caps:
1159  * @h: a #GstHarness
1160  * @caps: (transfer full): a #GstCaps to set on the harness srcpad
1161  *
1162  * Sets the @GstHarness srcpad caps. This must be done before any buffers
1163  * can legally be pushed from the harness to the element.
1164  *
1165  * MT safe.
1166  *
1167  * Since: 1.6
1168  */
1169 void
gst_harness_set_src_caps(GstHarness * h,GstCaps * caps)1170 gst_harness_set_src_caps (GstHarness * h, GstCaps * caps)
1171 {
1172   GstHarnessPrivate *priv = h->priv;
1173   GstSegment segment;
1174   gboolean handled;
1175 
1176   handled = gst_pad_push_event (h->srcpad, gst_event_new_caps (caps));
1177   g_assert (handled);
1178   gst_caps_take (&priv->src_caps, caps);
1179 
1180   gst_segment_init (&segment, GST_FORMAT_TIME);
1181   handled = gst_pad_push_event (h->srcpad, gst_event_new_segment (&segment));
1182   g_assert (handled);
1183 }
1184 
1185 /**
1186  * gst_harness_set_sink_caps:
1187  * @h: a #GstHarness
1188  * @caps: (transfer full): a #GstCaps to set on the harness sinkpad
1189  *
1190  * Sets the @GstHarness sinkpad caps.
1191  *
1192  * MT safe.
1193  *
1194  * Since: 1.6
1195  */
1196 void
gst_harness_set_sink_caps(GstHarness * h,GstCaps * caps)1197 gst_harness_set_sink_caps (GstHarness * h, GstCaps * caps)
1198 {
1199   GstHarnessPrivate *priv = h->priv;
1200 
1201   gst_caps_take (&priv->sink_caps, caps);
1202   gst_pad_push_event (h->sinkpad, gst_event_new_reconfigure ());
1203 }
1204 
1205 /**
1206  * gst_harness_set_caps:
1207  * @h: a #GstHarness
1208  * @in: (transfer full): a #GstCaps to set on the harness srcpad
1209  * @out: (transfer full): a #GstCaps to set on the harness sinkpad
1210  *
1211  * Sets the @GstHarness srcpad and sinkpad caps.
1212  *
1213  * MT safe.
1214  *
1215  * Since: 1.6
1216  */
1217 void
gst_harness_set_caps(GstHarness * h,GstCaps * in,GstCaps * out)1218 gst_harness_set_caps (GstHarness * h, GstCaps * in, GstCaps * out)
1219 {
1220   gst_harness_set_sink_caps (h, out);
1221   gst_harness_set_src_caps (h, in);
1222 }
1223 
1224 /**
1225  * gst_harness_set_src_caps_str:
1226  * @h: a #GstHarness
1227  * @str: a @gchar describing a #GstCaps to set on the harness srcpad
1228  *
1229  * Sets the @GstHarness srcpad caps using a string. This must be done before
1230  * any buffers can legally be pushed from the harness to the element.
1231  *
1232  * MT safe.
1233  *
1234  * Since: 1.6
1235  */
1236 void
gst_harness_set_src_caps_str(GstHarness * h,const gchar * str)1237 gst_harness_set_src_caps_str (GstHarness * h, const gchar * str)
1238 {
1239   gst_harness_set_src_caps (h, gst_caps_from_string (str));
1240 }
1241 
1242 /**
1243  * gst_harness_set_sink_caps_str:
1244  * @h: a #GstHarness
1245  * @str: a @gchar describing a #GstCaps to set on the harness sinkpad
1246  *
1247  * Sets the @GstHarness sinkpad caps using a string.
1248  *
1249  * MT safe.
1250  *
1251  * Since: 1.6
1252  */
1253 void
gst_harness_set_sink_caps_str(GstHarness * h,const gchar * str)1254 gst_harness_set_sink_caps_str (GstHarness * h, const gchar * str)
1255 {
1256   gst_harness_set_sink_caps (h, gst_caps_from_string (str));
1257 }
1258 
1259 /**
1260  * gst_harness_set_caps_str:
1261  * @h: a #GstHarness
1262  * @in: a @gchar describing a #GstCaps to set on the harness srcpad
1263  * @out: a @gchar describing a #GstCaps to set on the harness sinkpad
1264  *
1265  * Sets the @GstHarness srcpad and sinkpad caps using strings.
1266  *
1267  * MT safe.
1268  *
1269  * Since: 1.6
1270  */
1271 void
gst_harness_set_caps_str(GstHarness * h,const gchar * in,const gchar * out)1272 gst_harness_set_caps_str (GstHarness * h, const gchar * in, const gchar * out)
1273 {
1274   gst_harness_set_sink_caps_str (h, out);
1275   gst_harness_set_src_caps_str (h, in);
1276 }
1277 
1278 /**
1279  * gst_harness_use_systemclock:
1280  * @h: a #GstHarness
1281  *
1282  * Sets the system #GstClock on the @GstHarness #GstElement
1283  *
1284  * MT safe.
1285  *
1286  * Since: 1.6
1287  */
1288 void
gst_harness_use_systemclock(GstHarness * h)1289 gst_harness_use_systemclock (GstHarness * h)
1290 {
1291   GstClock *clock = gst_system_clock_obtain ();
1292   g_assert (clock != NULL);
1293   gst_element_set_clock (h->element, clock);
1294   gst_object_unref (clock);
1295 }
1296 
1297 /**
1298  * gst_harness_use_testclock:
1299  * @h: a #GstHarness
1300  *
1301  * Sets the #GstTestClock on the #GstHarness #GstElement
1302  *
1303  * MT safe.
1304  *
1305  * Since: 1.6
1306  */
1307 void
gst_harness_use_testclock(GstHarness * h)1308 gst_harness_use_testclock (GstHarness * h)
1309 {
1310   gst_element_set_clock (h->element, GST_CLOCK_CAST (h->priv->testclock));
1311 }
1312 
1313 /**
1314  * gst_harness_get_testclock:
1315  * @h: a #GstHarness
1316  *
1317  * Get the #GstTestClock. Useful if specific operations on the testclock is
1318  * needed.
1319  *
1320  * MT safe.
1321  *
1322  * Returns: (transfer full): a #GstTestClock, or %NULL if the testclock is not
1323  * present.
1324  *
1325  * Since: 1.6
1326  */
1327 GstTestClock *
gst_harness_get_testclock(GstHarness * h)1328 gst_harness_get_testclock (GstHarness * h)
1329 {
1330   return gst_object_ref (h->priv->testclock);
1331 }
1332 
1333 /**
1334  * gst_harness_set_time:
1335  * @h: a #GstHarness
1336  * @time: a #GstClockTime to advance the clock to
1337  *
1338  * Advance the #GstTestClock to a specific time.
1339  *
1340  * MT safe.
1341  *
1342  * Returns: a @gboolean %TRUE if the time could be set. %FALSE if not.
1343  *
1344  * Since: 1.6
1345  */
1346 gboolean
gst_harness_set_time(GstHarness * h,GstClockTime time)1347 gst_harness_set_time (GstHarness * h, GstClockTime time)
1348 {
1349   gst_test_clock_set_time (h->priv->testclock, time);
1350   return TRUE;
1351 }
1352 
1353 /**
1354  * gst_harness_wait_for_clock_id_waits:
1355  * @h: a #GstHarness
1356  * @waits: a #guint describing the numbers of #GstClockID registered with
1357  * the #GstTestClock
1358  * @timeout: a #guint describing how many seconds to wait for @waits to be true
1359  *
1360  * Waits for @timeout seconds until @waits number of #GstClockID waits is
1361  * registered with the #GstTestClock. Useful for writing deterministic tests,
1362  * where you want to make sure that an expected number of waits have been
1363  * reached.
1364  *
1365  * MT safe.
1366  *
1367  * Returns: a @gboolean %TRUE if the waits have been registered, %FALSE if not.
1368  * (Could be that it timed out waiting or that more waits than waits was found)
1369  *
1370  * Since: 1.6
1371  */
1372 gboolean
gst_harness_wait_for_clock_id_waits(GstHarness * h,guint waits,guint timeout)1373 gst_harness_wait_for_clock_id_waits (GstHarness * h, guint waits, guint timeout)
1374 {
1375   return gst_test_clock_timed_wait_for_multiple_pending_ids (h->priv->testclock,
1376       waits, timeout * 1000, NULL);
1377 }
1378 
1379 /**
1380  * gst_harness_crank_single_clock_wait:
1381  * @h: a #GstHarness
1382  *
1383  * A "crank" consists of three steps:
1384  * 1: Wait for a #GstClockID to be registered with the #GstTestClock.
1385  * 2: Advance the #GstTestClock to the time the #GstClockID is waiting for.
1386  * 3: Release the #GstClockID wait.
1387  * Together, this provides an easy way to not have to think about the details
1388  * around clocks and time, but still being able to write deterministic tests
1389  * that are dependent on this. A "crank" can be though of as the notion of
1390  * manually driving the clock forward to its next logical step.
1391  *
1392  * MT safe.
1393  *
1394  * Returns: a @gboolean %TRUE if the "crank" was successful, %FALSE if not.
1395  *
1396  * Since: 1.6
1397  */
1398 gboolean
gst_harness_crank_single_clock_wait(GstHarness * h)1399 gst_harness_crank_single_clock_wait (GstHarness * h)
1400 {
1401   return gst_test_clock_crank (h->priv->testclock);
1402 }
1403 
1404 /**
1405  * gst_harness_crank_multiple_clock_waits:
1406  * @h: a #GstHarness
1407  * @waits: a #guint describing the number of #GstClockIDs to crank
1408  *
1409  * Similar to gst_harness_crank_single_clock_wait(), this is the function to use
1410  * if your harnessed element(s) are using more then one gst_clock_id_wait.
1411  * Failing to do so can (and will) make it racy which #GstClockID you actually
1412  * are releasing, where as this function will process all the waits at the
1413  * same time, ensuring that one thread can't register another wait before
1414  * both are released.
1415  *
1416  * MT safe.
1417  *
1418  * Returns: a @gboolean %TRUE if the "crank" was successful, %FALSE if not.
1419  *
1420  * Since: 1.6
1421  */
1422 gboolean
gst_harness_crank_multiple_clock_waits(GstHarness * h,guint waits)1423 gst_harness_crank_multiple_clock_waits (GstHarness * h, guint waits)
1424 {
1425   GstTestClock *testclock = h->priv->testclock;
1426   GList *pending;
1427   guint processed;
1428 
1429   gst_test_clock_wait_for_multiple_pending_ids (testclock, waits, &pending);
1430   gst_harness_set_time (h, gst_test_clock_id_list_get_latest_time (pending));
1431   processed = gst_test_clock_process_id_list (testclock, pending);
1432 
1433   g_list_free_full (pending, gst_clock_id_unref);
1434   return processed == waits;
1435 }
1436 
1437 /**
1438  * gst_harness_play:
1439  * @h: a #GstHarness
1440  *
1441  * This will set the harnessed #GstElement to %GST_STATE_PLAYING.
1442  * #GstElements without a sink-#GstPad and with the %GST_ELEMENT_FLAG_SOURCE
1443  * flag set is considered a src #GstElement
1444  * Non-src #GstElements (like sinks and filters) are automatically set to
1445  * playing by the #GstHarness, but src #GstElements are not to avoid them
1446  * starting to produce buffers.
1447  * Hence, for src #GstElement you must call gst_harness_play() explicitly.
1448  *
1449  * MT safe.
1450  *
1451  * Since: 1.6
1452  */
1453 void
gst_harness_play(GstHarness * h)1454 gst_harness_play (GstHarness * h)
1455 {
1456   GstState state, pending;
1457   gboolean state_change;
1458   state_change = gst_element_set_state (h->element, GST_STATE_PLAYING);
1459   g_assert_cmpint (GST_STATE_CHANGE_SUCCESS, ==, state_change);
1460   state_change = gst_element_get_state (h->element, &state, &pending, 0);
1461   g_assert_cmpint (GST_STATE_CHANGE_SUCCESS, ==, state_change);
1462   g_assert_cmpint (GST_STATE_PLAYING, ==, state);
1463 }
1464 
1465 /**
1466  * gst_harness_set_blocking_push_mode:
1467  * @h: a #GstHarness
1468  *
1469  * Setting this will make the harness block in the chain-function, and
1470  * then release when gst_harness_pull() or gst_harness_try_pull() is called.
1471  * Can be useful when wanting to control a src-element that is not implementing
1472  * gst_clock_id_wait() so it can't be controlled by the #GstTestClock, since
1473  * it otherwise would produce buffers as fast as possible.
1474  *
1475  * MT safe.
1476  *
1477  * Since: 1.6
1478  */
1479 void
gst_harness_set_blocking_push_mode(GstHarness * h)1480 gst_harness_set_blocking_push_mode (GstHarness * h)
1481 {
1482   GstHarnessPrivate *priv = h->priv;
1483   priv->blocking_push_mode = TRUE;
1484 }
1485 
1486 /**
1487  * gst_harness_set_forwarding:
1488  * @h: a #GstHarness
1489  * @forwarding: a #gboolean to enable/disable forwarding
1490  *
1491  * As a convenience, a src-harness will forward %GST_EVENT_STREAM_START,
1492  * %GST_EVENT_CAPS and %GST_EVENT_SEGMENT to the main-harness if forwarding
1493  * is enabled, and forward any sticky-events from the main-harness to
1494  * the sink-harness. It will also forward the %GST_QUERY_ALLOCATION.
1495  *
1496  * If forwarding is disabled, the user will have to either manually push
1497  * these events from the src-harness using gst_harness_src_push_event(), or
1498  * create and push them manually. While this will allow full control and
1499  * inspection of these events, for the most cases having forwarding enabled
1500  * will be sufficient when writing a test where the src-harness' main function
1501  * is providing data for the main-harness.
1502  *
1503  * Forwarding is enabled by default.
1504  *
1505  * MT safe.
1506  *
1507  * Since: 1.6
1508  */
1509 void
gst_harness_set_forwarding(GstHarness * h,gboolean forwarding)1510 gst_harness_set_forwarding (GstHarness * h, gboolean forwarding)
1511 {
1512   GstHarnessPrivate *priv = h->priv;
1513   priv->forwarding = forwarding;
1514   if (h->src_harness)
1515     gst_harness_set_forwarding (h->src_harness, forwarding);
1516   if (h->sink_harness)
1517     gst_harness_set_forwarding (h->sink_harness, forwarding);
1518 }
1519 
1520 static void
gst_harness_set_forward_pad(GstHarness * h,GstPad * fwdpad)1521 gst_harness_set_forward_pad (GstHarness * h, GstPad * fwdpad)
1522 {
1523   HARNESS_LOCK (h);
1524   gst_object_replace ((GstObject **) & h->priv->sink_forward_pad,
1525       (GstObject *) fwdpad);
1526   HARNESS_UNLOCK (h);
1527 }
1528 
1529 /**
1530  * gst_harness_create_buffer:
1531  * @h: a #GstHarness
1532  * @size: a #gsize specifying the size of the buffer
1533  *
1534  * Allocates a buffer using a #GstBufferPool if present, or else using the
1535  * configured #GstAllocator and #GstAllocationParams
1536  *
1537  * MT safe.
1538  *
1539  * Returns: a #GstBuffer of size @size
1540  *
1541  * Since: 1.6
1542  */
1543 GstBuffer *
gst_harness_create_buffer(GstHarness * h,gsize size)1544 gst_harness_create_buffer (GstHarness * h, gsize size)
1545 {
1546   GstHarnessPrivate *priv = h->priv;
1547   GstBuffer *ret = NULL;
1548   GstFlowReturn flow;
1549 
1550   if (gst_pad_check_reconfigure (h->srcpad))
1551     gst_harness_negotiate (h);
1552 
1553   if (priv->pool) {
1554     flow = gst_buffer_pool_acquire_buffer (priv->pool, &ret, NULL);
1555     g_assert_cmpint (flow, ==, GST_FLOW_OK);
1556     if (gst_buffer_get_size (ret) != size) {
1557       GST_DEBUG_OBJECT (h,
1558           "use fallback, pool is configured with a different size (%"
1559           G_GSIZE_FORMAT " != %" G_GSIZE_FORMAT ")",
1560           size, gst_buffer_get_size (ret));
1561       gst_buffer_unref (ret);
1562       ret = NULL;
1563     }
1564   }
1565 
1566   if (!ret)
1567     ret =
1568         gst_buffer_new_allocate (priv->allocator, size,
1569         &priv->allocation_params);
1570 
1571   g_assert (ret != NULL);
1572   return ret;
1573 }
1574 
1575 /**
1576  * gst_harness_push:
1577  * @h: a #GstHarness
1578  * @buffer: (transfer full): a #GstBuffer to push
1579  *
1580  * Pushes a #GstBuffer on the #GstHarness srcpad. The standard way of
1581  * interacting with an harnessed element.
1582  *
1583  * MT safe.
1584  *
1585  * Returns: a #GstFlowReturn with the result from the push
1586  *
1587  * Since: 1.6
1588  */
1589 GstFlowReturn
gst_harness_push(GstHarness * h,GstBuffer * buffer)1590 gst_harness_push (GstHarness * h, GstBuffer * buffer)
1591 {
1592   GstHarnessPrivate *priv = h->priv;
1593   g_assert (buffer != NULL);
1594   priv->last_push_ts = GST_BUFFER_TIMESTAMP (buffer);
1595   return gst_pad_push (h->srcpad, buffer);
1596 }
1597 
1598 /**
1599  * gst_harness_pull:
1600  * @h: a #GstHarness
1601  *
1602  * Pulls a #GstBuffer from the #GAsyncQueue on the #GstHarness sinkpad. The pull
1603  * will timeout in 60 seconds. This is the standard way of getting a buffer
1604  * from a harnessed #GstElement.
1605  *
1606  * MT safe.
1607  *
1608  * Returns: (transfer full): a #GstBuffer or %NULL if timed out.
1609  *
1610  * Since: 1.6
1611  */
1612 GstBuffer *
gst_harness_pull(GstHarness * h)1613 gst_harness_pull (GstHarness * h)
1614 {
1615   GstHarnessPrivate *priv = h->priv;
1616   GstBuffer *buf = (GstBuffer *) g_async_queue_timeout_pop (priv->buffer_queue,
1617       G_USEC_PER_SEC * 60);
1618 
1619   if (priv->blocking_push_mode) {
1620     g_mutex_lock (&priv->blocking_push_mutex);
1621     g_cond_signal (&priv->blocking_push_cond);
1622     g_mutex_unlock (&priv->blocking_push_mutex);
1623   }
1624 
1625   return buf;
1626 }
1627 
1628 /**
1629  * gst_harness_try_pull:
1630  * @h: a #GstHarness
1631  *
1632  * Pulls a #GstBuffer from the #GAsyncQueue on the #GstHarness sinkpad. Unlike
1633  * gst_harness_pull this will not wait for any buffers if not any are present,
1634  * and return %NULL straight away.
1635  *
1636  * MT safe.
1637  *
1638  * Returns: (transfer full): a #GstBuffer or %NULL if no buffers are present in the #GAsyncQueue
1639  *
1640  * Since: 1.6
1641  */
1642 GstBuffer *
gst_harness_try_pull(GstHarness * h)1643 gst_harness_try_pull (GstHarness * h)
1644 {
1645   GstHarnessPrivate *priv = h->priv;
1646   GstBuffer *buf = (GstBuffer *) g_async_queue_try_pop (priv->buffer_queue);
1647 
1648   if (priv->blocking_push_mode) {
1649     g_mutex_lock (&priv->blocking_push_mutex);
1650     g_cond_signal (&priv->blocking_push_cond);
1651     g_mutex_unlock (&priv->blocking_push_mutex);
1652   }
1653 
1654   return buf;
1655 }
1656 
1657 /**
1658  * gst_harness_push_and_pull:
1659  * @h: a #GstHarness
1660  * @buffer: (transfer full): a #GstBuffer to push
1661  *
1662  * Basically a gst_harness_push and a gst_harness_pull in one line. Reflects
1663  * the fact that you often want to do exactly this in your test: Push one buffer
1664  * in, and inspect the outcome.
1665  *
1666  * MT safe.
1667  *
1668  * Returns: (transfer full): a #GstBuffer or %NULL if timed out.
1669  *
1670  * Since: 1.6
1671  */
1672 GstBuffer *
gst_harness_push_and_pull(GstHarness * h,GstBuffer * buffer)1673 gst_harness_push_and_pull (GstHarness * h, GstBuffer * buffer)
1674 {
1675   gst_harness_push (h, buffer);
1676   return gst_harness_pull (h);
1677 }
1678 
1679 /**
1680  * gst_harness_buffers_received:
1681  * @h: a #GstHarness
1682  *
1683  * The total number of #GstBuffers that has arrived on the #GstHarness sinkpad.
1684  * This number includes buffers that have been dropped as well as buffers
1685  * that have already been pulled out.
1686  *
1687  * MT safe.
1688  *
1689  * Returns: a #guint number of buffers received
1690  *
1691  * Since: 1.6
1692  */
1693 guint
gst_harness_buffers_received(GstHarness * h)1694 gst_harness_buffers_received (GstHarness * h)
1695 {
1696   GstHarnessPrivate *priv = h->priv;
1697   return g_atomic_int_get (&priv->recv_buffers);
1698 }
1699 
1700 /**
1701  * gst_harness_buffers_in_queue:
1702  * @h: a #GstHarness
1703  *
1704  * The number of #GstBuffers currently in the #GstHarness sinkpad #GAsyncQueue
1705  *
1706  * MT safe.
1707  *
1708  * Returns: a #guint number of buffers in the queue
1709  *
1710  * Since: 1.6
1711  */
1712 guint
gst_harness_buffers_in_queue(GstHarness * h)1713 gst_harness_buffers_in_queue (GstHarness * h)
1714 {
1715   GstHarnessPrivate *priv = h->priv;
1716   return g_async_queue_length (priv->buffer_queue);
1717 }
1718 
1719 /**
1720  * gst_harness_set_drop_buffers:
1721  * @h: a #GstHarness
1722  * @drop_buffers: a #gboolean specifying to drop outgoing buffers or not
1723  *
1724  * When set to %TRUE, instead of placing the buffers arriving from the harnessed
1725  * #GstElement inside the sinkpads #GAsyncQueue, they are instead unreffed.
1726  *
1727  * MT safe.
1728  *
1729  * Since: 1.6
1730  */
1731 void
gst_harness_set_drop_buffers(GstHarness * h,gboolean drop_buffers)1732 gst_harness_set_drop_buffers (GstHarness * h, gboolean drop_buffers)
1733 {
1734   GstHarnessPrivate *priv = h->priv;
1735   priv->drop_buffers = drop_buffers;
1736 }
1737 
1738 /**
1739  * gst_harness_take_all_data_as_buffer:
1740  * @h: a #GstHarness
1741  *
1742  * Pulls all pending data from the harness and returns it as a single buffer.
1743  *
1744  * Returns: (transfer full): the data as a buffer. Unref with gst_buffer_unref()
1745  *     when no longer needed.
1746  *
1747  * Since: 1.14
1748  */
1749 GstBuffer *
gst_harness_take_all_data_as_buffer(GstHarness * h)1750 gst_harness_take_all_data_as_buffer (GstHarness * h)
1751 {
1752   GstHarnessPrivate *priv;
1753   GstBuffer *ret, *buf;
1754 
1755   g_return_val_if_fail (h != NULL, NULL);
1756 
1757   priv = h->priv;
1758 
1759   g_async_queue_lock (priv->buffer_queue);
1760 
1761   ret = g_async_queue_try_pop_unlocked (priv->buffer_queue);
1762 
1763   if (ret == NULL) {
1764     ret = gst_buffer_new ();
1765   } else {
1766     /* buffer appending isn't very efficient for larger numbers of buffers
1767      * or lots of memories, but this function is not performance critical and
1768      * we can still improve it if and when the need arises. For now KISS. */
1769     while ((buf = g_async_queue_try_pop_unlocked (priv->buffer_queue)))
1770       ret = gst_buffer_append (ret, buf);
1771   }
1772 
1773   g_async_queue_unlock (priv->buffer_queue);
1774 
1775   return ret;
1776 }
1777 
1778 /**
1779  * gst_harness_take_all_data: (skip)
1780  * @h: a #GstHarness
1781  * @size: (out): the size of the data in bytes
1782  *
1783  * Pulls all pending data from the harness and returns it as a single
1784  * data slice.
1785  *
1786  * Returns: (transfer full): a pointer to the data, newly allocated. Free
1787  *     with g_free() when no longer needed. Will return %NULL if there is no
1788  *     data.
1789  *
1790  * Since: 1.14
1791  */
1792 guint8 *
gst_harness_take_all_data(GstHarness * h,gsize * size)1793 gst_harness_take_all_data (GstHarness * h, gsize * size)
1794 {
1795   GstBuffer *buf;
1796   guint8 *data = NULL;
1797 
1798   g_return_val_if_fail (h != NULL, NULL);
1799   g_return_val_if_fail (size != NULL, NULL);
1800 
1801   buf = gst_harness_take_all_data_as_buffer (h);
1802   gst_buffer_extract_dup (buf, 0, -1, (gpointer *) & data, size);
1803   gst_buffer_unref (buf);
1804   return data;
1805 }
1806 
1807 /**
1808  * gst_harness_take_all_data_as_bytes: (rename-to gst_harness_take_all_data)
1809  * @h: a #GstHarness
1810  *
1811  * Pulls all pending data from the harness and returns it as a single #GBytes.
1812  *
1813  * Returns: (transfer full): a pointer to the data, newly allocated. Free
1814  *     with g_free() when no longer needed.
1815  *
1816  * Since: 1.14
1817  */
1818 GBytes *
gst_harness_take_all_data_as_bytes(GstHarness * h)1819 gst_harness_take_all_data_as_bytes (GstHarness * h)
1820 {
1821   guint8 *data;
1822   gsize size = 0;
1823 
1824   g_return_val_if_fail (h != NULL, NULL);
1825 
1826   data = gst_harness_take_all_data (h, &size);
1827   return g_bytes_new_take (data, size);
1828 }
1829 
1830 
1831 /**
1832  * gst_harness_dump_to_file:
1833  * @h: a #GstHarness
1834  * @filename: a #gchar with a the name of a file
1835  *
1836  * Allows you to dump the #GstBuffers the #GstHarness sinkpad #GAsyncQueue
1837  * to a file.
1838  *
1839  * MT safe.
1840  *
1841  * Since: 1.6
1842  */
1843 void
gst_harness_dump_to_file(GstHarness * h,const gchar * filename)1844 gst_harness_dump_to_file (GstHarness * h, const gchar * filename)
1845 {
1846   GError *err = NULL;
1847   gpointer data;
1848   gsize size;
1849 
1850   data = gst_harness_take_all_data (h, &size);
1851   if (!g_file_set_contents (filename, data ? data : "", size, &err)) {
1852     g_error ("GstHarness: Failed to write data to file: %s", err->message);
1853     g_clear_error (&err);
1854   }
1855   g_free (data);
1856 }
1857 
1858 /**
1859  * gst_harness_get_last_pushed_timestamp:
1860  * @h: a #GstHarness
1861  *
1862  * Get the timestamp of the last #GstBuffer pushed on the #GstHarness srcpad,
1863  * typically with gst_harness_push or gst_harness_push_from_src.
1864  *
1865  * MT safe.
1866  *
1867  * Returns: a #GstClockTime with the timestamp or %GST_CLOCK_TIME_NONE if no
1868  * #GstBuffer has been pushed on the #GstHarness srcpad
1869  *
1870  * Since: 1.6
1871  */
1872 GstClockTime
gst_harness_get_last_pushed_timestamp(GstHarness * h)1873 gst_harness_get_last_pushed_timestamp (GstHarness * h)
1874 {
1875   GstHarnessPrivate *priv = h->priv;
1876   return priv->last_push_ts;
1877 }
1878 
1879 /**
1880  * gst_harness_push_event:
1881  * @h: a #GstHarness
1882  * @event: a #GstEvent to push
1883  *
1884  * Pushes an #GstEvent on the #GstHarness srcpad.
1885  *
1886  * MT safe.
1887  *
1888  * Returns: a #gboolean with the result from the push
1889  *
1890  * Since: 1.6
1891  */
1892 gboolean
gst_harness_push_event(GstHarness * h,GstEvent * event)1893 gst_harness_push_event (GstHarness * h, GstEvent * event)
1894 {
1895   return gst_pad_push_event (h->srcpad, event);
1896 }
1897 
1898 /**
1899  * gst_harness_pull_event:
1900  * @h: a #GstHarness
1901  *
1902  * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness sinkpad.
1903  * Timeouts after 60 seconds similar to gst_harness_pull.
1904  *
1905  * MT safe.
1906  *
1907  * Returns: a #GstEvent or %NULL if timed out.
1908  *
1909  * Since: 1.6
1910  */
1911 GstEvent *
gst_harness_pull_event(GstHarness * h)1912 gst_harness_pull_event (GstHarness * h)
1913 {
1914   GstHarnessPrivate *priv = h->priv;
1915   return (GstEvent *) g_async_queue_timeout_pop (priv->sink_event_queue,
1916       G_USEC_PER_SEC * 60);
1917 }
1918 
1919 /**
1920  * gst_harness_try_pull_event:
1921  * @h: a #GstHarness
1922  *
1923  * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness sinkpad.
1924  * See gst_harness_try_pull for details.
1925  *
1926  * MT safe.
1927  *
1928  * Returns: a #GstEvent or %NULL if no buffers are present in the #GAsyncQueue
1929  *
1930  * Since: 1.6
1931  */
1932 GstEvent *
gst_harness_try_pull_event(GstHarness * h)1933 gst_harness_try_pull_event (GstHarness * h)
1934 {
1935   GstHarnessPrivate *priv = h->priv;
1936   return (GstEvent *) g_async_queue_try_pop (priv->sink_event_queue);
1937 }
1938 
1939 /**
1940  * gst_harness_events_received:
1941  * @h: a #GstHarness
1942  *
1943  * The total number of #GstEvents that has arrived on the #GstHarness sinkpad
1944  * This number includes events handled by the harness as well as events
1945  * that have already been pulled out.
1946  *
1947  * MT safe.
1948  *
1949  * Returns: a #guint number of events received
1950  *
1951  * Since: 1.6
1952  */
1953 guint
gst_harness_events_received(GstHarness * h)1954 gst_harness_events_received (GstHarness * h)
1955 {
1956   GstHarnessPrivate *priv = h->priv;
1957   return g_atomic_int_get (&priv->recv_events);
1958 }
1959 
1960 /**
1961  * gst_harness_events_in_queue:
1962  * @h: a #GstHarness
1963  *
1964  * The number of #GstEvents currently in the #GstHarness sinkpad #GAsyncQueue
1965  *
1966  * MT safe.
1967  *
1968  * Returns: a #guint number of events in the queue
1969  *
1970  * Since: 1.6
1971  */
1972 guint
gst_harness_events_in_queue(GstHarness * h)1973 gst_harness_events_in_queue (GstHarness * h)
1974 {
1975   GstHarnessPrivate *priv = h->priv;
1976   return g_async_queue_length (priv->sink_event_queue);
1977 }
1978 
1979 /**
1980  * gst_harness_push_upstream_event:
1981  * @h: a #GstHarness
1982  * @event: a #GstEvent to push
1983  *
1984  * Pushes an #GstEvent on the #GstHarness sinkpad.
1985  *
1986  * MT safe.
1987  *
1988  * Returns: a #gboolean with the result from the push
1989  *
1990  * Since: 1.6
1991  */
1992 gboolean
gst_harness_push_upstream_event(GstHarness * h,GstEvent * event)1993 gst_harness_push_upstream_event (GstHarness * h, GstEvent * event)
1994 {
1995   g_return_val_if_fail (event != NULL, FALSE);
1996   g_return_val_if_fail (GST_EVENT_IS_UPSTREAM (event), FALSE);
1997 
1998   return gst_pad_push_event (h->sinkpad, event);
1999 }
2000 
2001 /**
2002  * gst_harness_pull_upstream_event:
2003  * @h: a #GstHarness
2004  *
2005  * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness srcpad.
2006  * Timeouts after 60 seconds similar to gst_harness_pull.
2007  *
2008  * MT safe.
2009  *
2010  * Returns: a #GstEvent or %NULL if timed out.
2011  *
2012  * Since: 1.6
2013  */
2014 GstEvent *
gst_harness_pull_upstream_event(GstHarness * h)2015 gst_harness_pull_upstream_event (GstHarness * h)
2016 {
2017   GstHarnessPrivate *priv = h->priv;
2018   return (GstEvent *) g_async_queue_timeout_pop (priv->src_event_queue,
2019       G_USEC_PER_SEC * 60);
2020 }
2021 
2022 /**
2023  * gst_harness_try_pull_upstream_event:
2024  * @h: a #GstHarness
2025  *
2026  * Pulls an #GstEvent from the #GAsyncQueue on the #GstHarness srcpad.
2027  * See gst_harness_try_pull for details.
2028  *
2029  * MT safe.
2030  *
2031  * Returns: a #GstEvent or %NULL if no buffers are present in the #GAsyncQueue
2032  *
2033  * Since: 1.6
2034  */
2035 GstEvent *
gst_harness_try_pull_upstream_event(GstHarness * h)2036 gst_harness_try_pull_upstream_event (GstHarness * h)
2037 {
2038   GstHarnessPrivate *priv = h->priv;
2039   return (GstEvent *) g_async_queue_try_pop (priv->src_event_queue);
2040 }
2041 
2042 /**
2043  * gst_harness_upstream_events_received:
2044  * @h: a #GstHarness
2045  *
2046  * The total number of #GstEvents that has arrived on the #GstHarness srcpad
2047  * This number includes events handled by the harness as well as events
2048  * that have already been pulled out.
2049  *
2050  * MT safe.
2051  *
2052  * Returns: a #guint number of events received
2053  *
2054  * Since: 1.6
2055  */
2056 guint
gst_harness_upstream_events_received(GstHarness * h)2057 gst_harness_upstream_events_received (GstHarness * h)
2058 {
2059   GstHarnessPrivate *priv = h->priv;
2060   return g_atomic_int_get (&priv->recv_upstream_events);
2061 }
2062 
2063 /**
2064  * gst_harness_upstream_events_in_queue:
2065  * @h: a #GstHarness
2066  *
2067  * The number of #GstEvents currently in the #GstHarness srcpad #GAsyncQueue
2068  *
2069  * MT safe.
2070  *
2071  * Returns: a #guint number of events in the queue
2072  *
2073  * Since: 1.6
2074  */
2075 guint
gst_harness_upstream_events_in_queue(GstHarness * h)2076 gst_harness_upstream_events_in_queue (GstHarness * h)
2077 {
2078   GstHarnessPrivate *priv = h->priv;
2079   return g_async_queue_length (priv->src_event_queue);
2080 }
2081 
2082 /**
2083  * gst_harness_query_latency:
2084  * @h: a #GstHarness
2085  *
2086  * Get the min latency reported by any harnessed #GstElement.
2087  *
2088  * MT safe.
2089  *
2090  * Returns: a #GstClockTime with min latency
2091  *
2092  * Since: 1.6
2093  */
2094 GstClockTime
gst_harness_query_latency(GstHarness * h)2095 gst_harness_query_latency (GstHarness * h)
2096 {
2097   GstQuery *query;
2098   gboolean is_live;
2099   GstClockTime min = GST_CLOCK_TIME_NONE;
2100   GstClockTime max;
2101 
2102   query = gst_query_new_latency ();
2103 
2104   if (gst_pad_peer_query (h->sinkpad, query)) {
2105     gst_query_parse_latency (query, &is_live, &min, &max);
2106   }
2107   gst_query_unref (query);
2108 
2109   return min;
2110 }
2111 
2112 /**
2113  * gst_harness_set_upstream_latency:
2114  * @h: a #GstHarness
2115  * @latency: a #GstClockTime specifying the latency
2116  *
2117  * Sets the min latency reported by #GstHarness when receiving a latency-query
2118  *
2119  * Since: 1.6
2120  */
2121 void
gst_harness_set_upstream_latency(GstHarness * h,GstClockTime latency)2122 gst_harness_set_upstream_latency (GstHarness * h, GstClockTime latency)
2123 {
2124   GstHarnessPrivate *priv = h->priv;
2125   priv->latency_min = latency;
2126 }
2127 
2128 /**
2129  * gst_harness_get_allocator:
2130  * @h: a #GstHarness
2131  * @allocator: (out) (allow-none) (transfer none): the #GstAllocator used
2132  * @params: (out) (allow-none) (transfer full): the #GstAllocationParams of
2133  *   @allocator
2134  *
2135  * Gets the @allocator and its @params that has been decided to use after an
2136  * allocation query.
2137  *
2138  * MT safe.
2139  *
2140  * Since: 1.6
2141  */
2142 void
gst_harness_get_allocator(GstHarness * h,GstAllocator ** allocator,GstAllocationParams * params)2143 gst_harness_get_allocator (GstHarness * h, GstAllocator ** allocator,
2144     GstAllocationParams * params)
2145 {
2146   GstHarnessPrivate *priv = h->priv;
2147   if (allocator)
2148     *allocator = priv->allocator;
2149   if (params)
2150     *params = priv->allocation_params;
2151 }
2152 
2153 
2154 /**
2155  * gst_harness_set_propose_allocator:
2156  * @h: a #GstHarness
2157  * @allocator: (allow-none) (transfer full): a #GstAllocator
2158  * @params: (allow-none) (transfer none): a #GstAllocationParams
2159  *
2160  * Sets the @allocator and @params to propose when receiving an allocation
2161  * query.
2162  *
2163  * MT safe.
2164  *
2165  * Since: 1.6
2166  */
2167 void
gst_harness_set_propose_allocator(GstHarness * h,GstAllocator * allocator,const GstAllocationParams * params)2168 gst_harness_set_propose_allocator (GstHarness * h, GstAllocator * allocator,
2169     const GstAllocationParams * params)
2170 {
2171   GstHarnessPrivate *priv = h->priv;
2172   if (allocator)
2173     priv->propose_allocator = allocator;
2174   if (params)
2175     priv->propose_allocation_params = *params;
2176 }
2177 
2178 /**
2179  * gst_harness_add_propose_allocation_meta:
2180  * @h: a #GstHarness
2181  * @api: a metadata API
2182  * @params: (allow-none) (transfer none): API specific parameters
2183  *
2184  * Add api with params as one of the supported metadata API to propose when
2185  * receiving an allocation query.
2186  *
2187  * MT safe.
2188  *
2189  * Since: 1.16
2190  */
2191 void
gst_harness_add_propose_allocation_meta(GstHarness * h,GType api,const GstStructure * params)2192 gst_harness_add_propose_allocation_meta (GstHarness * h, GType api,
2193     const GstStructure * params)
2194 {
2195   GstHarnessPrivate *priv = h->priv;
2196   ProposeMeta meta;
2197 
2198   meta.api = api;
2199   meta.params = params ? gst_structure_copy (params) : NULL;
2200 
2201   if (!priv->propose_allocation_metas) {
2202     priv->propose_allocation_metas =
2203         g_array_new (FALSE, FALSE, sizeof (ProposeMeta));
2204     g_array_set_clear_func (priv->propose_allocation_metas,
2205         (GDestroyNotify) propose_meta_clear);
2206   }
2207   g_array_append_val (priv->propose_allocation_metas, meta);
2208 }
2209 
2210 /**
2211  * gst_harness_add_src_harness:
2212  * @h: a #GstHarness
2213  * @src_harness: (transfer full): a #GstHarness to be added as a src-harness.
2214  * @has_clock_wait: a #gboolean specifying if the #GstElement uses
2215  * gst_clock_wait_id internally.
2216  *
2217  * A src-harness is a great way of providing the #GstHarness with data.
2218  * By adding a src-type #GstElement, it is then easy to use functions like
2219  * gst_harness_push_from_src or gst_harness_src_crank_and_push_many
2220  * to provide your harnessed element with input. The @has_clock_wait variable
2221  * is a great way to control you src-element with, in that you can have it
2222  * produce a buffer for you by simply cranking the clock, and not have it
2223  * spin out of control producing buffers as fast as possible.
2224  *
2225  * If a src-harness already exists it will be replaced.
2226  *
2227  * MT safe.
2228  *
2229  * Since: 1.6
2230  */
2231 void
gst_harness_add_src_harness(GstHarness * h,GstHarness * src_harness,gboolean has_clock_wait)2232 gst_harness_add_src_harness (GstHarness * h,
2233     GstHarness * src_harness, gboolean has_clock_wait)
2234 {
2235   if (h->src_harness)
2236     gst_harness_teardown (h->src_harness);
2237   h->src_harness = src_harness;
2238   gst_harness_set_forward_pad (h->src_harness, h->srcpad);
2239   h->src_harness->priv->has_clock_wait = has_clock_wait;
2240   gst_harness_set_forwarding (h->src_harness, h->priv->forwarding);
2241 }
2242 
2243 /**
2244  * gst_harness_add_src:
2245  * @h: a #GstHarness
2246  * @src_element_name: a #gchar with the name of a #GstElement
2247  * @has_clock_wait: a #gboolean specifying if the #GstElement uses
2248  * gst_clock_wait_id internally.
2249  *
2250  * Similar to gst_harness_add_src_harness, this is a convenience to
2251  * directly create a src-harness using the @src_element_name name specified.
2252  *
2253  * MT safe.
2254  *
2255  * Since: 1.6
2256  */
2257 void
gst_harness_add_src(GstHarness * h,const gchar * src_element_name,gboolean has_clock_wait)2258 gst_harness_add_src (GstHarness * h,
2259     const gchar * src_element_name, gboolean has_clock_wait)
2260 {
2261   GstHarness *src_harness = gst_harness_new (src_element_name);
2262   gst_harness_add_src_harness (h, src_harness, has_clock_wait);
2263 }
2264 
2265 /**
2266  * gst_harness_add_src_parse:
2267  * @h: a #GstHarness
2268  * @launchline: a #gchar describing a gst-launch type line
2269  * @has_clock_wait: a #gboolean specifying if the #GstElement uses
2270  * gst_clock_wait_id internally.
2271  *
2272  * Similar to gst_harness_add_src, this allows you to specify a launch-line,
2273  * which can be useful for both having more then one #GstElement acting as your
2274  * src (Like a src producing raw buffers, and then an encoder, providing encoded
2275  * data), but also by allowing you to set properties like "is-live" directly on
2276  * the elements.
2277  *
2278  * MT safe.
2279  *
2280  * Since: 1.6
2281  */
2282 void
gst_harness_add_src_parse(GstHarness * h,const gchar * launchline,gboolean has_clock_wait)2283 gst_harness_add_src_parse (GstHarness * h,
2284     const gchar * launchline, gboolean has_clock_wait)
2285 {
2286   GstHarness *src_harness = gst_harness_new_parse (launchline);
2287   gst_harness_add_src_harness (h, src_harness, has_clock_wait);
2288 }
2289 
2290 /**
2291  * gst_harness_push_from_src:
2292  * @h: a #GstHarness
2293  *
2294  * Transfer data from the src-#GstHarness to the main-#GstHarness. It consists
2295  * of 4 steps:
2296  * 1: Make sure the src is started. (see: gst_harness_play)
2297  * 2: Crank the clock (see: gst_harness_crank_single_clock_wait)
2298  * 3: Pull a #GstBuffer from the src-#GstHarness (see: gst_harness_pull)
2299  * 4: Push the same #GstBuffer into the main-#GstHarness (see: gst_harness_push)
2300  *
2301  * MT safe.
2302  *
2303  * Returns: a #GstFlowReturn with the result of the push
2304  *
2305  * Since: 1.6
2306  */
2307 GstFlowReturn
gst_harness_push_from_src(GstHarness * h)2308 gst_harness_push_from_src (GstHarness * h)
2309 {
2310   GstBuffer *buf;
2311   gboolean crank;
2312 
2313   g_assert (h->src_harness);
2314 
2315   /* FIXME: this *is* the right time to start the src,
2316      but maybe a flag so we don't keep telling it to play? */
2317   gst_harness_play (h->src_harness);
2318 
2319   if (h->src_harness->priv->has_clock_wait) {
2320     crank = gst_harness_crank_single_clock_wait (h->src_harness);
2321     g_assert (crank);
2322   }
2323 
2324   buf = gst_harness_pull (h->src_harness);
2325   g_assert (buf != NULL);
2326   return gst_harness_push (h, buf);
2327 }
2328 
2329 /**
2330  * gst_harness_src_crank_and_push_many:
2331  * @h: a #GstHarness
2332  * @cranks: a #gint with the number of calls to gst_harness_crank_single_clock_wait
2333  * @pushes: a #gint with the number of calls to gst_harness_push
2334  *
2335  * Transfer data from the src-#GstHarness to the main-#GstHarness. Similar to
2336  * gst_harness_push_from_src, this variant allows you to specify how many cranks
2337  * and how many pushes to perform. This can be useful for both moving a lot
2338  * of data at the same time, as well as cases when one crank does not equal one
2339  * buffer to push and v.v.
2340  *
2341  * MT safe.
2342  *
2343  * Returns: a #GstFlowReturn with the result of the push
2344  *
2345  * Since: 1.6
2346  */
2347 GstFlowReturn
gst_harness_src_crank_and_push_many(GstHarness * h,gint cranks,gint pushes)2348 gst_harness_src_crank_and_push_many (GstHarness * h, gint cranks, gint pushes)
2349 {
2350   GstFlowReturn ret = GST_FLOW_OK;
2351   gboolean crank;
2352   int i;
2353 
2354   g_assert (h->src_harness);
2355   gst_harness_play (h->src_harness);
2356 
2357   for (i = 0; i < cranks; i++) {
2358     crank = gst_harness_crank_single_clock_wait (h->src_harness);
2359     g_assert (crank);
2360   }
2361 
2362   for (i = 0; i < pushes; i++) {
2363     GstBuffer *buf;
2364     buf = gst_harness_pull (h->src_harness);
2365     g_assert (buf != NULL);
2366     ret = gst_harness_push (h, buf);
2367     if (ret != GST_FLOW_OK)
2368       break;
2369   }
2370 
2371   return ret;
2372 }
2373 
2374 /**
2375  * gst_harness_src_push_event:
2376  * @h: a #GstHarness
2377  *
2378  * Similar to what gst_harness_src_push does with #GstBuffers, this transfers
2379  * a #GstEvent from the src-#GstHarness to the main-#GstHarness. Note that
2380  * some #GstEvents are being transferred automagically. Look at sink_forward_pad
2381  * for details.
2382  *
2383  * MT safe.
2384  *
2385  * Returns: a #gboolean with the result of the push
2386  *
2387  * Since: 1.6
2388  */
2389 gboolean
gst_harness_src_push_event(GstHarness * h)2390 gst_harness_src_push_event (GstHarness * h)
2391 {
2392   return gst_harness_push_event (h, gst_harness_pull_event (h->src_harness));
2393 }
2394 
2395 
2396 static gboolean
forward_sticky_events(GstPad * pad,GstEvent ** ev,gpointer user_data)2397 forward_sticky_events (GstPad * pad, GstEvent ** ev, gpointer user_data)
2398 {
2399   GstHarness *h = user_data;
2400   return gst_pad_push_event (h->priv->sink_forward_pad, gst_event_ref (*ev));
2401 }
2402 
2403 /**
2404  * gst_harness_add_sink_harness:
2405  * @h: a #GstHarness
2406  * @sink_harness: (transfer full): a #GstHarness to be added as a sink-harness.
2407  *
2408  * Similar to gst_harness_add_src, this allows you to send the data coming out
2409  * of your harnessed #GstElement to a sink-element, allowing to test different
2410  * responses the element output might create in sink elements. An example might
2411  * be an existing sink providing some analytical data on the input it receives that
2412  * can be useful to your testing. If the goal is to test a sink-element itself,
2413  * this is better achieved using gst_harness_new directly on the sink.
2414  *
2415  * If a sink-harness already exists it will be replaced.
2416  *
2417  * MT safe.
2418  *
2419  * Since: 1.6
2420  */
2421 void
gst_harness_add_sink_harness(GstHarness * h,GstHarness * sink_harness)2422 gst_harness_add_sink_harness (GstHarness * h, GstHarness * sink_harness)
2423 {
2424   GstHarnessPrivate *priv = h->priv;
2425 
2426   if (h->sink_harness) {
2427     gst_harness_set_forward_pad (h, NULL);
2428     gst_harness_teardown (h->sink_harness);
2429   }
2430   h->sink_harness = sink_harness;
2431   gst_harness_set_forward_pad (h, h->sink_harness->srcpad);
2432   if (priv->forwarding && h->sinkpad)
2433     gst_pad_sticky_events_foreach (h->sinkpad, forward_sticky_events, h);
2434   gst_harness_set_forwarding (h->sink_harness, priv->forwarding);
2435 }
2436 
2437 /**
2438  * gst_harness_add_sink:
2439  * @h: a #GstHarness
2440  * @sink_element_name: a #gchar with the name of a #GstElement
2441  *
2442  * Similar to gst_harness_add_sink_harness, this is a convenience to
2443  * directly create a sink-harness using the @sink_element_name name specified.
2444  *
2445  * MT safe.
2446  *
2447  * Since: 1.6
2448  */
2449 void
gst_harness_add_sink(GstHarness * h,const gchar * sink_element_name)2450 gst_harness_add_sink (GstHarness * h, const gchar * sink_element_name)
2451 {
2452   GstHarness *sink_harness = gst_harness_new (sink_element_name);
2453   gst_harness_add_sink_harness (h, sink_harness);
2454 }
2455 
2456 /**
2457  * gst_harness_add_sink_parse:
2458  * @h: a #GstHarness
2459  * @launchline: a #gchar with the name of a #GstElement
2460  *
2461  * Similar to gst_harness_add_sink, this allows you to specify a launch-line
2462  * instead of just an element name. See gst_harness_add_src_parse for details.
2463  *
2464  * MT safe.
2465  *
2466  * Since: 1.6
2467  */
2468 void
gst_harness_add_sink_parse(GstHarness * h,const gchar * launchline)2469 gst_harness_add_sink_parse (GstHarness * h, const gchar * launchline)
2470 {
2471   GstHarness *sink_harness = gst_harness_new_parse (launchline);
2472   gst_harness_add_sink_harness (h, sink_harness);
2473 }
2474 
2475 /**
2476  * gst_harness_push_to_sink:
2477  * @h: a #GstHarness
2478  *
2479  * Transfer one #GstBuffer from the main-#GstHarness to the sink-#GstHarness.
2480  * See gst_harness_push_from_src for details.
2481  *
2482  * MT safe.
2483  *
2484  * Returns: a #GstFlowReturn with the result of the push
2485  *
2486  * Since: 1.6
2487  */
2488 GstFlowReturn
gst_harness_push_to_sink(GstHarness * h)2489 gst_harness_push_to_sink (GstHarness * h)
2490 {
2491   GstBuffer *buf;
2492   g_assert (h->sink_harness);
2493   buf = gst_harness_pull (h);
2494   g_assert (buf != NULL);
2495   return gst_harness_push (h->sink_harness, buf);
2496 }
2497 
2498 /**
2499  * gst_harness_sink_push_many:
2500  * @h: a #GstHarness
2501  * @pushes: a #gint with the number of calls to gst_harness_push_to_sink
2502  *
2503  * Convenience that calls gst_harness_push_to_sink @pushes number of times.
2504  * Will abort the pushing if any one push fails.
2505  *
2506  * MT safe.
2507  *
2508  * Returns: a #GstFlowReturn with the result of the push
2509  *
2510  * Since: 1.6
2511  */
2512 GstFlowReturn
gst_harness_sink_push_many(GstHarness * h,gint pushes)2513 gst_harness_sink_push_many (GstHarness * h, gint pushes)
2514 {
2515   GstFlowReturn ret = GST_FLOW_OK;
2516   int i;
2517   g_assert (h->sink_harness);
2518   for (i = 0; i < pushes; i++) {
2519     ret = gst_harness_push_to_sink (h);
2520     if (ret != GST_FLOW_OK)
2521       break;
2522   }
2523   return ret;
2524 }
2525 
2526 /**
2527  * gst_harness_find_element:
2528  * @h: a #GstHarness
2529  * @element_name: a #gchar with a #GstElementFactory name
2530  *
2531  * Most useful in conjunction with gst_harness_new_parse, this will scan the
2532  * #GstElements inside the #GstHarness, and check if any of them matches
2533  * @element_name. Typical usecase being that you need to access one of the
2534  * harnessed elements for properties and/or signals.
2535  *
2536  * MT safe.
2537  *
2538  * Returns: (transfer full) (allow-none): a #GstElement or %NULL if not found
2539  *
2540  * Since: 1.6
2541  */
2542 GstElement *
gst_harness_find_element(GstHarness * h,const gchar * element_name)2543 gst_harness_find_element (GstHarness * h, const gchar * element_name)
2544 {
2545   gboolean done = FALSE;
2546   GstIterator *iter;
2547   GValue data = G_VALUE_INIT;
2548 
2549   if (!GST_IS_BIN (h->element)) {
2550     GstPluginFeature *feature;
2551 
2552     g_return_val_if_fail (GST_IS_ELEMENT (h->element), NULL);
2553 
2554     feature = GST_PLUGIN_FEATURE (gst_element_get_factory (h->element));
2555     if (!strcmp (element_name, gst_plugin_feature_get_name (feature)))
2556       return gst_object_ref (h->element);
2557 
2558     return NULL;
2559   }
2560 
2561   iter = gst_bin_iterate_elements (GST_BIN (h->element));
2562   done = FALSE;
2563 
2564   while (!done) {
2565     switch (gst_iterator_next (iter, &data)) {
2566       case GST_ITERATOR_OK:
2567       {
2568         GstElement *element = g_value_get_object (&data);
2569         GstPluginFeature *feature =
2570             GST_PLUGIN_FEATURE (gst_element_get_factory (element));
2571         if (!strcmp (element_name, gst_plugin_feature_get_name (feature))) {
2572           gst_iterator_free (iter);
2573           return element;
2574         }
2575         g_value_reset (&data);
2576         break;
2577       }
2578       case GST_ITERATOR_RESYNC:
2579         gst_iterator_resync (iter);
2580         break;
2581       case GST_ITERATOR_ERROR:
2582       case GST_ITERATOR_DONE:
2583         done = TRUE;
2584         break;
2585     }
2586   }
2587   gst_iterator_free (iter);
2588 
2589   return NULL;
2590 }
2591 
2592 /**
2593  * gst_harness_set:
2594  * @h: a #GstHarness
2595  * @element_name: a #gchar with a #GstElementFactory name
2596  * @first_property_name: a #gchar with the first property name
2597  * @...: value for the first property, followed optionally by more
2598  *  name/value pairs, followed by %NULL
2599  *
2600  * A convenience function to allows you to call g_object_set on a #GstElement
2601  * that are residing inside the #GstHarness, by using normal g_object_set
2602  * syntax.
2603  *
2604  * MT safe.
2605  *
2606  * Since: 1.6
2607  */
2608 void
gst_harness_set(GstHarness * h,const gchar * element_name,const gchar * first_property_name,...)2609 gst_harness_set (GstHarness * h,
2610     const gchar * element_name, const gchar * first_property_name, ...)
2611 {
2612   va_list var_args;
2613   GstElement *element = gst_harness_find_element (h, element_name);
2614   va_start (var_args, first_property_name);
2615   g_object_set_valist (G_OBJECT (element), first_property_name, var_args);
2616   va_end (var_args);
2617   gst_object_unref (element);
2618 }
2619 
2620 /**
2621  * gst_harness_get:
2622  * @h: a #GstHarness
2623  * @element_name: a #gchar with a #GstElementFactory name
2624  * @first_property_name: a #gchar with the first property name
2625  * @...: return location for the first property, followed optionally by more
2626  *  name/return location pairs, followed by %NULL
2627  *
2628  * A convenience function to allows you to call g_object_get on a #GstElement
2629  * that are residing inside the #GstHarness, by using normal g_object_get
2630  * syntax.
2631  *
2632  * MT safe.
2633  *
2634  * Since: 1.6
2635  */
2636 void
gst_harness_get(GstHarness * h,const gchar * element_name,const gchar * first_property_name,...)2637 gst_harness_get (GstHarness * h,
2638     const gchar * element_name, const gchar * first_property_name, ...)
2639 {
2640   va_list var_args;
2641   GstElement *element = gst_harness_find_element (h, element_name);
2642   va_start (var_args, first_property_name);
2643   g_object_get_valist (G_OBJECT (element), first_property_name, var_args);
2644   va_end (var_args);
2645   gst_object_unref (element);
2646 }
2647 
2648 /**
2649  * gst_harness_add_probe:
2650  * @h: a #GstHarness
2651  * @element_name: a #gchar with a #GstElementFactory name
2652  * @pad_name: a #gchar with the name of the pad to attach the probe to
2653  * @mask: a #GstPadProbeType (see gst_pad_add_probe)
2654  * @callback: a #GstPadProbeCallback (see gst_pad_add_probe)
2655  * @user_data: a #gpointer (see gst_pad_add_probe)
2656  * @destroy_data: a #GDestroyNotify (see gst_pad_add_probe)
2657  *
2658  * A convenience function to allows you to call gst_pad_add_probe on a
2659  * #GstPad of a #GstElement that are residing inside the #GstHarness,
2660  * by using normal gst_pad_add_probe syntax
2661  *
2662  * MT safe.
2663  *
2664  * Since: 1.6
2665  */
2666 void
gst_harness_add_probe(GstHarness * h,const gchar * element_name,const gchar * pad_name,GstPadProbeType mask,GstPadProbeCallback callback,gpointer user_data,GDestroyNotify destroy_data)2667 gst_harness_add_probe (GstHarness * h,
2668     const gchar * element_name, const gchar * pad_name, GstPadProbeType mask,
2669     GstPadProbeCallback callback, gpointer user_data,
2670     GDestroyNotify destroy_data)
2671 {
2672   GstElement *element = gst_harness_find_element (h, element_name);
2673   GstPad *pad = gst_element_get_static_pad (element, pad_name);
2674   gst_pad_add_probe (pad, mask, callback, user_data, destroy_data);
2675   gst_object_unref (pad);
2676   gst_object_unref (element);
2677 }
2678 
2679 /******************************************************************************/
2680 /*       STRESS                                                               */
2681 /******************************************************************************/
2682 struct _GstHarnessThread
2683 {
2684   GstHarness *h;
2685   GThread *thread;
2686   gboolean running;
2687 
2688   gulong sleep;
2689 
2690   GDestroyNotify freefunc;
2691 };
2692 
2693 typedef struct
2694 {
2695   GstHarnessThread t;
2696 
2697   GFunc init;
2698   GFunc callback;
2699   gpointer data;
2700 } GstHarnessCustomThread;
2701 
2702 typedef struct
2703 {
2704   GstHarnessThread t;
2705 
2706   GstCaps *caps;
2707   GstSegment segment;
2708   GstHarnessPrepareBufferFunc func;
2709   gpointer data;
2710   GDestroyNotify notify;
2711 } GstHarnessPushBufferThread;
2712 
2713 typedef struct
2714 {
2715   GstHarnessThread t;
2716 
2717   GstHarnessPrepareEventFunc func;
2718   gpointer data;
2719   GDestroyNotify notify;
2720 } GstHarnessPushEventThread;
2721 
2722 typedef struct
2723 {
2724   GstHarnessThread t;
2725 
2726   gchar *name;
2727   GValue value;
2728 } GstHarnessPropThread;
2729 
2730 typedef struct
2731 {
2732   GstHarnessThread t;
2733 
2734   GstPadTemplate *templ;
2735   gchar *name;
2736   GstCaps *caps;
2737   gboolean release;
2738 
2739   GSList *pads;
2740 } GstHarnessReqPadThread;
2741 
2742 static void
gst_harness_thread_init(GstHarnessThread * t,GDestroyNotify freefunc,GstHarness * h,gulong sleep)2743 gst_harness_thread_init (GstHarnessThread * t, GDestroyNotify freefunc,
2744     GstHarness * h, gulong sleep)
2745 {
2746   t->freefunc = freefunc;
2747   t->h = h;
2748   t->sleep = sleep;
2749 
2750   g_ptr_array_add (h->priv->stress, t);
2751 }
2752 
2753 static void
gst_harness_thread_free(GstHarnessThread * t)2754 gst_harness_thread_free (GstHarnessThread * t)
2755 {
2756   g_slice_free (GstHarnessThread, t);
2757 }
2758 
2759 static void
gst_harness_custom_thread_free(GstHarnessCustomThread * t)2760 gst_harness_custom_thread_free (GstHarnessCustomThread * t)
2761 {
2762   g_slice_free (GstHarnessCustomThread, t);
2763 }
2764 
2765 static void
gst_harness_push_buffer_thread_free(GstHarnessPushBufferThread * t)2766 gst_harness_push_buffer_thread_free (GstHarnessPushBufferThread * t)
2767 {
2768   if (t != NULL) {
2769     gst_caps_replace (&t->caps, NULL);
2770     if (t->notify != NULL)
2771       t->notify (t->data);
2772     g_slice_free (GstHarnessPushBufferThread, t);
2773   }
2774 }
2775 
2776 static void
gst_harness_push_event_thread_free(GstHarnessPushEventThread * t)2777 gst_harness_push_event_thread_free (GstHarnessPushEventThread * t)
2778 {
2779   if (t != NULL) {
2780     if (t->notify != NULL)
2781       t->notify (t->data);
2782     g_slice_free (GstHarnessPushEventThread, t);
2783   }
2784 }
2785 
2786 static void
gst_harness_property_thread_free(GstHarnessPropThread * t)2787 gst_harness_property_thread_free (GstHarnessPropThread * t)
2788 {
2789   if (t != NULL) {
2790     g_free (t->name);
2791     g_value_unset (&t->value);
2792     g_slice_free (GstHarnessPropThread, t);
2793   }
2794 }
2795 
2796 static void
gst_harness_requestpad_release(GstPad * pad,GstElement * element)2797 gst_harness_requestpad_release (GstPad * pad, GstElement * element)
2798 {
2799   gst_element_release_request_pad (element, pad);
2800   gst_object_unref (pad);
2801 }
2802 
2803 static void
gst_harness_requestpad_release_pads(GstHarnessReqPadThread * rpt)2804 gst_harness_requestpad_release_pads (GstHarnessReqPadThread * rpt)
2805 {
2806   g_slist_foreach (rpt->pads, (GFunc) gst_harness_requestpad_release,
2807       rpt->t.h->element);
2808   g_slist_free (rpt->pads);
2809   rpt->pads = NULL;
2810 }
2811 
2812 static void
gst_harness_requestpad_thread_free(GstHarnessReqPadThread * t)2813 gst_harness_requestpad_thread_free (GstHarnessReqPadThread * t)
2814 {
2815   if (t != NULL) {
2816     gst_object_replace ((GstObject **) & t->templ, NULL);
2817     g_free (t->name);
2818     gst_caps_replace (&t->caps, NULL);
2819 
2820     gst_harness_requestpad_release_pads (t);
2821     g_slice_free (GstHarnessReqPadThread, t);
2822   }
2823 }
2824 
2825 #define GST_HARNESS_THREAD_START(ID, t)                                        \
2826   (((GstHarnessThread *)t)->running = TRUE,                                    \
2827   ((GstHarnessThread *)t)->thread = g_thread_new (                             \
2828       "gst-harness-stress-"G_STRINGIFY(ID),                                    \
2829       (GThreadFunc)gst_harness_stress_##ID##_func, t))
2830 #define GST_HARNESS_THREAD_END(t)                                              \
2831    (t->running = FALSE,                                                        \
2832    GPOINTER_TO_UINT (g_thread_join (t->thread)))
2833 
2834 static void
gst_harness_stress_free(GstHarnessThread * t)2835 gst_harness_stress_free (GstHarnessThread * t)
2836 {
2837   if (t != NULL && t->freefunc != NULL)
2838     t->freefunc (t);
2839 }
2840 
2841 static gpointer
gst_harness_stress_custom_func(GstHarnessThread * t)2842 gst_harness_stress_custom_func (GstHarnessThread * t)
2843 {
2844   GstHarnessCustomThread *ct = (GstHarnessCustomThread *) t;
2845   guint count = 0;
2846 
2847   if (ct->init != NULL)
2848     ct->init (ct, ct->data);
2849 
2850   while (t->running) {
2851     ct->callback (ct, ct->data);
2852 
2853     count++;
2854     g_usleep (t->sleep);
2855   }
2856   return GUINT_TO_POINTER (count);
2857 }
2858 
2859 
2860 static gpointer
gst_harness_stress_statechange_func(GstHarnessThread * t)2861 gst_harness_stress_statechange_func (GstHarnessThread * t)
2862 {
2863   guint count = 0;
2864 
2865   while (t->running) {
2866     GstClock *clock = gst_element_get_clock (t->h->element);
2867     GstIterator *it;
2868     gboolean done = FALSE;
2869     gboolean change;
2870 
2871     change = gst_element_set_state (t->h->element, GST_STATE_NULL);
2872     g_assert (change == GST_STATE_CHANGE_SUCCESS);
2873     g_thread_yield ();
2874 
2875     it = gst_element_iterate_sink_pads (t->h->element);
2876     while (!done) {
2877       GValue item = G_VALUE_INIT;
2878       switch (gst_iterator_next (it, &item)) {
2879         case GST_ITERATOR_OK:
2880         {
2881           GstPad *sinkpad = g_value_get_object (&item);
2882           GstPad *srcpad = gst_pad_get_peer (sinkpad);
2883           if (srcpad != NULL) {
2884             gst_pad_unlink (srcpad, sinkpad);
2885             gst_pad_link (srcpad, sinkpad);
2886             gst_object_unref (srcpad);
2887           }
2888           g_value_reset (&item);
2889           break;
2890         }
2891         case GST_ITERATOR_RESYNC:
2892           gst_iterator_resync (it);
2893           break;
2894         case GST_ITERATOR_ERROR:
2895           g_assert_not_reached ();
2896         case GST_ITERATOR_DONE:
2897           done = TRUE;
2898           break;
2899       }
2900       g_value_unset (&item);
2901     }
2902     gst_iterator_free (it);
2903 
2904     if (clock != NULL) {
2905       gst_element_set_clock (t->h->element, clock);
2906       gst_object_unref (clock);
2907     }
2908     change = gst_element_set_state (t->h->element, GST_STATE_PLAYING);
2909     g_assert (change == GST_STATE_CHANGE_SUCCESS);
2910 
2911     count++;
2912     g_usleep (t->sleep);
2913   }
2914   return GUINT_TO_POINTER (count);
2915 }
2916 
2917 static gpointer
gst_harness_stress_buffer_func(GstHarnessThread * t)2918 gst_harness_stress_buffer_func (GstHarnessThread * t)
2919 {
2920   GstHarnessPushBufferThread *pt = (GstHarnessPushBufferThread *) t;
2921   guint count = 0;
2922   gchar *sid;
2923   gboolean handled;
2924 
2925   /* Push stream start, caps and segment events */
2926   sid = g_strdup_printf ("%s-%p", GST_OBJECT_NAME (t->h->element), t->h);
2927   handled = gst_pad_push_event (t->h->srcpad, gst_event_new_stream_start (sid));
2928   g_assert (handled);
2929   g_free (sid);
2930   handled = gst_pad_push_event (t->h->srcpad, gst_event_new_caps (pt->caps));
2931   g_assert (handled);
2932   handled = gst_pad_push_event (t->h->srcpad,
2933       gst_event_new_segment (&pt->segment));
2934   g_assert (handled);
2935 
2936   while (t->running) {
2937     gst_harness_push (t->h, pt->func (t->h, pt->data));
2938 
2939     count++;
2940     g_usleep (t->sleep);
2941   }
2942   return GUINT_TO_POINTER (count);
2943 }
2944 
2945 static gpointer
gst_harness_stress_event_func(GstHarnessThread * t)2946 gst_harness_stress_event_func (GstHarnessThread * t)
2947 {
2948   GstHarnessPushEventThread *pet = (GstHarnessPushEventThread *) t;
2949   guint count = 0;
2950 
2951   while (t->running) {
2952     gst_harness_push_event (t->h, pet->func (t->h, pet->data));
2953 
2954     count++;
2955     g_usleep (t->sleep);
2956   }
2957   return GUINT_TO_POINTER (count);
2958 }
2959 
2960 static gpointer
gst_harness_stress_upstream_event_func(GstHarnessThread * t)2961 gst_harness_stress_upstream_event_func (GstHarnessThread * t)
2962 {
2963   GstHarnessPushEventThread *pet = (GstHarnessPushEventThread *) t;
2964   guint count = 0;
2965 
2966   while (t->running) {
2967     gst_harness_push_upstream_event (t->h, pet->func (t->h, pet->data));
2968 
2969     count++;
2970     g_usleep (t->sleep);
2971   }
2972   return GUINT_TO_POINTER (count);
2973 }
2974 
2975 static gpointer
gst_harness_stress_property_func(GstHarnessThread * t)2976 gst_harness_stress_property_func (GstHarnessThread * t)
2977 {
2978   GstHarnessPropThread *pt = (GstHarnessPropThread *) t;
2979   guint count = 0;
2980 
2981   while (t->running) {
2982     GValue value = G_VALUE_INIT;
2983 
2984     g_object_set_property (G_OBJECT (t->h->element), pt->name, &pt->value);
2985 
2986     g_value_init (&value, G_VALUE_TYPE (&pt->value));
2987     g_object_get_property (G_OBJECT (t->h->element), pt->name, &value);
2988     g_value_reset (&value);
2989 
2990     count++;
2991     g_usleep (t->sleep);
2992   }
2993   return GUINT_TO_POINTER (count);
2994 }
2995 
2996 static gpointer
gst_harness_stress_requestpad_func(GstHarnessThread * t)2997 gst_harness_stress_requestpad_func (GstHarnessThread * t)
2998 {
2999   GstHarnessReqPadThread *rpt = (GstHarnessReqPadThread *) t;
3000   guint count = 0;
3001 
3002   while (t->running) {
3003     GstPad *reqpad;
3004 
3005     if (rpt->release)
3006       gst_harness_requestpad_release_pads (rpt);
3007 
3008     g_thread_yield ();
3009 
3010     reqpad = gst_element_request_pad (t->h->element,
3011         rpt->templ, rpt->name, rpt->caps);
3012 
3013     g_assert (reqpad != NULL);
3014 
3015     rpt->pads = g_slist_prepend (rpt->pads, reqpad);
3016 
3017     count++;
3018     g_usleep (t->sleep);
3019   }
3020   return GUINT_TO_POINTER (count);
3021 }
3022 
3023 /**
3024  * gst_harness_stress_thread_stop:
3025  * @t: a #GstHarnessThread
3026  *
3027  * Stop the running #GstHarnessThread
3028  *
3029  * MT safe.
3030  *
3031  * Since: 1.6
3032  */
3033 guint
gst_harness_stress_thread_stop(GstHarnessThread * t)3034 gst_harness_stress_thread_stop (GstHarnessThread * t)
3035 {
3036   guint ret;
3037 
3038   g_return_val_if_fail (t != NULL, 0);
3039 
3040   ret = GST_HARNESS_THREAD_END (t);
3041   g_ptr_array_remove (t->h->priv->stress, t);
3042   return ret;
3043 }
3044 
3045 /**
3046  * gst_harness_stress_custom_start: (skip)
3047  * @h: a #GstHarness
3048  * @init: (allow-none): a #GFunc that is called initially and only once
3049  * @callback: a #GFunc that is called as often as possible
3050  * @data: a #gpointer with custom data to pass to the @callback function
3051  * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3052  * each call to the @callback
3053  *
3054  * Start a custom stress-thread that will call your @callback for every
3055  * iteration allowing you to do something nasty.
3056  *
3057  * MT safe.
3058  *
3059  * Returns: a #GstHarnessThread
3060  *
3061  * Since: 1.6
3062  */
3063 GstHarnessThread *
gst_harness_stress_custom_start(GstHarness * h,GFunc init,GFunc callback,gpointer data,gulong sleep)3064 gst_harness_stress_custom_start (GstHarness * h,
3065     GFunc init, GFunc callback, gpointer data, gulong sleep)
3066 {
3067   GstHarnessCustomThread *t = g_slice_new0 (GstHarnessCustomThread);
3068   gst_harness_thread_init (&t->t,
3069       (GDestroyNotify) gst_harness_custom_thread_free, h, sleep);
3070 
3071   t->init = init;
3072   t->callback = callback;
3073   t->data = data;
3074 
3075   GST_HARNESS_THREAD_START (custom, t);
3076   return &t->t;
3077 }
3078 
3079 /**
3080  * gst_harness_stress_statechange_start_full: (skip)
3081  * @h: a #GstHarness
3082  * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3083  * each state-change
3084  *
3085  * Change the state of your harnessed #GstElement from NULL to PLAYING and
3086  * back again, only pausing for @sleep microseconds every time.
3087  *
3088  * MT safe.
3089  *
3090  * Returns: a #GstHarnessThread
3091  *
3092  * Since: 1.6
3093  */
3094 GstHarnessThread *
gst_harness_stress_statechange_start_full(GstHarness * h,gulong sleep)3095 gst_harness_stress_statechange_start_full (GstHarness * h, gulong sleep)
3096 {
3097   GstHarnessThread *t = g_slice_new0 (GstHarnessThread);
3098   gst_harness_thread_init (t,
3099       (GDestroyNotify) gst_harness_thread_free, h, sleep);
3100   GST_HARNESS_THREAD_START (statechange, t);
3101   return t;
3102 }
3103 
3104 static GstBuffer *
gst_harness_ref_buffer(GstHarness * h,gpointer data)3105 gst_harness_ref_buffer (GstHarness * h, gpointer data)
3106 {
3107   (void) h;
3108   return gst_buffer_ref (GST_BUFFER_CAST (data));
3109 }
3110 
3111 static GstEvent *
gst_harness_ref_event(GstHarness * h,gpointer data)3112 gst_harness_ref_event (GstHarness * h, gpointer data)
3113 {
3114   (void) h;
3115   return gst_event_ref (GST_EVENT_CAST (data));
3116 }
3117 
3118 /**
3119  * gst_harness_stress_push_buffer_start_full: (skip)
3120  * @h: a #GstHarness
3121  * @caps: a #GstCaps for the #GstBuffer
3122  * @segment: a #GstSegment
3123  * @buf: a #GstBuffer to push
3124  * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3125  * each call to gst_pad_push
3126  *
3127  * Push a #GstBuffer in intervals of @sleep microseconds.
3128  *
3129  * MT safe.
3130  *
3131  * Returns: a #GstHarnessThread
3132  *
3133  * Since: 1.6
3134  */
3135 GstHarnessThread *
gst_harness_stress_push_buffer_start_full(GstHarness * h,GstCaps * caps,const GstSegment * segment,GstBuffer * buf,gulong sleep)3136 gst_harness_stress_push_buffer_start_full (GstHarness * h,
3137     GstCaps * caps, const GstSegment * segment, GstBuffer * buf, gulong sleep)
3138 {
3139   return gst_harness_stress_push_buffer_with_cb_start_full (h, caps, segment,
3140       gst_harness_ref_buffer, gst_buffer_ref (buf),
3141       (GDestroyNotify) gst_buffer_unref, sleep);
3142 }
3143 
3144 /**
3145  * gst_harness_stress_push_buffer_with_cb_start_full: (skip)
3146  * @h: a #GstHarness
3147  * @caps: a #GstCaps for the #GstBuffer
3148  * @segment: a #GstSegment
3149  * @func: a #GstHarnessPrepareBufferFunc function called before every iteration
3150  * to prepare / create a #GstBuffer for pushing
3151  * @data: a #gpointer with data to the #GstHarnessPrepareBufferFunc function
3152  * @notify: a #GDestroyNotify that is called when thread is stopped
3153  * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3154  * each call to gst_pad_push
3155  *
3156  * Push a #GstBuffer returned by @func in intervals of @sleep microseconds.
3157  *
3158  * MT safe.
3159  *
3160  * Returns: a #GstHarnessThread
3161  *
3162  * Since: 1.6
3163  */
3164 GstHarnessThread *
gst_harness_stress_push_buffer_with_cb_start_full(GstHarness * h,GstCaps * caps,const GstSegment * segment,GstHarnessPrepareBufferFunc func,gpointer data,GDestroyNotify notify,gulong sleep)3165 gst_harness_stress_push_buffer_with_cb_start_full (GstHarness * h,
3166     GstCaps * caps, const GstSegment * segment,
3167     GstHarnessPrepareBufferFunc func, gpointer data, GDestroyNotify notify,
3168     gulong sleep)
3169 {
3170   GstHarnessPushBufferThread *t = g_slice_new0 (GstHarnessPushBufferThread);
3171   gst_harness_thread_init (&t->t,
3172       (GDestroyNotify) gst_harness_push_buffer_thread_free, h, sleep);
3173 
3174   gst_caps_replace (&t->caps, caps);
3175   t->segment = *segment;
3176   t->func = func;
3177   t->data = data;
3178   t->notify = notify;
3179 
3180   GST_HARNESS_THREAD_START (buffer, t);
3181   return &t->t;
3182 }
3183 
3184 /**
3185  * gst_harness_stress_push_event_start_full: (skip)
3186  * @h: a #GstHarness
3187  * @event: a #GstEvent to push
3188  * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3189  * each gst_event_push with @event
3190  *
3191  * Push the @event onto the harnessed #GstElement sinkpad in intervals of
3192  * @sleep microseconds
3193  *
3194  * MT safe.
3195  *
3196  * Returns: a #GstHarnessThread
3197  *
3198  * Since: 1.6
3199  */
3200 GstHarnessThread *
gst_harness_stress_push_event_start_full(GstHarness * h,GstEvent * event,gulong sleep)3201 gst_harness_stress_push_event_start_full (GstHarness * h,
3202     GstEvent * event, gulong sleep)
3203 {
3204   return gst_harness_stress_push_event_with_cb_start_full (h,
3205       gst_harness_ref_event, gst_event_ref (event),
3206       (GDestroyNotify) gst_event_unref, sleep);
3207 }
3208 
3209 /**
3210  * gst_harness_stress_push_event_with_cb_start_full: (skip)
3211  * @h: a #GstHarness
3212  * @func: a #GstHarnessPrepareEventFunc function called before every iteration
3213  * to prepare / create a #GstEvent for pushing
3214  * @data: a #gpointer with data to the #GstHarnessPrepareEventFunc function
3215  * @notify: a #GDestroyNotify that is called when thread is stopped
3216  * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3217  * each call to gst_pad_push
3218  *
3219  * Push a #GstEvent returned by @func onto the harnessed #GstElement sinkpad
3220  * in intervals of @sleep microseconds.
3221  *
3222  * MT safe.
3223  *
3224  * Returns: a #GstHarnessThread
3225  *
3226  * Since: 1.8
3227  */
3228 GstHarnessThread *
gst_harness_stress_push_event_with_cb_start_full(GstHarness * h,GstHarnessPrepareEventFunc func,gpointer data,GDestroyNotify notify,gulong sleep)3229 gst_harness_stress_push_event_with_cb_start_full (GstHarness * h,
3230     GstHarnessPrepareEventFunc func, gpointer data, GDestroyNotify notify,
3231     gulong sleep)
3232 {
3233   GstHarnessPushEventThread *t = g_slice_new0 (GstHarnessPushEventThread);
3234   gst_harness_thread_init (&t->t,
3235       (GDestroyNotify) gst_harness_push_event_thread_free, h, sleep);
3236 
3237   t->func = func;
3238   t->data = data;
3239   t->notify = notify;
3240 
3241   GST_HARNESS_THREAD_START (event, t);
3242   return &t->t;
3243 }
3244 
3245 /**
3246  * gst_harness_stress_push_upstream_event_start_full: (skip)
3247  * @h: a #GstHarness
3248  * @event: a #GstEvent to push
3249  * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3250  * each gst_event_push with @event
3251  *
3252  * Push the @event onto the harnessed #GstElement srcpad in intervals of
3253  * @sleep microseconds.
3254  *
3255  * MT safe.
3256  *
3257  * Returns: a #GstHarnessThread
3258  *
3259  * Since: 1.6
3260  */
3261 GstHarnessThread *
gst_harness_stress_push_upstream_event_start_full(GstHarness * h,GstEvent * event,gulong sleep)3262 gst_harness_stress_push_upstream_event_start_full (GstHarness * h,
3263     GstEvent * event, gulong sleep)
3264 {
3265   return gst_harness_stress_push_upstream_event_with_cb_start_full (h,
3266       gst_harness_ref_event, gst_event_ref (event),
3267       (GDestroyNotify) gst_event_unref, sleep);
3268 }
3269 
3270 /**
3271  * gst_harness_stress_push_upstream_event_with_cb_start_full: (skip)
3272  * @h: a #GstHarness
3273  * @func: a #GstHarnessPrepareEventFunc function called before every iteration
3274  * to prepare / create a #GstEvent for pushing
3275  * @data: a #gpointer with data to the #GstHarnessPrepareEventFunc function
3276  * @notify: a #GDestroyNotify that is called when thread is stopped
3277  * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3278  * each call to gst_pad_push
3279  *
3280  * Push a #GstEvent returned by @func onto the harnessed #GstElement srcpad
3281  * in intervals of @sleep microseconds.
3282  *
3283  * MT safe.
3284  *
3285  * Returns: a #GstHarnessThread
3286  *
3287  * Since: 1.8
3288  */
3289 GstHarnessThread *
gst_harness_stress_push_upstream_event_with_cb_start_full(GstHarness * h,GstHarnessPrepareEventFunc func,gpointer data,GDestroyNotify notify,gulong sleep)3290 gst_harness_stress_push_upstream_event_with_cb_start_full (GstHarness * h,
3291     GstHarnessPrepareEventFunc func, gpointer data, GDestroyNotify notify,
3292     gulong sleep)
3293 {
3294   GstHarnessPushEventThread *t = g_slice_new0 (GstHarnessPushEventThread);
3295   gst_harness_thread_init (&t->t,
3296       (GDestroyNotify) gst_harness_push_event_thread_free, h, sleep);
3297 
3298   t->func = func;
3299   t->data = data;
3300   t->notify = notify;
3301 
3302   GST_HARNESS_THREAD_START (upstream_event, t);
3303   return &t->t;
3304 }
3305 
3306 /**
3307  * gst_harness_stress_property_start_full: (skip)
3308  * @h: a #GstHarness
3309  * @name: a #gchar specifying a property name
3310  * @value: a #GValue to set the property to
3311  * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3312  * each g_object_set with @name and @value
3313  *
3314  * Call g_object_set with @name and @value in intervals of @sleep microseconds
3315  *
3316  * MT safe.
3317  *
3318  * Returns: a #GstHarnessThread
3319  *
3320  * Since: 1.6
3321  */
3322 GstHarnessThread *
gst_harness_stress_property_start_full(GstHarness * h,const gchar * name,const GValue * value,gulong sleep)3323 gst_harness_stress_property_start_full (GstHarness * h,
3324     const gchar * name, const GValue * value, gulong sleep)
3325 {
3326   GstHarnessPropThread *t = g_slice_new0 (GstHarnessPropThread);
3327   gst_harness_thread_init (&t->t,
3328       (GDestroyNotify) gst_harness_property_thread_free, h, sleep);
3329 
3330   t->name = g_strdup (name);
3331   g_value_init (&t->value, G_VALUE_TYPE (value));
3332   g_value_copy (value, &t->value);
3333 
3334   GST_HARNESS_THREAD_START (property, t);
3335   return &t->t;
3336 }
3337 
3338 /**
3339  * gst_harness_stress_requestpad_start_full: (skip)
3340  * @h: a #GstHarness
3341  * @templ: a #GstPadTemplate
3342  * @name: a #gchar
3343  * @caps: a #GstCaps
3344  * @release: a #gboolean
3345  * @sleep: a #gulong specifying how long to sleep in (microseconds) for
3346  * each gst_element_request_pad
3347  *
3348  * Call gst_element_request_pad in intervals of @sleep microseconds
3349  *
3350  * MT safe.
3351  *
3352  * Returns: a #GstHarnessThread
3353  *
3354  * Since: 1.6
3355  */
3356 GstHarnessThread *
gst_harness_stress_requestpad_start_full(GstHarness * h,GstPadTemplate * templ,const gchar * name,GstCaps * caps,gboolean release,gulong sleep)3357 gst_harness_stress_requestpad_start_full (GstHarness * h,
3358     GstPadTemplate * templ, const gchar * name, GstCaps * caps,
3359     gboolean release, gulong sleep)
3360 {
3361   GstHarnessReqPadThread *t = g_slice_new0 (GstHarnessReqPadThread);
3362   gst_harness_thread_init (&t->t,
3363       (GDestroyNotify) gst_harness_requestpad_thread_free, h, sleep);
3364 
3365   t->templ = gst_object_ref (templ);
3366   t->name = g_strdup (name);
3367   gst_caps_replace (&t->caps, caps);
3368   t->release = release;
3369 
3370   GST_HARNESS_THREAD_START (requestpad, t);
3371   return &t->t;
3372 }
3373