GUAC-1305: Clean up WebP encoder.
This commit is contained in:
parent
0dd4d9b9fa
commit
3597a20890
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user