webp: decode directly to block storage when possible

This commit is contained in:
Benoit Pierre 2015-02-27 03:04:56 +01:00
parent 76c8dda681
commit bd369f78ae
3 changed files with 36 additions and 7 deletions

View File

@ -763,6 +763,7 @@ PyImaging_WebPDecoderNew(PyObject* self, PyObject* args)
context->has_alpha = has_alpha; context->has_alpha = has_alpha;
context->width = width; context->width = width;
context->height = height; context->height = height;
context->output = NULL;
context->decoder = NULL; context->decoder = NULL;
return (PyObject*) decoder; return (PyObject*) decoder;

View File

@ -25,6 +25,9 @@ typedef struct {
/* PRIVATE CONTEXT (set by decoder) */ /* PRIVATE CONTEXT (set by decoder) */
WebPDecoderConfig config; WebPDecoderConfig config;
/* Non-NULL when a temporary output buffer is in use. */
WebPDecBuffer *output;
/* Non-NULL when an incremental decoder is in use. */
WebPIDecoder *decoder; WebPIDecoder *decoder;
} WEBPSTATE; } WEBPSTATE;

View File

@ -40,12 +40,11 @@ static int _vp8_status_to_codec_status(VP8StatusCode code)
int ImagingWebPDecode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) int ImagingWebPDecode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes)
{ {
WEBPSTATE *context = (WEBPSTATE *)state->context; WEBPSTATE *context = (WEBPSTATE *)state->context;
WebPDecoderConfig *config = &context->config;
VP8StatusCode vp8_status_code; VP8StatusCode vp8_status_code;
if (!state->state) if (!state->state)
{ {
WebPDecoderConfig *config = &context->config;
if (!WebPInitDecoderConfig(config)) if (!WebPInitDecoderConfig(config))
{ {
/* Mismatched version. */ /* Mismatched version. */
@ -58,6 +57,23 @@ int ImagingWebPDecode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes
else else
config->output.colorspace = MODE_RGB; config->output.colorspace = MODE_RGB;
/* If block storage is used, and we're not stripping alpha, then directly decode to it. */
if (NULL != im->block && (MODE_RGBA == config->output.colorspace || !context->has_alpha))
{
assert(4 == im->pixelsize);
/* Force RGBA so RGB is correctly unpacked. */
config->output.colorspace = MODE_RGBA;
config->output.is_external_memory = 1;
config->output.u.RGBA.stride = im->linesize;
config->output.u.RGBA.size = config->output.u.RGBA.stride * state->ysize;
config->output.u.RGBA.rgba = (uint8_t *)im->block + state->xoff * 4 + state->yoff * im->linesize;
}
else
{
context->output = &config->output;
}
if (state->xsize != context->width || state->ysize != context->height) if (state->xsize != context->width || state->ysize != context->height)
{ {
config->options.scaled_width = state->xsize; config->options.scaled_width = state->xsize;
@ -102,7 +118,11 @@ int ImagingWebPDecode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes
assert(height == state->ysize); assert(height == state->ysize);
assert(last_y <= state->ysize); assert(last_y <= state->ysize);
for (; state->y < last_y; ++state->y) if (config->output.is_external_memory)
{
state->y = last_y;
}
else for (; state->y < last_y; ++state->y)
{ {
assert(state->y < state->ysize); assert(state->y < state->ysize);
state->shuffle((UINT8 *)im->image[state->y + state->yoff] + state->shuffle((UINT8 *)im->image[state->y + state->yoff] +
@ -131,9 +151,14 @@ int ImagingWebPDecodeCleanup(ImagingCodecState state)
{ {
WEBPSTATE* context = (WEBPSTATE*) state->context; WEBPSTATE* context = (WEBPSTATE*) state->context;
if (NULL != context->output)
{
WebPFreeDecBuffer(context->output);
context->output = NULL;
}
if (NULL != context->decoder) if (NULL != context->decoder)
{ {
WebPFreeDecBuffer(&context->config.output);
WebPIDelete(context->decoder); WebPIDelete(context->decoder);
context->decoder = NULL; context->decoder = NULL;
} }