1 /* GStreamer
2 *
3 * unit testing helper lib
4 *
5 * Copyright (C) 2006 Andy Wingo <wingo at pobox.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 /**
24 * SECTION:gstcheckbufferstraw
25 * @title: GstBufferStraw
26 * @short_description: Buffer interception code for GStreamer unit tests
27 *
28 * These macros and functions are for internal use of the unit tests found
29 * inside the 'check' directories of various GStreamer packages.
30 */
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include "gstbufferstraw.h"
36
37 static GCond cond;
38 static GMutex lock;
39 static GstBuffer *buf = NULL;
40 static gulong id;
41
42 /* called for every buffer. Waits until the global "buf" variable is unset,
43 * then sets it to the buffer received, and signals. */
44 static GstPadProbeReturn
buffer_probe(GstPad * pad,GstPadProbeInfo * info,gpointer unused)45 buffer_probe (GstPad * pad, GstPadProbeInfo * info, gpointer unused)
46 {
47 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
48
49 g_mutex_lock (&lock);
50
51 while (buf != NULL)
52 g_cond_wait (&cond, &lock);
53
54 /* increase the refcount because we store it globally for others to use */
55 buf = gst_buffer_ref (buffer);
56
57 g_cond_signal (&cond);
58
59 g_mutex_unlock (&lock);
60
61 return GST_PAD_PROBE_OK;
62 }
63
64 /**
65 * gst_buffer_straw_start_pipeline:
66 * @bin: the pipeline to run
67 * @pad: a pad on an element in @bin
68 *
69 * Sets up a pipeline for buffer sucking. This will allow you to call
70 * gst_buffer_straw_get_buffer() to access buffers as they pass over @pad.
71 *
72 * This function is normally used in unit tests that want to verify that a
73 * particular element is outputting correct buffers. For example, you would make
74 * a pipeline via gst_parse_launch(), pull out the pad you want to monitor, then
75 * call gst_buffer_straw_get_buffer() to get the buffers that pass through @pad.
76 * The pipeline will block until you have sucked off the buffers.
77 *
78 * This function will set the state of @bin to PLAYING; to clean up, be sure to
79 * call gst_buffer_straw_stop_pipeline().
80 *
81 * Note that you may not start two buffer straws at the same time. This function
82 * is intended for unit tests, not general API use. In fact it calls fail_if
83 * from libcheck, so you cannot use it outside unit tests.
84 */
85 void
gst_buffer_straw_start_pipeline(GstElement * bin,GstPad * pad)86 gst_buffer_straw_start_pipeline (GstElement * bin, GstPad * pad)
87 {
88 GstStateChangeReturn ret;
89
90 id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
91 buffer_probe, NULL, NULL);
92
93 ret = gst_element_set_state (bin, GST_STATE_PLAYING);
94 fail_if (ret == GST_STATE_CHANGE_FAILURE, "Could not start test pipeline");
95 if (ret == GST_STATE_CHANGE_ASYNC) {
96 ret = gst_element_get_state (bin, NULL, NULL, GST_CLOCK_TIME_NONE);
97 fail_if (ret != GST_STATE_CHANGE_SUCCESS, "Could not start test pipeline");
98 }
99 }
100
101 /**
102 * gst_buffer_straw_get_buffer:
103 * @bin: the pipeline previously started via gst_buffer_straw_start_pipeline()
104 * @pad: the pad previously passed to gst_buffer_straw_start_pipeline()
105 *
106 * Get one buffer from @pad. Implemented via buffer probes. This function will
107 * block until the pipeline passes a buffer over @pad, so for robust behavior
108 * in unit tests, you need to use check's timeout to fail out in the case that a
109 * buffer never arrives.
110 *
111 * You must have previously called gst_buffer_straw_start_pipeline() on
112 * @pipeline and @pad.
113 *
114 * Returns: the captured #GstBuffer.
115 */
116 GstBuffer *
gst_buffer_straw_get_buffer(GstElement * bin,GstPad * pad)117 gst_buffer_straw_get_buffer (GstElement * bin, GstPad * pad)
118 {
119 GstBuffer *ret;
120
121 g_mutex_lock (&lock);
122
123 while (buf == NULL)
124 g_cond_wait (&cond, &lock);
125
126 ret = buf;
127 buf = NULL;
128
129 g_cond_signal (&cond);
130
131 g_mutex_unlock (&lock);
132
133 return ret;
134 }
135
136 /**
137 * gst_buffer_straw_stop_pipeline:
138 * @bin: the pipeline previously started via gst_buffer_straw_start_pipeline()
139 * @pad: the pad previously passed to gst_buffer_straw_start_pipeline()
140 *
141 * Set @bin to #GST_STATE_NULL and release resource allocated in
142 * gst_buffer_straw_start_pipeline().
143 *
144 * You must have previously called gst_buffer_straw_start_pipeline() on
145 * @pipeline and @pad.
146 */
147 void
gst_buffer_straw_stop_pipeline(GstElement * bin,GstPad * pad)148 gst_buffer_straw_stop_pipeline (GstElement * bin, GstPad * pad)
149 {
150 GstStateChangeReturn ret;
151
152 g_mutex_lock (&lock);
153 if (buf)
154 gst_buffer_unref (buf);
155 buf = NULL;
156 gst_pad_remove_probe (pad, (guint) id);
157 id = 0;
158 g_cond_signal (&cond);
159 g_mutex_unlock (&lock);
160
161 ret = gst_element_set_state (bin, GST_STATE_NULL);
162 fail_if (ret == GST_STATE_CHANGE_FAILURE, "Could not stop test pipeline");
163 if (ret == GST_STATE_CHANGE_ASYNC) {
164 ret = gst_element_get_state (bin, NULL, NULL, GST_CLOCK_TIME_NONE);
165 fail_if (ret != GST_STATE_CHANGE_SUCCESS, "Could not stop test pipeline");
166 }
167
168 g_mutex_lock (&lock);
169 if (buf)
170 gst_buffer_unref (buf);
171 buf = NULL;
172 g_mutex_unlock (&lock);
173 }
174