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@xxxxxxxxxx> --- 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 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel