From 61c2d51fd72c44b6124bc227909b5be7f693e2e2 Mon Sep 17 00:00:00 2001 From: Pascal Massimino Date: Thu, 22 Mar 2012 10:30:20 +0000 Subject: [PATCH] move the rescaling code into its own file and make enc/ and dec/ use it. (cherry picked from commit 8e92d9e380a89b7443a2e2c3d16ce5a222e8c1e8) Conflicts: Android.mk makefile.unix src/dec/vp8l.c src/utils/Makefile.am --- Android.mk | 1 + Makefile.vc | 1 + makefile.unix | 4 +- src/dec/io.c | 52 ++++++--------- src/dec/webp.c | 93 +------------------------- src/dec/webpi.h | 32 +-------- src/enc/picture.c | 91 +++++-------------------- src/utils/Makefile.am | 2 +- src/utils/rescaler.c | 152 ++++++++++++++++++++++++++++++++++++++++++ src/utils/rescaler.h | 76 +++++++++++++++++++++ 10 files changed, 271 insertions(+), 233 deletions(-) create mode 100644 src/utils/rescaler.c create mode 100644 src/utils/rescaler.h diff --git a/Android.mk b/Android.mk index 5bba8d63..db321947 100644 --- a/Android.mk +++ b/Android.mk @@ -39,6 +39,7 @@ LOCAL_SRC_FILES := \ src/utils/bit_writer.c \ src/utils/filters.c \ src/utils/quant_levels.c \ + src/utils/rescaler.c \ src/utils/tcoder.c \ src/utils/thread.c \ diff --git a/Makefile.vc b/Makefile.vc index c5c62e1c..b44770d2 100644 --- a/Makefile.vc +++ b/Makefile.vc @@ -188,6 +188,7 @@ X_OBJS= \ $(DIROBJ)\utils\bit_writer.obj \ $(DIROBJ)\utils\filters.obj \ $(DIROBJ)\utils\quant_levels.obj \ + $(DIROBJ)\utils\rescaler.obj \ $(DIROBJ)\utils\tcoder.obj \ $(DIROBJ)\utils\thread.obj \ $(X_OBJS) \ diff --git a/makefile.unix b/makefile.unix index 94759db4..925f9ec5 100644 --- a/makefile.unix +++ b/makefile.unix @@ -72,8 +72,8 @@ DSP_OBJS = src/dsp/cpu.o src/dsp/enc.o \ src/dsp/dec_neon.o src/dsp/upsampling.o src/dsp/upsampling_sse2.o \ src/dsp/yuv.o UTILS_OBJS = src/utils/alpha.o src/utils/bit_reader.o src/utils/bit_writer.o \ - src/utils/filters.o src/utils/quant_levels.o src/utils/thread.o \ - src/utils/tcoder.o + src/utils/filters.o src/utils/quant_levels.o src/utils/rescaler.o \ + src/utils/thread.o src/utils/tcoder.o OBJS = $(DEC_OBJS) $(ENC_OBJS) $(DSP_OBJS) $(UTILS_OBJS) diff --git a/src/dec/io.c b/src/dec/io.c index 0df4d142..122cf1c6 100644 --- a/src/dec/io.c +++ b/src/dec/io.c @@ -234,14 +234,11 @@ static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p) { static int Rescale(const uint8_t* src, int src_stride, int new_lines, WebPRescaler* const wrk) { int num_lines_out = 0; - while (new_lines-- > 0) { // import new contribution of one source row. - WebPRescalerImportRow(src, 0, wrk); - src += src_stride; - wrk->y_accum -= wrk->y_sub; - while (wrk->y_accum <= 0) { // emit output row(s) - WebPRescalerExportRow(wrk); - ++num_lines_out; - } + while (new_lines > 0) { // import new contributions of source rows. + const int lines_in = WebPRescalerImport(wrk, new_lines, src, src_stride); + src += lines_in * src_stride; + new_lines -= lines_in; + num_lines_out += WebPRescalerExport(wrk); // emit output row(s) } return num_lines_out; } @@ -318,20 +315,6 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) { //------------------------------------------------------------------------------ // RGBA rescaling -// import new contributions until one row is ready to be output, or all input -// is consumed. -static int Import(const uint8_t* src, int src_stride, - int new_lines, WebPRescaler* const wrk) { - int num_lines_in = 0; - while (num_lines_in < new_lines && wrk->y_accum > 0) { - WebPRescalerImportRow(src, 0, wrk); - src += src_stride; - ++num_lines_in; - wrk->y_accum -= wrk->y_sub; - } - return num_lines_in; -} - static int ExportRGB(WebPDecParams* const p, int y_pos) { const WebPYUV444Converter convert = WebPYUV444Converters[p->output->colorspace]; @@ -340,7 +323,8 @@ static int ExportRGB(WebPDecParams* const p, int y_pos) { int num_lines_out = 0; // 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. - while (p->scaler_y.y_accum <= 0 && p->scaler_u.y_accum <= 0) { + while (WebPRescalerHasPendingOutput(&p->scaler_y) && + WebPRescalerHasPendingOutput(&p->scaler_u)) { assert(p->last_y + y_pos + num_lines_out < p->output->height); assert(p->scaler_u.y_accum == p->scaler_v.y_accum); WebPRescalerExportRow(&p->scaler_y); @@ -360,12 +344,15 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) { int j = 0, uv_j = 0; int num_lines_out = 0; while (j < mb_h) { - const int y_lines_in = Import(io->y + j * io->y_stride, io->y_stride, - mb_h - j, &p->scaler_y); - const int u_lines_in = Import(io->u + uv_j * io->uv_stride, io->uv_stride, - uv_mb_h - uv_j, &p->scaler_u); - const int v_lines_in = Import(io->v + uv_j * io->uv_stride, io->uv_stride, - uv_mb_h - uv_j, &p->scaler_v); + const int y_lines_in = + WebPRescalerImport(&p->scaler_y, mb_h - j, + io->y + j * io->y_stride, io->y_stride); + const int u_lines_in = + WebPRescalerImport(&p->scaler_u, uv_mb_h - uv_j, + io->u + uv_j * io->uv_stride, io->uv_stride); + const int v_lines_in = + WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j, + io->v + uv_j * io->uv_stride, io->uv_stride); (void)v_lines_in; // remove a gcc warning assert(u_lines_in == v_lines_in); j += y_lines_in; @@ -380,7 +367,7 @@ static int ExportAlpha(WebPDecParams* const p, int y_pos) { uint8_t* dst = buf->rgba + (p->last_y + y_pos) * buf->stride + (p->output->colorspace == MODE_ARGB ? 0 : 3); int num_lines_out = 0; - while (p->scaler_a.y_accum <= 0) { + while (WebPRescalerHasPendingOutput(&p->scaler_a)) { int i; assert(p->last_y + y_pos + num_lines_out < p->output->height); WebPRescalerExportRow(&p->scaler_a); @@ -397,7 +384,7 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) { const WebPRGBABuffer* const buf = &p->output->u.RGBA; uint8_t* dst = buf->rgba + (p->last_y + y_pos) * buf->stride + 1; int num_lines_out = 0; - while (p->scaler_a.y_accum <= 0) { + while (WebPRescalerHasPendingOutput(&p->scaler_a)) { int i; assert(p->last_y + y_pos + num_lines_out < p->output->height); WebPRescalerExportRow(&p->scaler_a); @@ -420,7 +407,8 @@ static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p) { WebPRescaler* const scaler = &p->scaler_a; int j = 0, pos = 0; while (j < io->mb_h) { - j += Import(io->a + j * io->width, io->width, io->mb_h - j, scaler); + j += WebPRescalerImport(scaler, io->mb_h - j, + io->a + j * io->width, io->width); pos += output_func(p, pos); } } diff --git a/src/dec/webp.c b/src/dec/webp.c index ffb0555b..c8f9afa1 100644 --- a/src/dec/webp.c +++ b/src/dec/webp.c @@ -610,7 +610,7 @@ VP8StatusCode WebPDecode(const uint8_t* data, uint32_t data_size, } //------------------------------------------------------------------------------ -// Cropping & rescaling. +// Cropping and rescaling. int WebPIoInitFromOptions(const WebPDecoderOptions* const options, VP8Io* const io) { @@ -664,97 +664,6 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options, return 1; } -#define RFIX 30 -#define MULT_FIX(x,y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX) - -void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, - uint8_t* const dst, int dst_width, int dst_height, - int dst_stride, int num_channels, int x_add, int x_sub, - int y_add, int y_sub, int32_t* const work) { - wrk->x_expand = (src_width < dst_width); - wrk->src_width = src_width; - wrk->src_height = src_height; - wrk->dst_width = dst_width; - wrk->dst_height = dst_height; - wrk->dst = dst; - wrk->dst_stride = dst_stride; - wrk->num_channels = num_channels; - // for 'x_expand', we use bilinear interpolation - wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add - x_sub; - wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub; - wrk->y_accum = y_add; - wrk->y_add = y_add; - wrk->y_sub = y_sub; - wrk->fx_scale = (1 << RFIX) / x_sub; - wrk->fy_scale = (1 << RFIX) / y_sub; - wrk->fxy_scale = wrk->x_expand ? - ((int64_t)dst_height << RFIX) / (x_sub * src_height) : - ((int64_t)dst_height << RFIX) / (x_add * src_height); - wrk->irow = work; - wrk->frow = work + num_channels * dst_width; -} - -void WebPRescalerImportRow(const uint8_t* const src, int channel, - WebPRescaler* const wrk) { - const int x_stride = wrk->num_channels; - const int x_out_max = wrk->dst_width * wrk->num_channels; - int x_in = channel; - int x_out; - int accum = 0; - if (!wrk->x_expand) { - int sum = 0; - for (x_out = channel; x_out < x_out_max; x_out += x_stride) { - accum += wrk->x_add; - for (; accum > 0; accum -= wrk->x_sub) { - sum += src[x_in]; - x_in += x_stride; - } - { // Emit next horizontal pixel. - const int32_t base = src[x_in]; - const int32_t frac = base * (-accum); - x_in += x_stride; - wrk->frow[x_out] = (sum + base) * wrk->x_sub - frac; - // fresh fractional start for next pixel - sum = (int)MULT_FIX(frac, wrk->fx_scale); - } - } - } else { // simple bilinear interpolation - int left = src[channel], right = src[channel]; - for (x_out = channel; x_out < x_out_max; x_out += x_stride) { - if (accum < 0) { - left = right; - x_in += x_stride; - right = src[x_in]; - accum += wrk->x_add; - } - wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum; - accum -= wrk->x_sub; - } - } - // Accumulate the new row's contribution - for (x_out = channel; x_out < x_out_max; x_out += x_stride) { - wrk->irow[x_out] += wrk->frow[x_out]; - } -} - -void WebPRescalerExportRow(WebPRescaler* const wrk) { - int x_out; - const int yscale = wrk->fy_scale * (-wrk->y_accum); - const int x_out_max = wrk->dst_width * wrk->num_channels; - assert(wrk->y_accum <= 0); - for (x_out = 0; x_out < x_out_max; ++x_out) { - const int frac = (int)MULT_FIX(wrk->frow[x_out], yscale); - const int v = (int)MULT_FIX(wrk->irow[x_out] - frac, wrk->fxy_scale); - wrk->dst[x_out] = (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255; - wrk->irow[x_out] = frac; // new fractional start - } - wrk->y_accum += wrk->y_add; - wrk->dst += wrk->dst_stride; -} - -#undef MULT_FIX -#undef RFIX - //------------------------------------------------------------------------------ #if defined(__cplusplus) || defined(c_plusplus) diff --git a/src/dec/webpi.h b/src/dec/webpi.h index c22ee0df..a40817b5 100644 --- a/src/dec/webpi.h +++ b/src/dec/webpi.h @@ -17,6 +17,7 @@ extern "C" { #endif #include "../webp/decode_vp8.h" +#include "../utils/rescaler.h" //------------------------------------------------------------------------------ // WebPDecParams: Decoding output parameters. Transient internal object. @@ -24,23 +25,6 @@ extern "C" { typedef struct WebPDecParams WebPDecParams; typedef int (*OutputFunc)(const VP8Io* const io, WebPDecParams* const p); -// Structure use for on-the-fly rescaling -typedef struct { - int x_expand; // true if we're expanding in the x direction - int num_channels; // bytes to jump between pixels - int fy_scale, fx_scale; // fixed-point scaling factor - int64_t fxy_scale; // '' - // we need hpel-precise add/sub increments, for the downsampled U/V planes. - int y_accum; // vertical accumulator - int y_add, y_sub; // vertical increments (add ~= src, sub ~= dst) - int x_add, x_sub; // horizontal increments (add ~= src, sub ~= dst) - int src_width, src_height; // source dimensions - int dst_width, dst_height; // destination dimensions - uint8_t* dst; - int dst_stride; - int32_t* irow, *frow; // work buffer -} WebPRescaler; - struct WebPDecParams { WebPDecBuffer* output; // output buffer. uint8_t* tmp_y, *tmp_u, *tmp_v; // cache for the fancy upsampler @@ -167,20 +151,6 @@ void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst); int WebPIoInitFromOptions(const WebPDecoderOptions* const options, VP8Io* const io); -// Initialize a rescaler given scratch area 'work' and dimensions of src & dst. -void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, - uint8_t* const dst, int dst_width, int dst_height, - int dst_stride, int num_channels, int x_add, int x_sub, - int y_add, int y_sub, int32_t* const work); - -// Import a row of data and save its contribution in the rescaler. -// 'channel' denotes the channel number to be imported. -void WebPRescalerImportRow(const uint8_t* const src, int channel, - WebPRescaler* const wrk); - -// Export a row from rescaler. -void WebPRescalerExportRow(WebPRescaler* const wrk); - //------------------------------------------------------------------------------ #if defined(__cplusplus) || defined(c_plusplus) diff --git a/src/enc/picture.c b/src/enc/picture.c index 89c216e6..ef20608d 100644 --- a/src/enc/picture.c +++ b/src/enc/picture.c @@ -14,6 +14,7 @@ #include #include "./vp8enci.h" +#include "../utils/rescaler.h" #if defined(__cplusplus) || defined(c_plusplus) extern "C" { @@ -224,89 +225,29 @@ int WebPPictureCrop(WebPPicture* const pic, //------------------------------------------------------------------------------ // Simple picture rescaler -#define RFIX 30 -#define MULT(x,y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX) -static WEBP_INLINE void ImportRow(const uint8_t* src, int src_width, - int32_t* frow, int32_t* irow, int dst_width) { - const int x_expand = (src_width < dst_width); - const int fx_scale = (1 << RFIX) / dst_width; - int x_in = 0; - int x_out; - int x_accum = 0; - if (!x_expand) { - int sum = 0; - for (x_out = 0; x_out < dst_width; ++x_out) { - x_accum += src_width - dst_width; - for (; x_accum > 0; x_accum -= dst_width) { - sum += src[x_in++]; - } - { // Emit next horizontal pixel. - const int32_t base = src[x_in++]; - const int32_t frac = base * (-x_accum); - frow[x_out] = (sum + base) * dst_width - frac; - sum = MULT(frac, fx_scale); // fresh fractional start for next pixel - } - } - } else { // simple bilinear interpolation - int left = src[0], right = src[0]; - for (x_out = 0; x_out < dst_width; ++x_out) { - if (x_accum < 0) { - left = right; - right = src[++x_in]; - x_accum += dst_width - 1; - } - frow[x_out] = right * (dst_width - 1) + (left - right) * x_accum; - x_accum -= src_width - 1; - } - } - // Accumulate the new row's contribution - for (x_out = 0; x_out < dst_width; ++x_out) { - irow[x_out] += frow[x_out]; - } -} - -static void ExportRow(int32_t* frow, int32_t* irow, uint8_t* dst, int dst_width, - const int yscale, const int64_t fxy_scale) { - int x_out; - for (x_out = 0; x_out < dst_width; ++x_out) { - const int frac = MULT(frow[x_out], yscale); - const int v = (int)(MULT(irow[x_out] - frac, fxy_scale)); - dst[x_out] = (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255; - irow[x_out] = frac; // new fractional start - } -} - static void RescalePlane(const uint8_t* src, int src_width, int src_height, int src_stride, uint8_t* dst, int dst_width, int dst_height, int dst_stride, int32_t* const work) { - const int x_expand = (src_width < dst_width); - const int fy_scale = (1 << RFIX) / dst_height; - const int64_t fxy_scale = x_expand ? - ((int64_t)dst_height << RFIX) / (dst_width * src_height) : - ((int64_t)dst_height << RFIX) / (src_width * src_height); - int y_accum = src_height; - int y; - int32_t* irow = work; // integral contribution - int32_t* frow = work + dst_width; // fractional contribution + WebPRescaler rescaler; + int y = 0; + WebPRescalerInit(&rescaler, src_width, src_height, + dst, dst_width, dst_height, dst_stride, + 1, + src_width, dst_width, + src_height, dst_height, + work); memset(work, 0, 2 * dst_width * sizeof(*work)); - for (y = 0; y < src_height; ++y) { - // import new contribution of one source row. - ImportRow(src, src_width, frow, irow, dst_width); - src += src_stride; - // emit output row(s) - y_accum -= dst_height; - for (; y_accum <= 0; y_accum += src_height) { - const int yscale = fy_scale * (-y_accum); - ExportRow(frow, irow, dst, dst_width, yscale, fxy_scale); - dst += dst_stride; - } + while (y < src_height) { + const int num_lines_in = + WebPRescalerImport(&rescaler, src_height - y, src, src_stride); + y += num_lines_in; + src += num_lines_in * src_stride; + WebPRescalerExport(&rescaler); } } -#undef MULT -#undef RFIX int WebPPictureRescale(WebPPicture* const pic, int width, int height) { WebPPicture tmp; @@ -332,7 +273,7 @@ int WebPPictureRescale(WebPPicture* const pic, int width, int height) { tmp.height = height; if (!WebPPictureAlloc(&tmp)) return 0; - work = (int32_t*)malloc(2 * width * sizeof(int32_t)); + work = (int32_t*)malloc(2 * width * sizeof(*work)); if (work == NULL) { WebPPictureFree(&tmp); return 0; diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am index a60d7724..40b64338 100644 --- a/src/utils/Makefile.am +++ b/src/utils/Makefile.am @@ -4,7 +4,7 @@ libwebputils_la_SOURCES = alpha.h alpha.c \ bit_reader.h bit_reader.c \ bit_writer.h bit_writer.c \ filters.h filters.c \ - quant_levels.c \ + quant_levels.c rescaler.c \ tcoder.h tcoderi.h tcoder.c \ thread.h thread.c libwebputilsinclude_HEADERS = ../webp/types.h diff --git a/src/utils/rescaler.c b/src/utils/rescaler.c new file mode 100644 index 00000000..9825dcbc --- /dev/null +++ b/src/utils/rescaler.c @@ -0,0 +1,152 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Rescaling functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include "./rescaler.h" + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define RFIX 30 +#define MULT_FIX(x,y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX) + +void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, + uint8_t* const dst, int dst_width, int dst_height, + int dst_stride, int num_channels, int x_add, int x_sub, + int y_add, int y_sub, int32_t* const work) { + wrk->x_expand = (src_width < dst_width); + wrk->src_width = src_width; + wrk->src_height = src_height; + wrk->dst_width = dst_width; + wrk->dst_height = dst_height; + wrk->dst = dst; + wrk->dst_stride = dst_stride; + wrk->num_channels = num_channels; + // for 'x_expand', we use bilinear interpolation + wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add - x_sub; + wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub; + wrk->y_accum = y_add; + wrk->y_add = y_add; + wrk->y_sub = y_sub; + wrk->fx_scale = (1 << RFIX) / x_sub; + wrk->fy_scale = (1 << RFIX) / y_sub; + wrk->fxy_scale = wrk->x_expand ? + ((int64_t)dst_height << RFIX) / (x_sub * src_height) : + ((int64_t)dst_height << RFIX) / (x_add * src_height); + wrk->irow = work; + wrk->frow = work + num_channels * dst_width; +} + +void WebPRescalerImportRow(WebPRescaler* const wrk, + const uint8_t* const src, int channel) { + const int x_stride = wrk->num_channels; + const int x_out_max = wrk->dst_width * wrk->num_channels; + int x_in = channel; + int x_out; + int accum = 0; + if (!wrk->x_expand) { + int sum = 0; + for (x_out = channel; x_out < x_out_max; x_out += x_stride) { + accum += wrk->x_add; + for (; accum > 0; accum -= wrk->x_sub) { + sum += src[x_in]; + x_in += x_stride; + } + { // Emit next horizontal pixel. + const int32_t base = src[x_in]; + const int32_t frac = base * (-accum); + x_in += x_stride; + wrk->frow[x_out] = (sum + base) * wrk->x_sub - frac; + // fresh fractional start for next pixel + sum = (int)MULT_FIX(frac, wrk->fx_scale); + } + } + } else { // simple bilinear interpolation + int left = src[channel], right = src[channel]; + for (x_out = channel; x_out < x_out_max; x_out += x_stride) { + if (accum < 0) { + left = right; + x_in += x_stride; + right = src[x_in]; + accum += wrk->x_add; + } + wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum; + accum -= wrk->x_sub; + } + } + // Accumulate the new row's contribution + for (x_out = channel; x_out < x_out_max; x_out += x_stride) { + wrk->irow[x_out] += wrk->frow[x_out]; + } +} + +uint8_t* WebPRescalerExportRow(WebPRescaler* const wrk) { + if (wrk->y_accum <= 0) { + int x_out; + uint8_t* const dst = wrk->dst; + int32_t* const irow = wrk->irow; + const int32_t* const frow = wrk->frow; + const int yscale = wrk->fy_scale * (-wrk->y_accum); + const int x_out_max = wrk->dst_width * wrk->num_channels; + + for (x_out = 0; x_out < x_out_max; ++x_out) { + const int frac = (int)MULT_FIX(frow[x_out], yscale); + const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); + dst[x_out] = (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255; + irow[x_out] = frac; // new fractional start + } + wrk->y_accum += wrk->y_add; + wrk->dst += wrk->dst_stride; + return dst; + } else { + return NULL; + } +} + +#undef MULT_FIX +#undef RFIX + +//------------------------------------------------------------------------------ +// all-in-one calls + +int WebPRescalerImport(WebPRescaler* const wrk, int num_lines, + const uint8_t* src, int src_stride) { + int total_imported = 0; + while (total_imported < num_lines && wrk->y_accum > 0) { + int channel; + for (channel = 0; channel < wrk->num_channels; ++channel) { + WebPRescalerImportRow(wrk, src, channel); + } + src += src_stride; + ++total_imported; + wrk->y_accum -= wrk->y_sub; + } + return total_imported; +} + +int WebPRescalerExport(WebPRescaler* const rescaler) { + int total_exported = 0; + while (WebPRescalerHasPendingOutput(rescaler)) { + WebPRescalerExportRow(rescaler); + ++total_exported; + } + return total_exported; +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/src/utils/rescaler.h b/src/utils/rescaler.h new file mode 100644 index 00000000..432fa4b4 --- /dev/null +++ b/src/utils/rescaler.h @@ -0,0 +1,76 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Rescaling functions +// +// Author: skal@google.com (Pascal Massimino) + +#ifndef WEBP_UTILS_RESCALER_H_ +#define WEBP_UTILS_RESCALER_H_ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include "../webp/types.h" + +// Structure used for on-the-fly rescaling +typedef struct { + int x_expand; // true if we're expanding in the x direction + int num_channels; // bytes to jump between pixels + int fy_scale, fx_scale; // fixed-point scaling factor + int64_t fxy_scale; // '' + // we need hpel-precise add/sub increments, for the downsampled U/V planes. + int y_accum; // vertical accumulator + int y_add, y_sub; // vertical increments (add ~= src, sub ~= dst) + int x_add, x_sub; // horizontal increments (add ~= src, sub ~= dst) + int src_width, src_height; // source dimensions + int dst_width, dst_height; // destination dimensions + uint8_t* dst; + int dst_stride; + int32_t* irow, *frow; // work buffer +} WebPRescaler; + +// Initialize a rescaler given scratch area 'work' and dimensions of src & dst. +void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, + uint8_t* const dst, + int dst_width, int dst_height, int dst_stride, + int num_channels, + int x_add, int x_sub, + int y_add, int y_sub, + int32_t* const work); + +// Import a row of data and save its contribution in the rescaler. +// 'channel' denotes the channel number to be imported. +void WebPRescalerImportRow(WebPRescaler* const rescaler, + const uint8_t* const src, int channel); + +// Import multiple rows over all channels, until at least one row is ready to +// be exported. Returns the actual number of lines that were imported. +int WebPRescalerImport(WebPRescaler* const rescaler, int num_rows, + const uint8_t* src, int src_stride); + +// Return true if there is pending output rows ready. +static WEBP_INLINE +int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) { + return (rescaler->y_accum <= 0); +} + +// Export one row from rescaler. Returns the pointer where output was written, +// or NULL if no row was pending. +uint8_t* WebPRescalerExportRow(WebPRescaler* const wrk); + +// Export as many rows as possible. Return the numbers of rows written. +int WebPRescalerExport(WebPRescaler* const wrk); + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_UTILS_RESCALER_H_ */