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 | 22 +++++ tests/test-quic.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 273 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..3fe4a5b 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], [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..02f679d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,9 @@ NULL = TESTS = test_logging test_marshallers +if HAVE_GDK_PIXBUF +TESTS += test_quic +endif noinst_PROGRAMS = $(TESTS) test_logging_SOURCES = test-logging.c @@ -33,6 +36,25 @@ test_marshallers_LDADD = \ $(GLIB2_LIBS) \ $(NULL) + +if HAVE_GDK_PIXBUF +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..b45794f --- /dev/null +++ b/tests/test-quic.c @@ -0,0 +1,235 @@ +#include "common/quic.h" +#include <glib.h> +#include <gdk-pixbuf/gdk-pixbuf.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; + int encoded_size; + QuicImageType quic_type; + 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 n_channels = g_random_int_range(3, 5); + 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