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. 11// 12// Author: Skal (pascal.massimino@gmail.com) 13 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" 21 22//------------------------------------------------------------------------------ 23// Main YUV<->RGB conversion functions 24 25static 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); 38 } 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); 42 } 43 return io->mb_h; 44} 45 46// Point-sampling U/V sampler. 47static 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; 56} 57 58//------------------------------------------------------------------------------ 59// Fancy upsampling 60 61#ifdef FANCY_UPSAMPLING 62static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) { 63 int num_lines_out = io->mb_h; // a priori guess 64 const WebPRGBABuffer* const buf = &p->output->u.RGBA; 65 uint8_t* dst = buf->rgba + io->mb_y * buf->stride; 66 WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace]; 67 const uint8_t* cur_y = io->y; 68 const uint8_t* cur_u = io->u; 69 const uint8_t* cur_v = io->v; 70 const uint8_t* top_u = p->tmp_u; 71 const uint8_t* top_v = p->tmp_v; 72 int y = io->mb_y; 73 const int y_end = io->mb_y + io->mb_h; 74 const int mb_w = io->mb_w; 75 const int uv_w = (mb_w + 1) / 2; 76 77 if (y == 0) { 78 // First line is special cased. We mirror the u/v samples at boundary. 79 upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, mb_w); 80 } else { 81 // We can finish the left-over line from previous call. 82 upsample(p->tmp_y, cur_y, top_u, top_v, cur_u, cur_v, 83 dst - buf->stride, dst, mb_w); 84 ++num_lines_out; 85 } 86 // Loop over each output pairs of row. 87 for (; y + 2 < y_end; y += 2) { 88 top_u = cur_u; 89 top_v = cur_v; 90 cur_u += io->uv_stride; 91 cur_v += io->uv_stride; 92 dst += 2 * buf->stride; 93 cur_y += 2 * io->y_stride; 94 upsample(cur_y - io->y_stride, cur_y, 95 top_u, top_v, cur_u, cur_v, 96 dst - buf->stride, dst, mb_w); 97 } 98 // move to last row 99 cur_y += io->y_stride; 100 if (io->crop_top + y_end < io->crop_bottom) { 101 // Save the unfinished samples for next call (as we're not done yet). 102 memcpy(p->tmp_y, cur_y, mb_w * sizeof(*p->tmp_y)); 103 memcpy(p->tmp_u, cur_u, uv_w * sizeof(*p->tmp_u)); 104 memcpy(p->tmp_v, cur_v, uv_w * sizeof(*p->tmp_v)); 105 // The fancy upsampler leaves a row unfinished behind 106 // (except for the very last row) 107 num_lines_out--; 108 } else { 109 // Process the very last row of even-sized picture 110 if (!(y_end & 1)) { 111 upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, 112 dst + buf->stride, NULL, mb_w); 113 } 114 } 115 return num_lines_out; 116} 117 118#endif /* FANCY_UPSAMPLING */ 119 120//------------------------------------------------------------------------------ 121 122static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p, 123 int expected_num_lines_out) { 124 const uint8_t* alpha = io->a; 125 const WebPYUVABuffer* const buf = &p->output->u.YUVA; 126 const int mb_w = io->mb_w; 127 const int mb_h = io->mb_h; 128 uint8_t* dst = buf->a + io->mb_y * buf->a_stride; 129 int j; 130 (void)expected_num_lines_out; 131 assert(expected_num_lines_out == mb_h); 132 if (alpha != NULL) { 133 for (j = 0; j < mb_h; ++j) { 134 memcpy(dst, alpha, mb_w * sizeof(*dst)); 135 alpha += io->width; 136 dst += buf->a_stride; 137 } 138 } else if (buf->a != NULL) { 139 // the user requested alpha, but there is none, set it to opaque. 140 for (j = 0; j < mb_h; ++j) { 141 memset(dst, 0xff, mb_w * sizeof(*dst)); 142 dst += buf->a_stride; 143 } 144 } 145 return 0; 146} 147 148static int GetAlphaSourceRow(const VP8Io* const io, 149 const uint8_t** alpha, int* const num_rows) { 150 int start_y = io->mb_y; 151 *num_rows = io->mb_h; 152 153 // Compensate for the 1-line delay of the fancy upscaler. 154 // This is similar to EmitFancyRGB(). 155 if (io->fancy_upsampling) { 156 if (start_y == 0) { 157 // We don't process the last row yet. It'll be done during the next call. 158 --*num_rows; 159 } else { 160 --start_y; 161 // Fortunately, *alpha data is persistent, so we can go back 162 // one row and finish alpha blending, now that the fancy upscaler 163 // completed the YUV->RGB interpolation. 164 *alpha -= io->width; 165 } 166 if (io->crop_top + io->mb_y + io->mb_h == io->crop_bottom) { 167 // If it's the very last call, we process all the remaining rows! 168 *num_rows = io->crop_bottom - io->crop_top - start_y; 169 } 170 } 171 return start_y; 172} 173 174static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p, 175 int expected_num_lines_out) { 176 const uint8_t* alpha = io->a; 177 if (alpha != NULL) { 178 const int mb_w = io->mb_w; 179 const WEBP_CSP_MODE colorspace = p->output->colorspace; 180 const int alpha_first = 181 (colorspace == MODE_ARGB || colorspace == MODE_Argb); 182 const WebPRGBABuffer* const buf = &p->output->u.RGBA; 183 int num_rows; 184 const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows); 185 uint8_t* const base_rgba = buf->rgba + start_y * buf->stride; 186 uint8_t* const dst = base_rgba + (alpha_first ? 0 : 3); 187 const int has_alpha = WebPDispatchAlpha(alpha, io->width, mb_w, 188 num_rows, dst, buf->stride); 189 (void)expected_num_lines_out; 190 assert(expected_num_lines_out == num_rows); 191 // has_alpha is true if there's non-trivial alpha to premultiply with. 192 if (has_alpha && WebPIsPremultipliedMode(colorspace)) { 193 WebPApplyAlphaMultiply(base_rgba, alpha_first, 194 mb_w, num_rows, buf->stride); 195 } 196 } 197 return 0; 198} 199 200static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p, 201 int expected_num_lines_out) { 202 const uint8_t* alpha = io->a; 203 if (alpha != NULL) { 204 const int mb_w = io->mb_w; 205 const WEBP_CSP_MODE colorspace = p->output->colorspace; 206 const WebPRGBABuffer* const buf = &p->output->u.RGBA; 207 int num_rows; 208 const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows); 209 uint8_t* const base_rgba = buf->rgba + start_y * buf->stride; 210#ifdef WEBP_SWAP_16BIT_CSP 211 uint8_t* alpha_dst = base_rgba; 212#else 213 uint8_t* alpha_dst = base_rgba + 1; 214#endif 215 uint32_t alpha_mask = 0x0f; 216 int i, j; 217 for (j = 0; j < num_rows; ++j) { 218 for (i = 0; i < mb_w; ++i) { 219 // Fill in the alpha value (converted to 4 bits). 220 const uint32_t alpha_value = alpha[i] >> 4; 221 alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value; 222 alpha_mask &= alpha_value; 223 } 224 alpha += io->width; 225 alpha_dst += buf->stride; 226 } 227 (void)expected_num_lines_out; 228 assert(expected_num_lines_out == num_rows); 229 if (alpha_mask != 0x0f && WebPIsPremultipliedMode(colorspace)) { 230 WebPApplyAlphaMultiply4444(base_rgba, mb_w, num_rows, buf->stride); 231 } 232 } 233 return 0; 234} 235 236//------------------------------------------------------------------------------ 237// YUV rescaling (no final RGB conversion needed) 238 239static int Rescale(const uint8_t* src, int src_stride, 240 int new_lines, WebPRescaler* const wrk) { 241 int num_lines_out = 0; 242 while (new_lines > 0) { // import new contributions of source rows. 243 const int lines_in = WebPRescalerImport(wrk, new_lines, src, src_stride); 244 src += lines_in * src_stride; 245 new_lines -= lines_in; 246 num_lines_out += WebPRescalerExport(wrk); // emit output row(s) 247 } 248 return num_lines_out; 249} 250 251static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) { 252 const int mb_h = io->mb_h; 253 const int uv_mb_h = (mb_h + 1) >> 1; 254 WebPRescaler* const scaler = &p->scaler_y; 255 int num_lines_out = 0; 256 if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) { 257 // Before rescaling, we premultiply the luma directly into the io->y 258 // internal buffer. This is OK since these samples are not used for 259 // intra-prediction (the top samples are saved in cache_y_/u_/v_). 260 // But we need to cast the const away, though. 261 WebPMultRows((uint8_t*)io->y, io->y_stride, 262 io->a, io->width, io->mb_w, mb_h, 0); 263 } 264 num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler); 265 Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u); 266 Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v); 267 return num_lines_out; 268} 269 270static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p, 271 int expected_num_lines_out) { 272 if (io->a != NULL) { 273 const WebPYUVABuffer* const buf = &p->output->u.YUVA; 274 uint8_t* dst_y = buf->y + p->last_y * buf->y_stride; 275 const uint8_t* src_a = buf->a + p->last_y * buf->a_stride; 276 const int num_lines_out = Rescale(io->a, io->width, io->mb_h, &p->scaler_a); 277 (void)expected_num_lines_out; 278 assert(expected_num_lines_out == num_lines_out); 279 if (num_lines_out > 0) { // unmultiply the Y 280 WebPMultRows(dst_y, buf->y_stride, src_a, buf->a_stride, 281 p->scaler_a.dst_width, num_lines_out, 1); 282 } 283 } 284 return 0; 285} 286 287static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) { 288 const int has_alpha = WebPIsAlphaMode(p->output->colorspace); 289 const WebPYUVABuffer* const buf = &p->output->u.YUVA; 290 const int out_width = io->scaled_width; 291 const int out_height = io->scaled_height; 292 const int uv_out_width = (out_width + 1) >> 1; 293 const int uv_out_height = (out_height + 1) >> 1; 294 const int uv_in_width = (io->mb_w + 1) >> 1; 295 const int uv_in_height = (io->mb_h + 1) >> 1; 296 const size_t work_size = 2 * out_width; // scratch memory for luma rescaler 297 const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones 298 size_t tmp_size; 299 rescaler_t* work; 300 301 tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work); 302 if (has_alpha) { 303 tmp_size += work_size * sizeof(*work); 304 } 305 p->memory = WebPSafeMalloc(1ULL, tmp_size); 306 if (p->memory == NULL) { 307 return 0; // memory error 308 } 309 work = (rescaler_t*)p->memory; 310 WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h, 311 buf->y, out_width, out_height, buf->y_stride, 1, 312 work); 313 WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height, 314 buf->u, uv_out_width, uv_out_height, buf->u_stride, 1, 315 work + work_size); 316 WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height, 317 buf->v, uv_out_width, uv_out_height, buf->v_stride, 1, 318 work + work_size + uv_work_size); 319 p->emit = EmitRescaledYUV; 320 321 if (has_alpha) { 322 WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h, 323 buf->a, out_width, out_height, buf->a_stride, 1, 324 work + work_size + 2 * uv_work_size); 325 p->emit_alpha = EmitRescaledAlphaYUV; 326 WebPInitAlphaProcessing(); 327 } 328 return 1; 329} 330 331//------------------------------------------------------------------------------ 332// RGBA rescaling 333 334static int ExportRGB(WebPDecParams* const p, int y_pos) { 335 const WebPYUV444Converter convert = 336 WebPYUV444Converters[p->output->colorspace]; 337 const WebPRGBABuffer* const buf = &p->output->u.RGBA; 338 uint8_t* dst = buf->rgba + y_pos * buf->stride; 339 int num_lines_out = 0; 340 // For RGB rescaling, because of the YUV420, current scan position 341 // U/V can be +1/-1 line from the Y one. Hence the double test. 342 while (WebPRescalerHasPendingOutput(&p->scaler_y) && 343 WebPRescalerHasPendingOutput(&p->scaler_u)) { 344 assert(y_pos + num_lines_out < p->output->height); 345 assert(p->scaler_u.y_accum == p->scaler_v.y_accum); 346 WebPRescalerExportRow(&p->scaler_y); 347 WebPRescalerExportRow(&p->scaler_u); 348 WebPRescalerExportRow(&p->scaler_v); 349 convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst, 350 dst, p->scaler_y.dst_width); 351 dst += buf->stride; 352 ++num_lines_out; 353 } 354 return num_lines_out; 355} 356 357static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) { 358 const int mb_h = io->mb_h; 359 const int uv_mb_h = (mb_h + 1) >> 1; 360 int j = 0, uv_j = 0; 361 int num_lines_out = 0; 362 while (j < mb_h) { 363 const int y_lines_in = 364 WebPRescalerImport(&p->scaler_y, mb_h - j, 365 io->y + j * io->y_stride, io->y_stride); 366 j += y_lines_in; 367 if (WebPRescaleNeededLines(&p->scaler_u, uv_mb_h - uv_j)) { 368 const int u_lines_in = 369 WebPRescalerImport(&p->scaler_u, uv_mb_h - uv_j, 370 io->u + uv_j * io->uv_stride, io->uv_stride); 371 const int v_lines_in = 372 WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j, 373 io->v + uv_j * io->uv_stride, io->uv_stride); 374 (void)v_lines_in; // remove a gcc warning 375 assert(u_lines_in == v_lines_in); 376 uv_j += u_lines_in; 377 } 378 num_lines_out += ExportRGB(p, p->last_y + num_lines_out); 379 } 380 return num_lines_out; 381} 382 383static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) { 384 const WebPRGBABuffer* const buf = &p->output->u.RGBA; 385 uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride; 386 const WEBP_CSP_MODE colorspace = p->output->colorspace; 387 const int alpha_first = 388 (colorspace == MODE_ARGB || colorspace == MODE_Argb); 389 uint8_t* dst = base_rgba + (alpha_first ? 0 : 3); 390 int num_lines_out = 0; 391 const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); 392 uint32_t non_opaque = 0; 393 const int width = p->scaler_a.dst_width; 394 395 while (WebPRescalerHasPendingOutput(&p->scaler_a) && 396 num_lines_out < max_lines_out) { 397 assert(y_pos + num_lines_out < p->output->height); 398 WebPRescalerExportRow(&p->scaler_a); 399 non_opaque |= WebPDispatchAlpha(p->scaler_a.dst, 0, width, 1, dst, 0); 400 dst += buf->stride; 401 ++num_lines_out; 402 } 403 if (is_premult_alpha && non_opaque) { 404 WebPApplyAlphaMultiply(base_rgba, alpha_first, 405 width, num_lines_out, buf->stride); 406 } 407 return num_lines_out; 408} 409 410static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos, 411 int max_lines_out) { 412 const WebPRGBABuffer* const buf = &p->output->u.RGBA; 413 uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride; 414#ifdef WEBP_SWAP_16BIT_CSP 415 uint8_t* alpha_dst = base_rgba; 416#else 417 uint8_t* alpha_dst = base_rgba + 1; 418#endif 419 int num_lines_out = 0; 420 const WEBP_CSP_MODE colorspace = p->output->colorspace; 421 const int width = p->scaler_a.dst_width; 422 const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); 423 uint32_t alpha_mask = 0x0f; 424 425 while (WebPRescalerHasPendingOutput(&p->scaler_a) && 426 num_lines_out < max_lines_out) { 427 int i; 428 assert(y_pos + num_lines_out < p->output->height); 429 WebPRescalerExportRow(&p->scaler_a); 430 for (i = 0; i < width; ++i) { 431 // Fill in the alpha value (converted to 4 bits). 432 const uint32_t alpha_value = p->scaler_a.dst[i] >> 4; 433 alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value; 434 alpha_mask &= alpha_value; 435 } 436 alpha_dst += buf->stride; 437 ++num_lines_out; 438 } 439 if (is_premult_alpha && alpha_mask != 0x0f) { 440 WebPApplyAlphaMultiply4444(base_rgba, width, num_lines_out, buf->stride); 441 } 442 return num_lines_out; 443} 444 445static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p, 446 int expected_num_out_lines) { 447 if (io->a != NULL) { 448 WebPRescaler* const scaler = &p->scaler_a; 449 int lines_left = expected_num_out_lines; 450 const int y_end = p->last_y + lines_left; 451 while (lines_left > 0) { 452 const int row_offset = scaler->src_y - io->mb_y; 453 WebPRescalerImport(scaler, io->mb_h + io->mb_y - scaler->src_y, 454 io->a + row_offset * io->width, io->width); 455 lines_left -= p->emit_alpha_row(p, y_end - lines_left, lines_left); 456 } 457 } 458 return 0; 459} 460 461static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) { 462 const int has_alpha = WebPIsAlphaMode(p->output->colorspace); 463 const int out_width = io->scaled_width; 464 const int out_height = io->scaled_height; 465 const int uv_in_width = (io->mb_w + 1) >> 1; 466 const int uv_in_height = (io->mb_h + 1) >> 1; 467 const size_t work_size = 2 * out_width; // scratch memory for one rescaler 468 rescaler_t* work; // rescalers work area 469 uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion 470 size_t tmp_size1, tmp_size2, total_size; 471 472 tmp_size1 = 3 * work_size; 473 tmp_size2 = 3 * out_width; 474 if (has_alpha) { 475 tmp_size1 += work_size; 476 tmp_size2 += out_width; 477 } 478 total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp); 479 p->memory = WebPSafeMalloc(1ULL, total_size); 480 if (p->memory == NULL) { 481 return 0; // memory error 482 } 483 work = (rescaler_t*)p->memory; 484 tmp = (uint8_t*)(work + tmp_size1); 485 WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h, 486 tmp + 0 * out_width, out_width, out_height, 0, 1, 487 work + 0 * work_size); 488 WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height, 489 tmp + 1 * out_width, out_width, out_height, 0, 1, 490 work + 1 * work_size); 491 WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height, 492 tmp + 2 * out_width, out_width, out_height, 0, 1, 493 work + 2 * work_size); 494 p->emit = EmitRescaledRGB; 495 WebPInitYUV444Converters(); 496 497 if (has_alpha) { 498 WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h, 499 tmp + 3 * out_width, out_width, out_height, 0, 1, 500 work + 3 * work_size); 501 p->emit_alpha = EmitRescaledAlphaRGB; 502 if (p->output->colorspace == MODE_RGBA_4444 || 503 p->output->colorspace == MODE_rgbA_4444) { 504 p->emit_alpha_row = ExportAlphaRGBA4444; 505 } else { 506 p->emit_alpha_row = ExportAlpha; 507 } 508 WebPInitAlphaProcessing(); 509 } 510 return 1; 511} 512 513//------------------------------------------------------------------------------ 514// Default custom functions 515 516static int CustomSetup(VP8Io* io) { 517 WebPDecParams* const p = (WebPDecParams*)io->opaque; 518 const WEBP_CSP_MODE colorspace = p->output->colorspace; 519 const int is_rgb = WebPIsRGBMode(colorspace); 520 const int is_alpha = WebPIsAlphaMode(colorspace); 521 522 p->memory = NULL; 523 p->emit = NULL; 524 p->emit_alpha = NULL; 525 p->emit_alpha_row = NULL; 526 if (!WebPIoInitFromOptions(p->options, io, is_alpha ? MODE_YUV : MODE_YUVA)) { 527 return 0; 528 } 529 if (is_alpha && WebPIsPremultipliedMode(colorspace)) { 530 WebPInitUpsamplers(); 531 } 532 if (io->use_scaling) { 533 const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p); 534 if (!ok) { 535 return 0; // memory error 536 } 537 } else { 538 if (is_rgb) { 539 WebPInitSamplers(); 540 p->emit = EmitSampledRGB; // default 541 if (io->fancy_upsampling) { 542#ifdef FANCY_UPSAMPLING 543 const int uv_width = (io->mb_w + 1) >> 1; 544 p->memory = WebPSafeMalloc(1ULL, (size_t)(io->mb_w + 2 * uv_width)); 545 if (p->memory == NULL) { 546 return 0; // memory error. 547 } 548 p->tmp_y = (uint8_t*)p->memory; 549 p->tmp_u = p->tmp_y + io->mb_w; 550 p->tmp_v = p->tmp_u + uv_width; 551 p->emit = EmitFancyRGB; 552 WebPInitUpsamplers(); 553#endif 554 } 555 } else { 556 p->emit = EmitYUV; 557 } 558 if (is_alpha) { // need transparency output 559 p->emit_alpha = 560 (colorspace == MODE_RGBA_4444 || colorspace == MODE_rgbA_4444) ? 561 EmitAlphaRGBA4444 562 : is_rgb ? EmitAlphaRGB 563 : EmitAlphaYUV; 564 if (is_rgb) { 565 WebPInitAlphaProcessing(); 566 } 567 } 568 } 569 570 if (is_rgb) { 571 VP8YUVInit(); 572 } 573 return 1; 574} 575 576//------------------------------------------------------------------------------ 577 578static int CustomPut(const VP8Io* io) { 579 WebPDecParams* const p = (WebPDecParams*)io->opaque; 580 const int mb_w = io->mb_w; 581 const int mb_h = io->mb_h; 582 int num_lines_out; 583 assert(!(io->mb_y & 1)); 584 585 if (mb_w <= 0 || mb_h <= 0) { 586 return 0; 587 } 588 num_lines_out = p->emit(io, p); 589 if (p->emit_alpha != NULL) { 590 p->emit_alpha(io, p, num_lines_out); 591 } 592 p->last_y += num_lines_out; 593 return 1; 594} 595 596//------------------------------------------------------------------------------ 597 598static void CustomTeardown(const VP8Io* io) { 599 WebPDecParams* const p = (WebPDecParams*)io->opaque; 600 WebPSafeFree(p->memory); 601 p->memory = NULL; 602} 603 604//------------------------------------------------------------------------------ 605// Main entry point 606 607void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io) { 608 io->put = CustomPut; 609 io->setup = CustomSetup; 610 io->teardown = CustomTeardown; 611 io->opaque = params; 612} 613 614//------------------------------------------------------------------------------ 615