[Spice-devel] [spice-common v3 12/12] quic: Add test case for compression/decompression

Christophe Fergeau cfergeau at redhat.com
Thu Aug 3 14:24:38 UTC 2017


This only adds a basic test relying on gdk-pixbuf.
The main limitation is that gdk-pixbuf does not handle 16bpp images,
nor 32bpp/no alpha images. I should have picked something else instead ;)

This allows at least to exercise the QUIC_IMAGE_TYPE_RGB24 and
QUIC_IMAGE_TYPE_RGBA codepaths.

Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
---
 configure.ac      |   1 +
 m4/spice-deps.m4  |  15 ++++
 tests/Makefile.am |  21 +++++
 tests/test-quic.c | 253 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 290 insertions(+)
 create mode 100644 tests/test-quic.c

diff --git a/configure.ac b/configure.ac
index 3542161..1f2ecc0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -47,6 +47,7 @@ SPICE_CHECK_CELT051
 SPICE_CHECK_GLIB2
 SPICE_CHECK_OPUS
 SPICE_CHECK_OPENSSL
+SPICE_CHECK_GDK_PIXBUF
 
 SPICE_COMMON_CFLAGS='$(PIXMAN_CFLAGS) $(SMARTCARD_CFLAGS) $(CELT051_CFLAGS) $(GLIB2_CFLAGS) $(OPUS_CFLAGS) $(OPENSSL_CFLAGS)'
 SPICE_COMMON_CFLAGS="$SPICE_COMMON_CFLAGS -DG_LOG_DOMAIN=\\\"Spice\\\""
diff --git a/m4/spice-deps.m4 b/m4/spice-deps.m4
index 68e3091..0754117 100644
--- a/m4/spice-deps.m4
+++ b/m4/spice-deps.m4
@@ -147,6 +147,21 @@ AC_DEFUN([SPICE_CHECK_GLIB2], [
     PKG_CHECK_MODULES(GLIB2, glib-2.0 >= 2.22 gio-2.0 >= 2.22 gthread-2.0 >= 2.22)
 ])
 
+# SPICE_CHECK_GDK_PIXBUF
+# ----------------------
+# Check for the availability of gdk-pixbuf. If found, it will return the flags to use
+# in the GDK_PIXBUF_CFLAGS and GDK_PIXBUF_LIBS variables, and it will define a
+# HAVE_GDK_PIXBUF preprocessor symbol as well as a HAVE_GDK_PIXBUF Makefile conditional.
+# ----------------
+AC_DEFUN([SPICE_CHECK_GDK_PIXBUF], [
+    PKG_CHECK_MODULES([GDK_PIXBUF], [gdk-pixbuf-2.0 >= 2.26], [have_gdk_pixbuf=yes], [have_gdk_pixbuf=no])
+
+    AM_CONDITIONAL([HAVE_GDK_PIXBUF], [test "x$have_gdk_pixbuf" = "xyes"])
+    if test "x$have_gdk_pixbuf" = "xyes" ; then
+      AC_DEFINE([HAVE_GDK_PIXBUF], [1], [Define if gdk-pixbuf was found])
+    fi
+])
+
 # SPICE_CHECK_PYTHON_MODULES()
 # --------------------------
 # Adds a --enable-python-checks configure flags as well as checks for the
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 10033c0..436c5a9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -33,6 +33,27 @@ test_marshallers_LDADD =				\
 	$(GLIB2_LIBS)			\
 	$(NULL)
 
+
+if HAVE_GDK_PIXBUF
+TESTS += test_quic
+
+test_quic_SOURCES =			\
+	test-quic.c			\
+	$(NULL)
+test_quic_CFLAGS =			\
+	-I$(top_srcdir)			\
+	$(GLIB2_CFLAGS)			\
+	$(GDK_PIXBUF_CFLAGS)		\
+	$(PROTOCOL_CFLAGS)		\
+	$(NULL)
+test_quic_LDADD =					\
+	$(top_builddir)/common/libspice-common.la	\
+	$(GLIB2_LIBS)					\
+	$(GDK_PIXBUF_LIBS)				\
+	$(NULL)
+endif
+
+
 # Avoid need for python(pyparsing) by end users
 TEST_MARSHALLERS =				\
 	generated_test_marshallers.c		\
