use pointers for WebPRescaler's in WebPDecParams

This makes the structure more generic, without the hard-coded
internal structure.

This is a borderline incompatible ABI change, even if WebPIDecoder structure
is opaque.

Change-Id: I518765c3f76fc17a136cef045a5a8aa70ed70e85
This commit is contained in:
Pascal Massimino 2017-01-16 00:07:41 -08:00
parent db013a8d5c
commit 9ed5e3e5dd
2 changed files with 62 additions and 40 deletions

View File

@ -256,7 +256,7 @@ static int Rescale(const uint8_t* src, int src_stride,
static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) { static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
const int mb_h = io->mb_h; const int mb_h = io->mb_h;
const int uv_mb_h = (mb_h + 1) >> 1; const int uv_mb_h = (mb_h + 1) >> 1;
WebPRescaler* const scaler = &p->scaler_y; WebPRescaler* const scaler = p->scaler_y;
int num_lines_out = 0; int num_lines_out = 0;
if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) { if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) {
// Before rescaling, we premultiply the luma directly into the io->y // Before rescaling, we premultiply the luma directly into the io->y
@ -267,8 +267,8 @@ static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
io->a, io->width, io->mb_w, mb_h, 0); io->a, io->width, io->mb_w, mb_h, 0);
} }
num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler); num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler);
Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u); Rescale(io->u, io->uv_stride, uv_mb_h, p->scaler_u);
Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v); Rescale(io->v, io->uv_stride, uv_mb_h, p->scaler_v);
return num_lines_out; return num_lines_out;
} }
@ -278,11 +278,11 @@ static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p,
uint8_t* const dst_a = buf->a + p->last_y * buf->a_stride; uint8_t* const dst_a = buf->a + p->last_y * buf->a_stride;
if (io->a != NULL) { if (io->a != NULL) {
uint8_t* const dst_y = buf->y + p->last_y * buf->y_stride; uint8_t* const dst_y = buf->y + p->last_y * buf->y_stride;
const int num_lines_out = Rescale(io->a, io->width, io->mb_h, &p->scaler_a); const int num_lines_out = Rescale(io->a, io->width, io->mb_h, p->scaler_a);
assert(expected_num_lines_out == num_lines_out); assert(expected_num_lines_out == num_lines_out);
if (num_lines_out > 0) { // unmultiply the Y if (num_lines_out > 0) { // unmultiply the Y
WebPMultRows(dst_y, buf->y_stride, dst_a, buf->a_stride, WebPMultRows(dst_y, buf->y_stride, dst_a, buf->a_stride,
p->scaler_a.dst_width, num_lines_out, 1); p->scaler_a->dst_width, num_lines_out, 1);
} }
} else if (buf->a != NULL) { } else if (buf->a != NULL) {
// the user requested alpha, but there is none, set it to opaque. // the user requested alpha, but there is none, set it to opaque.
@ -304,31 +304,42 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
const int uv_in_height = (io->mb_h + 1) >> 1; const int uv_in_height = (io->mb_h + 1) >> 1;
const size_t work_size = 2 * out_width; // scratch memory for luma rescaler const size_t work_size = 2 * out_width; // scratch memory for luma rescaler
const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
size_t tmp_size; size_t tmp_size, rescaler_size;
rescaler_t* work; rescaler_t* work;
WebPRescaler* scalers;
const int num_rescalers = has_alpha ? 4 : 3;
tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work); tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work);
if (has_alpha) { if (has_alpha) {
tmp_size += work_size * sizeof(*work); tmp_size += work_size * sizeof(*work);
} }
p->memory = WebPSafeMalloc(1ULL, tmp_size); rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
p->memory = WebPSafeMalloc(1ULL, tmp_size + rescaler_size);
if (p->memory == NULL) { if (p->memory == NULL) {
return 0; // memory error return 0; // memory error
} }
work = (rescaler_t*)p->memory; work = (rescaler_t*)p->memory;
WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + tmp_size);
p->scaler_y = &scalers[0];
p->scaler_u = &scalers[1];
p->scaler_v = &scalers[2];
p->scaler_a = has_alpha ? &scalers[3] : NULL;
WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
buf->y, out_width, out_height, buf->y_stride, 1, buf->y, out_width, out_height, buf->y_stride, 1,
work); work);
WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height, WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
buf->u, uv_out_width, uv_out_height, buf->u_stride, 1, buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
work + work_size); work + work_size);
WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height, WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
buf->v, uv_out_width, uv_out_height, buf->v_stride, 1, buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
work + work_size + uv_work_size); work + work_size + uv_work_size);
p->emit = EmitRescaledYUV; p->emit = EmitRescaledYUV;
if (has_alpha) { if (has_alpha) {
WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h, WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
buf->a, out_width, out_height, buf->a_stride, 1, buf->a, out_width, out_height, buf->a_stride, 1,
work + work_size + 2 * uv_work_size); work + work_size + 2 * uv_work_size);
p->emit_alpha = EmitRescaledAlphaYUV; p->emit_alpha = EmitRescaledAlphaYUV;
@ -348,15 +359,15 @@ static int ExportRGB(WebPDecParams* const p, int y_pos) {
int num_lines_out = 0; int num_lines_out = 0;
// For RGB rescaling, because of the YUV420, current scan position // For RGB rescaling, because of the YUV420, current scan position
// U/V can be +1/-1 line from the Y one. Hence the double test. // U/V can be +1/-1 line from the Y one. Hence the double test.
while (WebPRescalerHasPendingOutput(&p->scaler_y) && while (WebPRescalerHasPendingOutput(p->scaler_y) &&
WebPRescalerHasPendingOutput(&p->scaler_u)) { WebPRescalerHasPendingOutput(p->scaler_u)) {
assert(y_pos + num_lines_out < p->output->height); assert(y_pos + num_lines_out < p->output->height);
assert(p->scaler_u.y_accum == p->scaler_v.y_accum); assert(p->scaler_u->y_accum == p->scaler_v->y_accum);
WebPRescalerExportRow(&p->scaler_y); WebPRescalerExportRow(p->scaler_y);
WebPRescalerExportRow(&p->scaler_u); WebPRescalerExportRow(p->scaler_u);
WebPRescalerExportRow(&p->scaler_v); WebPRescalerExportRow(p->scaler_v);
convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst, convert(p->scaler_y->dst, p->scaler_u->dst, p->scaler_v->dst,
dst, p->scaler_y.dst_width); dst, p->scaler_y->dst_width);
dst += buf->stride; dst += buf->stride;
++num_lines_out; ++num_lines_out;
} }
@ -370,15 +381,15 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
int num_lines_out = 0; int num_lines_out = 0;
while (j < mb_h) { while (j < mb_h) {
const int y_lines_in = const int y_lines_in =
WebPRescalerImport(&p->scaler_y, mb_h - j, WebPRescalerImport(p->scaler_y, mb_h - j,
io->y + j * io->y_stride, io->y_stride); io->y + j * io->y_stride, io->y_stride);
j += y_lines_in; j += y_lines_in;
if (WebPRescaleNeededLines(&p->scaler_u, uv_mb_h - uv_j)) { if (WebPRescaleNeededLines(p->scaler_u, uv_mb_h - uv_j)) {
const int u_lines_in = const int u_lines_in =
WebPRescalerImport(&p->scaler_u, uv_mb_h - uv_j, WebPRescalerImport(p->scaler_u, uv_mb_h - uv_j,
io->u + uv_j * io->uv_stride, io->uv_stride); io->u + uv_j * io->uv_stride, io->uv_stride);
const int v_lines_in = const int v_lines_in =
WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j, WebPRescalerImport(p->scaler_v, uv_mb_h - uv_j,
io->v + uv_j * io->uv_stride, io->uv_stride); io->v + uv_j * io->uv_stride, io->uv_stride);
(void)v_lines_in; // remove a gcc warning (void)v_lines_in; // remove a gcc warning
assert(u_lines_in == v_lines_in); assert(u_lines_in == v_lines_in);
@ -399,13 +410,13 @@ static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) {
int num_lines_out = 0; int num_lines_out = 0;
const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
uint32_t non_opaque = 0; uint32_t non_opaque = 0;
const int width = p->scaler_a.dst_width; const int width = p->scaler_a->dst_width;
while (WebPRescalerHasPendingOutput(&p->scaler_a) && while (WebPRescalerHasPendingOutput(p->scaler_a) &&
num_lines_out < max_lines_out) { num_lines_out < max_lines_out) {
assert(y_pos + num_lines_out < p->output->height); assert(y_pos + num_lines_out < p->output->height);
WebPRescalerExportRow(&p->scaler_a); WebPRescalerExportRow(p->scaler_a);
non_opaque |= WebPDispatchAlpha(p->scaler_a.dst, 0, width, 1, dst, 0); non_opaque |= WebPDispatchAlpha(p->scaler_a->dst, 0, width, 1, dst, 0);
dst += buf->stride; dst += buf->stride;
++num_lines_out; ++num_lines_out;
} }
@ -427,18 +438,18 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos,
#endif #endif
int num_lines_out = 0; int num_lines_out = 0;
const WEBP_CSP_MODE colorspace = p->output->colorspace; const WEBP_CSP_MODE colorspace = p->output->colorspace;
const int width = p->scaler_a.dst_width; const int width = p->scaler_a->dst_width;
const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
uint32_t alpha_mask = 0x0f; uint32_t alpha_mask = 0x0f;
while (WebPRescalerHasPendingOutput(&p->scaler_a) && while (WebPRescalerHasPendingOutput(p->scaler_a) &&
num_lines_out < max_lines_out) { num_lines_out < max_lines_out) {
int i; int i;
assert(y_pos + num_lines_out < p->output->height); assert(y_pos + num_lines_out < p->output->height);
WebPRescalerExportRow(&p->scaler_a); WebPRescalerExportRow(p->scaler_a);
for (i = 0; i < width; ++i) { for (i = 0; i < width; ++i) {
// Fill in the alpha value (converted to 4 bits). // Fill in the alpha value (converted to 4 bits).
const uint32_t alpha_value = p->scaler_a.dst[i] >> 4; const uint32_t alpha_value = p->scaler_a->dst[i] >> 4;
alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value; alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
alpha_mask &= alpha_value; alpha_mask &= alpha_value;
} }
@ -454,7 +465,7 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos,
static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p, static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p,
int expected_num_out_lines) { int expected_num_out_lines) {
if (io->a != NULL) { if (io->a != NULL) {
WebPRescaler* const scaler = &p->scaler_a; WebPRescaler* const scaler = p->scaler_a;
int lines_left = expected_num_out_lines; int lines_left = expected_num_out_lines;
const int y_end = p->last_y + lines_left; const int y_end = p->last_y + lines_left;
while (lines_left > 0) { while (lines_left > 0) {
@ -476,7 +487,9 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
const size_t work_size = 2 * out_width; // scratch memory for one rescaler const size_t work_size = 2 * out_width; // scratch memory for one rescaler
rescaler_t* work; // rescalers work area rescaler_t* work; // rescalers work area
uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
size_t tmp_size1, tmp_size2, total_size; size_t tmp_size1, tmp_size2, total_size, rescaler_size;
WebPRescaler* scalers;
const int num_rescalers = has_alpha ? 4 : 3;
tmp_size1 = 3 * work_size; tmp_size1 = 3 * work_size;
tmp_size2 = 3 * out_width; tmp_size2 = 3 * out_width;
@ -485,26 +498,35 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
tmp_size2 += out_width; tmp_size2 += out_width;
} }
total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp); total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp);
p->memory = WebPSafeMalloc(1ULL, total_size); rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
p->memory = WebPSafeMalloc(1ULL, total_size + rescaler_size);
if (p->memory == NULL) { if (p->memory == NULL) {
return 0; // memory error return 0; // memory error
} }
work = (rescaler_t*)p->memory; work = (rescaler_t*)p->memory;
tmp = (uint8_t*)(work + tmp_size1); tmp = (uint8_t*)(work + tmp_size1);
WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size);
p->scaler_y = &scalers[0];
p->scaler_u = &scalers[1];
p->scaler_v = &scalers[2];
p->scaler_a = has_alpha ? &scalers[3] : NULL;
WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
tmp + 0 * out_width, out_width, out_height, 0, 1, tmp + 0 * out_width, out_width, out_height, 0, 1,
work + 0 * work_size); work + 0 * work_size);
WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height, WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
tmp + 1 * out_width, out_width, out_height, 0, 1, tmp + 1 * out_width, out_width, out_height, 0, 1,
work + 1 * work_size); work + 1 * work_size);
WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height, WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
tmp + 2 * out_width, out_width, out_height, 0, 1, tmp + 2 * out_width, out_width, out_height, 0, 1,
work + 2 * work_size); work + 2 * work_size);
p->emit = EmitRescaledRGB; p->emit = EmitRescaledRGB;
WebPInitYUV444Converters(); WebPInitYUV444Converters();
if (has_alpha) { if (has_alpha) {
WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h, WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
tmp + 3 * out_width, out_width, out_height, 0, 1, tmp + 3 * out_width, out_width, out_height, 0, 1,
work + 3 * work_size); work + 3 * work_size);
p->emit_alpha = EmitRescaledAlphaRGB; p->emit_alpha = EmitRescaledAlphaRGB;

View File

@ -38,8 +38,8 @@ struct WebPDecParams {
int last_y; // coordinate of the line that was last output int last_y; // coordinate of the line that was last output
const WebPDecoderOptions* options; // if not NULL, use alt decoding features const WebPDecoderOptions* options; // if not NULL, use alt decoding features
// rescalers
WebPRescaler scaler_y, scaler_u, scaler_v, scaler_a; WebPRescaler* scaler_y, *scaler_u, *scaler_v, *scaler_a; // rescalers
void* memory; // overall scratch memory for the output work. void* memory; // overall scratch memory for the output work.
OutputFunc emit; // output RGB or YUV samples OutputFunc emit; // output RGB or YUV samples