[Session restore] Rename group name Enabled to Restore.
[chromium-blink-merge.git] / third_party / libwebp / dec / io.c
blob8094e44f632ed4338c31d7225c5bde8af209d852
1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the COPYING file in the root of the source
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
8 // -----------------------------------------------------------------------------
9 //
10 // functions for sample output.
12 // Author: Skal (pascal.massimino@gmail.com)
14 #include <assert.h>
15 #include <stdlib.h>
16 #include "../dec/vp8i.h"
17 #include "./webpi.h"
18 #include "../dsp/dsp.h"
19 #include "../dsp/yuv.h"
20 #include "../utils/utils.h"
22 //------------------------------------------------------------------------------
23 // Main YUV<->RGB conversion functions
25 static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) {
26 WebPDecBuffer* output = p->output;
27 const WebPYUVABuffer* const buf = &output->u.YUVA;
28 uint8_t* const y_dst = buf->y + io->mb_y * buf->y_stride;
29 uint8_t* const u_dst = buf->u + (io->mb_y >> 1) * buf->u_stride;
30 uint8_t* const v_dst = buf->v + (io->mb_y >> 1) * buf->v_stride;
31 const int mb_w = io->mb_w;
32 const int mb_h = io->mb_h;
33 const int uv_w = (mb_w + 1) / 2;
34 const int uv_h = (mb_h + 1) / 2;
35 int j;
36 for (j = 0; j < mb_h; ++j) {
37 memcpy(y_dst + j * buf->y_stride, io->y + j * io->y_stride, mb_w);
39 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(v_dst + j * buf->v_stride, io->v + j * io->uv_stride, uv_w);
43 return io->mb_h;
46 // Point-sampling U/V sampler.
47 static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) {
48 WebPDecBuffer* const output = p->output;
49 WebPRGBABuffer* const buf = &output->u.RGBA;
50 uint8_t* const dst = buf->rgba + io->mb_y * buf->stride;
51 WebPSamplerProcessPlane(io->y, io->y_stride,
52 io->u, io->v, io->uv_stride,
53 dst, buf->stride, io->mb_w, io->mb_h,
54 WebPSamplers[output->colorspace]);
55 return io->mb_h;
58 //------------------------------------------------------------------------------
59 // YUV444 -> RGB conversion
61 #if 0 // TODO(skal): this is for future rescaling.
62 static int EmitRGB(const VP8Io* const io, WebPDecParams* const p) {
63 WebPDecBuffer* output = p->output;
64 const WebPRGBABuffer* const buf = &output->u.RGBA;
65 uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
66 const uint8_t* y_src = io->y;
67 const uint8_t* u_src = io->u;
68 const uint8_t* v_src = io->v;
69 const WebPYUV444Converter convert = WebPYUV444Converters[output->colorspace];
70 const int mb_w = io->mb_w;
71 const int last = io->mb_h;
72 int j;
73 for (j = 0; j < last; ++j) {
74 convert(y_src, u_src, v_src, dst, mb_w);
75 y_src += io->y_stride;
76 u_src += io->uv_stride;
77 v_src += io->uv_stride;
78 dst += buf->stride;
80 return io->mb_h;
82 #endif
84 //------------------------------------------------------------------------------
85 // Fancy upsampling
87 #ifdef FANCY_UPSAMPLING
88 static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {
89 int num_lines_out = io->mb_h; // a priori guess
90 const WebPRGBABuffer* const buf = &p->output->u.RGBA;
91 uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
92 WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace];
93 const uint8_t* cur_y = io->y;
94 const uint8_t* cur_u = io->u;
95 const uint8_t* cur_v = io->v;
96 const uint8_t* top_u = p->tmp_u;
97 const uint8_t* top_v = p->tmp_v;
98 int y = io->mb_y;
99 const int y_end = io->mb_y + io->mb_h;
100 const int mb_w = io->mb_w;
101 const int uv_w = (mb_w + 1) / 2;
103 if (y == 0) {
104 // First line is special cased. We mirror the u/v samples at boundary.
105 upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, mb_w);
106 } else {
107 // We can finish the left-over line from previous call.
108 upsample(p->tmp_y, cur_y, top_u, top_v, cur_u, cur_v,
109 dst - buf->stride, dst, mb_w);
110 ++num_lines_out;
112 // Loop over each output pairs of row.
113 for (; y + 2 < y_end; y += 2) {
114 top_u = cur_u;
115 top_v = cur_v;
116 cur_u += io->uv_stride;
117 cur_v += io->uv_stride;
118 dst += 2 * buf->stride;
119 cur_y += 2 * io->y_stride;
120 upsample(cur_y - io->y_stride, cur_y,
121 top_u, top_v, cur_u, cur_v,
122 dst - buf->stride, dst, mb_w);
124 // move to last row
125 cur_y += io->y_stride;
126 if (io->crop_top + y_end < io->crop_bottom) {
127 // Save the unfinished samples for next call (as we're not done yet).
128 memcpy(p->tmp_y, cur_y, mb_w * sizeof(*p->tmp_y));
129 memcpy(p->tmp_u, cur_u, uv_w * sizeof(*p->tmp_u));
130 memcpy(p->tmp_v, cur_v, uv_w * sizeof(*p->tmp_v));
131 // The fancy upsampler leaves a row unfinished behind
132 // (except for the very last row)
133 num_lines_out--;
134 } else {
135 // Process the very last row of even-sized picture
136 if (!(y_end & 1)) {
137 upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v,
138 dst + buf->stride, NULL, mb_w);
141 return num_lines_out;
144 #endif /* FANCY_UPSAMPLING */
146 //------------------------------------------------------------------------------
148 static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
149 const uint8_t* alpha = io->a;
150 const WebPYUVABuffer* const buf = &p->output->u.YUVA;
151 const int mb_w = io->mb_w;
152 const int mb_h = io->mb_h;
153 uint8_t* dst = buf->a + io->mb_y * buf->a_stride;
154 int j;
156 if (alpha != NULL) {
157 for (j = 0; j < mb_h; ++j) {
158 memcpy(dst, alpha, mb_w * sizeof(*dst));
159 alpha += io->width;
160 dst += buf->a_stride;
162 } else if (buf->a != NULL) {
163 // the user requested alpha, but there is none, set it to opaque.
164 for (j = 0; j < mb_h; ++j) {
165 memset(dst, 0xff, mb_w * sizeof(*dst));
166 dst += buf->a_stride;
169 return 0;
172 static int GetAlphaSourceRow(const VP8Io* const io,
173 const uint8_t** alpha, int* const num_rows) {
174 int start_y = io->mb_y;
175 *num_rows = io->mb_h;
177 // Compensate for the 1-line delay of the fancy upscaler.
178 // This is similar to EmitFancyRGB().
179 if (io->fancy_upsampling) {
180 if (start_y == 0) {
181 // We don't process the last row yet. It'll be done during the next call.
182 --*num_rows;
183 } else {
184 --start_y;
185 // Fortunately, *alpha data is persistent, so we can go back
186 // one row and finish alpha blending, now that the fancy upscaler
187 // completed the YUV->RGB interpolation.
188 *alpha -= io->width;
190 if (io->crop_top + io->mb_y + io->mb_h == io->crop_bottom) {
191 // If it's the very last call, we process all the remaining rows!
192 *num_rows = io->crop_bottom - io->crop_top - start_y;
195 return start_y;
198 static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
199 const uint8_t* alpha = io->a;
200 if (alpha != NULL) {
201 const int mb_w = io->mb_w;
202 const WEBP_CSP_MODE colorspace = p->output->colorspace;
203 const int alpha_first =
204 (colorspace == MODE_ARGB || colorspace == MODE_Argb);
205 const WebPRGBABuffer* const buf = &p->output->u.RGBA;
206 int num_rows;
207 const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
208 uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
209 uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
210 uint32_t alpha_mask = 0xff;
211 int i, j;
213 for (j = 0; j < num_rows; ++j) {
214 for (i = 0; i < mb_w; ++i) {
215 const uint32_t alpha_value = alpha[i];
216 dst[4 * i] = alpha_value;
217 alpha_mask &= alpha_value;
219 alpha += io->width;
220 dst += buf->stride;
222 // alpha_mask is < 0xff if there's non-trivial alpha to premultiply with.
223 if (alpha_mask != 0xff && WebPIsPremultipliedMode(colorspace)) {
224 WebPApplyAlphaMultiply(base_rgba, alpha_first,
225 mb_w, num_rows, buf->stride);
228 return 0;
231 static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p) {
232 const uint8_t* alpha = io->a;
233 if (alpha != NULL) {
234 const int mb_w = io->mb_w;
235 const WEBP_CSP_MODE colorspace = p->output->colorspace;
236 const WebPRGBABuffer* const buf = &p->output->u.RGBA;
237 int num_rows;
238 const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
239 uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
240 #ifdef WEBP_SWAP_16BIT_CSP
241 uint8_t* alpha_dst = base_rgba;
242 #else
243 uint8_t* alpha_dst = base_rgba + 1;
244 #endif
245 uint32_t alpha_mask = 0x0f;
246 int i, j;
248 for (j = 0; j < num_rows; ++j) {
249 for (i = 0; i < mb_w; ++i) {
250 // Fill in the alpha value (converted to 4 bits).
251 const uint32_t alpha_value = alpha[i] >> 4;
252 alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
253 alpha_mask &= alpha_value;
255 alpha += io->width;
256 alpha_dst += buf->stride;
258 if (alpha_mask != 0x0f && WebPIsPremultipliedMode(colorspace)) {
259 WebPApplyAlphaMultiply4444(base_rgba, mb_w, num_rows, buf->stride);
262 return 0;
265 //------------------------------------------------------------------------------
266 // YUV rescaling (no final RGB conversion needed)
268 static int Rescale(const uint8_t* src, int src_stride,
269 int new_lines, WebPRescaler* const wrk) {
270 int num_lines_out = 0;
271 while (new_lines > 0) { // import new contributions of source rows.
272 const int lines_in = WebPRescalerImport(wrk, new_lines, src, src_stride);
273 src += lines_in * src_stride;
274 new_lines -= lines_in;
275 num_lines_out += WebPRescalerExport(wrk); // emit output row(s)
277 return num_lines_out;
280 static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
281 const int mb_h = io->mb_h;
282 const int uv_mb_h = (mb_h + 1) >> 1;
283 WebPRescaler* const scaler = &p->scaler_y;
284 int num_lines_out = 0;
285 if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) {
286 // Before rescaling, we premultiply the luma directly into the io->y
287 // internal buffer. This is OK since these samples are not used for
288 // intra-prediction (the top samples are saved in cache_y_/u_/v_).
289 // But we need to cast the const away, though.
290 WebPMultRows((uint8_t*)io->y, io->y_stride,
291 io->a, io->width, io->mb_w, mb_h, 0);
293 num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler);
294 Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u);
295 Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v);
296 return num_lines_out;
299 static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
300 if (io->a != NULL) {
301 const WebPYUVABuffer* const buf = &p->output->u.YUVA;
302 uint8_t* dst_y = buf->y + p->last_y * buf->y_stride;
303 const uint8_t* src_a = buf->a + p->last_y * buf->a_stride;
304 const int num_lines_out = Rescale(io->a, io->width, io->mb_h, &p->scaler_a);
305 if (num_lines_out > 0) { // unmultiply the Y
306 WebPMultRows(dst_y, buf->y_stride, src_a, buf->a_stride,
307 p->scaler_a.dst_width, num_lines_out, 1);
310 return 0;
313 static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
314 const int has_alpha = WebPIsAlphaMode(p->output->colorspace);
315 const WebPYUVABuffer* const buf = &p->output->u.YUVA;
316 const int out_width = io->scaled_width;
317 const int out_height = io->scaled_height;
318 const int uv_out_width = (out_width + 1) >> 1;
319 const int uv_out_height = (out_height + 1) >> 1;
320 const int uv_in_width = (io->mb_w + 1) >> 1;
321 const int uv_in_height = (io->mb_h + 1) >> 1;
322 const size_t work_size = 2 * out_width; // scratch memory for luma rescaler
323 const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
324 size_t tmp_size;
325 int32_t* work;
327 tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work);
328 if (has_alpha) {
329 tmp_size += work_size * sizeof(*work);
331 p->memory = WebPSafeCalloc(1ULL, tmp_size);
332 if (p->memory == NULL) {
333 return 0; // memory error
335 work = (int32_t*)p->memory;
336 WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
337 buf->y, out_width, out_height, buf->y_stride, 1,
338 io->mb_w, out_width, io->mb_h, out_height,
339 work);
340 WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
341 buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
342 uv_in_width, uv_out_width,
343 uv_in_height, uv_out_height,
344 work + work_size);
345 WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
346 buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
347 uv_in_width, uv_out_width,
348 uv_in_height, uv_out_height,
349 work + work_size + uv_work_size);
350 p->emit = EmitRescaledYUV;
352 if (has_alpha) {
353 WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
354 buf->a, out_width, out_height, buf->a_stride, 1,
355 io->mb_w, out_width, io->mb_h, out_height,
356 work + work_size + 2 * uv_work_size);
357 p->emit_alpha = EmitRescaledAlphaYUV;
358 WebPInitAlphaProcessing();
360 return 1;
363 //------------------------------------------------------------------------------
364 // RGBA rescaling
366 static int ExportRGB(WebPDecParams* const p, int y_pos) {
367 const WebPYUV444Converter convert =
368 WebPYUV444Converters[p->output->colorspace];
369 const WebPRGBABuffer* const buf = &p->output->u.RGBA;
370 uint8_t* dst = buf->rgba + (p->last_y + y_pos) * buf->stride;
371 int num_lines_out = 0;
372 // For RGB rescaling, because of the YUV420, current scan position
373 // U/V can be +1/-1 line from the Y one. Hence the double test.
374 while (WebPRescalerHasPendingOutput(&p->scaler_y) &&
375 WebPRescalerHasPendingOutput(&p->scaler_u)) {
376 assert(p->last_y + y_pos + num_lines_out < p->output->height);
377 assert(p->scaler_u.y_accum == p->scaler_v.y_accum);
378 WebPRescalerExportRow(&p->scaler_y, 0);
379 WebPRescalerExportRow(&p->scaler_u, 0);
380 WebPRescalerExportRow(&p->scaler_v, 0);
381 convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst,
382 dst, p->scaler_y.dst_width);
383 dst += buf->stride;
384 ++num_lines_out;
386 return num_lines_out;
389 static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
390 const int mb_h = io->mb_h;
391 const int uv_mb_h = (mb_h + 1) >> 1;
392 int j = 0, uv_j = 0;
393 int num_lines_out = 0;
394 while (j < mb_h) {
395 const int y_lines_in =
396 WebPRescalerImport(&p->scaler_y, mb_h - j,
397 io->y + j * io->y_stride, io->y_stride);
398 const int u_lines_in =
399 WebPRescalerImport(&p->scaler_u, uv_mb_h - uv_j,
400 io->u + uv_j * io->uv_stride, io->uv_stride);
401 const int v_lines_in =
402 WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j,
403 io->v + uv_j * io->uv_stride, io->uv_stride);
404 (void)v_lines_in; // remove a gcc warning
405 assert(u_lines_in == v_lines_in);
406 j += y_lines_in;
407 uv_j += u_lines_in;
408 num_lines_out += ExportRGB(p, num_lines_out);
410 return num_lines_out;
413 static int ExportAlpha(WebPDecParams* const p, int y_pos) {
414 const WebPRGBABuffer* const buf = &p->output->u.RGBA;
415 uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride;
416 const WEBP_CSP_MODE colorspace = p->output->colorspace;
417 const int alpha_first =
418 (colorspace == MODE_ARGB || colorspace == MODE_Argb);
419 uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
420 int num_lines_out = 0;
421 const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
422 uint32_t alpha_mask = 0xff;
423 const int width = p->scaler_a.dst_width;
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, 0);
429 for (i = 0; i < width; ++i) {
430 const uint32_t alpha_value = p->scaler_a.dst[i];
431 dst[4 * i] = alpha_value;
432 alpha_mask &= alpha_value;
434 dst += buf->stride;
435 ++num_lines_out;
437 if (is_premult_alpha && alpha_mask != 0xff) {
438 WebPApplyAlphaMultiply(base_rgba, alpha_first,
439 width, num_lines_out, buf->stride);
441 return num_lines_out;
444 static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) {
445 const WebPRGBABuffer* const buf = &p->output->u.RGBA;
446 uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride;
447 #ifdef WEBP_SWAP_16BIT_CSP
448 uint8_t* alpha_dst = base_rgba;
449 #else
450 uint8_t* alpha_dst = base_rgba + 1;
451 #endif
452 int num_lines_out = 0;
453 const WEBP_CSP_MODE colorspace = p->output->colorspace;
454 const int width = p->scaler_a.dst_width;
455 const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
456 uint32_t alpha_mask = 0x0f;
458 while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
459 int i;
460 assert(p->last_y + y_pos + num_lines_out < p->output->height);
461 WebPRescalerExportRow(&p->scaler_a, 0);
462 for (i = 0; i < width; ++i) {
463 // Fill in the alpha value (converted to 4 bits).
464 const uint32_t alpha_value = p->scaler_a.dst[i] >> 4;
465 alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
466 alpha_mask &= alpha_value;
468 alpha_dst += buf->stride;
469 ++num_lines_out;
471 if (is_premult_alpha && alpha_mask != 0x0f) {
472 WebPApplyAlphaMultiply4444(base_rgba, width, num_lines_out, buf->stride);
474 return num_lines_out;
477 static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
478 if (io->a != NULL) {
479 WebPRescaler* const scaler = &p->scaler_a;
480 int j = 0;
481 int pos = 0;
482 while (j < io->mb_h) {
483 j += WebPRescalerImport(scaler, io->mb_h - j,
484 io->a + j * io->width, io->width);
485 pos += p->emit_alpha_row(p, pos);
488 return 0;
491 static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
492 const int has_alpha = WebPIsAlphaMode(p->output->colorspace);
493 const int out_width = io->scaled_width;
494 const int out_height = io->scaled_height;
495 const int uv_in_width = (io->mb_w + 1) >> 1;
496 const int uv_in_height = (io->mb_h + 1) >> 1;
497 const size_t work_size = 2 * out_width; // scratch memory for one rescaler
498 int32_t* work; // rescalers work area
499 uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
500 size_t tmp_size1, tmp_size2, total_size;
502 tmp_size1 = 3 * work_size;
503 tmp_size2 = 3 * out_width;
504 if (has_alpha) {
505 tmp_size1 += work_size;
506 tmp_size2 += out_width;
508 total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp);
509 p->memory = WebPSafeCalloc(1ULL, total_size);
510 if (p->memory == NULL) {
511 return 0; // memory error
513 work = (int32_t*)p->memory;
514 tmp = (uint8_t*)(work + tmp_size1);
515 WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
516 tmp + 0 * out_width, out_width, out_height, 0, 1,
517 io->mb_w, out_width, io->mb_h, out_height,
518 work + 0 * work_size);
519 WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
520 tmp + 1 * out_width, out_width, out_height, 0, 1,
521 io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
522 work + 1 * work_size);
523 WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
524 tmp + 2 * out_width, out_width, out_height, 0, 1,
525 io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
526 work + 2 * work_size);
527 p->emit = EmitRescaledRGB;
529 if (has_alpha) {
530 WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
531 tmp + 3 * out_width, out_width, out_height, 0, 1,
532 io->mb_w, out_width, io->mb_h, out_height,
533 work + 3 * work_size);
534 p->emit_alpha = EmitRescaledAlphaRGB;
535 if (p->output->colorspace == MODE_RGBA_4444 ||
536 p->output->colorspace == MODE_rgbA_4444) {
537 p->emit_alpha_row = ExportAlphaRGBA4444;
538 } else {
539 p->emit_alpha_row = ExportAlpha;
541 WebPInitAlphaProcessing();
543 return 1;
546 //------------------------------------------------------------------------------
547 // Default custom functions
549 static int CustomSetup(VP8Io* io) {
550 WebPDecParams* const p = (WebPDecParams*)io->opaque;
551 const WEBP_CSP_MODE colorspace = p->output->colorspace;
552 const int is_rgb = WebPIsRGBMode(colorspace);
553 const int is_alpha = WebPIsAlphaMode(colorspace);
555 p->memory = NULL;
556 p->emit = NULL;
557 p->emit_alpha = NULL;
558 p->emit_alpha_row = NULL;
559 if (!WebPIoInitFromOptions(p->options, io, is_alpha ? MODE_YUV : MODE_YUVA)) {
560 return 0;
562 if (is_alpha && WebPIsPremultipliedMode(colorspace)) {
563 WebPInitUpsamplers();
565 if (io->use_scaling) {
566 const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p);
567 if (!ok) {
568 return 0; // memory error
570 } else {
571 if (is_rgb) {
572 p->emit = EmitSampledRGB; // default
573 if (io->fancy_upsampling) {
574 #ifdef FANCY_UPSAMPLING
575 const int uv_width = (io->mb_w + 1) >> 1;
576 p->memory = WebPSafeMalloc(1ULL, (size_t)(io->mb_w + 2 * uv_width));
577 if (p->memory == NULL) {
578 return 0; // memory error.
580 p->tmp_y = (uint8_t*)p->memory;
581 p->tmp_u = p->tmp_y + io->mb_w;
582 p->tmp_v = p->tmp_u + uv_width;
583 p->emit = EmitFancyRGB;
584 WebPInitUpsamplers();
585 #endif
586 } else {
587 WebPInitSamplers();
589 } else {
590 p->emit = EmitYUV;
592 if (is_alpha) { // need transparency output
593 p->emit_alpha =
594 (colorspace == MODE_RGBA_4444 || colorspace == MODE_rgbA_4444) ?
595 EmitAlphaRGBA4444
596 : is_rgb ? EmitAlphaRGB
597 : EmitAlphaYUV;
598 if (is_rgb) {
599 WebPInitAlphaProcessing();
604 if (is_rgb) {
605 VP8YUVInit();
607 return 1;
610 //------------------------------------------------------------------------------
612 static int CustomPut(const VP8Io* io) {
613 WebPDecParams* const p = (WebPDecParams*)io->opaque;
614 const int mb_w = io->mb_w;
615 const int mb_h = io->mb_h;
616 int num_lines_out;
617 assert(!(io->mb_y & 1));
619 if (mb_w <= 0 || mb_h <= 0) {
620 return 0;
622 num_lines_out = p->emit(io, p);
623 if (p->emit_alpha != NULL) {
624 p->emit_alpha(io, p);
626 p->last_y += num_lines_out;
627 return 1;
630 //------------------------------------------------------------------------------
632 static void CustomTeardown(const VP8Io* io) {
633 WebPDecParams* const p = (WebPDecParams*)io->opaque;
634 WebPSafeFree(p->memory);
635 p->memory = NULL;
638 //------------------------------------------------------------------------------
639 // Main entry point
641 void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io) {
642 io->put = CustomPut;
643 io->setup = CustomSetup;
644 io->teardown = CustomTeardown;
645 io->opaque = params;
648 //------------------------------------------------------------------------------