| OLD | NEW |
| 1 // Copyright 2014 Google Inc. All Rights Reserved. | 1 // Copyright 2014 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 // WebPPicture utils for colorspace conversion | 10 // WebPPicture utils for colorspace conversion |
| (...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 static WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) { | 374 static WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) { |
| 375 const int u = -9719 * r - 19081 * g + 28800 * b + SROUNDER; | 375 const int u = -9719 * r - 19081 * g + 28800 * b + SROUNDER; |
| 376 return clip_8b(128 + (u >> (YUV_FIX + SFIX))); | 376 return clip_8b(128 + (u >> (YUV_FIX + SFIX))); |
| 377 } | 377 } |
| 378 | 378 |
| 379 static WEBP_INLINE uint8_t ConvertRGBToV(int r, int g, int b) { | 379 static WEBP_INLINE uint8_t ConvertRGBToV(int r, int g, int b) { |
| 380 const int v = +28800 * r - 24116 * g - 4684 * b + SROUNDER; | 380 const int v = +28800 * r - 24116 * g - 4684 * b + SROUNDER; |
| 381 return clip_8b(128 + (v >> (YUV_FIX + SFIX))); | 381 return clip_8b(128 + (v >> (YUV_FIX + SFIX))); |
| 382 } | 382 } |
| 383 | 383 |
| 384 static int ConvertWRGBToYUV(const fixed_y_t* const best_y, | 384 static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv, |
| 385 const fixed_t* const best_uv, | |
| 386 WebPPicture* const picture) { | 385 WebPPicture* const picture) { |
| 387 int i, j; | 386 int i, j; |
| 387 uint8_t* dst_y = picture->y; |
| 388 uint8_t* dst_u = picture->u; |
| 389 uint8_t* dst_v = picture->v; |
| 390 const fixed_t* const best_uv_base = best_uv; |
| 388 const int w = (picture->width + 1) & ~1; | 391 const int w = (picture->width + 1) & ~1; |
| 389 const int h = (picture->height + 1) & ~1; | 392 const int h = (picture->height + 1) & ~1; |
| 390 const int uv_w = w >> 1; | 393 const int uv_w = w >> 1; |
| 391 const int uv_h = h >> 1; | 394 const int uv_h = h >> 1; |
| 392 for (j = 0; j < picture->height; ++j) { | 395 for (best_uv = best_uv_base, j = 0; j < picture->height; ++j) { |
| 393 for (i = 0; i < picture->width; ++i) { | 396 for (i = 0; i < picture->width; ++i) { |
| 394 const int off = 3 * ((i >> 1) + (j >> 1) * uv_w); | 397 const int off = 3 * (i >> 1); |
| 395 const int off2 = i + j * picture->y_stride; | 398 const int W = best_y[i]; |
| 396 const int W = best_y[i + j * w]; | |
| 397 const int r = best_uv[off + 0] + W; | 399 const int r = best_uv[off + 0] + W; |
| 398 const int g = best_uv[off + 1] + W; | 400 const int g = best_uv[off + 1] + W; |
| 399 const int b = best_uv[off + 2] + W; | 401 const int b = best_uv[off + 2] + W; |
| 400 picture->y[off2] = ConvertRGBToY(r, g, b); | 402 dst_y[i] = ConvertRGBToY(r, g, b); |
| 401 } | 403 } |
| 404 best_y += w; |
| 405 best_uv += (j & 1) * 3 * uv_w; |
| 406 dst_y += picture->y_stride; |
| 402 } | 407 } |
| 403 for (j = 0; j < uv_h; ++j) { | 408 for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) { |
| 404 uint8_t* const dst_u = picture->u + j * picture->uv_stride; | |
| 405 uint8_t* const dst_v = picture->v + j * picture->uv_stride; | |
| 406 for (i = 0; i < uv_w; ++i) { | 409 for (i = 0; i < uv_w; ++i) { |
| 407 const int off = 3 * (i + j * uv_w); | 410 const int off = 3 * i; |
| 408 const int r = best_uv[off + 0]; | 411 const int r = best_uv[off + 0]; |
| 409 const int g = best_uv[off + 1]; | 412 const int g = best_uv[off + 1]; |
| 410 const int b = best_uv[off + 2]; | 413 const int b = best_uv[off + 2]; |
| 411 dst_u[i] = ConvertRGBToU(r, g, b); | 414 dst_u[i] = ConvertRGBToU(r, g, b); |
| 412 dst_v[i] = ConvertRGBToV(r, g, b); | 415 dst_v[i] = ConvertRGBToV(r, g, b); |
| 413 } | 416 } |
| 417 best_uv += 3 * uv_w; |
| 418 dst_u += picture->uv_stride; |
| 419 dst_v += picture->uv_stride; |
| 414 } | 420 } |
| 415 return 1; | 421 return 1; |
| 416 } | 422 } |
| 417 | 423 |
| 418 //------------------------------------------------------------------------------ | 424 //------------------------------------------------------------------------------ |
| 419 // Main function | 425 // Main function |
| 420 | 426 |
| 421 #define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T))) | 427 #define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T))) |
| 422 | 428 |
| 423 static int PreprocessARGB(const uint8_t* const r_ptr, | 429 static int PreprocessARGB(const uint8_t* r_ptr, |
| 424 const uint8_t* const g_ptr, | 430 const uint8_t* g_ptr, |
| 425 const uint8_t* const b_ptr, | 431 const uint8_t* b_ptr, |
| 426 int step, int rgb_stride, | 432 int step, int rgb_stride, |
| 427 WebPPicture* const picture) { | 433 WebPPicture* const picture) { |
| 428 // we expand the right/bottom border if needed | 434 // we expand the right/bottom border if needed |
| 429 const int w = (picture->width + 1) & ~1; | 435 const int w = (picture->width + 1) & ~1; |
| 430 const int h = (picture->height + 1) & ~1; | 436 const int h = (picture->height + 1) & ~1; |
| 431 const int uv_w = w >> 1; | 437 const int uv_w = w >> 1; |
| 432 const int uv_h = h >> 1; | 438 const int uv_h = h >> 1; |
| 433 int i, j, iter; | 439 int i, j, iter; |
| 434 | 440 |
| 435 // TODO(skal): allocate one big memory chunk. But for now, it's easier | 441 // TODO(skal): allocate one big memory chunk. But for now, it's easier |
| 436 // for valgrind debugging to have several chunks. | 442 // for valgrind debugging to have several chunks. |
| 437 fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch | 443 fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch |
| 438 fixed_y_t* const best_y = SAFE_ALLOC(w, h, fixed_y_t); | 444 fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t); |
| 439 fixed_y_t* const target_y = SAFE_ALLOC(w, h, fixed_y_t); | 445 fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t); |
| 440 fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t); | 446 fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t); |
| 441 fixed_t* const best_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); | 447 fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); |
| 442 fixed_t* const target_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); | 448 fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); |
| 443 fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t); | 449 fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t); |
| 450 fixed_y_t* best_y = best_y_base; |
| 451 fixed_y_t* target_y = target_y_base; |
| 452 fixed_t* best_uv = best_uv_base; |
| 453 fixed_t* target_uv = target_uv_base; |
| 444 int ok; | 454 int ok; |
| 445 int diff_sum = 0; | 455 int diff_sum = 0; |
| 446 const int first_diff_threshold = (int)(2.5 * w * h); | 456 const int first_diff_threshold = (int)(2.5 * w * h); |
| 447 const int min_improvement = 5; // stop if improvement is below this % | 457 const int min_improvement = 5; // stop if improvement is below this % |
| 448 const int min_first_improvement = 80; | 458 const int min_first_improvement = 80; |
| 449 | 459 |
| 450 if (best_y == NULL || best_uv == NULL || | 460 if (best_y_base == NULL || best_uv_base == NULL || |
| 451 target_y == NULL || target_uv == NULL || | 461 target_y_base == NULL || target_uv_base == NULL || |
| 452 best_rgb_y == NULL || best_rgb_uv == NULL || | 462 best_rgb_y == NULL || best_rgb_uv == NULL || |
| 453 tmp_buffer == NULL) { | 463 tmp_buffer == NULL) { |
| 454 ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); | 464 ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); |
| 455 goto End; | 465 goto End; |
| 456 } | 466 } |
| 457 assert(picture->width >= kMinDimensionIterativeConversion); | 467 assert(picture->width >= kMinDimensionIterativeConversion); |
| 458 assert(picture->height >= kMinDimensionIterativeConversion); | 468 assert(picture->height >= kMinDimensionIterativeConversion); |
| 459 | 469 |
| 460 // Import RGB samples to W/RGB representation. | 470 // Import RGB samples to W/RGB representation. |
| 461 for (j = 0; j < picture->height; j += 2) { | 471 for (j = 0; j < picture->height; j += 2) { |
| 462 const int is_last_row = (j == picture->height - 1); | 472 const int is_last_row = (j == picture->height - 1); |
| 463 fixed_y_t* const src1 = tmp_buffer; | 473 fixed_y_t* const src1 = tmp_buffer; |
| 464 fixed_y_t* const src2 = tmp_buffer + 3 * w; | 474 fixed_y_t* const src2 = tmp_buffer + 3 * w; |
| 465 const int off1 = j * rgb_stride; | |
| 466 const int off2 = off1 + rgb_stride; | |
| 467 const int uv_off = (j >> 1) * 3 * uv_w; | |
| 468 fixed_y_t* const dst_y = best_y + j * w; | |
| 469 | 475 |
| 470 // prepare two rows of input | 476 // prepare two rows of input |
| 471 ImportOneRow(r_ptr + off1, g_ptr + off1, b_ptr + off1, | 477 ImportOneRow(r_ptr, g_ptr, b_ptr, step, picture->width, src1); |
| 472 step, picture->width, src1); | |
| 473 if (!is_last_row) { | 478 if (!is_last_row) { |
| 474 ImportOneRow(r_ptr + off2, g_ptr + off2, b_ptr + off2, | 479 ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride, |
| 475 step, picture->width, src2); | 480 step, picture->width, src2); |
| 476 } else { | 481 } else { |
| 477 memcpy(src2, src1, 3 * w * sizeof(*src2)); | 482 memcpy(src2, src1, 3 * w * sizeof(*src2)); |
| 478 } | 483 } |
| 479 UpdateW(src1, target_y + (j + 0) * w, w); | 484 UpdateW(src1, target_y, w); |
| 480 UpdateW(src2, target_y + (j + 1) * w, w); | 485 UpdateW(src2, target_y + w, w); |
| 481 diff_sum += UpdateChroma(src1, src2, target_uv + uv_off, dst_y, uv_w); | 486 diff_sum += UpdateChroma(src1, src2, target_uv, best_y, uv_w); |
| 482 memcpy(best_uv + uv_off, target_uv + uv_off, 3 * uv_w * sizeof(*best_uv)); | 487 memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv)); |
| 483 memcpy(dst_y + w, dst_y, w * sizeof(*dst_y)); | 488 memcpy(best_y + w, best_y, w * sizeof(*best_y)); |
| 489 best_y += 2 * w; |
| 490 best_uv += 3 * uv_w; |
| 491 target_y += 2 * w; |
| 492 target_uv += 3 * uv_w; |
| 493 r_ptr += 2 * rgb_stride; |
| 494 g_ptr += 2 * rgb_stride; |
| 495 b_ptr += 2 * rgb_stride; |
| 484 } | 496 } |
| 485 | 497 |
| 486 // Iterate and resolve clipping conflicts. | 498 // Iterate and resolve clipping conflicts. |
| 487 for (iter = 0; iter < kNumIterations; ++iter) { | 499 for (iter = 0; iter < kNumIterations; ++iter) { |
| 488 int k; | 500 int k; |
| 489 const fixed_t* cur_uv = best_uv; | 501 const fixed_t* cur_uv = best_uv_base; |
| 490 const fixed_t* prev_uv = best_uv; | 502 const fixed_t* prev_uv = best_uv_base; |
| 491 const int old_diff_sum = diff_sum; | 503 const int old_diff_sum = diff_sum; |
| 492 diff_sum = 0; | 504 diff_sum = 0; |
| 505 |
| 506 best_y = best_y_base; |
| 507 best_uv = best_uv_base; |
| 508 target_y = target_y_base; |
| 509 target_uv = target_uv_base; |
| 493 for (j = 0; j < h; j += 2) { | 510 for (j = 0; j < h; j += 2) { |
| 494 fixed_y_t* const src1 = tmp_buffer; | 511 fixed_y_t* const src1 = tmp_buffer; |
| 495 fixed_y_t* const src2 = tmp_buffer + 3 * w; | 512 fixed_y_t* const src2 = tmp_buffer + 3 * w; |
| 496 { | 513 { |
| 497 const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0); | 514 const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0); |
| 498 InterpolateTwoRows(best_y + j * w, prev_uv, cur_uv, next_uv, | 515 InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w, src1, src2); |
| 499 w, src1, src2); | |
| 500 prev_uv = cur_uv; | 516 prev_uv = cur_uv; |
| 501 cur_uv = next_uv; | 517 cur_uv = next_uv; |
| 502 } | 518 } |
| 503 | 519 |
| 504 UpdateW(src1, best_rgb_y + 0 * w, w); | 520 UpdateW(src1, best_rgb_y + 0 * w, w); |
| 505 UpdateW(src2, best_rgb_y + 1 * w, w); | 521 UpdateW(src2, best_rgb_y + 1 * w, w); |
| 506 diff_sum += UpdateChroma(src1, src2, best_rgb_uv, NULL, uv_w); | 522 diff_sum += UpdateChroma(src1, src2, best_rgb_uv, NULL, uv_w); |
| 507 | 523 |
| 508 // update two rows of Y and one row of RGB | 524 // update two rows of Y and one row of RGB |
| 509 for (i = 0; i < 2 * w; ++i) { | 525 for (i = 0; i < 2 * w; ++i) { |
| 510 const int off = i + j * w; | 526 const int diff_y = target_y[i] - best_rgb_y[i]; |
| 511 const int diff_y = target_y[off] - best_rgb_y[i]; | 527 const int new_y = (int)best_y[i] + diff_y; |
| 512 const int new_y = (int)best_y[off] + diff_y; | 528 best_y[i] = clip_y(new_y); |
| 513 best_y[off] = clip_y(new_y); | |
| 514 } | 529 } |
| 515 for (i = 0; i < uv_w; ++i) { | 530 for (i = 0; i < uv_w; ++i) { |
| 516 const int off = 3 * (i + (j >> 1) * uv_w); | 531 const int off = 3 * i; |
| 517 int W; | 532 int W; |
| 518 for (k = 0; k <= 2; ++k) { | 533 for (k = 0; k <= 2; ++k) { |
| 519 const int diff_uv = (int)target_uv[off + k] - best_rgb_uv[3 * i + k]; | 534 const int diff_uv = (int)target_uv[off + k] - best_rgb_uv[off + k]; |
| 520 best_uv[off + k] += diff_uv; | 535 best_uv[off + k] += diff_uv; |
| 521 } | 536 } |
| 522 W = RGBToGray(best_uv[off + 0], best_uv[off + 1], best_uv[off + 2]); | 537 W = RGBToGray(best_uv[off + 0], best_uv[off + 1], best_uv[off + 2]); |
| 523 for (k = 0; k <= 2; ++k) { | 538 for (k = 0; k <= 2; ++k) { |
| 524 best_uv[off + k] -= W; | 539 best_uv[off + k] -= W; |
| 525 } | 540 } |
| 526 } | 541 } |
| 542 best_y += 2 * w; |
| 543 best_uv += 3 * uv_w; |
| 544 target_y += 2 * w; |
| 545 target_uv += 3 * uv_w; |
| 527 } | 546 } |
| 528 // test exit condition | 547 // test exit condition |
| 529 if (diff_sum > 0) { | 548 if (diff_sum > 0) { |
| 530 const int improvement = 100 * abs(diff_sum - old_diff_sum) / diff_sum; | 549 const int improvement = 100 * abs(diff_sum - old_diff_sum) / diff_sum; |
| 531 // Check if first iteration gave good result already, without a large | 550 // Check if first iteration gave good result already, without a large |
| 532 // jump of improvement (otherwise it means we need to try few extra | 551 // jump of improvement (otherwise it means we need to try few extra |
| 533 // iterations, just to be sure). | 552 // iterations, just to be sure). |
| 534 if (iter == 0 && diff_sum < first_diff_threshold && | 553 if (iter == 0 && diff_sum < first_diff_threshold && |
| 535 improvement < min_first_improvement) { | 554 improvement < min_first_improvement) { |
| 536 break; | 555 break; |
| 537 } | 556 } |
| 538 // then, check if improvement is stalling. | 557 // then, check if improvement is stalling. |
| 539 if (improvement < min_improvement) { | 558 if (improvement < min_improvement) { |
| 540 break; | 559 break; |
| 541 } | 560 } |
| 542 } else { | 561 } else { |
| 543 break; | 562 break; |
| 544 } | 563 } |
| 545 } | 564 } |
| 546 | 565 |
| 547 // final reconstruction | 566 // final reconstruction |
| 548 ok = ConvertWRGBToYUV(best_y, best_uv, picture); | 567 ok = ConvertWRGBToYUV(best_y_base, best_uv_base, picture); |
| 549 | 568 |
| 550 End: | 569 End: |
| 551 WebPSafeFree(best_y); | 570 WebPSafeFree(best_y_base); |
| 552 WebPSafeFree(best_uv); | 571 WebPSafeFree(best_uv_base); |
| 553 WebPSafeFree(target_y); | 572 WebPSafeFree(target_y_base); |
| 554 WebPSafeFree(target_uv); | 573 WebPSafeFree(target_uv_base); |
| 555 WebPSafeFree(best_rgb_y); | 574 WebPSafeFree(best_rgb_y); |
| 556 WebPSafeFree(best_rgb_uv); | 575 WebPSafeFree(best_rgb_uv); |
| 557 WebPSafeFree(tmp_buffer); | 576 WebPSafeFree(tmp_buffer); |
| 558 return ok; | 577 return ok; |
| 559 } | 578 } |
| 560 #undef SAFE_ALLOC | 579 #undef SAFE_ALLOC |
| 561 | 580 |
| 562 //------------------------------------------------------------------------------ | 581 //------------------------------------------------------------------------------ |
| 563 // "Fast" regular RGB->YUV | 582 // "Fast" regular RGB->YUV |
| 564 | 583 |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 823 int width, | 842 int width, |
| 824 VP8Random* const rg) { | 843 VP8Random* const rg) { |
| 825 int i; | 844 int i; |
| 826 for (i = 0; i < width; i += 1, rgb += 4) { | 845 for (i = 0; i < width; i += 1, rgb += 4) { |
| 827 const int r = rgb[0], g = rgb[1], b = rgb[2]; | 846 const int r = rgb[0], g = rgb[1], b = rgb[2]; |
| 828 dst_u[i] = RGBToU(r, g, b, rg); | 847 dst_u[i] = RGBToU(r, g, b, rg); |
| 829 dst_v[i] = RGBToV(r, g, b, rg); | 848 dst_v[i] = RGBToV(r, g, b, rg); |
| 830 } | 849 } |
| 831 } | 850 } |
| 832 | 851 |
| 833 static int ImportYUVAFromRGBA(const uint8_t* const r_ptr, | 852 static int ImportYUVAFromRGBA(const uint8_t* r_ptr, |
| 834 const uint8_t* const g_ptr, | 853 const uint8_t* g_ptr, |
| 835 const uint8_t* const b_ptr, | 854 const uint8_t* b_ptr, |
| 836 const uint8_t* const a_ptr, | 855 const uint8_t* a_ptr, |
| 837 int step, // bytes per pixel | 856 int step, // bytes per pixel |
| 838 int rgb_stride, // bytes per scanline | 857 int rgb_stride, // bytes per scanline |
| 839 float dithering, | 858 float dithering, |
| 840 int use_iterative_conversion, | 859 int use_iterative_conversion, |
| 841 WebPPicture* const picture) { | 860 WebPPicture* const picture) { |
| 842 int y; | 861 int y; |
| 843 const int width = picture->width; | 862 const int width = picture->width; |
| 844 const int height = picture->height; | 863 const int height = picture->height; |
| 845 const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride); | 864 const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride); |
| 846 const int is_rgb = (r_ptr < b_ptr); // otherwise it's bgr | 865 const int is_rgb = (r_ptr < b_ptr); // otherwise it's bgr |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 893 use_dsp = 0; // can't use dsp in this case | 912 use_dsp = 0; // can't use dsp in this case |
| 894 } | 913 } |
| 895 WebPInitConvertARGBToYUV(); | 914 WebPInitConvertARGBToYUV(); |
| 896 InitGammaTables(); | 915 InitGammaTables(); |
| 897 | 916 |
| 898 if (tmp_rgb == NULL) return 0; // malloc error | 917 if (tmp_rgb == NULL) return 0; // malloc error |
| 899 | 918 |
| 900 // Downsample Y/U/V planes, two rows at a time | 919 // Downsample Y/U/V planes, two rows at a time |
| 901 for (y = 0; y < (height >> 1); ++y) { | 920 for (y = 0; y < (height >> 1); ++y) { |
| 902 int rows_have_alpha = has_alpha; | 921 int rows_have_alpha = has_alpha; |
| 903 const int off1 = (2 * y + 0) * rgb_stride; | |
| 904 const int off2 = (2 * y + 1) * rgb_stride; | |
| 905 if (use_dsp) { | 922 if (use_dsp) { |
| 906 if (is_rgb) { | 923 if (is_rgb) { |
| 907 WebPConvertRGB24ToY(r_ptr + off1, dst_y, width); | 924 WebPConvertRGB24ToY(r_ptr, dst_y, width); |
| 908 WebPConvertRGB24ToY(r_ptr + off2, dst_y + picture->y_stride, width); | 925 WebPConvertRGB24ToY(r_ptr + rgb_stride, |
| 926 dst_y + picture->y_stride, width); |
| 909 } else { | 927 } else { |
| 910 WebPConvertBGR24ToY(b_ptr + off1, dst_y, width); | 928 WebPConvertBGR24ToY(b_ptr, dst_y, width); |
| 911 WebPConvertBGR24ToY(b_ptr + off2, dst_y + picture->y_stride, width); | 929 WebPConvertBGR24ToY(b_ptr + rgb_stride, |
| 930 dst_y + picture->y_stride, width); |
| 912 } | 931 } |
| 913 } else { | 932 } else { |
| 914 ConvertRowToY(r_ptr + off1, g_ptr + off1, b_ptr + off1, step, | 933 ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg); |
| 915 dst_y, width, rg); | 934 ConvertRowToY(r_ptr + rgb_stride, |
| 916 ConvertRowToY(r_ptr + off2, g_ptr + off2, b_ptr + off2, step, | 935 g_ptr + rgb_stride, |
| 936 b_ptr + rgb_stride, step, |
| 917 dst_y + picture->y_stride, width, rg); | 937 dst_y + picture->y_stride, width, rg); |
| 918 } | 938 } |
| 919 dst_y += 2 * picture->y_stride; | 939 dst_y += 2 * picture->y_stride; |
| 920 if (has_alpha) { | 940 if (has_alpha) { |
| 921 rows_have_alpha &= !WebPExtractAlpha(a_ptr + off1, rgb_stride, | 941 rows_have_alpha &= !WebPExtractAlpha(a_ptr, rgb_stride, width, 2, |
| 922 width, 2, | |
| 923 dst_a, picture->a_stride); | 942 dst_a, picture->a_stride); |
| 924 dst_a += 2 * picture->a_stride; | 943 dst_a += 2 * picture->a_stride; |
| 925 } | 944 } |
| 926 // Collect averaged R/G/B(/A) | 945 // Collect averaged R/G/B(/A) |
| 927 if (!rows_have_alpha) { | 946 if (!rows_have_alpha) { |
| 928 AccumulateRGB(r_ptr + off1, g_ptr + off1, b_ptr + off1, | 947 AccumulateRGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, tmp_rgb, width); |
| 929 step, rgb_stride, tmp_rgb, width); | |
| 930 } else { | 948 } else { |
| 931 AccumulateRGBA(r_ptr + off1, g_ptr + off1, b_ptr + off1, a_ptr + off1, | 949 AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, rgb_stride, tmp_rgb, width); |
| 932 rgb_stride, tmp_rgb, width); | |
| 933 } | 950 } |
| 934 // Convert to U/V | 951 // Convert to U/V |
| 935 if (rg == NULL) { | 952 if (rg == NULL) { |
| 936 WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width); | 953 WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width); |
| 937 } else { | 954 } else { |
| 938 ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg); | 955 ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg); |
| 939 } | 956 } |
| 940 dst_u += picture->uv_stride; | 957 dst_u += picture->uv_stride; |
| 941 dst_v += picture->uv_stride; | 958 dst_v += picture->uv_stride; |
| 959 r_ptr += 2 * rgb_stride; |
| 960 b_ptr += 2 * rgb_stride; |
| 961 g_ptr += 2 * rgb_stride; |
| 962 if (has_alpha) a_ptr += 2 * rgb_stride; |
| 942 } | 963 } |
| 943 if (height & 1) { // extra last row | 964 if (height & 1) { // extra last row |
| 944 const int off = 2 * y * rgb_stride; | |
| 945 int row_has_alpha = has_alpha; | 965 int row_has_alpha = has_alpha; |
| 946 if (use_dsp) { | 966 if (use_dsp) { |
| 947 if (r_ptr < b_ptr) { | 967 if (r_ptr < b_ptr) { |
| 948 WebPConvertRGB24ToY(r_ptr + off, dst_y, width); | 968 WebPConvertRGB24ToY(r_ptr, dst_y, width); |
| 949 } else { | 969 } else { |
| 950 WebPConvertBGR24ToY(b_ptr + off, dst_y, width); | 970 WebPConvertBGR24ToY(b_ptr, dst_y, width); |
| 951 } | 971 } |
| 952 } else { | 972 } else { |
| 953 ConvertRowToY(r_ptr + off, g_ptr + off, b_ptr + off, step, | 973 ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg); |
| 954 dst_y, width, rg); | |
| 955 } | 974 } |
| 956 if (row_has_alpha) { | 975 if (row_has_alpha) { |
| 957 row_has_alpha &= !WebPExtractAlpha(a_ptr + off, 0, width, 1, dst_a, 0); | 976 row_has_alpha &= !WebPExtractAlpha(a_ptr, 0, width, 1, dst_a, 0); |
| 958 } | 977 } |
| 959 // Collect averaged R/G/B(/A) | 978 // Collect averaged R/G/B(/A) |
| 960 if (!row_has_alpha) { | 979 if (!row_has_alpha) { |
| 961 // Collect averaged R/G/B | 980 // Collect averaged R/G/B |
| 962 AccumulateRGB(r_ptr + off, g_ptr + off, b_ptr + off, | 981 AccumulateRGB(r_ptr, g_ptr, b_ptr, step, /* rgb_stride = */ 0, |
| 963 step, /* rgb_stride = */ 0, tmp_rgb, width); | 982 tmp_rgb, width); |
| 964 } else { | 983 } else { |
| 965 AccumulateRGBA(r_ptr + off, g_ptr + off, b_ptr + off, a_ptr + off, | 984 AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, /* rgb_stride = */ 0, |
| 966 /* rgb_stride = */ 0, tmp_rgb, width); | 985 tmp_rgb, width); |
| 967 } | 986 } |
| 968 if (rg == NULL) { | 987 if (rg == NULL) { |
| 969 WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width); | 988 WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width); |
| 970 } else { | 989 } else { |
| 971 ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg); | 990 ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg); |
| 972 } | 991 } |
| 973 } | 992 } |
| 974 WebPSafeFree(tmp_rgb); | 993 WebPSafeFree(tmp_rgb); |
| 975 } | 994 } |
| 976 return 1; | 995 return 1; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1079 return 1; | 1098 return 1; |
| 1080 } | 1099 } |
| 1081 | 1100 |
| 1082 //------------------------------------------------------------------------------ | 1101 //------------------------------------------------------------------------------ |
| 1083 // automatic import / conversion | 1102 // automatic import / conversion |
| 1084 | 1103 |
| 1085 static int Import(WebPPicture* const picture, | 1104 static int Import(WebPPicture* const picture, |
| 1086 const uint8_t* const rgb, int rgb_stride, | 1105 const uint8_t* const rgb, int rgb_stride, |
| 1087 int step, int swap_rb, int import_alpha) { | 1106 int step, int swap_rb, int import_alpha) { |
| 1088 int y; | 1107 int y; |
| 1089 const uint8_t* const r_ptr = rgb + (swap_rb ? 2 : 0); | 1108 const uint8_t* r_ptr = rgb + (swap_rb ? 2 : 0); |
| 1090 const uint8_t* const g_ptr = rgb + 1; | 1109 const uint8_t* g_ptr = rgb + 1; |
| 1091 const uint8_t* const b_ptr = rgb + (swap_rb ? 0 : 2); | 1110 const uint8_t* b_ptr = rgb + (swap_rb ? 0 : 2); |
| 1092 const uint8_t* const a_ptr = import_alpha ? rgb + 3 : NULL; | 1111 const uint8_t* a_ptr = import_alpha ? rgb + 3 : NULL; |
| 1093 const int width = picture->width; | 1112 const int width = picture->width; |
| 1094 const int height = picture->height; | 1113 const int height = picture->height; |
| 1095 | 1114 |
| 1096 if (!picture->use_argb) { | 1115 if (!picture->use_argb) { |
| 1097 return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride, | 1116 return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride, |
| 1098 0.f /* no dithering */, 0, picture); | 1117 0.f /* no dithering */, 0, picture); |
| 1099 } | 1118 } |
| 1100 if (!WebPPictureAlloc(picture)) return 0; | 1119 if (!WebPPictureAlloc(picture)) return 0; |
| 1101 | 1120 |
| 1102 VP8EncDspARGBInit(); | 1121 VP8EncDspARGBInit(); |
| 1103 | 1122 |
| 1104 if (import_alpha) { | 1123 if (import_alpha) { |
| 1124 uint32_t* dst = picture->argb; |
| 1105 assert(step == 4); | 1125 assert(step == 4); |
| 1106 for (y = 0; y < height; ++y) { | 1126 for (y = 0; y < height; ++y) { |
| 1107 uint32_t* const dst = &picture->argb[y * picture->argb_stride]; | 1127 VP8PackARGB(a_ptr, r_ptr, g_ptr, b_ptr, width, dst); |
| 1108 const int offset = y * rgb_stride; | 1128 a_ptr += rgb_stride; |
| 1109 VP8PackARGB(a_ptr + offset, r_ptr + offset, g_ptr + offset, | 1129 r_ptr += rgb_stride; |
| 1110 b_ptr + offset, width, dst); | 1130 g_ptr += rgb_stride; |
| 1131 b_ptr += rgb_stride; |
| 1132 dst += picture->argb_stride; |
| 1111 } | 1133 } |
| 1112 } else { | 1134 } else { |
| 1135 uint32_t* dst = picture->argb; |
| 1113 assert(step >= 3); | 1136 assert(step >= 3); |
| 1114 for (y = 0; y < height; ++y) { | 1137 for (y = 0; y < height; ++y) { |
| 1115 uint32_t* const dst = &picture->argb[y * picture->argb_stride]; | 1138 VP8PackRGB(r_ptr, g_ptr, b_ptr, width, step, dst); |
| 1116 const int offset = y * rgb_stride; | 1139 r_ptr += rgb_stride; |
| 1117 VP8PackRGB(r_ptr + offset, g_ptr + offset, b_ptr + offset, | 1140 g_ptr += rgb_stride; |
| 1118 width, step, dst); | 1141 b_ptr += rgb_stride; |
| 1142 dst += picture->argb_stride; |
| 1119 } | 1143 } |
| 1120 } | 1144 } |
| 1121 return 1; | 1145 return 1; |
| 1122 } | 1146 } |
| 1123 | 1147 |
| 1124 // Public API | 1148 // Public API |
| 1125 | 1149 |
| 1126 int WebPPictureImportRGB(WebPPicture* picture, | 1150 int WebPPictureImportRGB(WebPPicture* picture, |
| 1127 const uint8_t* rgb, int rgb_stride) { | 1151 const uint8_t* rgb, int rgb_stride) { |
| 1128 return (picture != NULL && rgb != NULL) | 1152 return (picture != NULL && rgb != NULL) |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1159 } | 1183 } |
| 1160 | 1184 |
| 1161 int WebPPictureImportBGRX(WebPPicture* picture, | 1185 int WebPPictureImportBGRX(WebPPicture* picture, |
| 1162 const uint8_t* rgba, int rgba_stride) { | 1186 const uint8_t* rgba, int rgba_stride) { |
| 1163 return (picture != NULL && rgba != NULL) | 1187 return (picture != NULL && rgba != NULL) |
| 1164 ? Import(picture, rgba, rgba_stride, 4, 1, 0) | 1188 ? Import(picture, rgba, rgba_stride, 4, 1, 0) |
| 1165 : 0; | 1189 : 0; |
| 1166 } | 1190 } |
| 1167 | 1191 |
| 1168 //------------------------------------------------------------------------------ | 1192 //------------------------------------------------------------------------------ |
| OLD | NEW |