summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog17
-rw-r--r--gst/alpha/gstalphacolor.c36
-rw-r--r--tests/check/Makefile.am3
-rw-r--r--tests/check/elements/.gitignore1
-rw-r--r--tests/check/elements/alphacolor.c294
5 files changed, 337 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index 1b0938f0..c26d49f6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,22 @@
2007-04-25 Tim-Philipp Müller <tim at centricular dot net>
+ * gst/alpha/gstalphacolor.c: (gst_alpha_color_base_init),
+ (gst_alpha_color_transform_caps), (gst_alpha_color_set_caps):
+ Double-check that RGB input caps are really RGBA caps (apparently
+ the core doesn't always catch it if those caps aren't a subset of
+ our template caps, also see #421543). Fixes #429319 in a way.
+ Also, don't leak the pad template in the transform_caps function.
+
+ * tests/check/Makefile.am:
+ * tests/check/elements/.cvsignore:
+ * tests/check/elements/alphacolor.c: (setup_alphacolor),
+ (cleanup_alphacolor), (create_caps_rgb24), (create_caps_rgba32),
+ (create_buffer_rgb24_3x4), (create_buffer_rgba32_3x4),
+ (GST_START_TEST), (alphacolor_suite):
+ Add some basic unit tests for alphacolor.
+
+2007-04-25 Tim-Philipp Müller <tim at centricular dot net>
+
* ext/libpng/gstpngdec.c: (gst_pngdec_task):
If we get a fatal flow return in the loop function, first post the
error message and only then send the EOS event downstream, otherwise
diff --git a/gst/alpha/gstalphacolor.c b/gst/alpha/gstalphacolor.c
index 118de628..36cc9205 100644
--- a/gst/alpha/gstalphacolor.c
+++ b/gst/alpha/gstalphacolor.c
@@ -49,15 +49,13 @@ GST_ELEMENT_DETAILS ("Alpha color filter",
"RGBA to AYUV colorspace conversion preserving the alpha channel",
"Wim Taymans <wim@fluendo.com>");
-static GstStaticPadTemplate gst_alpha_color_sink_template =
- GST_STATIC_PAD_TEMPLATE ("sink",
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_BGRA)
);
-static GstStaticPadTemplate gst_alpha_color_src_template =
-GST_STATIC_PAD_TEMPLATE ("src",
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV"))
@@ -81,9 +79,9 @@ gst_alpha_color_base_init (gpointer g_class)
gst_element_class_set_details (element_class, &gst_alpha_color_details);
gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_alpha_color_sink_template));
+ gst_static_pad_template_get (&sink_template));
gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_alpha_color_src_template));
+ gst_static_pad_template_get (&src_template));
}
static void
@@ -123,8 +121,8 @@ gst_alpha_color_transform_caps (GstBaseTransform * btrans,
GstPadDirection direction, GstCaps * caps)
{
GstAlphaColor *alpha = NULL;
+ const GstCaps *tmpl_caps = NULL;
GstCaps *result = NULL, *local_caps = NULL;
- GstPadTemplate *tmpl = NULL;
guint i;
alpha = GST_ALPHA_COLOR (btrans);
@@ -153,13 +151,13 @@ gst_alpha_color_transform_caps (GstBaseTransform * btrans,
/* Get the appropriate template */
if (direction == GST_PAD_SINK) {
- tmpl = gst_static_pad_template_get (&gst_alpha_color_src_template);
+ tmpl_caps = gst_static_pad_template_get_caps (&src_template);
} else if (direction == GST_PAD_SRC) {
- tmpl = gst_static_pad_template_get (&gst_alpha_color_sink_template);
+ tmpl_caps = gst_static_pad_template_get_caps (&sink_template);
}
/* Intersect with our template caps */
- result = gst_caps_intersect (local_caps, gst_pad_template_get_caps (tmpl));
+ result = gst_caps_intersect (local_caps, tmpl_caps);
gst_caps_unref (local_caps);
gst_caps_do_simplify (result);
@@ -177,20 +175,30 @@ gst_alpha_color_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
GstStructure *structure;
gboolean ret;
const GValue *fps;
- gint red_mask;
+ gint red_mask, alpha_mask;
+ gint w, h, depth, bpp;
alpha = GST_ALPHA_COLOR (btrans);
structure = gst_caps_get_structure (incaps, 0);
- ret = gst_structure_get_int (structure, "width", &alpha->in_width);
- ret &= gst_structure_get_int (structure, "height", &alpha->in_height);
+ ret = gst_structure_get_int (structure, "width", &w);
+ ret &= gst_structure_get_int (structure, "height", &h);
fps = gst_structure_get_value (structure, "framerate");
ret &= (fps != NULL && GST_VALUE_HOLDS_FRACTION (fps));
ret &= gst_structure_get_int (structure, "red_mask", &red_mask);
- if (!ret)
+ /* make sure these are really full RGBA caps */
+ ret &= gst_structure_get_int (structure, "alpha_mask", &alpha_mask);
+ ret &= gst_structure_get_int (structure, "depth", &depth);
+ ret &= gst_structure_get_int (structure, "bpp", &bpp);
+
+ if (!ret || alpha_mask == 0 || red_mask == 0 || depth != 32 || bpp != 32) {
+ GST_DEBUG_OBJECT (alpha, "incomplete or non-RGBA input caps!");
return FALSE;
+ }
+ alpha->in_width = w;
+ alpha->in_height = h;
alpha->in_rgba = TRUE;
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
if (red_mask != 0x000000ff)
diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am
index fbd9e138..7cc7ee19 100644
--- a/tests/check/Makefile.am
+++ b/tests/check/Makefile.am
@@ -43,6 +43,7 @@ endif
check_PROGRAMS = \
generic/states \
$(check_annodex) \
+ elements/alphacolor \
elements/audiopanorama \
elements/audioinvert \
elements/audioamplify \
@@ -84,6 +85,8 @@ elements_audiopanorama_CFLAGS = \
elements_cmmldec_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS)
elements_cmmlenc_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS)
+elements_alphacolor_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS)
+
elements_sunaudio_CFLAGS = \
$(GST_PLUGINS_BASE_CFLAGS) \
$(AM_CFLAGS)
diff --git a/tests/check/elements/.gitignore b/tests/check/elements/.gitignore
index 5a0a624e..c59b4370 100644
--- a/tests/check/elements/.gitignore
+++ b/tests/check/elements/.gitignore
@@ -1,4 +1,5 @@
.dirstamp
+alphacolor
audioamplify
audiodynamic
audioinvert
diff --git a/tests/check/elements/alphacolor.c b/tests/check/elements/alphacolor.c
new file mode 100644
index 00000000..3c51ea08
--- /dev/null
+++ b/tests/check/elements/alphacolor.c
@@ -0,0 +1,294 @@
+/* GStreamer unit test for the alphacolor element
+ *
+ * Copyright (C) 2007 Tim-Philipp Müller <tim centricular net>
+ *
+ * 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.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/video/video.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *mysrcpad, *mysinkpad;
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV"))
+ );
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_RGB)
+ );
+
+static GstElement *
+setup_alphacolor (void)
+{
+ GstElement *alphacolor;
+
+ alphacolor = gst_check_setup_element ("alphacolor");
+ mysrcpad = gst_check_setup_src_pad (alphacolor, &srctemplate, NULL);
+ mysinkpad = gst_check_setup_sink_pad (alphacolor, &sinktemplate, NULL);
+
+ gst_pad_set_active (mysrcpad, TRUE);
+ gst_pad_set_active (mysinkpad, TRUE);
+
+ return alphacolor;
+}
+
+static void
+cleanup_alphacolor (GstElement * alphacolor)
+{
+ GST_DEBUG ("cleaning up");
+
+ gst_pad_set_active (mysrcpad, FALSE);
+ gst_pad_set_active (mysinkpad, FALSE);
+ gst_check_teardown_src_pad (alphacolor);
+ gst_check_teardown_sink_pad (alphacolor);
+ gst_check_teardown_element (alphacolor);
+}
+
+#define WIDTH 3
+#define HEIGHT 4
+
+static GstCaps *
+create_caps_rgb24 (void)
+{
+ GstCaps *caps;
+
+ caps = gst_caps_new_simple ("video/x-raw-rgb",
+ "width", G_TYPE_INT, 3,
+ "height", G_TYPE_INT, 4,
+ "bpp", G_TYPE_INT, 24,
+ "depth", G_TYPE_INT, 24,
+ "framerate", GST_TYPE_FRACTION, 0, 1,
+ "endianness", G_TYPE_INT, G_BIG_ENDIAN,
+ "red_mask", G_TYPE_INT, 0x00ff0000,
+ "green_mask", G_TYPE_INT, 0x0000ff00,
+ "blue_mask", G_TYPE_INT, 0x000000ff, NULL);
+
+ return caps;
+}
+
+static GstCaps *
+create_caps_rgba32 (void)
+{
+ GstCaps *caps;
+
+ caps = gst_caps_new_simple ("video/x-raw-rgb",
+ "width", G_TYPE_INT, 3,
+ "height", G_TYPE_INT, 4,
+ "bpp", G_TYPE_INT, 32,
+ "depth", G_TYPE_INT, 32,
+ "framerate", GST_TYPE_FRACTION, 0, 1,
+ "endianness", G_TYPE_INT, G_BIG_ENDIAN,
+ "red_mask", G_TYPE_INT, 0xff000000,
+ "green_mask", G_TYPE_INT, 0x00ff0000,
+ "blue_mask", G_TYPE_INT, 0x0000ff00,
+ "alpha_mask", G_TYPE_INT, 0x000000ff, NULL);
+
+ return caps;
+}
+
+static GstBuffer *
+create_buffer_rgb24_3x4 (void)
+{
+ /* stride is rounded up to multiple of 4, so 3 bytes padding for each row */
+ const guint8 rgb24_3x4_img[HEIGHT * GST_ROUND_UP_4 (WIDTH * 3)] = {
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00
+ };
+ guint rowstride = GST_ROUND_UP_4 (WIDTH * 3);
+ GstBuffer *buf;
+ GstCaps *caps;
+
+ buf = gst_buffer_new_and_alloc (HEIGHT * rowstride);
+ fail_unless_equals_int (GST_BUFFER_SIZE (buf), sizeof (rgb24_3x4_img));
+ memcpy (GST_BUFFER_DATA (buf), rgb24_3x4_img, sizeof (rgb24_3x4_img));
+
+ caps = create_caps_rgb24 ();
+ gst_buffer_set_caps (buf, caps);
+ gst_caps_unref (caps);
+
+ return buf;
+}
+
+static GstBuffer *
+create_buffer_rgba32_3x4 (void)
+{
+ /* stride is rounded up to multiple of 4, so 3 bytes padding for each row */
+ /* should be: RED BLUE WHITE where 'nothing' is fully transparent
+ * GREEN RED BLUE and all other colours are fully
+ * NOTHING GREEN RED opaque.
+ * BLACK NOTHING GREEN
+ */
+ const guint8 rgba32_3x4_img[HEIGHT * WIDTH * 4] = {
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff
+ };
+ guint rowstride = WIDTH * 4;
+ GstBuffer *buf;
+ GstCaps *caps;
+
+ buf = gst_buffer_new_and_alloc (HEIGHT * rowstride);
+ fail_unless_equals_int (GST_BUFFER_SIZE (buf), sizeof (rgba32_3x4_img));
+ memcpy (GST_BUFFER_DATA (buf), rgba32_3x4_img, sizeof (rgba32_3x4_img));
+
+ caps = create_caps_rgba32 ();
+ gst_buffer_set_caps (buf, caps);
+ gst_caps_unref (caps);
+
+ return buf;
+}
+
+GST_START_TEST (test_rgb24)
+{
+ GstElement *alphacolor;
+ GstBuffer *inbuffer;
+ GstBuffer *outbuffer;
+ GstCaps *incaps;
+ guint outlength;
+
+ incaps = create_caps_rgb24 ();
+ alphacolor = setup_alphacolor ();
+
+ fail_unless_equals_int (gst_element_set_state (alphacolor, GST_STATE_PLAYING),
+ GST_STATE_CHANGE_SUCCESS);
+
+ inbuffer = create_buffer_rgb24_3x4 ();
+ ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+ /* pushing gives away reference; this should error out with a not-negotiated
+ * error, alphacolor should only accept RGBA caps, not but plain RGB24 caps */
+ GST_DEBUG ("push it");
+ fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer),
+ GST_FLOW_NOT_NEGOTIATED);
+ GST_DEBUG ("pushed it");
+
+ fail_unless (g_list_length (buffers) == 0);
+
+ fail_unless_equals_int (gst_element_set_state (alphacolor, GST_STATE_NULL),
+ GST_STATE_CHANGE_SUCCESS);
+
+ /* cleanup */
+ GST_DEBUG ("cleanup alphacolor");
+ cleanup_alphacolor (alphacolor);
+ GST_DEBUG ("cleanup, unref incaps");
+ ASSERT_CAPS_REFCOUNT (incaps, "incaps", 1);
+ gst_caps_unref (incaps);
+}
+
+GST_END_TEST;
+
+/* these macros assume WIDTH and HEIGHT is fixed to what's defined above */
+#define fail_unless_ayuv_pixel_has_alpha(ayuv,x,y,a) \
+ { \
+ guint8 *pixel; \
+ pixel = ((guint8*)(ayuv) + ((WIDTH * 4) * (y)) + ((x) * 4)); \
+ fail_unless_equals_int (pixel[0], a); \
+ }
+
+GST_START_TEST (test_rgba32)
+{
+ GstElement *alphacolor;
+ GstBuffer *inbuffer;
+ GstBuffer *outbuffer;
+ GstCaps *incaps;
+ guint8 *ayuv;
+ guint outlength;
+
+ incaps = create_caps_rgba32 ();
+ alphacolor = setup_alphacolor ();
+
+ fail_unless_equals_int (gst_element_set_state (alphacolor, GST_STATE_PLAYING),
+ GST_STATE_CHANGE_SUCCESS);
+
+ inbuffer = create_buffer_rgba32_3x4 ();
+ GST_DEBUG ("Created buffer of %d bytes", GST_BUFFER_SIZE (inbuffer));
+ ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+ /* pushing gives away reference */
+ GST_DEBUG ("push it");
+ fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
+ GST_DEBUG ("pushed it");
+
+ /* ... and puts a new buffer on the global list */
+ fail_unless (g_list_length (buffers) == 1);
+ outbuffer = (GstBuffer *) buffers->data;
+ fail_if (outbuffer == NULL);
+ fail_unless (GST_IS_BUFFER (outbuffer));
+
+ ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
+ outlength = WIDTH * HEIGHT * 4; /* output is AYUV */
+ fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), outlength);
+
+ ayuv = GST_BUFFER_DATA (outbuffer);
+
+ /* check alpha values (0x00 = totally transparent, 0xff = totally opaque) */
+ fail_unless_ayuv_pixel_has_alpha (ayuv, 0, 0, 0xff);
+ fail_unless_ayuv_pixel_has_alpha (ayuv, 1, 0, 0xff);
+ fail_unless_ayuv_pixel_has_alpha (ayuv, 2, 0, 0xff);
+ fail_unless_ayuv_pixel_has_alpha (ayuv, 0, 1, 0xff);
+ fail_unless_ayuv_pixel_has_alpha (ayuv, 1, 1, 0xff);
+ fail_unless_ayuv_pixel_has_alpha (ayuv, 2, 1, 0xff);
+ fail_unless_ayuv_pixel_has_alpha (ayuv, 0, 2, 0x00);
+ fail_unless_ayuv_pixel_has_alpha (ayuv, 1, 2, 0xff);
+ fail_unless_ayuv_pixel_has_alpha (ayuv, 2, 2, 0xff);
+ fail_unless_ayuv_pixel_has_alpha (ayuv, 0, 3, 0xff);
+ fail_unless_ayuv_pixel_has_alpha (ayuv, 1, 3, 0x00);
+ fail_unless_ayuv_pixel_has_alpha (ayuv, 2, 3, 0xff);
+
+ /* we don't check the YUV data, because apparently results differ slightly
+ * depending on whether we run in valgrind or not */
+
+ buffers = g_list_remove (buffers, outbuffer);
+ gst_buffer_unref (outbuffer);
+
+ fail_unless_equals_int (gst_element_set_state (alphacolor, GST_STATE_NULL),
+ GST_STATE_CHANGE_SUCCESS);
+
+ /* cleanup */
+ GST_DEBUG ("cleanup alphacolor");
+ cleanup_alphacolor (alphacolor);
+ GST_DEBUG ("cleanup, unref incaps");
+ ASSERT_CAPS_REFCOUNT (incaps, "incaps", 1);
+ gst_caps_unref (incaps);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+alphacolor_suite (void)
+{
+ Suite *s = suite_create ("alphacolor");
+ TCase *tc_chain = tcase_create ("general");
+
+ suite_add_tcase (s, tc_chain);
+ tcase_add_test (tc_chain, test_rgb24);
+ tcase_add_test (tc_chain, test_rgba32);
+
+ return s;
+}
+
+GST_CHECK_MAIN (alphacolor);