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