--- /dev/null
+
+#include <gst/base/gstbasetransform.h>
+
+typedef struct
+{
+ GstPad *srcpad;
+ GstPad *sinkpad;
+ GList *events;
+ GList *buffers;
+ GstElement *trans;
+ GstBaseTransformClass *klass;
+} TestTransData;
+
+static GstStaticPadTemplate gst_test_trans_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("foo/x-bar")
+ );
+
+static GstStaticPadTemplate gst_test_trans_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("foo/x-bar")
+ );
+
+typedef struct _GstTestTrans GstTestTrans;
+typedef struct _GstTestTransClass GstTestTransClass;
+
+#define GST_TYPE_TEST_TRANS \
+ (gst_test_trans_get_type())
+#define GST_TEST_TRANS(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TEST_TRANS,GstTestTrans))
+#define GST_TEST_TRANS_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TEST_TRANS,GstTestTransClass))
+#define GST_TEST_TRANS_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_TEST_TRANS, GstTestTransClass))
+#define GST_IS_TEST_TRANS(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TEST_TRANS))
+#define GST_IS_TEST_TRANS_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TEST_TRANS))
+
+struct _GstTestTrans
+{
+ GstBaseTransform element;
+
+ TestTransData *data;
+};
+
+struct _GstTestTransClass
+{
+ GstBaseTransformClass parent_class;
+};
+
+GST_BOILERPLATE (GstTestTrans, gst_test_trans, GstBaseTransform,
+ GST_TYPE_BASE_TRANSFORM);
+
+static void
+gst_test_trans_base_init (gpointer g_class)
+{
+ GstElementClass *element_class;
+
+ element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details_simple (element_class, "TestTrans",
+ "Filter/Test", "Test transform", "Wim Taymans <wim.taymans@gmail.com>");
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_test_trans_sink_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_test_trans_src_template));
+}
+
+static GstFlowReturn (*klass_transform) (GstBaseTransform * trans,
+ GstBuffer * inbuf, GstBuffer * outbuf) = NULL;
+static GstFlowReturn (*klass_transform_ip) (GstBaseTransform * trans,
+ GstBuffer * buf) = NULL;
+static gboolean (*klass_set_caps) (GstBaseTransform * trans, GstCaps * incaps,
+ GstCaps * outcaps) = NULL;
+
+static void
+gst_test_trans_class_init (GstTestTransClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstBaseTransformClass *trans_class;
+
+ gobject_class = (GObjectClass *) klass;
+ trans_class = (GstBaseTransformClass *) klass;
+
+ trans_class->transform_ip = klass_transform_ip;
+ trans_class->transform = klass_transform;
+ trans_class->set_caps = klass_set_caps;
+}
+
+static void
+gst_test_trans_init (GstTestTrans * this, GstTestTransClass * g_class)
+{
+}
+
+static void
+gst_test_trans_set_data (GstTestTrans * this, TestTransData * data)
+{
+ this->data = data;
+}
+
+static GstFlowReturn
+result_sink_chain (GstPad * pad, GstBuffer * buffer)
+{
+ TestTransData *data;
+
+ data = gst_pad_get_element_private (pad);
+
+ data->buffers = g_list_append (data->buffers, buffer);
+
+ return GST_FLOW_OK;
+}
+
+static TestTransData *
+gst_test_trans_new (void)
+{
+ TestTransData *res;
+ GstPad *tmp;
+
+ res = g_new0 (TestTransData, 1);
+ res->trans = g_object_new (GST_TYPE_TEST_TRANS, NULL);
+ res->srcpad =
+ gst_pad_new_from_static_template (&gst_test_trans_src_template, "src");
+ res->sinkpad =
+ gst_pad_new_from_static_template (&gst_test_trans_sink_template, "sink");
+ res->klass = GST_BASE_TRANSFORM_GET_CLASS (res->trans);
+
+ gst_test_trans_set_data (GST_TEST_TRANS (res->trans), res);
+ gst_pad_set_element_private (res->sinkpad, res);
+
+ gst_pad_set_chain_function (res->sinkpad, result_sink_chain);
+
+ tmp = gst_element_get_static_pad (res->trans, "sink");
+ gst_pad_link (res->srcpad, tmp);
+ gst_object_unref (tmp);
+
+ tmp = gst_element_get_static_pad (res->trans, "src");
+ gst_pad_link (tmp, res->sinkpad);
+ gst_object_unref (tmp);
+
+ gst_pad_set_active (res->sinkpad, TRUE);
+ gst_element_set_state (res->trans, GST_STATE_PAUSED);
+ gst_pad_set_active (res->srcpad, TRUE);
+
+ return res;
+}
+
+static void
+gst_test_trans_free (TestTransData * data)
+{
+ GstPad *tmp;
+
+ gst_pad_set_active (data->sinkpad, FALSE);
+ gst_element_set_state (data->trans, GST_STATE_NULL);
+ gst_pad_set_active (data->srcpad, FALSE);
+
+ tmp = gst_element_get_static_pad (data->trans, "src");
+ gst_pad_unlink (tmp, data->sinkpad);
+ gst_object_unref (tmp);
+
+ tmp = gst_element_get_static_pad (data->trans, "sink");
+ gst_pad_link (data->srcpad, tmp);
+ gst_object_unref (tmp);
+
+ gst_object_unref (data->srcpad);
+ gst_object_unref (data->sinkpad);
+ gst_object_unref (data->trans);
+
+ g_free (data);
+}
+
+static GstFlowReturn
+gst_test_trans_push (TestTransData * data, GstBuffer * buffer)
+{
+ GstFlowReturn ret;
+
+ ret = gst_pad_push (data->srcpad, buffer);
+
+ return ret;
+}
+
+static GstBuffer *
+gst_test_trans_pop (TestTransData * data)
+{
+ GstBuffer *ret;
+
+ if (data->buffers) {
+ ret = data->buffers->data;
+ data->buffers = g_list_delete_link (data->buffers, data->buffers);
+ } else {
+ ret = NULL;
+ }
+ return ret;
+}
--- /dev/null
+/* GStreamer
+ *
+ * some unit tests for GstBaseTransform
+ *
+ * Copyright (C) 2008 Wim Taymans <wim.taymans@gmail.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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <gst/gst.h>
+#include <gst/check/gstcheck.h>
+#include <gst/base/gstbasetransform.h>
+
+#undef FAILING_TESTS
+
+#include "test_transform.c"
+
+/* basic passthrough, we don't have any transform functions so we can only
+ * perform passthrough. We also don't have caps, which is fine */
+GST_START_TEST (basetransform_chain_pt1)
+{
+ TestTransData *trans;
+ GstBuffer *buffer;
+ GstFlowReturn res;
+
+ trans = gst_test_trans_new ();
+
+ buffer = gst_buffer_new_and_alloc (20);
+
+ res = gst_test_trans_push (trans, buffer);
+ fail_unless (res == GST_FLOW_OK);
+
+ buffer = gst_test_trans_pop (trans);
+ fail_unless (buffer != NULL);
+ fail_unless (GST_BUFFER_SIZE (buffer) == 20);
+ /* caps should not have been set */
+ fail_unless (GST_BUFFER_CAPS (buffer) == NULL);
+
+ gst_buffer_unref (buffer);
+
+ buffer = gst_buffer_new_and_alloc (10);
+ res = gst_test_trans_push (trans, buffer);
+ fail_unless (res == GST_FLOW_OK);
+
+ buffer = gst_test_trans_pop (trans);
+ fail_unless (buffer != NULL);
+ fail_unless (GST_BUFFER_SIZE (buffer) == 10);
+ /* caps should not have been set */
+ fail_unless (GST_BUFFER_CAPS (buffer) == NULL);
+
+ gst_buffer_unref (buffer);
+
+ gst_test_trans_free (trans);
+}
+
+GST_END_TEST;
+
+/* basic passthrough, we don't have any transform functions so we can only
+ * perform passthrough with same caps */
+GST_START_TEST (basetransform_chain_pt2)
+{
+ TestTransData *trans;
+ GstBuffer *buffer;
+ GstCaps *caps;
+ GstFlowReturn res;
+
+ trans = gst_test_trans_new ();
+
+ /* first buffer */
+ caps = gst_caps_new_simple ("foo/x-bar", NULL);
+
+ buffer = gst_buffer_new_and_alloc (20);
+ gst_buffer_set_caps (buffer, caps);
+
+ res = gst_test_trans_push (trans, buffer);
+ fail_unless (res == GST_FLOW_OK);
+
+ buffer = gst_test_trans_pop (trans);
+ fail_unless (buffer != NULL);
+ fail_unless (GST_BUFFER_SIZE (buffer) == 20);
+ fail_unless (GST_BUFFER_CAPS (buffer) == caps);
+
+ gst_buffer_unref (buffer);
+ gst_caps_unref (caps);
+
+ /* second buffer, renegotiates, keeps extra type arg in caps */
+ caps = gst_caps_new_simple ("foo/x-bar", "type", G_TYPE_INT, 1, NULL);
+
+ buffer = gst_buffer_new_and_alloc (10);
+ gst_buffer_set_caps (buffer, caps);
+
+ res = gst_test_trans_push (trans, buffer);
+ fail_unless (res == GST_FLOW_OK);
+
+ buffer = gst_test_trans_pop (trans);
+ fail_unless (buffer != NULL);
+ fail_unless (GST_BUFFER_SIZE (buffer) == 10);
+ fail_unless (GST_BUFFER_CAPS (buffer) == caps);
+
+ gst_buffer_unref (buffer);
+ gst_caps_unref (caps);
+
+ gst_test_trans_free (trans);
+}
+
+GST_END_TEST;
+
+static gboolean transform_ip_1_called;
+static gboolean transform_ip_1_writable;
+
+static GstFlowReturn
+transform_ip_1 (GstBaseTransform * trans, GstBuffer * buf)
+{
+ GST_DEBUG_OBJECT (trans, "transform called");
+
+ transform_ip_1_called = TRUE;
+ transform_ip_1_writable = gst_buffer_is_writable (buf);
+
+ GST_DEBUG_OBJECT (trans, "writable: %d", transform_ip_1_writable);
+
+ return GST_FLOW_OK;
+}
+
+/* basic in-place, check if the _ip function is called, buffer should
+ * be writable. no setcaps is set */
+GST_START_TEST (basetransform_chain_ip1)
+{
+ TestTransData *trans;
+ GstBuffer *buffer;
+ GstFlowReturn res;
+
+ klass_transform_ip = transform_ip_1;
+ trans = gst_test_trans_new ();
+
+ buffer = gst_buffer_new_and_alloc (20);
+
+ transform_ip_1_called = FALSE;;
+ transform_ip_1_writable = TRUE;;
+ res = gst_test_trans_push (trans, buffer);
+ fail_unless (res == GST_FLOW_OK);
+ fail_unless (transform_ip_1_called == TRUE);
+ fail_unless (transform_ip_1_writable == TRUE);
+
+ buffer = gst_test_trans_pop (trans);
+ fail_unless (buffer != NULL);
+ fail_unless (GST_BUFFER_SIZE (buffer) == 20);
+ gst_buffer_unref (buffer);
+
+ buffer = gst_buffer_new_and_alloc (20);
+ /* take additional ref to make it non-writable */
+ gst_buffer_ref (buffer);
+
+ fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (buffer) == 2);
+
+ transform_ip_1_called = FALSE;;
+ transform_ip_1_writable = FALSE;;
+ res = gst_test_trans_push (trans, buffer);
+ fail_unless (res == GST_FLOW_OK);
+ fail_unless (transform_ip_1_called == TRUE);
+ /* copy should have been taken */
+ fail_unless (transform_ip_1_writable == TRUE);
+ /* after push, get rid of the final ref we had */
+ gst_buffer_unref (buffer);
+
+ buffer = gst_test_trans_pop (trans);
+ fail_unless (buffer != NULL);
+ fail_unless (GST_BUFFER_SIZE (buffer) == 20);
+
+ /* output buffer has refcount 1 */
+ fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (buffer) == 1);
+ gst_buffer_unref (buffer);
+
+ gst_test_trans_free (trans);
+}
+
+GST_END_TEST;
+
+static gboolean set_caps_1_called;
+
+static gboolean
+set_caps_1 (GstBaseTransform * trans, GstCaps * incaps, GstCaps * outcaps)
+{
+ GstCaps *caps;
+
+ GST_DEBUG_OBJECT (trans, "set_caps called");
+
+ set_caps_1_called = TRUE;
+
+ caps = gst_caps_new_simple ("foo/x-bar", NULL);
+
+ fail_unless (gst_caps_is_equal (incaps, caps));
+ fail_unless (gst_caps_is_equal (outcaps, caps));
+
+ gst_caps_unref (caps);
+
+ return TRUE;
+}
+
+/* basic in-place, check if the _ip function is called, buffer should be
+ * writable. we also set a setcaps function and see if it's called. */
+GST_START_TEST (basetransform_chain_ip2)
+{
+ TestTransData *trans;
+ GstBuffer *buffer;
+ GstFlowReturn res;
+ GstCaps *caps;
+
+ klass_transform_ip = transform_ip_1;
+ klass_set_caps = set_caps_1;
+
+ trans = gst_test_trans_new ();
+
+ caps = gst_caps_new_simple ("foo/x-bar", NULL);
+
+ /* first try to push a buffer without caps, this should fail */
+ buffer = gst_buffer_new_and_alloc (20);
+
+ transform_ip_1_called = FALSE;;
+ transform_ip_1_writable = FALSE;;
+ set_caps_1_called = FALSE;;
+ res = gst_test_trans_push (trans, buffer);
+ fail_unless (res == GST_FLOW_NOT_NEGOTIATED);
+ fail_unless (transform_ip_1_called == FALSE);
+ fail_unless (transform_ip_1_writable == FALSE);
+ fail_unless (set_caps_1_called == FALSE);
+
+ /* try to push a buffer with caps */
+ buffer = gst_buffer_new_and_alloc (20);
+ gst_buffer_set_caps (buffer, caps);
+
+ transform_ip_1_called = FALSE;
+ transform_ip_1_writable = FALSE;
+ set_caps_1_called = FALSE;;
+ res = gst_test_trans_push (trans, buffer);
+ fail_unless (res == GST_FLOW_OK);
+ fail_unless (transform_ip_1_called == TRUE);
+ fail_unless (transform_ip_1_writable == TRUE);
+ fail_unless (set_caps_1_called == TRUE);
+
+ buffer = gst_test_trans_pop (trans);
+ fail_unless (buffer != NULL);
+ fail_unless (GST_BUFFER_SIZE (buffer) == 20);
+ fail_unless (GST_BUFFER_CAPS (buffer) == caps);
+ gst_buffer_unref (buffer);
+
+ buffer = gst_buffer_new_and_alloc (20);
+ gst_buffer_set_caps (buffer, caps);
+ /* take additional ref to make it non-writable */
+ gst_buffer_ref (buffer);
+
+ fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (buffer) == 2);
+
+ transform_ip_1_called = FALSE;;
+ transform_ip_1_writable = FALSE;;
+ res = gst_test_trans_push (trans, buffer);
+ fail_unless (res == GST_FLOW_OK);
+ fail_unless (transform_ip_1_called == TRUE);
+ fail_unless (transform_ip_1_writable == TRUE);
+ /* after push, get rid of the final ref we had */
+ gst_buffer_unref (buffer);
+
+ buffer = gst_test_trans_pop (trans);
+ fail_unless (buffer != NULL);
+ fail_unless (GST_BUFFER_SIZE (buffer) == 20);
+ fail_unless (GST_BUFFER_CAPS (buffer) == caps);
+
+ /* output buffer has refcount 1 */
+ fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (buffer) == 1);
+ gst_buffer_unref (buffer);
+
+ gst_caps_unref (caps);
+
+ trans->klass->transform_ip = NULL;
+ gst_test_trans_free (trans);
+}
+
+GST_END_TEST;
+
+static Suite *
+gst_basetransform_suite (void)
+{
+ Suite *s = suite_create ("GstBaseTransform");
+ TCase *tc = tcase_create ("general");
+
+ suite_add_tcase (s, tc);
+ tcase_add_test (tc, basetransform_chain_pt1);
+ tcase_add_test (tc, basetransform_chain_pt2);
+ tcase_add_test (tc, basetransform_chain_ip1);
+ tcase_add_test (tc, basetransform_chain_ip2);
+
+ return s;
+}
+
+GST_CHECK_MAIN (gst_basetransform);