| OLD | NEW |
| 1 // Copyright 2011 Google Inc. All Rights Reserved. | 1 // Copyright 2011 Google Inc. All Rights Reserved. |
| 2 // | 2 // |
| 3 // Use of this source code is governed by a BSD-style license | 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 | 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 | 5 // tree. An additional intellectual property rights grant can be found |
| 6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
| 7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
| 8 // ----------------------------------------------------------------------------- | 8 // ----------------------------------------------------------------------------- |
| 9 // | 9 // |
| 10 // functions for sample output. | 10 // functions for sample output. |
| 11 // | 11 // |
| 12 // Author: Skal (pascal.massimino@gmail.com) | 12 // Author: Skal (pascal.massimino@gmail.com) |
| 13 | 13 |
| 14 #include <assert.h> | 14 #include <assert.h> |
| 15 #include <stdlib.h> | 15 #include <stdlib.h> |
| 16 #include "../dec/vp8i.h" | 16 #include "../dec/vp8i_dec.h" |
| 17 #include "./webpi.h" | 17 #include "./webpi_dec.h" |
| 18 #include "../dsp/dsp.h" | 18 #include "../dsp/dsp.h" |
| 19 #include "../dsp/yuv.h" | 19 #include "../dsp/yuv.h" |
| 20 #include "../utils/utils.h" | 20 #include "../utils/utils.h" |
| 21 | 21 |
| 22 //------------------------------------------------------------------------------ | 22 //------------------------------------------------------------------------------ |
| 23 // Main YUV<->RGB conversion functions | 23 // Main YUV<->RGB conversion functions |
| 24 | 24 |
| 25 static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) { | 25 static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) { |
| 26 WebPDecBuffer* output = p->output; | 26 WebPDecBuffer* output = p->output; |
| 27 const WebPYUVABuffer* const buf = &output->u.YUVA; | 27 const WebPYUVABuffer* const buf = &output->u.YUVA; |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 src += lines_in * src_stride; | 249 src += lines_in * src_stride; |
| 250 new_lines -= lines_in; | 250 new_lines -= lines_in; |
| 251 num_lines_out += WebPRescalerExport(wrk); // emit output row(s) | 251 num_lines_out += WebPRescalerExport(wrk); // emit output row(s) |
| 252 } | 252 } |
| 253 return num_lines_out; | 253 return num_lines_out; |
| 254 } | 254 } |
| 255 | 255 |
| 256 static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) { | 256 static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) { |
| 257 const int mb_h = io->mb_h; | 257 const int mb_h = io->mb_h; |
| 258 const int uv_mb_h = (mb_h + 1) >> 1; | 258 const int uv_mb_h = (mb_h + 1) >> 1; |
| 259 WebPRescaler* const scaler = &p->scaler_y; | 259 WebPRescaler* const scaler = p->scaler_y; |
| 260 int num_lines_out = 0; | 260 int num_lines_out = 0; |
| 261 if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) { | 261 if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) { |
| 262 // Before rescaling, we premultiply the luma directly into the io->y | 262 // Before rescaling, we premultiply the luma directly into the io->y |
| 263 // internal buffer. This is OK since these samples are not used for | 263 // internal buffer. This is OK since these samples are not used for |
| 264 // intra-prediction (the top samples are saved in cache_y_/u_/v_). | 264 // intra-prediction (the top samples are saved in cache_y_/u_/v_). |
| 265 // But we need to cast the const away, though. | 265 // But we need to cast the const away, though. |
| 266 WebPMultRows((uint8_t*)io->y, io->y_stride, | 266 WebPMultRows((uint8_t*)io->y, io->y_stride, |
| 267 io->a, io->width, io->mb_w, mb_h, 0); | 267 io->a, io->width, io->mb_w, mb_h, 0); |
| 268 } | 268 } |
| 269 num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler); | 269 num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler); |
| 270 Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u); | 270 Rescale(io->u, io->uv_stride, uv_mb_h, p->scaler_u); |
| 271 Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v); | 271 Rescale(io->v, io->uv_stride, uv_mb_h, p->scaler_v); |
| 272 return num_lines_out; | 272 return num_lines_out; |
| 273 } | 273 } |
| 274 | 274 |
| 275 static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p, | 275 static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p, |
| 276 int expected_num_lines_out) { | 276 int expected_num_lines_out) { |
| 277 const WebPYUVABuffer* const buf = &p->output->u.YUVA; | 277 const WebPYUVABuffer* const buf = &p->output->u.YUVA; |
| 278 uint8_t* const dst_a = buf->a + p->last_y * buf->a_stride; |
| 278 if (io->a != NULL) { | 279 if (io->a != NULL) { |
| 279 uint8_t* dst_y = buf->y + p->last_y * buf->y_stride; | 280 uint8_t* const dst_y = buf->y + p->last_y * buf->y_stride; |
| 280 const uint8_t* src_a = buf->a + p->last_y * buf->a_stride; | 281 const int num_lines_out = Rescale(io->a, io->width, io->mb_h, p->scaler_a); |
| 281 const int num_lines_out = Rescale(io->a, io->width, io->mb_h, &p->scaler_a); | |
| 282 (void)expected_num_lines_out; | |
| 283 assert(expected_num_lines_out == num_lines_out); | 282 assert(expected_num_lines_out == num_lines_out); |
| 284 if (num_lines_out > 0) { // unmultiply the Y | 283 if (num_lines_out > 0) { // unmultiply the Y |
| 285 WebPMultRows(dst_y, buf->y_stride, src_a, buf->a_stride, | 284 WebPMultRows(dst_y, buf->y_stride, dst_a, buf->a_stride, |
| 286 p->scaler_a.dst_width, num_lines_out, 1); | 285 p->scaler_a->dst_width, num_lines_out, 1); |
| 287 } | 286 } |
| 288 } else if (buf->a != NULL) { | 287 } else if (buf->a != NULL) { |
| 289 // the user requested alpha, but there is none, set it to opaque. | 288 // the user requested alpha, but there is none, set it to opaque. |
| 290 assert(p->last_y + expected_num_lines_out <= io->scaled_height); | 289 assert(p->last_y + expected_num_lines_out <= io->scaled_height); |
| 291 FillAlphaPlane(buf->a + p->last_y * buf->a_stride, | 290 FillAlphaPlane(dst_a, io->scaled_width, expected_num_lines_out, |
| 292 io->scaled_width, expected_num_lines_out, buf->a_stride); | 291 buf->a_stride); |
| 293 } | 292 } |
| 294 return 0; | 293 return 0; |
| 295 } | 294 } |
| 296 | 295 |
| 297 static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) { | 296 static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) { |
| 298 const int has_alpha = WebPIsAlphaMode(p->output->colorspace); | 297 const int has_alpha = WebPIsAlphaMode(p->output->colorspace); |
| 299 const WebPYUVABuffer* const buf = &p->output->u.YUVA; | 298 const WebPYUVABuffer* const buf = &p->output->u.YUVA; |
| 300 const int out_width = io->scaled_width; | 299 const int out_width = io->scaled_width; |
| 301 const int out_height = io->scaled_height; | 300 const int out_height = io->scaled_height; |
| 302 const int uv_out_width = (out_width + 1) >> 1; | 301 const int uv_out_width = (out_width + 1) >> 1; |
| 303 const int uv_out_height = (out_height + 1) >> 1; | 302 const int uv_out_height = (out_height + 1) >> 1; |
| 304 const int uv_in_width = (io->mb_w + 1) >> 1; | 303 const int uv_in_width = (io->mb_w + 1) >> 1; |
| 305 const int uv_in_height = (io->mb_h + 1) >> 1; | 304 const int uv_in_height = (io->mb_h + 1) >> 1; |
| 306 const size_t work_size = 2 * out_width; // scratch memory for luma rescaler | 305 const size_t work_size = 2 * out_width; // scratch memory for luma rescaler |
| 307 const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones | 306 const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones |
| 308 size_t tmp_size; | 307 size_t tmp_size, rescaler_size; |
| 309 rescaler_t* work; | 308 rescaler_t* work; |
| 309 WebPRescaler* scalers; |
| 310 const int num_rescalers = has_alpha ? 4 : 3; |
| 310 | 311 |
| 311 tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work); | 312 tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work); |
| 312 if (has_alpha) { | 313 if (has_alpha) { |
| 313 tmp_size += work_size * sizeof(*work); | 314 tmp_size += work_size * sizeof(*work); |
| 314 } | 315 } |
| 315 p->memory = WebPSafeMalloc(1ULL, tmp_size); | 316 rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST; |
| 317 |
| 318 p->memory = WebPSafeMalloc(1ULL, tmp_size + rescaler_size); |
| 316 if (p->memory == NULL) { | 319 if (p->memory == NULL) { |
| 317 return 0; // memory error | 320 return 0; // memory error |
| 318 } | 321 } |
| 319 work = (rescaler_t*)p->memory; | 322 work = (rescaler_t*)p->memory; |
| 320 WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h, | 323 |
| 324 scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + tmp_size); |
| 325 p->scaler_y = &scalers[0]; |
| 326 p->scaler_u = &scalers[1]; |
| 327 p->scaler_v = &scalers[2]; |
| 328 p->scaler_a = has_alpha ? &scalers[3] : NULL; |
| 329 |
| 330 WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h, |
| 321 buf->y, out_width, out_height, buf->y_stride, 1, | 331 buf->y, out_width, out_height, buf->y_stride, 1, |
| 322 work); | 332 work); |
| 323 WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height, | 333 WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height, |
| 324 buf->u, uv_out_width, uv_out_height, buf->u_stride, 1, | 334 buf->u, uv_out_width, uv_out_height, buf->u_stride, 1, |
| 325 work + work_size); | 335 work + work_size); |
| 326 WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height, | 336 WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height, |
| 327 buf->v, uv_out_width, uv_out_height, buf->v_stride, 1, | 337 buf->v, uv_out_width, uv_out_height, buf->v_stride, 1, |
| 328 work + work_size + uv_work_size); | 338 work + work_size + uv_work_size); |
| 329 p->emit = EmitRescaledYUV; | 339 p->emit = EmitRescaledYUV; |
| 330 | 340 |
| 331 if (has_alpha) { | 341 if (has_alpha) { |
| 332 WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h, | 342 WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h, |
| 333 buf->a, out_width, out_height, buf->a_stride, 1, | 343 buf->a, out_width, out_height, buf->a_stride, 1, |
| 334 work + work_size + 2 * uv_work_size); | 344 work + work_size + 2 * uv_work_size); |
| 335 p->emit_alpha = EmitRescaledAlphaYUV; | 345 p->emit_alpha = EmitRescaledAlphaYUV; |
| 336 WebPInitAlphaProcessing(); | 346 WebPInitAlphaProcessing(); |
| 337 } | 347 } |
| 338 return 1; | 348 return 1; |
| 339 } | 349 } |
| 340 | 350 |
| 341 //------------------------------------------------------------------------------ | 351 //------------------------------------------------------------------------------ |
| 342 // RGBA rescaling | 352 // RGBA rescaling |
| 343 | 353 |
| 344 static int ExportRGB(WebPDecParams* const p, int y_pos) { | 354 static int ExportRGB(WebPDecParams* const p, int y_pos) { |
| 345 const WebPYUV444Converter convert = | 355 const WebPYUV444Converter convert = |
| 346 WebPYUV444Converters[p->output->colorspace]; | 356 WebPYUV444Converters[p->output->colorspace]; |
| 347 const WebPRGBABuffer* const buf = &p->output->u.RGBA; | 357 const WebPRGBABuffer* const buf = &p->output->u.RGBA; |
| 348 uint8_t* dst = buf->rgba + y_pos * buf->stride; | 358 uint8_t* dst = buf->rgba + y_pos * buf->stride; |
| 349 int num_lines_out = 0; | 359 int num_lines_out = 0; |
| 350 // For RGB rescaling, because of the YUV420, current scan position | 360 // For RGB rescaling, because of the YUV420, current scan position |
| 351 // U/V can be +1/-1 line from the Y one. Hence the double test. | 361 // U/V can be +1/-1 line from the Y one. Hence the double test. |
| 352 while (WebPRescalerHasPendingOutput(&p->scaler_y) && | 362 while (WebPRescalerHasPendingOutput(p->scaler_y) && |
| 353 WebPRescalerHasPendingOutput(&p->scaler_u)) { | 363 WebPRescalerHasPendingOutput(p->scaler_u)) { |
| 354 assert(y_pos + num_lines_out < p->output->height); | 364 assert(y_pos + num_lines_out < p->output->height); |
| 355 assert(p->scaler_u.y_accum == p->scaler_v.y_accum); | 365 assert(p->scaler_u->y_accum == p->scaler_v->y_accum); |
| 356 WebPRescalerExportRow(&p->scaler_y); | 366 WebPRescalerExportRow(p->scaler_y); |
| 357 WebPRescalerExportRow(&p->scaler_u); | 367 WebPRescalerExportRow(p->scaler_u); |
| 358 WebPRescalerExportRow(&p->scaler_v); | 368 WebPRescalerExportRow(p->scaler_v); |
| 359 convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst, | 369 convert(p->scaler_y->dst, p->scaler_u->dst, p->scaler_v->dst, |
| 360 dst, p->scaler_y.dst_width); | 370 dst, p->scaler_y->dst_width); |
| 361 dst += buf->stride; | 371 dst += buf->stride; |
| 362 ++num_lines_out; | 372 ++num_lines_out; |
| 363 } | 373 } |
| 364 return num_lines_out; | 374 return num_lines_out; |
| 365 } | 375 } |
| 366 | 376 |
| 367 static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) { | 377 static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) { |
| 368 const int mb_h = io->mb_h; | 378 const int mb_h = io->mb_h; |
| 369 const int uv_mb_h = (mb_h + 1) >> 1; | 379 const int uv_mb_h = (mb_h + 1) >> 1; |
| 370 int j = 0, uv_j = 0; | 380 int j = 0, uv_j = 0; |
| 371 int num_lines_out = 0; | 381 int num_lines_out = 0; |
| 372 while (j < mb_h) { | 382 while (j < mb_h) { |
| 373 const int y_lines_in = | 383 const int y_lines_in = |
| 374 WebPRescalerImport(&p->scaler_y, mb_h - j, | 384 WebPRescalerImport(p->scaler_y, mb_h - j, |
| 375 io->y + j * io->y_stride, io->y_stride); | 385 io->y + j * io->y_stride, io->y_stride); |
| 376 j += y_lines_in; | 386 j += y_lines_in; |
| 377 if (WebPRescaleNeededLines(&p->scaler_u, uv_mb_h - uv_j)) { | 387 if (WebPRescaleNeededLines(p->scaler_u, uv_mb_h - uv_j)) { |
| 378 const int u_lines_in = | 388 const int u_lines_in = |
| 379 WebPRescalerImport(&p->scaler_u, uv_mb_h - uv_j, | 389 WebPRescalerImport(p->scaler_u, uv_mb_h - uv_j, |
| 380 io->u + uv_j * io->uv_stride, io->uv_stride); | 390 io->u + uv_j * io->uv_stride, io->uv_stride); |
| 381 const int v_lines_in = | 391 const int v_lines_in = |
| 382 WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j, | 392 WebPRescalerImport(p->scaler_v, uv_mb_h - uv_j, |
| 383 io->v + uv_j * io->uv_stride, io->uv_stride); | 393 io->v + uv_j * io->uv_stride, io->uv_stride); |
| 384 (void)v_lines_in; // remove a gcc warning | 394 (void)v_lines_in; // remove a gcc warning |
| 385 assert(u_lines_in == v_lines_in); | 395 assert(u_lines_in == v_lines_in); |
| 386 uv_j += u_lines_in; | 396 uv_j += u_lines_in; |
| 387 } | 397 } |
| 388 num_lines_out += ExportRGB(p, p->last_y + num_lines_out); | 398 num_lines_out += ExportRGB(p, p->last_y + num_lines_out); |
| 389 } | 399 } |
| 390 return num_lines_out; | 400 return num_lines_out; |
| 391 } | 401 } |
| 392 | 402 |
| 393 static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) { | 403 static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) { |
| 394 const WebPRGBABuffer* const buf = &p->output->u.RGBA; | 404 const WebPRGBABuffer* const buf = &p->output->u.RGBA; |
| 395 uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride; | 405 uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride; |
| 396 const WEBP_CSP_MODE colorspace = p->output->colorspace; | 406 const WEBP_CSP_MODE colorspace = p->output->colorspace; |
| 397 const int alpha_first = | 407 const int alpha_first = |
| 398 (colorspace == MODE_ARGB || colorspace == MODE_Argb); | 408 (colorspace == MODE_ARGB || colorspace == MODE_Argb); |
| 399 uint8_t* dst = base_rgba + (alpha_first ? 0 : 3); | 409 uint8_t* dst = base_rgba + (alpha_first ? 0 : 3); |
| 400 int num_lines_out = 0; | 410 int num_lines_out = 0; |
| 401 const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); | 411 const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); |
| 402 uint32_t non_opaque = 0; | 412 uint32_t non_opaque = 0; |
| 403 const int width = p->scaler_a.dst_width; | 413 const int width = p->scaler_a->dst_width; |
| 404 | 414 |
| 405 while (WebPRescalerHasPendingOutput(&p->scaler_a) && | 415 while (WebPRescalerHasPendingOutput(p->scaler_a) && |
| 406 num_lines_out < max_lines_out) { | 416 num_lines_out < max_lines_out) { |
| 407 assert(y_pos + num_lines_out < p->output->height); | 417 assert(y_pos + num_lines_out < p->output->height); |
| 408 WebPRescalerExportRow(&p->scaler_a); | 418 WebPRescalerExportRow(p->scaler_a); |
| 409 non_opaque |= WebPDispatchAlpha(p->scaler_a.dst, 0, width, 1, dst, 0); | 419 non_opaque |= WebPDispatchAlpha(p->scaler_a->dst, 0, width, 1, dst, 0); |
| 410 dst += buf->stride; | 420 dst += buf->stride; |
| 411 ++num_lines_out; | 421 ++num_lines_out; |
| 412 } | 422 } |
| 413 if (is_premult_alpha && non_opaque) { | 423 if (is_premult_alpha && non_opaque) { |
| 414 WebPApplyAlphaMultiply(base_rgba, alpha_first, | 424 WebPApplyAlphaMultiply(base_rgba, alpha_first, |
| 415 width, num_lines_out, buf->stride); | 425 width, num_lines_out, buf->stride); |
| 416 } | 426 } |
| 417 return num_lines_out; | 427 return num_lines_out; |
| 418 } | 428 } |
| 419 | 429 |
| 420 static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos, | 430 static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos, |
| 421 int max_lines_out) { | 431 int max_lines_out) { |
| 422 const WebPRGBABuffer* const buf = &p->output->u.RGBA; | 432 const WebPRGBABuffer* const buf = &p->output->u.RGBA; |
| 423 uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride; | 433 uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride; |
| 424 #ifdef WEBP_SWAP_16BIT_CSP | 434 #ifdef WEBP_SWAP_16BIT_CSP |
| 425 uint8_t* alpha_dst = base_rgba; | 435 uint8_t* alpha_dst = base_rgba; |
| 426 #else | 436 #else |
| 427 uint8_t* alpha_dst = base_rgba + 1; | 437 uint8_t* alpha_dst = base_rgba + 1; |
| 428 #endif | 438 #endif |
| 429 int num_lines_out = 0; | 439 int num_lines_out = 0; |
| 430 const WEBP_CSP_MODE colorspace = p->output->colorspace; | 440 const WEBP_CSP_MODE colorspace = p->output->colorspace; |
| 431 const int width = p->scaler_a.dst_width; | 441 const int width = p->scaler_a->dst_width; |
| 432 const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); | 442 const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); |
| 433 uint32_t alpha_mask = 0x0f; | 443 uint32_t alpha_mask = 0x0f; |
| 434 | 444 |
| 435 while (WebPRescalerHasPendingOutput(&p->scaler_a) && | 445 while (WebPRescalerHasPendingOutput(p->scaler_a) && |
| 436 num_lines_out < max_lines_out) { | 446 num_lines_out < max_lines_out) { |
| 437 int i; | 447 int i; |
| 438 assert(y_pos + num_lines_out < p->output->height); | 448 assert(y_pos + num_lines_out < p->output->height); |
| 439 WebPRescalerExportRow(&p->scaler_a); | 449 WebPRescalerExportRow(p->scaler_a); |
| 440 for (i = 0; i < width; ++i) { | 450 for (i = 0; i < width; ++i) { |
| 441 // Fill in the alpha value (converted to 4 bits). | 451 // Fill in the alpha value (converted to 4 bits). |
| 442 const uint32_t alpha_value = p->scaler_a.dst[i] >> 4; | 452 const uint32_t alpha_value = p->scaler_a->dst[i] >> 4; |
| 443 alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value; | 453 alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value; |
| 444 alpha_mask &= alpha_value; | 454 alpha_mask &= alpha_value; |
| 445 } | 455 } |
| 446 alpha_dst += buf->stride; | 456 alpha_dst += buf->stride; |
| 447 ++num_lines_out; | 457 ++num_lines_out; |
| 448 } | 458 } |
| 449 if (is_premult_alpha && alpha_mask != 0x0f) { | 459 if (is_premult_alpha && alpha_mask != 0x0f) { |
| 450 WebPApplyAlphaMultiply4444(base_rgba, width, num_lines_out, buf->stride); | 460 WebPApplyAlphaMultiply4444(base_rgba, width, num_lines_out, buf->stride); |
| 451 } | 461 } |
| 452 return num_lines_out; | 462 return num_lines_out; |
| 453 } | 463 } |
| 454 | 464 |
| 455 static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p, | 465 static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p, |
| 456 int expected_num_out_lines) { | 466 int expected_num_out_lines) { |
| 457 if (io->a != NULL) { | 467 if (io->a != NULL) { |
| 458 WebPRescaler* const scaler = &p->scaler_a; | 468 WebPRescaler* const scaler = p->scaler_a; |
| 459 int lines_left = expected_num_out_lines; | 469 int lines_left = expected_num_out_lines; |
| 460 const int y_end = p->last_y + lines_left; | 470 const int y_end = p->last_y + lines_left; |
| 461 while (lines_left > 0) { | 471 while (lines_left > 0) { |
| 462 const int row_offset = scaler->src_y - io->mb_y; | 472 const int row_offset = scaler->src_y - io->mb_y; |
| 463 WebPRescalerImport(scaler, io->mb_h + io->mb_y - scaler->src_y, | 473 WebPRescalerImport(scaler, io->mb_h + io->mb_y - scaler->src_y, |
| 464 io->a + row_offset * io->width, io->width); | 474 io->a + row_offset * io->width, io->width); |
| 465 lines_left -= p->emit_alpha_row(p, y_end - lines_left, lines_left); | 475 lines_left -= p->emit_alpha_row(p, y_end - lines_left, lines_left); |
| 466 } | 476 } |
| 467 } | 477 } |
| 468 return 0; | 478 return 0; |
| 469 } | 479 } |
| 470 | 480 |
| 471 static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) { | 481 static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) { |
| 472 const int has_alpha = WebPIsAlphaMode(p->output->colorspace); | 482 const int has_alpha = WebPIsAlphaMode(p->output->colorspace); |
| 473 const int out_width = io->scaled_width; | 483 const int out_width = io->scaled_width; |
| 474 const int out_height = io->scaled_height; | 484 const int out_height = io->scaled_height; |
| 475 const int uv_in_width = (io->mb_w + 1) >> 1; | 485 const int uv_in_width = (io->mb_w + 1) >> 1; |
| 476 const int uv_in_height = (io->mb_h + 1) >> 1; | 486 const int uv_in_height = (io->mb_h + 1) >> 1; |
| 477 const size_t work_size = 2 * out_width; // scratch memory for one rescaler | 487 const size_t work_size = 2 * out_width; // scratch memory for one rescaler |
| 478 rescaler_t* work; // rescalers work area | 488 rescaler_t* work; // rescalers work area |
| 479 uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion | 489 uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion |
| 480 size_t tmp_size1, tmp_size2, total_size; | 490 size_t tmp_size1, tmp_size2, total_size, rescaler_size; |
| 491 WebPRescaler* scalers; |
| 492 const int num_rescalers = has_alpha ? 4 : 3; |
| 481 | 493 |
| 482 tmp_size1 = 3 * work_size; | 494 tmp_size1 = 3 * work_size; |
| 483 tmp_size2 = 3 * out_width; | 495 tmp_size2 = 3 * out_width; |
| 484 if (has_alpha) { | 496 if (has_alpha) { |
| 485 tmp_size1 += work_size; | 497 tmp_size1 += work_size; |
| 486 tmp_size2 += out_width; | 498 tmp_size2 += out_width; |
| 487 } | 499 } |
| 488 total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp); | 500 total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp); |
| 489 p->memory = WebPSafeMalloc(1ULL, total_size); | 501 rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST; |
| 502 |
| 503 p->memory = WebPSafeMalloc(1ULL, total_size + rescaler_size); |
| 490 if (p->memory == NULL) { | 504 if (p->memory == NULL) { |
| 491 return 0; // memory error | 505 return 0; // memory error |
| 492 } | 506 } |
| 493 work = (rescaler_t*)p->memory; | 507 work = (rescaler_t*)p->memory; |
| 494 tmp = (uint8_t*)(work + tmp_size1); | 508 tmp = (uint8_t*)(work + tmp_size1); |
| 495 WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h, | 509 |
| 510 scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size); |
| 511 p->scaler_y = &scalers[0]; |
| 512 p->scaler_u = &scalers[1]; |
| 513 p->scaler_v = &scalers[2]; |
| 514 p->scaler_a = has_alpha ? &scalers[3] : NULL; |
| 515 |
| 516 WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h, |
| 496 tmp + 0 * out_width, out_width, out_height, 0, 1, | 517 tmp + 0 * out_width, out_width, out_height, 0, 1, |
| 497 work + 0 * work_size); | 518 work + 0 * work_size); |
| 498 WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height, | 519 WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height, |
| 499 tmp + 1 * out_width, out_width, out_height, 0, 1, | 520 tmp + 1 * out_width, out_width, out_height, 0, 1, |
| 500 work + 1 * work_size); | 521 work + 1 * work_size); |
| 501 WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height, | 522 WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height, |
| 502 tmp + 2 * out_width, out_width, out_height, 0, 1, | 523 tmp + 2 * out_width, out_width, out_height, 0, 1, |
| 503 work + 2 * work_size); | 524 work + 2 * work_size); |
| 504 p->emit = EmitRescaledRGB; | 525 p->emit = EmitRescaledRGB; |
| 505 WebPInitYUV444Converters(); | 526 WebPInitYUV444Converters(); |
| 506 | 527 |
| 507 if (has_alpha) { | 528 if (has_alpha) { |
| 508 WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h, | 529 WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h, |
| 509 tmp + 3 * out_width, out_width, out_height, 0, 1, | 530 tmp + 3 * out_width, out_width, out_height, 0, 1, |
| 510 work + 3 * work_size); | 531 work + 3 * work_size); |
| 511 p->emit_alpha = EmitRescaledAlphaRGB; | 532 p->emit_alpha = EmitRescaledAlphaRGB; |
| 512 if (p->output->colorspace == MODE_RGBA_4444 || | 533 if (p->output->colorspace == MODE_RGBA_4444 || |
| 513 p->output->colorspace == MODE_rgbA_4444) { | 534 p->output->colorspace == MODE_rgbA_4444) { |
| 514 p->emit_alpha_row = ExportAlphaRGBA4444; | 535 p->emit_alpha_row = ExportAlphaRGBA4444; |
| 515 } else { | 536 } else { |
| 516 p->emit_alpha_row = ExportAlpha; | 537 p->emit_alpha_row = ExportAlpha; |
| 517 } | 538 } |
| 518 WebPInitAlphaProcessing(); | 539 WebPInitAlphaProcessing(); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 615 // Main entry point | 636 // Main entry point |
| 616 | 637 |
| 617 void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io) { | 638 void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io) { |
| 618 io->put = CustomPut; | 639 io->put = CustomPut; |
| 619 io->setup = CustomSetup; | 640 io->setup = CustomSetup; |
| 620 io->teardown = CustomTeardown; | 641 io->teardown = CustomTeardown; |
| 621 io->opaque = params; | 642 io->opaque = params; |
| 622 } | 643 } |
| 623 | 644 |
| 624 //------------------------------------------------------------------------------ | 645 //------------------------------------------------------------------------------ |
| OLD | NEW |