1 // Copyright 2012 Google Inc. All Rights Reserved. 2 // 3 // This code is licensed under the same terms as WebM: 4 // Software License Agreement: http://www.webmproject.org/license/software/ 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ 6 // ----------------------------------------------------------------------------- 7 // 8 // Rescaling functions 9 // 10 // Author: Skal (pascal.massimino (at) gmail.com) 11 12 #include <assert.h> 13 #include <stdlib.h> 14 #include "./rescaler.h" 15 16 //------------------------------------------------------------------------------ 17 18 #if defined(__cplusplus) || defined(c_plusplus) 19 extern "C" { 20 #endif 21 22 #define RFIX 30 23 #define MULT_FIX(x,y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX) 24 25 void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, 26 uint8_t* const dst, int dst_width, int dst_height, 27 int dst_stride, int num_channels, int x_add, int x_sub, 28 int y_add, int y_sub, int32_t* const work) { 29 wrk->x_expand = (src_width < dst_width); 30 wrk->src_width = src_width; 31 wrk->src_height = src_height; 32 wrk->dst_width = dst_width; 33 wrk->dst_height = dst_height; 34 wrk->dst = dst; 35 wrk->dst_stride = dst_stride; 36 wrk->num_channels = num_channels; 37 // for 'x_expand', we use bilinear interpolation 38 wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add - x_sub; 39 wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub; 40 wrk->y_accum = y_add; 41 wrk->y_add = y_add; 42 wrk->y_sub = y_sub; 43 wrk->fx_scale = (1 << RFIX) / x_sub; 44 wrk->fy_scale = (1 << RFIX) / y_sub; 45 wrk->fxy_scale = wrk->x_expand ? 46 ((int64_t)dst_height << RFIX) / (x_sub * src_height) : 47 ((int64_t)dst_height << RFIX) / (x_add * src_height); 48 wrk->irow = work; 49 wrk->frow = work + num_channels * dst_width; 50 } 51 52 void WebPRescalerImportRow(WebPRescaler* const wrk, 53 const uint8_t* const src, int channel) { 54 const int x_stride = wrk->num_channels; 55 const int x_out_max = wrk->dst_width * wrk->num_channels; 56 int x_in = channel; 57 int x_out; 58 int accum = 0; 59 if (!wrk->x_expand) { 60 int sum = 0; 61 for (x_out = channel; x_out < x_out_max; x_out += x_stride) { 62 accum += wrk->x_add; 63 for (; accum > 0; accum -= wrk->x_sub) { 64 sum += src[x_in]; 65 x_in += x_stride; 66 } 67 { // Emit next horizontal pixel. 68 const int32_t base = src[x_in]; 69 const int32_t frac = base * (-accum); 70 x_in += x_stride; 71 wrk->frow[x_out] = (sum + base) * wrk->x_sub - frac; 72 // fresh fractional start for next pixel 73 sum = (int)MULT_FIX(frac, wrk->fx_scale); 74 } 75 } 76 } else { // simple bilinear interpolation 77 int left = src[channel], right = src[channel]; 78 for (x_out = channel; x_out < x_out_max; x_out += x_stride) { 79 if (accum < 0) { 80 left = right; 81 x_in += x_stride; 82 right = src[x_in]; 83 accum += wrk->x_add; 84 } 85 wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum; 86 accum -= wrk->x_sub; 87 } 88 } 89 // Accumulate the new row's contribution 90 for (x_out = channel; x_out < x_out_max; x_out += x_stride) { 91 wrk->irow[x_out] += wrk->frow[x_out]; 92 } 93 } 94 95 uint8_t* WebPRescalerExportRow(WebPRescaler* const wrk) { 96 if (wrk->y_accum <= 0) { 97 int x_out; 98 uint8_t* const dst = wrk->dst; 99 int32_t* const irow = wrk->irow; 100 const int32_t* const frow = wrk->frow; 101 const int yscale = wrk->fy_scale * (-wrk->y_accum); 102 const int x_out_max = wrk->dst_width * wrk->num_channels; 103 104 for (x_out = 0; x_out < x_out_max; ++x_out) { 105 const int frac = (int)MULT_FIX(frow[x_out], yscale); 106 const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); 107 dst[x_out] = (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255; 108 irow[x_out] = frac; // new fractional start 109 } 110 wrk->y_accum += wrk->y_add; 111 wrk->dst += wrk->dst_stride; 112 return dst; 113 } else { 114 return NULL; 115 } 116 } 117 118 #undef MULT_FIX 119 #undef RFIX 120 121 //------------------------------------------------------------------------------ 122 // all-in-one calls 123 124 int WebPRescalerImport(WebPRescaler* const wrk, int num_lines, 125 const uint8_t* src, int src_stride) { 126 int total_imported = 0; 127 while (total_imported < num_lines && wrk->y_accum > 0) { 128 int channel; 129 for (channel = 0; channel < wrk->num_channels; ++channel) { 130 WebPRescalerImportRow(wrk, src, channel); 131 } 132 src += src_stride; 133 ++total_imported; 134 wrk->y_accum -= wrk->y_sub; 135 } 136 return total_imported; 137 } 138 139 int WebPRescalerExport(WebPRescaler* const rescaler) { 140 int total_exported = 0; 141 while (WebPRescalerHasPendingOutput(rescaler)) { 142 WebPRescalerExportRow(rescaler); 143 ++total_exported; 144 } 145 return total_exported; 146 } 147 148 //------------------------------------------------------------------------------ 149 150 #if defined(__cplusplus) || defined(c_plusplus) 151 } // extern "C" 152 #endif 153