Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(153)

Side by Side Diff: third_party/libwebp/dec/io.c

Issue 10832153: libwebp: update snapshot to v0.2.0-rc1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2011 Google Inc. 1 // Copyright 2011 Google Inc. All Rights Reserved.
2 // 2 //
3 // This code is licensed under the same terms as WebM: 3 // This code is licensed under the same terms as WebM:
4 // Software License Agreement: http://www.webmproject.org/license/software/ 4 // Software License Agreement: http://www.webmproject.org/license/software/
5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/
6 // ----------------------------------------------------------------------------- 6 // -----------------------------------------------------------------------------
7 // 7 //
8 // functions for sample output. 8 // functions for sample output.
9 // 9 //
10 // Author: Skal (pascal.massimino@gmail.com) 10 // Author: Skal (pascal.massimino@gmail.com)
11 11
(...skipping 13 matching lines...) Expand all
25 25
26 static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) { 26 static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) {
27 WebPDecBuffer* output = p->output; 27 WebPDecBuffer* output = p->output;
28 const WebPYUVABuffer* const buf = &output->u.YUVA; 28 const WebPYUVABuffer* const buf = &output->u.YUVA;
29 uint8_t* const y_dst = buf->y + io->mb_y * buf->y_stride; 29 uint8_t* const y_dst = buf->y + io->mb_y * buf->y_stride;
30 uint8_t* const u_dst = buf->u + (io->mb_y >> 1) * buf->u_stride; 30 uint8_t* const u_dst = buf->u + (io->mb_y >> 1) * buf->u_stride;
31 uint8_t* const v_dst = buf->v + (io->mb_y >> 1) * buf->v_stride; 31 uint8_t* const v_dst = buf->v + (io->mb_y >> 1) * buf->v_stride;
32 const int mb_w = io->mb_w; 32 const int mb_w = io->mb_w;
33 const int mb_h = io->mb_h; 33 const int mb_h = io->mb_h;
34 const int uv_w = (mb_w + 1) / 2; 34 const int uv_w = (mb_w + 1) / 2;
35 const int uv_h = (mb_h + 1) / 2;
35 int j; 36 int j;
36 for (j = 0; j < mb_h; ++j) { 37 for (j = 0; j < mb_h; ++j) {
37 memcpy(y_dst + j * buf->y_stride, io->y + j * io->y_stride, mb_w); 38 memcpy(y_dst + j * buf->y_stride, io->y + j * io->y_stride, mb_w);
38 } 39 }
39 for (j = 0; j < (mb_h + 1) / 2; ++j) { 40 for (j = 0; j < uv_h; ++j) {
40 memcpy(u_dst + j * buf->u_stride, io->u + j * io->uv_stride, uv_w); 41 memcpy(u_dst + j * buf->u_stride, io->u + j * io->uv_stride, uv_w);
41 memcpy(v_dst + j * buf->v_stride, io->v + j * io->uv_stride, uv_w); 42 memcpy(v_dst + j * buf->v_stride, io->v + j * io->uv_stride, uv_w);
42 } 43 }
43 return io->mb_h; 44 return io->mb_h;
44 } 45 }
45 46
46 // Point-sampling U/V sampler. 47 // Point-sampling U/V sampler.
47 static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) { 48 static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) {
48 WebPDecBuffer* output = p->output; 49 WebPDecBuffer* output = p->output;
49 const WebPRGBABuffer* const buf = &output->u.RGBA; 50 const WebPRGBABuffer* const buf = &output->u.RGBA;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 #endif 97 #endif
97 98
98 //------------------------------------------------------------------------------ 99 //------------------------------------------------------------------------------
99 // Fancy upsampling 100 // Fancy upsampling
100 101
101 #ifdef FANCY_UPSAMPLING 102 #ifdef FANCY_UPSAMPLING
102 static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) { 103 static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {
103 int num_lines_out = io->mb_h; // a priori guess 104 int num_lines_out = io->mb_h; // a priori guess
104 const WebPRGBABuffer* const buf = &p->output->u.RGBA; 105 const WebPRGBABuffer* const buf = &p->output->u.RGBA;
105 uint8_t* dst = buf->rgba + io->mb_y * buf->stride; 106 uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
106 const WebPUpsampleLinePairFunc upsample = 107 WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace];
107 io->a ? WebPUpsamplersKeepAlpha[p->output->colorspace]
108 : WebPUpsamplers[p->output->colorspace];
109 const uint8_t* cur_y = io->y; 108 const uint8_t* cur_y = io->y;
110 const uint8_t* cur_u = io->u; 109 const uint8_t* cur_u = io->u;
111 const uint8_t* cur_v = io->v; 110 const uint8_t* cur_v = io->v;
112 const uint8_t* top_u = p->tmp_u; 111 const uint8_t* top_u = p->tmp_u;
113 const uint8_t* top_v = p->tmp_v; 112 const uint8_t* top_v = p->tmp_v;
114 int y = io->mb_y; 113 int y = io->mb_y;
115 int y_end = io->mb_y + io->mb_h; 114 int y_end = io->mb_y + io->mb_h;
116 const int mb_w = io->mb_w; 115 const int mb_w = io->mb_w;
117 const int uv_w = (mb_w + 1) / 2; 116 const int uv_w = (mb_w + 1) / 2;
118 117
119 if (y == 0) { 118 if (y == 0) {
120 // First line is special cased. We mirror the u/v samples at boundary. 119 // First line is special cased. We mirror the u/v samples at boundary.
121 upsample(NULL, cur_y, cur_u, cur_v, cur_u, cur_v, NULL, dst, mb_w); 120 upsample(NULL, cur_y, cur_u, cur_v, cur_u, cur_v, NULL, dst, mb_w);
122 } else { 121 } else {
123 // We can finish the left-over line from previous call. 122 // We can finish the left-over line from previous call.
124 // Warning! Don't overwrite the alpha values (if any), as they
125 // are not lagging one line behind but are already written.
126 upsample(p->tmp_y, cur_y, top_u, top_v, cur_u, cur_v, 123 upsample(p->tmp_y, cur_y, top_u, top_v, cur_u, cur_v,
127 dst - buf->stride, dst, mb_w); 124 dst - buf->stride, dst, mb_w);
128 num_lines_out++; 125 ++num_lines_out;
129 } 126 }
130 // Loop over each output pairs of row. 127 // Loop over each output pairs of row.
131 for (; y + 2 < y_end; y += 2) { 128 for (; y + 2 < y_end; y += 2) {
132 top_u = cur_u; 129 top_u = cur_u;
133 top_v = cur_v; 130 top_v = cur_v;
134 cur_u += io->uv_stride; 131 cur_u += io->uv_stride;
135 cur_v += io->uv_stride; 132 cur_v += io->uv_stride;
136 dst += 2 * buf->stride; 133 dst += 2 * buf->stride;
137 cur_y += 2 * io->y_stride; 134 cur_y += 2 * io->y_stride;
138 upsample(cur_y - io->y_stride, cur_y, 135 upsample(cur_y - io->y_stride, cur_y,
(...skipping 17 matching lines...) Expand all
156 dst + buf->stride, NULL, mb_w); 153 dst + buf->stride, NULL, mb_w);
157 } 154 }
158 } 155 }
159 return num_lines_out; 156 return num_lines_out;
160 } 157 }
161 158
162 #endif /* FANCY_UPSAMPLING */ 159 #endif /* FANCY_UPSAMPLING */
163 160
164 //------------------------------------------------------------------------------ 161 //------------------------------------------------------------------------------
165 162
166 #ifdef WEBP_EXPERIMENTAL_FEATURES
167 static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p) { 163 static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
164 const uint8_t* alpha = io->a;
165 const WebPYUVABuffer* const buf = &p->output->u.YUVA;
168 const int mb_w = io->mb_w; 166 const int mb_w = io->mb_w;
169 const int mb_h = io->mb_h; 167 const int mb_h = io->mb_h;
168 uint8_t* dst = buf->a + io->mb_y * buf->a_stride;
170 int j; 169 int j;
171 const WebPYUVABuffer* const buf = &p->output->u.YUVA; 170
172 uint8_t* dst = buf->a + io->mb_y * buf->a_stride; 171 if (alpha != NULL) {
173 const uint8_t* alpha = io->a;
174 if (alpha) {
175 for (j = 0; j < mb_h; ++j) { 172 for (j = 0; j < mb_h; ++j) {
176 memcpy(dst, alpha, mb_w * sizeof(*dst)); 173 memcpy(dst, alpha, mb_w * sizeof(*dst));
177 alpha += io->width; 174 alpha += io->width;
178 dst += buf->a_stride; 175 dst += buf->a_stride;
179 } 176 }
177 } else if (buf->a != NULL) {
178 // the user requested alpha, but there is none, set it to opaque.
179 for (j = 0; j < mb_h; ++j) {
180 memset(dst, 0xff, mb_w * sizeof(*dst));
181 dst += buf->a_stride;
182 }
180 } 183 }
181 return 0; 184 return 0;
182 } 185 }
183 186
184 static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p) { 187 static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
185 const int mb_w = io->mb_w;
186 const int mb_h = io->mb_h;
187 int i, j;
188 const WebPRGBABuffer* const buf = &p->output->u.RGBA;
189 uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
190 const uint8_t* alpha = io->a; 188 const uint8_t* alpha = io->a;
191 if (alpha) { 189 if (alpha != NULL) {
192 for (j = 0; j < mb_h; ++j) { 190 const int mb_w = io->mb_w;
193 for (i = 0; i < mb_w; ++i) { 191 const int mb_h = io->mb_h;
194 dst[4 * i + 3] = alpha[i]; 192 int i, j;
193 const WEBP_CSP_MODE colorspace = p->output->colorspace;
194 const int alpha_first =
195 (colorspace == MODE_ARGB || colorspace == MODE_Argb);
196 const WebPRGBABuffer* const buf = &p->output->u.RGBA;
197 int start_y = io->mb_y;
198 int num_rows = mb_h;
199
200 // We compensate for the 1-line delay of fancy upscaler.
201 // This is similar to EmitFancyRGB().
202 if (io->fancy_upsampling) {
203 if (start_y == 0) {
204 // We don't process the last row yet. It'll be done during next call.
205 --num_rows;
206 } else {
207 --start_y;
208 // Fortunately, *alpha data is persistent, so we can go back
209 // one row and finish alpha blending, now that the fancy upscaler
210 // completed the YUV->RGB interpolation.
211 alpha -= io->width;
195 } 212 }
196 alpha += io->width; 213 if (io->crop_top + io->mb_y + mb_h == io->crop_bottom) {
197 dst += buf->stride; 214 // If it's the very last call, we process all the remaing rows!
215 num_rows = io->crop_bottom - io->crop_top - start_y;
216 }
217 }
218 {
219 uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
220 uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
221 for (j = 0; j < num_rows; ++j) {
222 for (i = 0; i < mb_w; ++i) dst[4 * i] = alpha[i];
223 alpha += io->width;
224 dst += buf->stride;
225 }
226 if (WebPIsPremultipliedMode(colorspace)) {
227 WebPApplyAlphaMultiply(base_rgba, alpha_first,
228 mb_w, num_rows, buf->stride);
229 }
198 } 230 }
199 } 231 }
200 return 0; 232 return 0;
201 } 233 }
202 234
203 #endif /* WEBP_EXPERIMENTAL_FEATURES */ 235 static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p) {
204 236 const uint8_t* alpha = io->a;
205 //------------------------------------------------------------------------------ 237 if (alpha != NULL) {
206 // Simple picture rescaler 238 const int mb_w = io->mb_w;
207 239 const int mb_h = io->mb_h;
208 // TODO(skal): start a common library for encoder and decoder, and factorize 240 int i, j;
209 // this code in. 241 const WebPRGBABuffer* const buf = &p->output->u.RGBA;
210 242 uint8_t* const base_rgba = buf->rgba + io->mb_y * buf->stride;
211 #define RFIX 30 243 uint8_t* alpha_dst = base_rgba + 1;
212 #define MULT(x,y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX) 244 for (j = 0; j < mb_h; ++j) {
213 245 for (i = 0; i < mb_w; ++i) {
214 static void InitRescaler(WebPRescaler* const wrk, 246 // Fill in the alpha value (converted to 4 bits).
215 int src_width, int src_height, 247 const uint32_t alpha_val = VP8Clip4Bits(alpha[i]);
216 uint8_t* dst, 248 alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_val;
217 int dst_width, int dst_height, int dst_stride,
218 int x_add, int x_sub, int y_add, int y_sub,
219 int32_t* work) {
220 wrk->x_expand = (src_width < dst_width);
221 wrk->src_width = src_width;
222 wrk->src_height = src_height;
223 wrk->dst_width = dst_width;
224 wrk->dst_height = dst_height;
225 wrk->dst = dst;
226 wrk->dst_stride = dst_stride;
227 // for 'x_expand', we use bilinear interpolation
228 wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add - x_sub;
229 wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub;
230 wrk->y_accum = y_add;
231 wrk->y_add = y_add;
232 wrk->y_sub = y_sub;
233 wrk->fx_scale = (1 << RFIX) / x_sub;
234 wrk->fy_scale = (1 << RFIX) / y_sub;
235 wrk->fxy_scale = wrk->x_expand ?
236 ((int64_t)dst_height << RFIX) / (x_sub * src_height) :
237 ((int64_t)dst_height << RFIX) / (x_add * src_height);
238 wrk->irow = work;
239 wrk->frow = work + dst_width;
240 }
241
242 static inline void ImportRow(const uint8_t* const src,
243 WebPRescaler* const wrk) {
244 int x_in = 0;
245 int x_out;
246 int accum = 0;
247 if (!wrk->x_expand) {
248 int sum = 0;
249 for (x_out = 0; x_out < wrk->dst_width; ++x_out) {
250 accum += wrk->x_add;
251 for (; accum > 0; accum -= wrk->x_sub) {
252 sum += src[x_in++];
253 } 249 }
254 { // Emit next horizontal pixel. 250 alpha += io->width;
255 const int32_t base = src[x_in++]; 251 alpha_dst += buf->stride;
256 const int32_t frac = base * (-accum);
257 wrk->frow[x_out] = (sum + base) * wrk->x_sub - frac;
258 // fresh fractional start for next pixel
259 sum = (int)MULT(frac, wrk->fx_scale);
260 }
261 } 252 }
262 } else { // simple bilinear interpolation 253 if (p->output->colorspace == MODE_rgbA_4444) {
263 int left = src[0], right = src[0]; 254 WebPApplyAlphaMultiply4444(base_rgba, mb_w, mb_h, buf->stride);
264 for (x_out = 0; x_out < wrk->dst_width; ++x_out) {
265 if (accum < 0) {
266 left = right;
267 right = src[++x_in];
268 accum += wrk->x_add;
269 }
270 wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
271 accum -= wrk->x_sub;
272 } 255 }
273 } 256 }
274 // Accumulate the new row's contribution 257 return 0;
275 for (x_out = 0; x_out < wrk->dst_width; ++x_out) {
276 wrk->irow[x_out] += wrk->frow[x_out];
277 }
278 } 258 }
279 259
280 static void ExportRow(WebPRescaler* const wrk) {
281 int x_out;
282 const int yscale = wrk->fy_scale * (-wrk->y_accum);
283 assert(wrk->y_accum <= 0);
284 for (x_out = 0; x_out < wrk->dst_width; ++x_out) {
285 const int frac = (int)MULT(wrk->frow[x_out], yscale);
286 const int v = (int)MULT(wrk->irow[x_out] - frac, wrk->fxy_scale);
287 wrk->dst[x_out] = (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255;
288 wrk->irow[x_out] = frac; // new fractional start
289 }
290 wrk->y_accum += wrk->y_add;
291 wrk->dst += wrk->dst_stride;
292 }
293
294 #undef MULT
295 #undef RFIX
296
297 //------------------------------------------------------------------------------ 260 //------------------------------------------------------------------------------
298 // YUV rescaling (no final RGB conversion needed) 261 // YUV rescaling (no final RGB conversion needed)
299 262
300 static int Rescale(const uint8_t* src, int src_stride, 263 static int Rescale(const uint8_t* src, int src_stride,
301 int new_lines, WebPRescaler* const wrk) { 264 int new_lines, WebPRescaler* const wrk) {
302 int num_lines_out = 0; 265 int num_lines_out = 0;
303 while (new_lines-- > 0) { // import new contribution of one source row. 266 while (new_lines > 0) { // import new contributions of source rows.
304 ImportRow(src, wrk); 267 const int lines_in = WebPRescalerImport(wrk, new_lines, src, src_stride);
305 src += src_stride; 268 src += lines_in * src_stride;
306 wrk->y_accum -= wrk->y_sub; 269 new_lines -= lines_in;
307 while (wrk->y_accum <= 0) { // emit output row(s) 270 num_lines_out += WebPRescalerExport(wrk); // emit output row(s)
308 ExportRow(wrk);
309 num_lines_out++;
310 }
311 } 271 }
312 return num_lines_out; 272 return num_lines_out;
313 } 273 }
314 274
315 static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) { 275 static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
316 const int mb_h = io->mb_h; 276 const int mb_h = io->mb_h;
317 const int uv_mb_h = (mb_h + 1) >> 1; 277 const int uv_mb_h = (mb_h + 1) >> 1;
318 const int num_lines_out = Rescale(io->y, io->y_stride, mb_h, &p->scaler_y); 278 const int num_lines_out = Rescale(io->y, io->y_stride, mb_h, &p->scaler_y);
319 Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u); 279 Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u);
320 Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v); 280 Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v);
321 return num_lines_out; 281 return num_lines_out;
322 } 282 }
323 283
324 static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p) { 284 static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
325 if (io->a) { 285 if (io->a != NULL) {
326 Rescale(io->a, io->width, io->mb_h, &p->scaler_a); 286 Rescale(io->a, io->width, io->mb_h, &p->scaler_a);
327 } 287 }
328 return 0; 288 return 0;
329 } 289 }
330 290
331 static int IsAlphaMode(WEBP_CSP_MODE mode) {
332 return (mode == MODE_RGBA || mode == MODE_BGRA || mode == MODE_ARGB ||
333 mode == MODE_RGBA_4444 || mode == MODE_YUVA);
334 }
335
336 static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) { 291 static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
337 const int has_alpha = IsAlphaMode(p->output->colorspace); 292 const int has_alpha = WebPIsAlphaMode(p->output->colorspace);
338 const WebPYUVABuffer* const buf = &p->output->u.YUVA; 293 const WebPYUVABuffer* const buf = &p->output->u.YUVA;
339 const int out_width = io->scaled_width; 294 const int out_width = io->scaled_width;
340 const int out_height = io->scaled_height; 295 const int out_height = io->scaled_height;
341 const int uv_out_width = (out_width + 1) >> 1; 296 const int uv_out_width = (out_width + 1) >> 1;
342 const int uv_out_height = (out_height + 1) >> 1; 297 const int uv_out_height = (out_height + 1) >> 1;
343 const int uv_in_width = (io->mb_w + 1) >> 1; 298 const int uv_in_width = (io->mb_w + 1) >> 1;
344 const int uv_in_height = (io->mb_h + 1) >> 1; 299 const int uv_in_height = (io->mb_h + 1) >> 1;
345 const size_t work_size = 2 * out_width; // scratch memory for luma rescaler 300 const size_t work_size = 2 * out_width; // scratch memory for luma rescaler
346 const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones 301 const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
347 size_t tmp_size; 302 size_t tmp_size;
348 int32_t* work; 303 int32_t* work;
349 304
350 tmp_size = work_size + 2 * uv_work_size; 305 tmp_size = work_size + 2 * uv_work_size;
351 if (has_alpha) { 306 if (has_alpha) {
352 tmp_size += work_size; 307 tmp_size += work_size;
353 } 308 }
354 p->memory = calloc(1, tmp_size * sizeof(*work)); 309 p->memory = calloc(1, tmp_size * sizeof(*work));
355 if (p->memory == NULL) { 310 if (p->memory == NULL) {
356 return 0; // memory error 311 return 0; // memory error
357 } 312 }
358 work = (int32_t*)p->memory; 313 work = (int32_t*)p->memory;
359 InitRescaler(&p->scaler_y, io->mb_w, io->mb_h, 314 WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
360 buf->y, out_width, out_height, buf->y_stride, 315 buf->y, out_width, out_height, buf->y_stride, 1,
361 io->mb_w, out_width, io->mb_h, out_height, 316 io->mb_w, out_width, io->mb_h, out_height,
362 work); 317 work);
363 InitRescaler(&p->scaler_u, uv_in_width, uv_in_height, 318 WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
364 buf->u, uv_out_width, uv_out_height, buf->u_stride, 319 buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
365 uv_in_width, uv_out_width, 320 uv_in_width, uv_out_width,
366 uv_in_height, uv_out_height, 321 uv_in_height, uv_out_height,
367 work + work_size); 322 work + work_size);
368 InitRescaler(&p->scaler_v, uv_in_width, uv_in_height, 323 WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
369 buf->v, uv_out_width, uv_out_height, buf->v_stride, 324 buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
370 uv_in_width, uv_out_width, 325 uv_in_width, uv_out_width,
371 uv_in_height, uv_out_height, 326 uv_in_height, uv_out_height,
372 work + work_size + uv_work_size); 327 work + work_size + uv_work_size);
373 p->emit = EmitRescaledYUV; 328 p->emit = EmitRescaledYUV;
329
374 if (has_alpha) { 330 if (has_alpha) {
375 InitRescaler(&p->scaler_a, io->mb_w, io->mb_h, 331 WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
376 buf->a, out_width, out_height, buf->a_stride, 332 buf->a, out_width, out_height, buf->a_stride, 1,
377 io->mb_w, out_width, io->mb_h, out_height, 333 io->mb_w, out_width, io->mb_h, out_height,
378 work + work_size + 2 * uv_work_size); 334 work + work_size + 2 * uv_work_size);
379 p->emit_alpha = EmitRescaledAlphaYUV; 335 p->emit_alpha = EmitRescaledAlphaYUV;
380 } 336 }
381 return 1; 337 return 1;
382 } 338 }
383 339
384 //------------------------------------------------------------------------------ 340 //------------------------------------------------------------------------------
385 // RGBA rescaling 341 // RGBA rescaling
386 342
387 // import new contributions until one row is ready to be output, or all input
388 // is consumed.
389 static int Import(const uint8_t* src, int src_stride,
390 int new_lines, WebPRescaler* const wrk) {
391 int num_lines_in = 0;
392 while (num_lines_in < new_lines && wrk->y_accum > 0) {
393 ImportRow(src, wrk);
394 src += src_stride;
395 ++num_lines_in;
396 wrk->y_accum -= wrk->y_sub;
397 }
398 return num_lines_in;
399 }
400
401 static int ExportRGB(WebPDecParams* const p, int y_pos) { 343 static int ExportRGB(WebPDecParams* const p, int y_pos) {
402 const WebPYUV444Converter convert = 344 const WebPYUV444Converter convert =
403 WebPYUV444Converters[p->output->colorspace]; 345 WebPYUV444Converters[p->output->colorspace];
404 const WebPRGBABuffer* const buf = &p->output->u.RGBA; 346 const WebPRGBABuffer* const buf = &p->output->u.RGBA;
405 uint8_t* dst = buf->rgba + (p->last_y + y_pos) * buf->stride; 347 uint8_t* dst = buf->rgba + (p->last_y + y_pos) * buf->stride;
406 int num_lines_out = 0; 348 int num_lines_out = 0;
407 // For RGB rescaling, because of the YUV420, current scan position 349 // For RGB rescaling, because of the YUV420, current scan position
408 // U/V can be +1/-1 line from the Y one. Hence the double test. 350 // U/V can be +1/-1 line from the Y one. Hence the double test.
409 while (p->scaler_y.y_accum <= 0 && p->scaler_u.y_accum <= 0) { 351 while (WebPRescalerHasPendingOutput(&p->scaler_y) &&
352 WebPRescalerHasPendingOutput(&p->scaler_u)) {
410 assert(p->last_y + y_pos + num_lines_out < p->output->height); 353 assert(p->last_y + y_pos + num_lines_out < p->output->height);
411 assert(p->scaler_u.y_accum == p->scaler_v.y_accum); 354 assert(p->scaler_u.y_accum == p->scaler_v.y_accum);
412 ExportRow(&p->scaler_y); 355 WebPRescalerExportRow(&p->scaler_y);
413 ExportRow(&p->scaler_u); 356 WebPRescalerExportRow(&p->scaler_u);
414 ExportRow(&p->scaler_v); 357 WebPRescalerExportRow(&p->scaler_v);
415 convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst, 358 convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst,
416 dst, p->scaler_y.dst_width); 359 dst, p->scaler_y.dst_width);
417 dst += buf->stride; 360 dst += buf->stride;
418 num_lines_out++; 361 ++num_lines_out;
419 } 362 }
420 return num_lines_out; 363 return num_lines_out;
421 } 364 }
422 365
423 static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) { 366 static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
424 const int mb_h = io->mb_h; 367 const int mb_h = io->mb_h;
425 const int uv_mb_h = (mb_h + 1) >> 1; 368 const int uv_mb_h = (mb_h + 1) >> 1;
426 int j = 0, uv_j = 0; 369 int j = 0, uv_j = 0;
427 int num_lines_out = 0; 370 int num_lines_out = 0;
428 while (j < mb_h) { 371 while (j < mb_h) {
429 const int y_lines_in = Import(io->y + j * io->y_stride, io->y_stride, 372 const int y_lines_in =
430 mb_h - j, &p->scaler_y); 373 WebPRescalerImport(&p->scaler_y, mb_h - j,
431 const int u_lines_in = Import(io->u + uv_j * io->uv_stride, io->uv_stride, 374 io->y + j * io->y_stride, io->y_stride);
432 uv_mb_h - uv_j, &p->scaler_u); 375 const int u_lines_in =
433 const int v_lines_in = Import(io->v + uv_j * io->uv_stride, io->uv_stride, 376 WebPRescalerImport(&p->scaler_u, uv_mb_h - uv_j,
434 uv_mb_h - uv_j, &p->scaler_v); 377 io->u + uv_j * io->uv_stride, io->uv_stride);
378 const int v_lines_in =
379 WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j,
380 io->v + uv_j * io->uv_stride, io->uv_stride);
435 (void)v_lines_in; // remove a gcc warning 381 (void)v_lines_in; // remove a gcc warning
436 assert(u_lines_in == v_lines_in); 382 assert(u_lines_in == v_lines_in);
437 j += y_lines_in; 383 j += y_lines_in;
438 uv_j += u_lines_in; 384 uv_j += u_lines_in;
439 num_lines_out += ExportRGB(p, num_lines_out); 385 num_lines_out += ExportRGB(p, num_lines_out);
440 } 386 }
441 return num_lines_out; 387 return num_lines_out;
442 } 388 }
443 389
444 static int ExportAlpha(WebPDecParams* const p, int y_pos) { 390 static int ExportAlpha(WebPDecParams* const p, int y_pos) {
445 const WebPRGBABuffer* const buf = &p->output->u.RGBA; 391 const WebPRGBABuffer* const buf = &p->output->u.RGBA;
446 uint8_t* dst = buf->rgba + (p->last_y + y_pos) * buf->stride; 392 uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride;
393 const WEBP_CSP_MODE colorspace = p->output->colorspace;
394 const int alpha_first =
395 (colorspace == MODE_ARGB || colorspace == MODE_Argb);
396 uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
447 int num_lines_out = 0; 397 int num_lines_out = 0;
448 while (p->scaler_a.y_accum <= 0) { 398 const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
399 const int width = p->scaler_a.dst_width;
400
401 while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
449 int i; 402 int i;
450 assert(p->last_y + y_pos + num_lines_out < p->output->height); 403 assert(p->last_y + y_pos + num_lines_out < p->output->height);
451 ExportRow(&p->scaler_a); 404 WebPRescalerExportRow(&p->scaler_a);
452 for (i = 0; i < p->scaler_a.dst_width; ++i) { 405 for (i = 0; i < width; ++i) dst[4 * i] = p->scaler_a.dst[i];
453 dst[4 * i + 3] = p->scaler_a.dst[i]; 406 dst += buf->stride;
407 ++num_lines_out;
408 }
409 if (is_premult_alpha) {
410 WebPApplyAlphaMultiply(base_rgba, alpha_first,
411 width, num_lines_out, buf->stride);
412 }
413 return num_lines_out;
414 }
415
416 static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) {
417 const WebPRGBABuffer* const buf = &p->output->u.RGBA;
418 uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride;
419 uint8_t* alpha_dst = base_rgba + 1;
420 int num_lines_out = 0;
421 const WEBP_CSP_MODE colorspace = p->output->colorspace;
422 const int width = p->scaler_a.dst_width;
423 const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
424
425 while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
426 int i;
427 assert(p->last_y + y_pos + num_lines_out < p->output->height);
428 WebPRescalerExportRow(&p->scaler_a);
429 for (i = 0; i < width; ++i) {
430 // Fill in the alpha value (converted to 4 bits).
431 const uint32_t alpha_val = VP8Clip4Bits(p->scaler_a.dst[i]);
432 alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_val;
454 } 433 }
455 dst += buf->stride; 434 alpha_dst += buf->stride;
456 num_lines_out++; 435 ++num_lines_out;
436 }
437 if (is_premult_alpha) {
438 WebPApplyAlphaMultiply4444(base_rgba, width, num_lines_out, buf->stride);
457 } 439 }
458 return num_lines_out; 440 return num_lines_out;
459 } 441 }
460 442
461 static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p) { 443 static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
462 if (io->a) { 444 if (io->a != NULL) {
463 int j = 0, pos = 0; 445 WebPRescaler* const scaler = &p->scaler_a;
446 int j = 0;
447 int pos = 0;
464 while (j < io->mb_h) { 448 while (j < io->mb_h) {
465 j += Import(io->a + j * io->width, io->width, io->mb_h - j, &p->scaler_a); 449 j += WebPRescalerImport(scaler, io->mb_h - j,
466 pos += ExportAlpha(p, pos); 450 io->a + j * io->width, io->width);
451 pos += p->emit_alpha_row(p, pos);
467 } 452 }
468 } 453 }
469 return 0; 454 return 0;
470 } 455 }
471 456
472 static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) { 457 static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
473 const int has_alpha = IsAlphaMode(p->output->colorspace); 458 const int has_alpha = WebPIsAlphaMode(p->output->colorspace);
474 const int out_width = io->scaled_width; 459 const int out_width = io->scaled_width;
475 const int out_height = io->scaled_height; 460 const int out_height = io->scaled_height;
476 const int uv_in_width = (io->mb_w + 1) >> 1; 461 const int uv_in_width = (io->mb_w + 1) >> 1;
477 const int uv_in_height = (io->mb_h + 1) >> 1; 462 const int uv_in_height = (io->mb_h + 1) >> 1;
478 const size_t work_size = 2 * out_width; // scratch memory for one rescaler 463 const size_t work_size = 2 * out_width; // scratch memory for one rescaler
479 int32_t* work; // rescalers work area 464 int32_t* work; // rescalers work area
480 uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion 465 uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
481 size_t tmp_size1, tmp_size2; 466 size_t tmp_size1, tmp_size2;
482 467
483 tmp_size1 = 3 * work_size; 468 tmp_size1 = 3 * work_size;
484 tmp_size2 = 3 * out_width; 469 tmp_size2 = 3 * out_width;
485 if (has_alpha) { 470 if (has_alpha) {
486 tmp_size1 += work_size; 471 tmp_size1 += work_size;
487 tmp_size2 += out_width; 472 tmp_size2 += out_width;
488 } 473 }
489 p->memory = 474 p->memory =
490 calloc(1, tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp)); 475 calloc(1, tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp));
491 if (p->memory == NULL) { 476 if (p->memory == NULL) {
492 return 0; // memory error 477 return 0; // memory error
493 } 478 }
494 work = (int32_t*)p->memory; 479 work = (int32_t*)p->memory;
495 tmp = (uint8_t*)(work + tmp_size1); 480 tmp = (uint8_t*)(work + tmp_size1);
496 InitRescaler(&p->scaler_y, io->mb_w, io->mb_h, 481 WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
497 tmp + 0 * out_width, out_width, out_height, 0, 482 tmp + 0 * out_width, out_width, out_height, 0, 1,
498 io->mb_w, out_width, io->mb_h, out_height, 483 io->mb_w, out_width, io->mb_h, out_height,
499 work + 0 * work_size); 484 work + 0 * work_size);
500 InitRescaler(&p->scaler_u, uv_in_width, uv_in_height, 485 WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
501 tmp + 1 * out_width, out_width, out_height, 0, 486 tmp + 1 * out_width, out_width, out_height, 0, 1,
502 io->mb_w, 2 * out_width, io->mb_h, 2 * out_height, 487 io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
503 work + 1 * work_size); 488 work + 1 * work_size);
504 InitRescaler(&p->scaler_v, uv_in_width, uv_in_height, 489 WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
505 tmp + 2 * out_width, out_width, out_height, 0, 490 tmp + 2 * out_width, out_width, out_height, 0, 1,
506 io->mb_w, 2 * out_width, io->mb_h, 2 * out_height, 491 io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
507 work + 2 * work_size); 492 work + 2 * work_size);
508 p->emit = EmitRescaledRGB; 493 p->emit = EmitRescaledRGB;
509 494
510 if (has_alpha) { 495 if (has_alpha) {
511 InitRescaler(&p->scaler_a, io->mb_w, io->mb_h, 496 WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
512 tmp + 3 * out_width, out_width, out_height, 0, 497 tmp + 3 * out_width, out_width, out_height, 0, 1,
513 io->mb_w, out_width, io->mb_h, out_height, 498 io->mb_w, out_width, io->mb_h, out_height,
514 work + 3 * work_size); 499 work + 3 * work_size);
515 p->emit_alpha = EmitRescaledAlphaRGB; 500 p->emit_alpha = EmitRescaledAlphaRGB;
501 if (p->output->colorspace == MODE_RGBA_4444 ||
502 p->output->colorspace == MODE_rgbA_4444) {
503 p->emit_alpha_row = ExportAlphaRGBA4444;
504 } else {
505 p->emit_alpha_row = ExportAlpha;
506 }
516 } 507 }
517 return 1; 508 return 1;
518 } 509 }
519 510
520 //------------------------------------------------------------------------------ 511 //------------------------------------------------------------------------------
521 // Default custom functions 512 // Default custom functions
522 513
523 // Setup crop_xxx fields, mb_w and mb_h
524 static int InitFromOptions(const WebPDecoderOptions* const options,
525 VP8Io* const io) {
526 const int W = io->width;
527 const int H = io->height;
528 int x = 0, y = 0, w = W, h = H;
529
530 // Cropping
531 io->use_cropping = (options != NULL) && (options->use_cropping > 0);
532 if (io->use_cropping) {
533 w = options->crop_width;
534 h = options->crop_height;
535 // TODO(skal): take colorspace into account. Don't assume YUV420.
536 x = options->crop_left & ~1;
537 y = options->crop_top & ~1;
538 if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > W || y + h > H) {
539 return 0; // out of frame boundary error
540 }
541 }
542 io->crop_left = x;
543 io->crop_top = y;
544 io->crop_right = x + w;
545 io->crop_bottom = y + h;
546 io->mb_w = w;
547 io->mb_h = h;
548
549 // Scaling
550 io->use_scaling = (options != NULL) && (options->use_scaling > 0);
551 if (io->use_scaling) {
552 if (options->scaled_width <= 0 || options->scaled_height <= 0) {
553 return 0;
554 }
555 io->scaled_width = options->scaled_width;
556 io->scaled_height = options->scaled_height;
557 }
558
559 // Filter
560 io->bypass_filtering = options && options->bypass_filtering;
561
562 // Fancy upsampler
563 #ifdef FANCY_UPSAMPLING
564 io->fancy_upsampling = (options == NULL) || (!options->no_fancy_upsampling);
565 #endif
566
567 if (io->use_scaling) {
568 // disable filter (only for large downscaling ratio).
569 io->bypass_filtering = (io->scaled_width < W * 3 / 4) &&
570 (io->scaled_height < H * 3 / 4);
571 io->fancy_upsampling = 0;
572 }
573 return 1;
574 }
575
576 static int CustomSetup(VP8Io* io) { 514 static int CustomSetup(VP8Io* io) {
577 WebPDecParams* const p = (WebPDecParams*)io->opaque; 515 WebPDecParams* const p = (WebPDecParams*)io->opaque;
578 const int is_rgb = (p->output->colorspace < MODE_YUV); 516 const WEBP_CSP_MODE colorspace = p->output->colorspace;
517 const int is_rgb = WebPIsRGBMode(colorspace);
518 const int is_alpha = WebPIsAlphaMode(colorspace);
579 519
580 p->memory = NULL; 520 p->memory = NULL;
581 p->emit = NULL; 521 p->emit = NULL;
582 p->emit_alpha = NULL; 522 p->emit_alpha = NULL;
583 if (!InitFromOptions(p->options, io)) { 523 p->emit_alpha_row = NULL;
524 if (!WebPIoInitFromOptions(p->options, io, is_alpha ? MODE_YUV : MODE_YUVA)) {
584 return 0; 525 return 0;
585 } 526 }
586 527
587 if (io->use_scaling) { 528 if (io->use_scaling) {
588 const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p); 529 const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p);
589 if (!ok) { 530 if (!ok) {
590 return 0; // memory error 531 return 0; // memory error
591 } 532 }
592 } else { 533 } else {
593 if (is_rgb) { 534 if (is_rgb) {
594 p->emit = EmitSampledRGB; // default 535 p->emit = EmitSampledRGB; // default
595 #ifdef FANCY_UPSAMPLING 536 #ifdef FANCY_UPSAMPLING
596 if (io->fancy_upsampling) { 537 if (io->fancy_upsampling) {
597 const int uv_width = (io->mb_w + 1) >> 1; 538 const int uv_width = (io->mb_w + 1) >> 1;
598 p->memory = malloc(io->mb_w + 2 * uv_width); 539 p->memory = malloc(io->mb_w + 2 * uv_width);
599 if (p->memory == NULL) { 540 if (p->memory == NULL) {
600 return 0; // memory error. 541 return 0; // memory error.
601 } 542 }
602 p->tmp_y = (uint8_t*)p->memory; 543 p->tmp_y = (uint8_t*)p->memory;
603 p->tmp_u = p->tmp_y + io->mb_w; 544 p->tmp_u = p->tmp_y + io->mb_w;
604 p->tmp_v = p->tmp_u + uv_width; 545 p->tmp_v = p->tmp_u + uv_width;
605 p->emit = EmitFancyRGB; 546 p->emit = EmitFancyRGB;
606 WebPInitUpsamplers(); 547 WebPInitUpsamplers();
607 } 548 }
608 #endif 549 #endif
609 } else { 550 } else {
610 p->emit = EmitYUV; 551 p->emit = EmitYUV;
611 } 552 }
612 #ifdef WEBP_EXPERIMENTAL_FEATURES 553 if (is_alpha) { // need transparency output
613 if (IsAlphaMode(p->output->colorspace)) { 554 if (WebPIsPremultipliedMode(colorspace)) WebPInitPremultiply();
614 // We need transparency output 555 p->emit_alpha =
615 p->emit_alpha = is_rgb ? EmitAlphaRGB : EmitAlphaYUV; 556 (colorspace == MODE_RGBA_4444 || colorspace == MODE_rgbA_4444) ?
557 EmitAlphaRGBA4444
558 : is_rgb ? EmitAlphaRGB
559 : EmitAlphaYUV;
616 } 560 }
617 #endif
618 } 561 }
619 562
620 if (is_rgb) { 563 if (is_rgb) {
621 VP8YUVInit(); 564 VP8YUVInit();
622 } 565 }
623 return 1; 566 return 1;
624 } 567 }
625 568
626 //------------------------------------------------------------------------------ 569 //------------------------------------------------------------------------------
627 570
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
659 io->setup = CustomSetup; 602 io->setup = CustomSetup;
660 io->teardown = CustomTeardown; 603 io->teardown = CustomTeardown;
661 io->opaque = params; 604 io->opaque = params;
662 } 605 }
663 606
664 //------------------------------------------------------------------------------ 607 //------------------------------------------------------------------------------
665 608
666 #if defined(__cplusplus) || defined(c_plusplus) 609 #if defined(__cplusplus) || defined(c_plusplus)
667 } // extern "C" 610 } // extern "C"
668 #endif 611 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698