GUAC-1305: Send WebP images in preference to JPEG when supported.
This commit is contained in:
parent
be64fd23c7
commit
0dd4d9b9fa
@ -91,6 +91,13 @@
|
|||||||
*/
|
*/
|
||||||
#define GUAC_COMMON_SURFACE_JPEG_FRAMERATE 3
|
#define GUAC_COMMON_SURFACE_JPEG_FRAMERATE 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the coordinates of the given rectangle to be within the bounds of
|
* Updates the coordinates of the given rectangle to be within the bounds of
|
||||||
* the given surface.
|
* the given surface.
|
||||||
@ -314,8 +321,9 @@ static unsigned int __guac_common_surface_calculate_framerate(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Guesses whether a rectangle within a particular surface would be better
|
* Guesses whether a rectangle within a particular surface would be better
|
||||||
* compressed as PNG or as JPEG. Positive values indicate PNG is likely to
|
* compressed as PNG or using a lossy format like JPEG. Positive values
|
||||||
* be superior, while negative values indicate JPEG.
|
* indicate PNG is likely to be superior, while negative values indicate the
|
||||||
|
* opposite.
|
||||||
*
|
*
|
||||||
* @param surface
|
* @param surface
|
||||||
* The surface containing the image data to check.
|
* The surface containing the image data to check.
|
||||||
@ -325,7 +333,8 @@ static unsigned int __guac_common_surface_calculate_framerate(
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* Positive values if PNG compression is likely to perform better than
|
* Positive values if PNG compression is likely to perform better than
|
||||||
* JPEG, or negative values if JPEG is likely to perform better than PNG.
|
* lossy alternatives, or negative values if PNG is likely to perform
|
||||||
|
* worse.
|
||||||
*/
|
*/
|
||||||
static int __guac_common_surface_png_optimality(guac_common_surface* surface,
|
static int __guac_common_surface_png_optimality(guac_common_surface* surface,
|
||||||
const guac_common_rect* rect) {
|
const guac_common_rect* rect) {
|
||||||
@ -405,6 +414,32 @@ static int __guac_common_surface_should_use_jpeg(guac_common_surface* surface,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given rectangle would be optimally encoded as WebP
|
||||||
|
* rather than PNG.
|
||||||
|
*
|
||||||
|
* @param surface
|
||||||
|
* The surface to be queried.
|
||||||
|
*
|
||||||
|
* @param rect
|
||||||
|
* The rectangle to check.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Non-zero if the rectangle would be optimally encoded as WebP, zero
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
static int __guac_common_surface_should_use_webp(guac_common_surface* surface,
|
||||||
|
const guac_common_rect* rect) {
|
||||||
|
|
||||||
|
/* Do not use WebP if not supported */
|
||||||
|
if (!guac_client_supports_webp(surface->client))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Usage criteria are currently the same as JPEG */
|
||||||
|
return __guac_common_surface_should_use_jpeg(surface, rect);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the heat map cells which intersect the given rectangle using the
|
* Updates the heat map cells which intersect the given rectangle using the
|
||||||
* given timestamp. This timestamp, along with timestamps from past updates,
|
* given timestamp. This timestamp, along with timestamps from past updates,
|
||||||
@ -1276,6 +1311,47 @@ static void __guac_common_surface_flush_to_jpeg(guac_common_surface* surface) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes the bitmap update currently described by the dirty rectangle within
|
||||||
|
* the given surface directly via an "img" instruction as WebP data. The
|
||||||
|
* resulting instructions will be sent over the socket associated with the
|
||||||
|
* given surface.
|
||||||
|
*
|
||||||
|
* @param surface
|
||||||
|
* The surface to flush.
|
||||||
|
*/
|
||||||
|
static void __guac_common_surface_flush_to_webp(guac_common_surface* surface) {
|
||||||
|
|
||||||
|
if (surface->dirty) {
|
||||||
|
|
||||||
|
guac_socket* socket = surface->socket;
|
||||||
|
const guac_layer* layer = surface->layer;
|
||||||
|
|
||||||
|
/* Get Cairo surface for specified rect */
|
||||||
|
unsigned char* buffer = surface->buffer
|
||||||
|
+ surface->dirty_rect.y * surface->stride
|
||||||
|
+ surface->dirty_rect.x * 4;
|
||||||
|
|
||||||
|
cairo_surface_t* rect = cairo_image_surface_create_for_data(buffer,
|
||||||
|
CAIRO_FORMAT_RGB24,
|
||||||
|
surface->dirty_rect.width, surface->dirty_rect.height,
|
||||||
|
surface->stride);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
cairo_surface_destroy(rect);
|
||||||
|
surface->realized = 1;
|
||||||
|
|
||||||
|
/* Surface is no longer dirty */
|
||||||
|
surface->dirty = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comparator for instances of guac_common_surface_bitmap_rect, the elements
|
* Comparator for instances of guac_common_surface_bitmap_rect, the elements
|
||||||
* which make up a surface's bitmap buffer.
|
* which make up a surface's bitmap buffer.
|
||||||
@ -1357,12 +1433,17 @@ void guac_common_surface_flush(guac_common_surface* surface) {
|
|||||||
|
|
||||||
flushed++;
|
flushed++;
|
||||||
|
|
||||||
/* Flush as JPEG if JPEG is preferred */
|
/* Prefer WebP when reasonable */
|
||||||
if (__guac_common_surface_should_use_jpeg(surface,
|
if (__guac_common_surface_should_use_webp(surface,
|
||||||
|
&surface->dirty_rect))
|
||||||
|
__guac_common_surface_flush_to_webp(surface);
|
||||||
|
|
||||||
|
/* If not WebP, JPEG is the next best (lossy) choice */
|
||||||
|
else if (__guac_common_surface_should_use_jpeg(surface,
|
||||||
&surface->dirty_rect))
|
&surface->dirty_rect))
|
||||||
__guac_common_surface_flush_to_jpeg(surface);
|
__guac_common_surface_flush_to_jpeg(surface);
|
||||||
|
|
||||||
/* Otherwise, use PNG */
|
/* Use PNG if no lossy formats are appropriate */
|
||||||
else
|
else
|
||||||
__guac_common_surface_flush_to_png(surface);
|
__guac_common_surface_flush_to_png(surface);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user