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