diff --git a/tests/test-quic.c b/tests/test-quic.c
new file mode 100644
index 0000000..56ca4ce
--- /dev/null
+++ b/tests/test-quic.c
@@ -0,0 +1,253 @@
+/*
+   Copyright (C) 2017 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "common/quic.h"
+
+typedef struct {
+    QuicUsrContext usr;
+    GByteArray *dest;
+} QuicData;
+
+static SPICE_GNUC_NORETURN SPICE_GNUC_PRINTF(2, 3) void
+quic_usr_error(QuicUsrContext *usr, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, fmt, ap);
+    va_end(ap);
+
+    g_assert_not_reached();
+}
+
+static SPICE_GNUC_PRINTF(2, 3) void
+quic_usr_warn(QuicUsrContext *usr, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, fmt, ap);
+    va_end(ap);
+}
+
+static void *quic_usr_malloc(QuicUsrContext *usr, int size)
+{
+    return g_malloc(size);
+}
+
+
+static void quic_usr_free(QuicUsrContext *usr, void *ptr)
+{
+    g_free(ptr);
+}
+
+static int quic_usr_more_space(QuicUsrContext *usr, uint32_t **io_ptr, int rows_completed)
+{
+    QuicData *quic_data = (QuicData *)usr;
+    int initial_len = quic_data->dest->len;
+
+    g_byte_array_set_size(quic_data->dest, quic_data->dest->len*2);
+
+    *io_ptr = (uint32_t *)(quic_data->dest->data + initial_len);
+    return (quic_data->dest->len - initial_len)/4;
+}
+
+
+static int quic_usr_more_lines(QuicUsrContext *usr, uint8_t **lines)
+{
+    g_return_val_if_reached(0);
+}
+
+
+static void init_quic_data(QuicData *quic_data)
+{
+    quic_data->usr.error = quic_usr_error;
+    quic_data->usr.warn = quic_usr_warn;
+    quic_data->usr.info = quic_usr_warn;
+    quic_data->usr.malloc = quic_usr_malloc;
+    quic_data->usr.free = quic_usr_free;
+    quic_data->usr.more_space = quic_usr_more_space;
+    quic_data->usr.more_lines = quic_usr_more_lines;
+    quic_data->dest = g_byte_array_new();
+}
+
+static GByteArray *quic_encode_from_pixbuf(GdkPixbuf *pixbuf)
+{
+    QuicData quic_data;
+    QuicContext *quic;
+    int encoded_size;
+    QuicImageType quic_type;
+
+    init_quic_data(&quic_data);
+    g_byte_array_set_size(quic_data.dest, 1024);
+
+    quic = quic_create(&quic_data.usr);
+    g_assert(quic != NULL);
+    switch (gdk_pixbuf_get_n_channels(pixbuf)) {
+        case 3:
+            quic_type = QUIC_IMAGE_TYPE_RGB24;
+            break;
+        case 4:
+            quic_type = QUIC_IMAGE_TYPE_RGBA;
+            break;
+        default:
+            g_assert_not_reached();
+    }
+    encoded_size = quic_encode(quic, quic_type,
+                               gdk_pixbuf_get_width(pixbuf),
+                               gdk_pixbuf_get_height(pixbuf),
+                               gdk_pixbuf_get_pixels(pixbuf),
+                               gdk_pixbuf_get_height(pixbuf),
+                               gdk_pixbuf_get_rowstride(pixbuf),
+                               (uint32_t *)quic_data.dest->data,
+                               quic_data.dest->len/sizeof(uint32_t));
+    encoded_size *= 4;
+    g_byte_array_set_size(quic_data.dest, encoded_size);
+    quic_destroy(quic);
+
+    return quic_data.dest;
+}
+
+static GdkPixbuf *quic_decode_to_pixbuf(GByteArray *compressed_data)
+{
+    QuicData quic_data;
+    QuicContext *quic;
+    GdkPixbuf *pixbuf;
+    QuicImageType type;
+    int width;
+    int height;
+    int status;
+
+    init_quic_data(&quic_data);
+    g_byte_array_free(quic_data.dest, TRUE);
+    quic_data.dest = NULL;
+
+    quic = quic_create(&quic_data.usr);
+    g_assert(quic != NULL);
+
+    status = quic_decode_begin(quic,
+                               (uint32_t *)compressed_data->data, compressed_data->len/4,
+                               &type, &width, &height);
+    g_assert(status == QUIC_OK);
+
+    pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
+                            (type == QUIC_IMAGE_TYPE_RGBA), 8,
+                            width, height);
+    status = quic_decode(quic, type,
+                         gdk_pixbuf_get_pixels(pixbuf),
+                         gdk_pixbuf_get_rowstride(pixbuf));
+    g_assert(status == QUIC_OK);
+    quic_destroy(quic);
+
+    return pixbuf;
+}
+
+static void gdk_pixbuf_compare(GdkPixbuf *pixbuf_a, GdkPixbuf *pixbuf_b)
+{
+    int width = gdk_pixbuf_get_width(pixbuf_a);
+    int height = gdk_pixbuf_get_height(pixbuf_a);
+    int n_channels = gdk_pixbuf_get_n_channels (pixbuf_a);
+    int x;
+    int y;
+    guint8 *pixels_a = gdk_pixbuf_get_pixels(pixbuf_a);
+    guint8 *pixels_b = gdk_pixbuf_get_pixels(pixbuf_a);
+
+    g_assert(width == gdk_pixbuf_get_width(pixbuf_b));
+    g_assert(height == gdk_pixbuf_get_height(pixbuf_b));
+    g_assert(n_channels == gdk_pixbuf_get_n_channels (pixbuf_b));
+    for (y = 0; y < height; y++) {
+        for (x = 0; x < width; x++) {
+            guint8 *p_a = pixels_a + y*gdk_pixbuf_get_rowstride(pixbuf_a) + x*n_channels;
+            guint8 *p_b = pixels_b + y*gdk_pixbuf_get_rowstride(pixbuf_b) + x*n_channels;
+
+            g_assert(p_a[0] == p_b[0]);
+            g_assert(p_a[1] == p_b[1]);
+            g_assert(p_a[2] == p_b[2]);
+            if (gdk_pixbuf_get_has_alpha(pixbuf_a)) {
+                g_assert(p_a[3] == p_b[3]);
+            }
+        }
+    }
+}
+
+static GdkPixbuf *gdk_pixbuf_new_random(void)
+{
+    gboolean has_alpha = g_random_boolean();
+    gint width = g_random_int_range(100, 2000);
+    gint height = g_random_int_range(100, 2000);
+    GdkPixbuf *random_pixbuf;
+    gint i;
+    guint8 *pixels;
+
+    random_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8, width, height);
+    pixels = gdk_pixbuf_get_pixels(random_pixbuf);
+    for (i = 0; i < gdk_pixbuf_get_byte_length(random_pixbuf); i++) {
+        pixels[i] = g_random_int_range(0, 256);
+    }
+
+    return random_pixbuf;
+}
+
+static void test_pixbuf(GdkPixbuf *pixbuf)
+{
+    GdkPixbuf *uncompressed_pixbuf;
+    GByteArray *compressed_data;
+    g_assert(pixbuf != NULL);
+    g_assert (gdk_pixbuf_get_colorspace(pixbuf) == GDK_COLORSPACE_RGB);
+    g_assert (gdk_pixbuf_get_bits_per_sample(pixbuf) == 8);
+
+    compressed_data = quic_encode_from_pixbuf(pixbuf);
+
+    uncompressed_pixbuf = quic_decode_to_pixbuf(compressed_data);
+
+    g_assert(gdk_pixbuf_get_byte_length(pixbuf) == gdk_pixbuf_get_byte_length(uncompressed_pixbuf));
+    //g_assert(memcmp(gdk_pixbuf_get_pixels(pixbuf), gdk_pixbuf_get_pixels(uncompressed_pixbuf), gdk_pixbuf_get_byte_length(uncompressed_pixbuf)));
+    gdk_pixbuf_compare(pixbuf, uncompressed_pixbuf);
+
+    g_byte_array_free(compressed_data, TRUE);
+    g_object_unref(uncompressed_pixbuf);
+
+}
+
+int main(int argc, char **argv)
+{
+    if (argc == 2) {
+        GdkPixbuf *source_pixbuf;
+
+        source_pixbuf = gdk_pixbuf_new_from_file(argv[1], NULL);
+        test_pixbuf(source_pixbuf);
+        g_object_unref(source_pixbuf);
+    } else if (argc == 1) {
+        unsigned int count;
+
+        for (count = 0; count < 50; count++) {
+            GdkPixbuf *pixbuf = gdk_pixbuf_new_random();
+            test_pixbuf(pixbuf);
+            g_object_unref(pixbuf);
+        }
+    } else {
+        g_assert_not_reached();
+    }
+
+    return 0;
+}
-- 
2.13.3



More information about the Spice-devel mailing list