gstreamer/libs/gst/check/gstbufferstraw.c
Wim Taymans ba3028aeeb pad: Add GstPadProbeInfo
Make a new GstPadProbeInfo structure and pass this in the probe callback. This
allows us to add more things later and also allow the callback to replace or
modify the passed object.
2011-11-08 11:04:19 +01:00

179 lines
5.3 KiB
C

/* GStreamer
*
* unit testing helper lib
*
* Copyright (C) 2006 Andy Wingo <wingo at pobox.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:gstcheckbufferstraw
* @short_description: Buffer interception code for GStreamer unit tests
*
* These macros and functions are for internal use of the unit tests found
* inside the 'check' directories of various GStreamer packages.
*/
#include "gstbufferstraw.h"
static GCond *cond = NULL;
static GMutex *lock = NULL;
static GstBuffer *buf = NULL;
static gulong id;
/* called for every buffer. Waits until the global "buf" variable is unset,
* then sets it to the buffer received, and signals. */
static GstPadProbeReturn
buffer_probe (GstPad * pad, GstPadProbeInfo * info, gpointer unused)
{
GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
g_mutex_lock (lock);
while (buf != NULL)
g_cond_wait (cond, lock);
/* increase the refcount because we store it globally for others to use */
buf = gst_buffer_ref (buffer);
g_cond_signal (cond);
g_mutex_unlock (lock);
return GST_PAD_PROBE_OK;
}
/**
* gst_buffer_straw_start_pipeline:
* @bin: the pipeline to run
* @pad: a pad on an element in @bin
*
* Sets up a pipeline for buffer sucking. This will allow you to call
* gst_buffer_straw_get_buffer() to access buffers as they pass over @pad.
*
* This function is normally used in unit tests that want to verify that a
* particular element is outputting correct buffers. For example, you would make
* a pipeline via gst_parse_launch(), pull out the pad you want to monitor, then
* call gst_buffer_straw_get_buffer() to get the buffers that pass through @pad.
* The pipeline will block until you have sucked off the buffers.
*
* This function will set the state of @bin to PLAYING; to clean up, be sure to
* call gst_buffer_straw_stop_pipeline().
*
* Note that you may not start two buffer straws at the same time. This function
* is intended for unit tests, not general API use. In fact it calls fail_if
* from libcheck, so you cannot use it outside unit tests.
*/
void
gst_buffer_straw_start_pipeline (GstElement * bin, GstPad * pad)
{
GstStateChangeReturn ret;
id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
buffer_probe, NULL, NULL);
cond = g_cond_new ();
lock = g_mutex_new ();
ret = gst_element_set_state (bin, GST_STATE_PLAYING);
fail_if (ret == GST_STATE_CHANGE_FAILURE, "Could not start test pipeline");
if (ret == GST_STATE_CHANGE_ASYNC) {
ret = gst_element_get_state (bin, NULL, NULL, GST_CLOCK_TIME_NONE);
fail_if (ret != GST_STATE_CHANGE_SUCCESS, "Could not start test pipeline");
}
}
/**
* gst_buffer_straw_get_buffer:
* @bin: the pipeline previously started via gst_buffer_straw_start_pipeline()
* @pad: the pad previously passed to gst_buffer_straw_start_pipeline()
*
* Get one buffer from @pad. Implemented via buffer probes. This function will
* block until the pipeline passes a buffer over @pad, so for robust behavior
* in unit tests, you need to use check's timeout to fail out in the case that a
* buffer never arrives.
*
* You must have previously called gst_buffer_straw_start_pipeline() on
* @pipeline and @pad.
*
* Returns: the captured #GstBuffer.
*/
GstBuffer *
gst_buffer_straw_get_buffer (GstElement * bin, GstPad * pad)
{
GstBuffer *ret;
g_mutex_lock (lock);
while (buf == NULL)
g_cond_wait (cond, lock);
ret = buf;
buf = NULL;
g_cond_signal (cond);
g_mutex_unlock (lock);
return ret;
}
/**
* gst_buffer_straw_stop_pipeline:
* @bin: the pipeline previously started via gst_buffer_straw_start_pipeline()
* @pad: the pad previously passed to gst_buffer_straw_start_pipeline()
*
* Set @bin to #GST_STATE_NULL and release resource allocated in
* gst_buffer_straw_start_pipeline().
*
* You must have previously called gst_buffer_straw_start_pipeline() on
* @pipeline and @pad.
*/
void
gst_buffer_straw_stop_pipeline (GstElement * bin, GstPad * pad)
{
GstStateChangeReturn ret;
g_mutex_lock (lock);
if (buf)
gst_buffer_unref (buf);
buf = NULL;
gst_pad_remove_probe (pad, (guint) id);
id = 0;
g_cond_signal (cond);
g_mutex_unlock (lock);
ret = gst_element_set_state (bin, GST_STATE_NULL);
fail_if (ret == GST_STATE_CHANGE_FAILURE, "Could not stop test pipeline");
if (ret == GST_STATE_CHANGE_ASYNC) {
ret = gst_element_get_state (bin, NULL, NULL, GST_CLOCK_TIME_NONE);
fail_if (ret != GST_STATE_CHANGE_SUCCESS, "Could not stop test pipeline");
}
g_mutex_lock (lock);
if (buf)
gst_buffer_unref (buf);
buf = NULL;
g_mutex_unlock (lock);
g_mutex_free (lock);
g_cond_free (cond);
lock = NULL;
cond = NULL;
}