GUAC-1305: Clean up WebP encoder.

This commit is contained in:
Michael Jumper 2015-09-20 21:06:46 -07:00
parent 0dd4d9b9fa
commit 3597a20890

View File

@ -31,11 +31,15 @@
#include <cairo/cairo.h> #include <cairo/cairo.h>
#include <webp/encode.h> #include <webp/encode.h>
#include <assert.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
/**
* Structure which describes the current state of the WebP image writer.
*/
typedef struct guac_webp_stream_writer { typedef struct guac_webp_stream_writer {
/** /**
@ -118,15 +122,14 @@ static void guac_webp_stream_writer_init(guac_webp_stream_writer* writer,
* picture->custom_ptr which contains the Guacamole stream writer structure. * picture->custom_ptr which contains the Guacamole stream writer structure.
* *
* @return * @return
* True if writing was successful, false on failure. * Non-zero if writing was successful, zero on failure.
*/ */
static int guac_webp_stream_write(const uint8_t* data, size_t data_size, static int guac_webp_stream_write(const uint8_t* data, size_t data_size,
const WebPPicture* picture) { const WebPPicture* picture) {
guac_webp_stream_writer* const writer = (guac_webp_stream_writer*)picture->custom_ptr; guac_webp_stream_writer* const writer =
if (writer == NULL) { (guac_webp_stream_writer*) picture->custom_ptr;
return 0; assert(writer != NULL);
}
const unsigned char* current = data; const unsigned char* current = data;
int length = data_size; int length = data_size;
@ -165,10 +168,17 @@ static int guac_webp_stream_write(const uint8_t* data, size_t data_size,
int guac_webp_write(guac_socket* socket, guac_stream* stream, int guac_webp_write(guac_socket* socket, guac_stream* stream,
cairo_surface_t* surface, int quality) { cairo_surface_t* surface, int quality) {
guac_webp_stream_writer writer;
WebPPicture picture;
uint32_t* argb_output;
int x, y;
int width = cairo_image_surface_get_width(surface); int width = cairo_image_surface_get_width(surface);
int height = cairo_image_surface_get_height(surface); int height = cairo_image_surface_get_height(surface);
int stride = cairo_image_surface_get_stride(surface); int stride = cairo_image_surface_get_stride(surface);
cairo_format_t format = cairo_image_surface_get_format(surface); cairo_format_t format = cairo_image_surface_get_format(surface);
unsigned char* data = cairo_image_surface_get_data(surface);
if (format != CAIRO_FORMAT_RGB24 && format != CAIRO_FORMAT_ARGB32) { if (format != CAIRO_FORMAT_RGB24 && format != CAIRO_FORMAT_ARGB32) {
guac_error = GUAC_STATUS_INTERNAL_ERROR; guac_error = GUAC_STATUS_INTERNAL_ERROR;
@ -179,54 +189,61 @@ int guac_webp_write(guac_socket* socket, guac_stream* stream,
/* Flush pending operations to surface */ /* Flush pending operations to surface */
cairo_surface_flush(surface); cairo_surface_flush(surface);
unsigned char* data = cairo_image_surface_get_data(surface);
/* Configure WebP compression bits */ /* Configure WebP compression bits */
WebPConfig config; WebPConfig config;
if (!WebPConfigPreset(&config, WEBP_HINT_DEFAULT, quality)) return -1; // version error if (!WebPConfigPreset(&config, WEBP_HINT_DEFAULT, quality))
/* Add additional tuning: */ return -1;
/* Add additional tuning */
config.lossless = 0; config.lossless = 0;
config.quality = quality; config.quality = quality;
config.thread_level = 1; /* Multi threaded */ config.thread_level = 1; /* Multi threaded */
config.method = 2; /* Compression method (0=fast/larger, 6=slow/smaller) */ config.method = 2; /* Compression method (0=fast/larger, 6=slow/smaller) */
WebPValidateConfig(&config); /* verify parameter ranges */ /* Validate configuration */
WebPValidateConfig(&config);
/* Set up WebP picture and writer */ /* Set up WebP picture */
guac_webp_stream_writer writer;
WebPPicture picture;
WebPPictureInit(&picture); WebPPictureInit(&picture);
picture.use_argb = 1; picture.use_argb = 1;
picture.width = width; picture.width = width;
picture.height = height; picture.height = height;
/* Allocate and init writer */
WebPPictureAlloc(&picture); WebPPictureAlloc(&picture);
picture.writer = guac_webp_stream_write; picture.writer = guac_webp_stream_write;
picture.custom_ptr = &writer; picture.custom_ptr = &writer;
guac_webp_stream_writer_init(&writer, socket, stream); guac_webp_stream_writer_init(&writer, socket, stream);
/* Copy image data into WebP picture */ /* Copy image data into WebP picture */
for (int y = 0; y < height; ++y) { argb_output = picture.argb;
for (y = 0; y < height; y++) {
unsigned char *inptr = data + (stride * y); /* Get pixels at start of each row */
unsigned char *outptr = (unsigned char*)&picture.argb[y * picture.argb_stride]; uint32_t* src = (uint32_t*) data;
uint32_t* dst = argb_output;
for (int x = 0; x < width; ++x) { /* For each pixel in row */
for (x = 0; x < width; x++) {
outptr[0] = *inptr++; // B /* Pull pixel data, removing alpha channel if necessary */
outptr[1] = *inptr++; // G uint32_t src_pixel = *src;
outptr[2] = *inptr++; // R if (format != CAIRO_FORMAT_ARGB32)
src_pixel |= 0xFF000000;
if (format != CAIRO_FORMAT_ARGB32) { /* Store converted pixel data */
outptr[3] = 0xFF; *dst = src_pixel;
}
else {
outptr[3] = *inptr; // A
}
inptr++; /* Next pixel */
outptr += 4; src++;
dst++;
} }
/* Next row */
data += stride;
argb_output += picture.argb_stride;
} }
/* Encode image */ /* Encode image */
@ -241,3 +258,4 @@ int guac_webp_write(guac_socket* socket, guac_stream* stream,
return 0; return 0;
} }