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