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