From 45e8503ead5aa90ee8f53ddf43257c019069653d Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 17 May 2016 20:49:51 -0700 Subject: [PATCH] GUACAMOLE-632: Dynamically scale JPEG/WebP quality depending on measured processing lag. --- src/common/surface.c | 48 +++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/common/surface.c b/src/common/surface.c index 8c690b75..c31dfbf0 100644 --- a/src/common/surface.c +++ b/src/common/surface.c @@ -78,13 +78,6 @@ #define cairo_format_stride_for_width(format, width) (width*4) #endif -/** - * The JPEG image quality ('quantization') setting to use. Range 0-100 where - * 100 is the highest quality/largest file size, and 0 is the lowest - * quality/smallest file size. - */ -#define GUAC_SURFACE_JPEG_IMAGE_QUALITY 90 - /** * The framerate which, if exceeded, indicates that JPEG is preferred. */ @@ -96,13 +89,6 @@ */ #define GUAC_SURFACE_JPEG_MIN_BITMAP_SIZE 4096 -/** - * The WebP image quality ('quantization') setting to use. Range 0-100 where - * 100 is the highest quality/largest file size, and 0 is the lowest - * quality/smallest file size. - */ -#define GUAC_SURFACE_WEBP_IMAGE_QUALITY 90 - /** * The JPEG compression min block size. This defines the optimal rectangle block * size factor for JPEG compression. Usually 8x8 would suffice, but use 16 to @@ -1666,6 +1652,36 @@ static void __guac_common_surface_flush_to_png(guac_common_surface* surface, } +/** + * Returns an appropriate quality between 0 and 100 for lossy encoding + * depending on the current processing lag calculated for the given client. + * + * @param client + * The client for which the lossy quality is being calculated. + * + * @return + * A value between 0 and 100 inclusive which seems appropriate for the + * client based on lag measurements. + */ +static int guac_common_surface_suggest_quality(guac_client* client) { + + int lag = guac_client_get_processing_lag(client); + + /* Scale quality linearly from 90 to 30 as lag varies from 20ms to 80ms */ + int quality = 90 - (lag - 20); + + /* Do not exceed 90 for quality */ + if (quality > 90) + return 90; + + /* Do not go below 30 for quality */ + if (quality < 30) + return 30; + + return quality; + +} + /** * Flushes the bitmap update currently described by the dirty rectangle within * the given surface directly via an "img" instruction as JPEG data. The @@ -1702,7 +1718,7 @@ static void __guac_common_surface_flush_to_jpeg(guac_common_surface* surface) { /* Send JPEG for rect */ guac_client_stream_jpeg(surface->client, socket, GUAC_COMP_OVER, layer, surface->dirty_rect.x, surface->dirty_rect.y, rect, - GUAC_SURFACE_JPEG_IMAGE_QUALITY); + guac_common_surface_suggest_quality(surface->client)); cairo_surface_destroy(rect); surface->realized = 1; @@ -1764,7 +1780,7 @@ static void __guac_common_surface_flush_to_webp(guac_common_surface* surface, /* Send WebP for rect */ guac_client_stream_webp(surface->client, socket, GUAC_COMP_OVER, layer, surface->dirty_rect.x, surface->dirty_rect.y, rect, - GUAC_SURFACE_WEBP_IMAGE_QUALITY, 0); + guac_common_surface_suggest_quality(surface->client), 0); cairo_surface_destroy(rect); surface->realized = 1;