| OLD | NEW |
| 1 // Copyright 2015 Google Inc. All Rights Reserved. | 1 // Copyright 2015 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 // Image transform methods for lossless encoder. | 10 // Image transform methods for lossless encoder. |
| 11 // | 11 // |
| 12 // Authors: Vikas Arora (vikaas.arora@gmail.com) | 12 // Authors: Vikas Arora (vikaas.arora@gmail.com) |
| 13 // Jyrki Alakuijala (jyrki@google.com) | 13 // Jyrki Alakuijala (jyrki@google.com) |
| 14 // Urvang Joshi (urvang@google.com) | 14 // Urvang Joshi (urvang@google.com) |
| 15 | 15 |
| 16 #include "./dsp.h" | 16 #include "./dsp.h" |
| 17 | 17 |
| 18 #include <math.h> | 18 #include <math.h> |
| 19 #include <stdlib.h> | 19 #include <stdlib.h> |
| 20 #include "../dec/vp8li.h" | 20 #include "../dec/vp8li_dec.h" |
| 21 #include "../utils/endian_inl.h" | 21 #include "../utils/endian_inl_utils.h" |
| 22 #include "./lossless.h" | 22 #include "./lossless.h" |
| 23 #include "./lossless_common.h" |
| 23 #include "./yuv.h" | 24 #include "./yuv.h" |
| 24 | 25 |
| 25 #define MAX_DIFF_COST (1e30f) | |
| 26 | |
| 27 static const int kPredLowEffort = 11; | |
| 28 static const uint32_t kMaskAlpha = 0xff000000; | |
| 29 | |
| 30 // lookup table for small values of log2(int) | 26 // lookup table for small values of log2(int) |
| 31 const float kLog2Table[LOG_LOOKUP_IDX_MAX] = { | 27 const float kLog2Table[LOG_LOOKUP_IDX_MAX] = { |
| 32 0.0000000000000000f, 0.0000000000000000f, | 28 0.0000000000000000f, 0.0000000000000000f, |
| 33 1.0000000000000000f, 1.5849625007211560f, | 29 1.0000000000000000f, 1.5849625007211560f, |
| 34 2.0000000000000000f, 2.3219280948873621f, | 30 2.0000000000000000f, 2.3219280948873621f, |
| 35 2.5849625007211560f, 2.8073549220576041f, | 31 2.5849625007211560f, 2.8073549220576041f, |
| 36 3.0000000000000000f, 3.1699250014423121f, | 32 3.0000000000000000f, 3.1699250014423121f, |
| 37 3.3219280948873621f, 3.4594316186372973f, | 33 3.3219280948873621f, 3.4594316186372973f, |
| 38 3.5849625007211560f, 3.7004397181410921f, | 34 3.5849625007211560f, 3.7004397181410921f, |
| 39 3.8073549220576041f, 3.9068905956085187f, | 35 3.8073549220576041f, 3.9068905956085187f, |
| (...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 // for large values of 'v'. | 369 // for large values of 'v'. |
| 374 const int correction = (23 * (orig_v & (y - 1))) >> 4; | 370 const int correction = (23 * (orig_v & (y - 1))) >> 4; |
| 375 log_2 += (double)correction / orig_v; | 371 log_2 += (double)correction / orig_v; |
| 376 } | 372 } |
| 377 return (float)log_2; | 373 return (float)log_2; |
| 378 } else { | 374 } else { |
| 379 return (float)(LOG_2_RECIPROCAL * log((double)v)); | 375 return (float)(LOG_2_RECIPROCAL * log((double)v)); |
| 380 } | 376 } |
| 381 } | 377 } |
| 382 | 378 |
| 383 // Mostly used to reduce code size + readability | |
| 384 static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; } | |
| 385 static WEBP_INLINE int GetMax(int a, int b) { return (a < b) ? b : a; } | |
| 386 | |
| 387 //------------------------------------------------------------------------------ | 379 //------------------------------------------------------------------------------ |
| 388 // Methods to calculate Entropy (Shannon). | 380 // Methods to calculate Entropy (Shannon). |
| 389 | 381 |
| 390 static float PredictionCostSpatial(const int counts[256], int weight_0, | |
| 391 double exp_val) { | |
| 392 const int significant_symbols = 256 >> 4; | |
| 393 const double exp_decay_factor = 0.6; | |
| 394 double bits = weight_0 * counts[0]; | |
| 395 int i; | |
| 396 for (i = 1; i < significant_symbols; ++i) { | |
| 397 bits += exp_val * (counts[i] + counts[256 - i]); | |
| 398 exp_val *= exp_decay_factor; | |
| 399 } | |
| 400 return (float)(-0.1 * bits); | |
| 401 } | |
| 402 | |
| 403 // Compute the combined Shanon's entropy for distribution {X} and {X+Y} | 382 // Compute the combined Shanon's entropy for distribution {X} and {X+Y} |
| 404 static float CombinedShannonEntropy(const int X[256], const int Y[256]) { | 383 static float CombinedShannonEntropy(const int X[256], const int Y[256]) { |
| 405 int i; | 384 int i; |
| 406 double retval = 0.; | 385 double retval = 0.; |
| 407 int sumX = 0, sumXY = 0; | 386 int sumX = 0, sumXY = 0; |
| 408 for (i = 0; i < 256; ++i) { | 387 for (i = 0; i < 256; ++i) { |
| 409 const int x = X[i]; | 388 const int x = X[i]; |
| 410 if (x != 0) { | 389 if (x != 0) { |
| 411 const int xy = x + Y[i]; | 390 const int xy = x + Y[i]; |
| 412 sumX += x; | 391 sumX += x; |
| 413 retval -= VP8LFastSLog2(x); | 392 retval -= VP8LFastSLog2(x); |
| 414 sumXY += xy; | 393 sumXY += xy; |
| 415 retval -= VP8LFastSLog2(xy); | 394 retval -= VP8LFastSLog2(xy); |
| 416 } else if (Y[i] != 0) { | 395 } else if (Y[i] != 0) { |
| 417 sumXY += Y[i]; | 396 sumXY += Y[i]; |
| 418 retval -= VP8LFastSLog2(Y[i]); | 397 retval -= VP8LFastSLog2(Y[i]); |
| 419 } | 398 } |
| 420 } | 399 } |
| 421 retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY); | 400 retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY); |
| 422 return (float)retval; | 401 return (float)retval; |
| 423 } | 402 } |
| 424 | 403 |
| 425 static float PredictionCostSpatialHistogram(const int accumulated[4][256], | |
| 426 const int tile[4][256]) { | |
| 427 int i; | |
| 428 double retval = 0; | |
| 429 for (i = 0; i < 4; ++i) { | |
| 430 const double kExpValue = 0.94; | |
| 431 retval += PredictionCostSpatial(tile[i], 1, kExpValue); | |
| 432 retval += VP8LCombinedShannonEntropy(tile[i], accumulated[i]); | |
| 433 } | |
| 434 return (float)retval; | |
| 435 } | |
| 436 | |
| 437 void VP8LBitEntropyInit(VP8LBitEntropy* const entropy) { | 404 void VP8LBitEntropyInit(VP8LBitEntropy* const entropy) { |
| 438 entropy->entropy = 0.; | 405 entropy->entropy = 0.; |
| 439 entropy->sum = 0; | 406 entropy->sum = 0; |
| 440 entropy->nonzeros = 0; | 407 entropy->nonzeros = 0; |
| 441 entropy->max_val = 0; | 408 entropy->max_val = 0; |
| 442 entropy->nonzero_code = VP8L_NON_TRIVIAL_SYM; | 409 entropy->nonzero_code = VP8L_NON_TRIVIAL_SYM; |
| 443 } | 410 } |
| 444 | 411 |
| 445 void VP8LBitsEntropyUnrefined(const uint32_t* const array, int n, | 412 void VP8LBitsEntropyUnrefined(const uint32_t* const array, int n, |
| 446 VP8LBitEntropy* const entropy) { | 413 VP8LBitEntropy* const entropy) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 } | 446 } |
| 480 | 447 |
| 481 // Gather info for the Huffman cost. | 448 // Gather info for the Huffman cost. |
| 482 stats->counts[*val_prev != 0] += (streak > 3); | 449 stats->counts[*val_prev != 0] += (streak > 3); |
| 483 stats->streaks[*val_prev != 0][(streak > 3)] += streak; | 450 stats->streaks[*val_prev != 0][(streak > 3)] += streak; |
| 484 | 451 |
| 485 *val_prev = val; | 452 *val_prev = val; |
| 486 *i_prev = i; | 453 *i_prev = i; |
| 487 } | 454 } |
| 488 | 455 |
| 489 void VP8LGetEntropyUnrefined(const uint32_t* const X, int length, | 456 static void GetEntropyUnrefined(const uint32_t X[], int length, |
| 490 VP8LBitEntropy* const bit_entropy, | 457 VP8LBitEntropy* const bit_entropy, |
| 491 VP8LStreaks* const stats) { | 458 VP8LStreaks* const stats) { |
| 492 int i; | 459 int i; |
| 493 int i_prev = 0; | 460 int i_prev = 0; |
| 494 uint32_t x_prev = X[0]; | 461 uint32_t x_prev = X[0]; |
| 495 | 462 |
| 496 memset(stats, 0, sizeof(*stats)); | 463 memset(stats, 0, sizeof(*stats)); |
| 497 VP8LBitEntropyInit(bit_entropy); | 464 VP8LBitEntropyInit(bit_entropy); |
| 498 | 465 |
| 499 for (i = 1; i < length; ++i) { | 466 for (i = 1; i < length; ++i) { |
| 500 const uint32_t x = X[i]; | 467 const uint32_t x = X[i]; |
| 501 if (x != x_prev) { | 468 if (x != x_prev) { |
| 502 VP8LGetEntropyUnrefinedHelper(x, i, &x_prev, &i_prev, bit_entropy, stats); | 469 GetEntropyUnrefinedHelper(x, i, &x_prev, &i_prev, bit_entropy, stats); |
| 503 } | 470 } |
| 504 } | 471 } |
| 505 VP8LGetEntropyUnrefinedHelper(0, i, &x_prev, &i_prev, bit_entropy, stats); | 472 GetEntropyUnrefinedHelper(0, i, &x_prev, &i_prev, bit_entropy, stats); |
| 506 | 473 |
| 507 bit_entropy->entropy += VP8LFastSLog2(bit_entropy->sum); | 474 bit_entropy->entropy += VP8LFastSLog2(bit_entropy->sum); |
| 508 } | 475 } |
| 509 | 476 |
| 510 void VP8LGetCombinedEntropyUnrefined(const uint32_t* const X, | 477 static void GetCombinedEntropyUnrefined(const uint32_t X[], const uint32_t Y[], |
| 511 const uint32_t* const Y, int length, | 478 int length, |
| 512 VP8LBitEntropy* const bit_entropy, | 479 VP8LBitEntropy* const bit_entropy, |
| 513 VP8LStreaks* const stats) { | 480 VP8LStreaks* const stats) { |
| 514 int i = 1; | 481 int i = 1; |
| 515 int i_prev = 0; | 482 int i_prev = 0; |
| 516 uint32_t xy_prev = X[0] + Y[0]; | 483 uint32_t xy_prev = X[0] + Y[0]; |
| 517 | 484 |
| 518 memset(stats, 0, sizeof(*stats)); | 485 memset(stats, 0, sizeof(*stats)); |
| 519 VP8LBitEntropyInit(bit_entropy); | 486 VP8LBitEntropyInit(bit_entropy); |
| 520 | 487 |
| 521 for (i = 1; i < length; ++i) { | 488 for (i = 1; i < length; ++i) { |
| 522 const uint32_t xy = X[i] + Y[i]; | 489 const uint32_t xy = X[i] + Y[i]; |
| 523 if (xy != xy_prev) { | 490 if (xy != xy_prev) { |
| 524 VP8LGetEntropyUnrefinedHelper(xy, i, &xy_prev, &i_prev, bit_entropy, | 491 GetEntropyUnrefinedHelper(xy, i, &xy_prev, &i_prev, bit_entropy, stats); |
| 525 stats); | |
| 526 } | 492 } |
| 527 } | 493 } |
| 528 VP8LGetEntropyUnrefinedHelper(0, i, &xy_prev, &i_prev, bit_entropy, stats); | 494 GetEntropyUnrefinedHelper(0, i, &xy_prev, &i_prev, bit_entropy, stats); |
| 529 | 495 |
| 530 bit_entropy->entropy += VP8LFastSLog2(bit_entropy->sum); | 496 bit_entropy->entropy += VP8LFastSLog2(bit_entropy->sum); |
| 531 } | 497 } |
| 532 | 498 |
| 533 static WEBP_INLINE void UpdateHisto(int histo_argb[4][256], uint32_t argb) { | |
| 534 ++histo_argb[0][argb >> 24]; | |
| 535 ++histo_argb[1][(argb >> 16) & 0xff]; | |
| 536 ++histo_argb[2][(argb >> 8) & 0xff]; | |
| 537 ++histo_argb[3][argb & 0xff]; | |
| 538 } | |
| 539 | |
| 540 //------------------------------------------------------------------------------ | 499 //------------------------------------------------------------------------------ |
| 541 | 500 |
| 542 static WEBP_INLINE uint32_t Predict(VP8LPredictorFunc pred_func, | |
| 543 int x, int y, | |
| 544 const uint32_t* current_row, | |
| 545 const uint32_t* upper_row) { | |
| 546 if (y == 0) { | |
| 547 return (x == 0) ? ARGB_BLACK : current_row[x - 1]; // Left. | |
| 548 } else if (x == 0) { | |
| 549 return upper_row[x]; // Top. | |
| 550 } else { | |
| 551 return pred_func(current_row[x - 1], upper_row + x); | |
| 552 } | |
| 553 } | |
| 554 | |
| 555 static int MaxDiffBetweenPixels(uint32_t p1, uint32_t p2) { | |
| 556 const int diff_a = abs((int)(p1 >> 24) - (int)(p2 >> 24)); | |
| 557 const int diff_r = abs((int)((p1 >> 16) & 0xff) - (int)((p2 >> 16) & 0xff)); | |
| 558 const int diff_g = abs((int)((p1 >> 8) & 0xff) - (int)((p2 >> 8) & 0xff)); | |
| 559 const int diff_b = abs((int)(p1 & 0xff) - (int)(p2 & 0xff)); | |
| 560 return GetMax(GetMax(diff_a, diff_r), GetMax(diff_g, diff_b)); | |
| 561 } | |
| 562 | |
| 563 static int MaxDiffAroundPixel(uint32_t current, uint32_t up, uint32_t down, | |
| 564 uint32_t left, uint32_t right) { | |
| 565 const int diff_up = MaxDiffBetweenPixels(current, up); | |
| 566 const int diff_down = MaxDiffBetweenPixels(current, down); | |
| 567 const int diff_left = MaxDiffBetweenPixels(current, left); | |
| 568 const int diff_right = MaxDiffBetweenPixels(current, right); | |
| 569 return GetMax(GetMax(diff_up, diff_down), GetMax(diff_left, diff_right)); | |
| 570 } | |
| 571 | |
| 572 static uint32_t AddGreenToBlueAndRed(uint32_t argb) { | |
| 573 const uint32_t green = (argb >> 8) & 0xff; | |
| 574 uint32_t red_blue = argb & 0x00ff00ffu; | |
| 575 red_blue += (green << 16) | green; | |
| 576 red_blue &= 0x00ff00ffu; | |
| 577 return (argb & 0xff00ff00u) | red_blue; | |
| 578 } | |
| 579 | |
| 580 static void MaxDiffsForRow(int width, int stride, const uint32_t* const argb, | |
| 581 uint8_t* const max_diffs, int used_subtract_green) { | |
| 582 uint32_t current, up, down, left, right; | |
| 583 int x; | |
| 584 if (width <= 2) return; | |
| 585 current = argb[0]; | |
| 586 right = argb[1]; | |
| 587 if (used_subtract_green) { | |
| 588 current = AddGreenToBlueAndRed(current); | |
| 589 right = AddGreenToBlueAndRed(right); | |
| 590 } | |
| 591 // max_diffs[0] and max_diffs[width - 1] are never used. | |
| 592 for (x = 1; x < width - 1; ++x) { | |
| 593 up = argb[-stride + x]; | |
| 594 down = argb[stride + x]; | |
| 595 left = current; | |
| 596 current = right; | |
| 597 right = argb[x + 1]; | |
| 598 if (used_subtract_green) { | |
| 599 up = AddGreenToBlueAndRed(up); | |
| 600 down = AddGreenToBlueAndRed(down); | |
| 601 right = AddGreenToBlueAndRed(right); | |
| 602 } | |
| 603 max_diffs[x] = MaxDiffAroundPixel(current, up, down, left, right); | |
| 604 } | |
| 605 } | |
| 606 | |
| 607 // Quantize the difference between the actual component value and its prediction | |
| 608 // to a multiple of quantization, working modulo 256, taking care not to cross | |
| 609 // a boundary (inclusive upper limit). | |
| 610 static uint8_t NearLosslessComponent(uint8_t value, uint8_t predict, | |
| 611 uint8_t boundary, int quantization) { | |
| 612 const int residual = (value - predict) & 0xff; | |
| 613 const int boundary_residual = (boundary - predict) & 0xff; | |
| 614 const int lower = residual & ~(quantization - 1); | |
| 615 const int upper = lower + quantization; | |
| 616 // Resolve ties towards a value closer to the prediction (i.e. towards lower | |
| 617 // if value comes after prediction and towards upper otherwise). | |
| 618 const int bias = ((boundary - value) & 0xff) < boundary_residual; | |
| 619 if (residual - lower < upper - residual + bias) { | |
| 620 // lower is closer to residual than upper. | |
| 621 if (residual > boundary_residual && lower <= boundary_residual) { | |
| 622 // Halve quantization step to avoid crossing boundary. This midpoint is | |
| 623 // on the same side of boundary as residual because midpoint >= residual | |
| 624 // (since lower is closer than upper) and residual is above the boundary. | |
| 625 return lower + (quantization >> 1); | |
| 626 } | |
| 627 return lower; | |
| 628 } else { | |
| 629 // upper is closer to residual than lower. | |
| 630 if (residual <= boundary_residual && upper > boundary_residual) { | |
| 631 // Halve quantization step to avoid crossing boundary. This midpoint is | |
| 632 // on the same side of boundary as residual because midpoint <= residual | |
| 633 // (since upper is closer than lower) and residual is below the boundary. | |
| 634 return lower + (quantization >> 1); | |
| 635 } | |
| 636 return upper & 0xff; | |
| 637 } | |
| 638 } | |
| 639 | |
| 640 // Quantize every component of the difference between the actual pixel value and | |
| 641 // its prediction to a multiple of a quantization (a power of 2, not larger than | |
| 642 // max_quantization which is a power of 2, smaller than max_diff). Take care if | |
| 643 // value and predict have undergone subtract green, which means that red and | |
| 644 // blue are represented as offsets from green. | |
| 645 static uint32_t NearLossless(uint32_t value, uint32_t predict, | |
| 646 int max_quantization, int max_diff, | |
| 647 int used_subtract_green) { | |
| 648 int quantization; | |
| 649 uint8_t new_green = 0; | |
| 650 uint8_t green_diff = 0; | |
| 651 uint8_t a, r, g, b; | |
| 652 if (max_diff <= 2) { | |
| 653 return VP8LSubPixels(value, predict); | |
| 654 } | |
| 655 quantization = max_quantization; | |
| 656 while (quantization >= max_diff) { | |
| 657 quantization >>= 1; | |
| 658 } | |
| 659 if ((value >> 24) == 0 || (value >> 24) == 0xff) { | |
| 660 // Preserve transparency of fully transparent or fully opaque pixels. | |
| 661 a = ((value >> 24) - (predict >> 24)) & 0xff; | |
| 662 } else { | |
| 663 a = NearLosslessComponent(value >> 24, predict >> 24, 0xff, quantization); | |
| 664 } | |
| 665 g = NearLosslessComponent((value >> 8) & 0xff, (predict >> 8) & 0xff, 0xff, | |
| 666 quantization); | |
| 667 if (used_subtract_green) { | |
| 668 // The green offset will be added to red and blue components during decoding | |
| 669 // to obtain the actual red and blue values. | |
| 670 new_green = ((predict >> 8) + g) & 0xff; | |
| 671 // The amount by which green has been adjusted during quantization. It is | |
| 672 // subtracted from red and blue for compensation, to avoid accumulating two | |
| 673 // quantization errors in them. | |
| 674 green_diff = (new_green - (value >> 8)) & 0xff; | |
| 675 } | |
| 676 r = NearLosslessComponent(((value >> 16) - green_diff) & 0xff, | |
| 677 (predict >> 16) & 0xff, 0xff - new_green, | |
| 678 quantization); | |
| 679 b = NearLosslessComponent((value - green_diff) & 0xff, predict & 0xff, | |
| 680 0xff - new_green, quantization); | |
| 681 return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; | |
| 682 } | |
| 683 | |
| 684 // Returns the difference between the pixel and its prediction. In case of a | |
| 685 // lossy encoding, updates the source image to avoid propagating the deviation | |
| 686 // further to pixels which depend on the current pixel for their predictions. | |
| 687 static WEBP_INLINE uint32_t GetResidual(int width, int height, | |
| 688 uint32_t* const upper_row, | |
| 689 uint32_t* const current_row, | |
| 690 const uint8_t* const max_diffs, | |
| 691 int mode, VP8LPredictorFunc pred_func, | |
| 692 int x, int y, int max_quantization, | |
| 693 int exact, int used_subtract_green) { | |
| 694 const uint32_t predict = Predict(pred_func, x, y, current_row, upper_row); | |
| 695 uint32_t residual; | |
| 696 if (max_quantization == 1 || mode == 0 || y == 0 || y == height - 1 || | |
| 697 x == 0 || x == width - 1) { | |
| 698 residual = VP8LSubPixels(current_row[x], predict); | |
| 699 } else { | |
| 700 residual = NearLossless(current_row[x], predict, max_quantization, | |
| 701 max_diffs[x], used_subtract_green); | |
| 702 // Update the source image. | |
| 703 current_row[x] = VP8LAddPixels(predict, residual); | |
| 704 // x is never 0 here so we do not need to update upper_row like below. | |
| 705 } | |
| 706 if (!exact && (current_row[x] & kMaskAlpha) == 0) { | |
| 707 // If alpha is 0, cleanup RGB. We can choose the RGB values of the residual | |
| 708 // for best compression. The prediction of alpha itself can be non-zero and | |
| 709 // must be kept though. We choose RGB of the residual to be 0. | |
| 710 residual &= kMaskAlpha; | |
| 711 // Update the source image. | |
| 712 current_row[x] = predict & ~kMaskAlpha; | |
| 713 // The prediction for the rightmost pixel in a row uses the leftmost pixel | |
| 714 // in that row as its top-right context pixel. Hence if we change the | |
| 715 // leftmost pixel of current_row, the corresponding change must be applied | |
| 716 // to upper_row as well where top-right context is being read from. | |
| 717 if (x == 0 && y != 0) upper_row[width] = current_row[0]; | |
| 718 } | |
| 719 return residual; | |
| 720 } | |
| 721 | |
| 722 // Returns best predictor and updates the accumulated histogram. | |
| 723 // If max_quantization > 1, assumes that near lossless processing will be | |
| 724 // applied, quantizing residuals to multiples of quantization levels up to | |
| 725 // max_quantization (the actual quantization level depends on smoothness near | |
| 726 // the given pixel). | |
| 727 static int GetBestPredictorForTile(int width, int height, | |
| 728 int tile_x, int tile_y, int bits, | |
| 729 int accumulated[4][256], | |
| 730 uint32_t* const argb_scratch, | |
| 731 const uint32_t* const argb, | |
| 732 int max_quantization, | |
| 733 int exact, int used_subtract_green) { | |
| 734 const int kNumPredModes = 14; | |
| 735 const int start_x = tile_x << bits; | |
| 736 const int start_y = tile_y << bits; | |
| 737 const int tile_size = 1 << bits; | |
| 738 const int max_y = GetMin(tile_size, height - start_y); | |
| 739 const int max_x = GetMin(tile_size, width - start_x); | |
| 740 // Whether there exist columns just outside the tile. | |
| 741 const int have_left = (start_x > 0); | |
| 742 const int have_right = (max_x < width - start_x); | |
| 743 // Position and size of the strip covering the tile and adjacent columns if | |
| 744 // they exist. | |
| 745 const int context_start_x = start_x - have_left; | |
| 746 const int context_width = max_x + have_left + have_right; | |
| 747 // The width of upper_row and current_row is one pixel larger than image width | |
| 748 // to allow the top right pixel to point to the leftmost pixel of the next row | |
| 749 // when at the right edge. | |
| 750 uint32_t* upper_row = argb_scratch; | |
| 751 uint32_t* current_row = upper_row + width + 1; | |
| 752 uint8_t* const max_diffs = (uint8_t*)(current_row + width + 1); | |
| 753 float best_diff = MAX_DIFF_COST; | |
| 754 int best_mode = 0; | |
| 755 int mode; | |
| 756 int histo_stack_1[4][256]; | |
| 757 int histo_stack_2[4][256]; | |
| 758 // Need pointers to be able to swap arrays. | |
| 759 int (*histo_argb)[256] = histo_stack_1; | |
| 760 int (*best_histo)[256] = histo_stack_2; | |
| 761 int i, j; | |
| 762 | |
| 763 for (mode = 0; mode < kNumPredModes; ++mode) { | |
| 764 const VP8LPredictorFunc pred_func = VP8LPredictors[mode]; | |
| 765 float cur_diff; | |
| 766 int relative_y; | |
| 767 memset(histo_argb, 0, sizeof(histo_stack_1)); | |
| 768 if (start_y > 0) { | |
| 769 // Read the row above the tile which will become the first upper_row. | |
| 770 // Include a pixel to the left if it exists; include a pixel to the right | |
| 771 // in all cases (wrapping to the leftmost pixel of the next row if it does | |
| 772 // not exist). | |
| 773 memcpy(current_row + context_start_x, | |
| 774 argb + (start_y - 1) * width + context_start_x, | |
| 775 sizeof(*argb) * (max_x + have_left + 1)); | |
| 776 } | |
| 777 for (relative_y = 0; relative_y < max_y; ++relative_y) { | |
| 778 const int y = start_y + relative_y; | |
| 779 int relative_x; | |
| 780 uint32_t* tmp = upper_row; | |
| 781 upper_row = current_row; | |
| 782 current_row = tmp; | |
| 783 // Read current_row. Include a pixel to the left if it exists; include a | |
| 784 // pixel to the right in all cases except at the bottom right corner of | |
| 785 // the image (wrapping to the leftmost pixel of the next row if it does | |
| 786 // not exist in the current row). | |
| 787 memcpy(current_row + context_start_x, | |
| 788 argb + y * width + context_start_x, | |
| 789 sizeof(*argb) * (max_x + have_left + (y + 1 < height))); | |
| 790 if (max_quantization > 1 && y >= 1 && y + 1 < height) { | |
| 791 MaxDiffsForRow(context_width, width, argb + y * width + context_start_x, | |
| 792 max_diffs + context_start_x, used_subtract_green); | |
| 793 } | |
| 794 | |
| 795 for (relative_x = 0; relative_x < max_x; ++relative_x) { | |
| 796 const int x = start_x + relative_x; | |
| 797 UpdateHisto(histo_argb, | |
| 798 GetResidual(width, height, upper_row, current_row, | |
| 799 max_diffs, mode, pred_func, x, y, | |
| 800 max_quantization, exact, used_subtract_green)); | |
| 801 } | |
| 802 } | |
| 803 cur_diff = PredictionCostSpatialHistogram( | |
| 804 (const int (*)[256])accumulated, (const int (*)[256])histo_argb); | |
| 805 if (cur_diff < best_diff) { | |
| 806 int (*tmp)[256] = histo_argb; | |
| 807 histo_argb = best_histo; | |
| 808 best_histo = tmp; | |
| 809 best_diff = cur_diff; | |
| 810 best_mode = mode; | |
| 811 } | |
| 812 } | |
| 813 | |
| 814 for (i = 0; i < 4; i++) { | |
| 815 for (j = 0; j < 256; j++) { | |
| 816 accumulated[i][j] += best_histo[i][j]; | |
| 817 } | |
| 818 } | |
| 819 | |
| 820 return best_mode; | |
| 821 } | |
| 822 | |
| 823 // Converts pixels of the image to residuals with respect to predictions. | |
| 824 // If max_quantization > 1, applies near lossless processing, quantizing | |
| 825 // residuals to multiples of quantization levels up to max_quantization | |
| 826 // (the actual quantization level depends on smoothness near the given pixel). | |
| 827 static void CopyImageWithPrediction(int width, int height, | |
| 828 int bits, uint32_t* const modes, | |
| 829 uint32_t* const argb_scratch, | |
| 830 uint32_t* const argb, | |
| 831 int low_effort, int max_quantization, | |
| 832 int exact, int used_subtract_green) { | |
| 833 const int tiles_per_row = VP8LSubSampleSize(width, bits); | |
| 834 const int mask = (1 << bits) - 1; | |
| 835 // The width of upper_row and current_row is one pixel larger than image width | |
| 836 // to allow the top right pixel to point to the leftmost pixel of the next row | |
| 837 // when at the right edge. | |
| 838 uint32_t* upper_row = argb_scratch; | |
| 839 uint32_t* current_row = upper_row + width + 1; | |
| 840 uint8_t* current_max_diffs = (uint8_t*)(current_row + width + 1); | |
| 841 uint8_t* lower_max_diffs = current_max_diffs + width; | |
| 842 int y; | |
| 843 int mode = 0; | |
| 844 VP8LPredictorFunc pred_func = NULL; | |
| 845 | |
| 846 for (y = 0; y < height; ++y) { | |
| 847 int x; | |
| 848 uint32_t* const tmp32 = upper_row; | |
| 849 upper_row = current_row; | |
| 850 current_row = tmp32; | |
| 851 memcpy(current_row, argb + y * width, | |
| 852 sizeof(*argb) * (width + (y + 1 < height))); | |
| 853 | |
| 854 if (low_effort) { | |
| 855 for (x = 0; x < width; ++x) { | |
| 856 const uint32_t predict = Predict(VP8LPredictors[kPredLowEffort], x, y, | |
| 857 current_row, upper_row); | |
| 858 argb[y * width + x] = VP8LSubPixels(current_row[x], predict); | |
| 859 } | |
| 860 } else { | |
| 861 if (max_quantization > 1) { | |
| 862 // Compute max_diffs for the lower row now, because that needs the | |
| 863 // contents of argb for the current row, which we will overwrite with | |
| 864 // residuals before proceeding with the next row. | |
| 865 uint8_t* const tmp8 = current_max_diffs; | |
| 866 current_max_diffs = lower_max_diffs; | |
| 867 lower_max_diffs = tmp8; | |
| 868 if (y + 2 < height) { | |
| 869 MaxDiffsForRow(width, width, argb + (y + 1) * width, lower_max_diffs, | |
| 870 used_subtract_green); | |
| 871 } | |
| 872 } | |
| 873 for (x = 0; x < width; ++x) { | |
| 874 if ((x & mask) == 0) { | |
| 875 mode = (modes[(y >> bits) * tiles_per_row + (x >> bits)] >> 8) & 0xff; | |
| 876 pred_func = VP8LPredictors[mode]; | |
| 877 } | |
| 878 argb[y * width + x] = GetResidual( | |
| 879 width, height, upper_row, current_row, current_max_diffs, mode, | |
| 880 pred_func, x, y, max_quantization, exact, used_subtract_green); | |
| 881 } | |
| 882 } | |
| 883 } | |
| 884 } | |
| 885 | |
| 886 // Finds the best predictor for each tile, and converts the image to residuals | |
| 887 // with respect to predictions. If near_lossless_quality < 100, applies | |
| 888 // near lossless processing, shaving off more bits of residuals for lower | |
| 889 // qualities. | |
| 890 void VP8LResidualImage(int width, int height, int bits, int low_effort, | |
| 891 uint32_t* const argb, uint32_t* const argb_scratch, | |
| 892 uint32_t* const image, int near_lossless_quality, | |
| 893 int exact, int used_subtract_green) { | |
| 894 const int tiles_per_row = VP8LSubSampleSize(width, bits); | |
| 895 const int tiles_per_col = VP8LSubSampleSize(height, bits); | |
| 896 int tile_y; | |
| 897 int histo[4][256]; | |
| 898 const int max_quantization = 1 << VP8LNearLosslessBits(near_lossless_quality); | |
| 899 if (low_effort) { | |
| 900 int i; | |
| 901 for (i = 0; i < tiles_per_row * tiles_per_col; ++i) { | |
| 902 image[i] = ARGB_BLACK | (kPredLowEffort << 8); | |
| 903 } | |
| 904 } else { | |
| 905 memset(histo, 0, sizeof(histo)); | |
| 906 for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) { | |
| 907 int tile_x; | |
| 908 for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) { | |
| 909 const int pred = GetBestPredictorForTile(width, height, tile_x, tile_y, | |
| 910 bits, histo, argb_scratch, argb, max_quantization, exact, | |
| 911 used_subtract_green); | |
| 912 image[tile_y * tiles_per_row + tile_x] = ARGB_BLACK | (pred << 8); | |
| 913 } | |
| 914 } | |
| 915 } | |
| 916 | |
| 917 CopyImageWithPrediction(width, height, bits, image, argb_scratch, argb, | |
| 918 low_effort, max_quantization, exact, | |
| 919 used_subtract_green); | |
| 920 } | |
| 921 | |
| 922 void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels) { | 501 void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels) { |
| 923 int i; | 502 int i; |
| 924 for (i = 0; i < num_pixels; ++i) { | 503 for (i = 0; i < num_pixels; ++i) { |
| 925 const uint32_t argb = argb_data[i]; | 504 const int argb = argb_data[i]; |
| 926 const uint32_t green = (argb >> 8) & 0xff; | 505 const int green = (argb >> 8) & 0xff; |
| 927 const uint32_t new_r = (((argb >> 16) & 0xff) - green) & 0xff; | 506 const uint32_t new_r = (((argb >> 16) & 0xff) - green) & 0xff; |
| 928 const uint32_t new_b = ((argb & 0xff) - green) & 0xff; | 507 const uint32_t new_b = (((argb >> 0) & 0xff) - green) & 0xff; |
| 929 argb_data[i] = (argb & 0xff00ff00) | (new_r << 16) | new_b; | 508 argb_data[i] = (argb & 0xff00ff00u) | (new_r << 16) | new_b; |
| 930 } | 509 } |
| 931 } | 510 } |
| 932 | 511 |
| 933 static WEBP_INLINE void MultipliersClear(VP8LMultipliers* const m) { | 512 static WEBP_INLINE int ColorTransformDelta(int8_t color_pred, int8_t color) { |
| 934 m->green_to_red_ = 0; | 513 return ((int)color_pred * color) >> 5; |
| 935 m->green_to_blue_ = 0; | |
| 936 m->red_to_blue_ = 0; | |
| 937 } | |
| 938 | |
| 939 static WEBP_INLINE uint32_t ColorTransformDelta(int8_t color_pred, | |
| 940 int8_t color) { | |
| 941 return (uint32_t)((int)(color_pred) * color) >> 5; | |
| 942 } | |
| 943 | |
| 944 static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code, | |
| 945 VP8LMultipliers* const m) { | |
| 946 m->green_to_red_ = (color_code >> 0) & 0xff; | |
| 947 m->green_to_blue_ = (color_code >> 8) & 0xff; | |
| 948 m->red_to_blue_ = (color_code >> 16) & 0xff; | |
| 949 } | |
| 950 | |
| 951 static WEBP_INLINE uint32_t MultipliersToColorCode( | |
| 952 const VP8LMultipliers* const m) { | |
| 953 return 0xff000000u | | |
| 954 ((uint32_t)(m->red_to_blue_) << 16) | | |
| 955 ((uint32_t)(m->green_to_blue_) << 8) | | |
| 956 m->green_to_red_; | |
| 957 } | 514 } |
| 958 | 515 |
| 959 void VP8LTransformColor_C(const VP8LMultipliers* const m, uint32_t* data, | 516 void VP8LTransformColor_C(const VP8LMultipliers* const m, uint32_t* data, |
| 960 int num_pixels) { | 517 int num_pixels) { |
| 961 int i; | 518 int i; |
| 962 for (i = 0; i < num_pixels; ++i) { | 519 for (i = 0; i < num_pixels; ++i) { |
| 963 const uint32_t argb = data[i]; | 520 const uint32_t argb = data[i]; |
| 964 const uint32_t green = argb >> 8; | 521 const uint32_t green = argb >> 8; |
| 965 const uint32_t red = argb >> 16; | 522 const uint32_t red = argb >> 16; |
| 966 uint32_t new_red = red; | 523 int new_red = red; |
| 967 uint32_t new_blue = argb; | 524 int new_blue = argb; |
| 968 new_red -= ColorTransformDelta(m->green_to_red_, green); | 525 new_red -= ColorTransformDelta(m->green_to_red_, green); |
| 969 new_red &= 0xff; | 526 new_red &= 0xff; |
| 970 new_blue -= ColorTransformDelta(m->green_to_blue_, green); | 527 new_blue -= ColorTransformDelta(m->green_to_blue_, green); |
| 971 new_blue -= ColorTransformDelta(m->red_to_blue_, red); | 528 new_blue -= ColorTransformDelta(m->red_to_blue_, red); |
| 972 new_blue &= 0xff; | 529 new_blue &= 0xff; |
| 973 data[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue); | 530 data[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue); |
| 974 } | 531 } |
| 975 } | 532 } |
| 976 | 533 |
| 977 static WEBP_INLINE uint8_t TransformColorRed(uint8_t green_to_red, | 534 static WEBP_INLINE uint8_t TransformColorRed(uint8_t green_to_red, |
| 978 uint32_t argb) { | 535 uint32_t argb) { |
| 979 const uint32_t green = argb >> 8; | 536 const uint32_t green = argb >> 8; |
| 980 uint32_t new_red = argb >> 16; | 537 int new_red = argb >> 16; |
| 981 new_red -= ColorTransformDelta(green_to_red, green); | 538 new_red -= ColorTransformDelta(green_to_red, green); |
| 982 return (new_red & 0xff); | 539 return (new_red & 0xff); |
| 983 } | 540 } |
| 984 | 541 |
| 985 static WEBP_INLINE uint8_t TransformColorBlue(uint8_t green_to_blue, | 542 static WEBP_INLINE uint8_t TransformColorBlue(uint8_t green_to_blue, |
| 986 uint8_t red_to_blue, | 543 uint8_t red_to_blue, |
| 987 uint32_t argb) { | 544 uint32_t argb) { |
| 988 const uint32_t green = argb >> 8; | 545 const uint32_t green = argb >> 8; |
| 989 const uint32_t red = argb >> 16; | 546 const uint32_t red = argb >> 16; |
| 990 uint8_t new_blue = argb; | 547 uint8_t new_blue = argb; |
| 991 new_blue -= ColorTransformDelta(green_to_blue, green); | 548 new_blue -= ColorTransformDelta(green_to_blue, green); |
| 992 new_blue -= ColorTransformDelta(red_to_blue, red); | 549 new_blue -= ColorTransformDelta(red_to_blue, red); |
| 993 return (new_blue & 0xff); | 550 return (new_blue & 0xff); |
| 994 } | 551 } |
| 995 | 552 |
| 996 static float PredictionCostCrossColor(const int accumulated[256], | |
| 997 const int counts[256]) { | |
| 998 // Favor low entropy, locally and globally. | |
| 999 // Favor small absolute values for PredictionCostSpatial | |
| 1000 static const double kExpValue = 2.4; | |
| 1001 return VP8LCombinedShannonEntropy(counts, accumulated) + | |
| 1002 PredictionCostSpatial(counts, 3, kExpValue); | |
| 1003 } | |
| 1004 | |
| 1005 void VP8LCollectColorRedTransforms_C(const uint32_t* argb, int stride, | 553 void VP8LCollectColorRedTransforms_C(const uint32_t* argb, int stride, |
| 1006 int tile_width, int tile_height, | 554 int tile_width, int tile_height, |
| 1007 int green_to_red, int histo[]) { | 555 int green_to_red, int histo[]) { |
| 1008 while (tile_height-- > 0) { | 556 while (tile_height-- > 0) { |
| 1009 int x; | 557 int x; |
| 1010 for (x = 0; x < tile_width; ++x) { | 558 for (x = 0; x < tile_width; ++x) { |
| 1011 ++histo[TransformColorRed(green_to_red, argb[x])]; | 559 ++histo[TransformColorRed(green_to_red, argb[x])]; |
| 1012 } | 560 } |
| 1013 argb += stride; | 561 argb += stride; |
| 1014 } | 562 } |
| 1015 } | 563 } |
| 1016 | 564 |
| 1017 static float GetPredictionCostCrossColorRed( | |
| 1018 const uint32_t* argb, int stride, int tile_width, int tile_height, | |
| 1019 VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_red, | |
| 1020 const int accumulated_red_histo[256]) { | |
| 1021 int histo[256] = { 0 }; | |
| 1022 float cur_diff; | |
| 1023 | |
| 1024 VP8LCollectColorRedTransforms(argb, stride, tile_width, tile_height, | |
| 1025 green_to_red, histo); | |
| 1026 | |
| 1027 cur_diff = PredictionCostCrossColor(accumulated_red_histo, histo); | |
| 1028 if ((uint8_t)green_to_red == prev_x.green_to_red_) { | |
| 1029 cur_diff -= 3; // favor keeping the areas locally similar | |
| 1030 } | |
| 1031 if ((uint8_t)green_to_red == prev_y.green_to_red_) { | |
| 1032 cur_diff -= 3; // favor keeping the areas locally similar | |
| 1033 } | |
| 1034 if (green_to_red == 0) { | |
| 1035 cur_diff -= 3; | |
| 1036 } | |
| 1037 return cur_diff; | |
| 1038 } | |
| 1039 | |
| 1040 static void GetBestGreenToRed( | |
| 1041 const uint32_t* argb, int stride, int tile_width, int tile_height, | |
| 1042 VP8LMultipliers prev_x, VP8LMultipliers prev_y, int quality, | |
| 1043 const int accumulated_red_histo[256], VP8LMultipliers* const best_tx) { | |
| 1044 const int kMaxIters = 4 + ((7 * quality) >> 8); // in range [4..6] | |
| 1045 int green_to_red_best = 0; | |
| 1046 int iter, offset; | |
| 1047 float best_diff = GetPredictionCostCrossColorRed( | |
| 1048 argb, stride, tile_width, tile_height, prev_x, prev_y, | |
| 1049 green_to_red_best, accumulated_red_histo); | |
| 1050 for (iter = 0; iter < kMaxIters; ++iter) { | |
| 1051 // ColorTransformDelta is a 3.5 bit fixed point, so 32 is equal to | |
| 1052 // one in color computation. Having initial delta here as 1 is sufficient | |
| 1053 // to explore the range of (-2, 2). | |
| 1054 const int delta = 32 >> iter; | |
| 1055 // Try a negative and a positive delta from the best known value. | |
| 1056 for (offset = -delta; offset <= delta; offset += 2 * delta) { | |
| 1057 const int green_to_red_cur = offset + green_to_red_best; | |
| 1058 const float cur_diff = GetPredictionCostCrossColorRed( | |
| 1059 argb, stride, tile_width, tile_height, prev_x, prev_y, | |
| 1060 green_to_red_cur, accumulated_red_histo); | |
| 1061 if (cur_diff < best_diff) { | |
| 1062 best_diff = cur_diff; | |
| 1063 green_to_red_best = green_to_red_cur; | |
| 1064 } | |
| 1065 } | |
| 1066 } | |
| 1067 best_tx->green_to_red_ = green_to_red_best; | |
| 1068 } | |
| 1069 | |
| 1070 void VP8LCollectColorBlueTransforms_C(const uint32_t* argb, int stride, | 565 void VP8LCollectColorBlueTransforms_C(const uint32_t* argb, int stride, |
| 1071 int tile_width, int tile_height, | 566 int tile_width, int tile_height, |
| 1072 int green_to_blue, int red_to_blue, | 567 int green_to_blue, int red_to_blue, |
| 1073 int histo[]) { | 568 int histo[]) { |
| 1074 while (tile_height-- > 0) { | 569 while (tile_height-- > 0) { |
| 1075 int x; | 570 int x; |
| 1076 for (x = 0; x < tile_width; ++x) { | 571 for (x = 0; x < tile_width; ++x) { |
| 1077 ++histo[TransformColorBlue(green_to_blue, red_to_blue, argb[x])]; | 572 ++histo[TransformColorBlue(green_to_blue, red_to_blue, argb[x])]; |
| 1078 } | 573 } |
| 1079 argb += stride; | 574 argb += stride; |
| 1080 } | 575 } |
| 1081 } | 576 } |
| 1082 | 577 |
| 1083 static float GetPredictionCostCrossColorBlue( | |
| 1084 const uint32_t* argb, int stride, int tile_width, int tile_height, | |
| 1085 VP8LMultipliers prev_x, VP8LMultipliers prev_y, | |
| 1086 int green_to_blue, int red_to_blue, const int accumulated_blue_histo[256]) { | |
| 1087 int histo[256] = { 0 }; | |
| 1088 float cur_diff; | |
| 1089 | |
| 1090 VP8LCollectColorBlueTransforms(argb, stride, tile_width, tile_height, | |
| 1091 green_to_blue, red_to_blue, histo); | |
| 1092 | |
| 1093 cur_diff = PredictionCostCrossColor(accumulated_blue_histo, histo); | |
| 1094 if ((uint8_t)green_to_blue == prev_x.green_to_blue_) { | |
| 1095 cur_diff -= 3; // favor keeping the areas locally similar | |
| 1096 } | |
| 1097 if ((uint8_t)green_to_blue == prev_y.green_to_blue_) { | |
| 1098 cur_diff -= 3; // favor keeping the areas locally similar | |
| 1099 } | |
| 1100 if ((uint8_t)red_to_blue == prev_x.red_to_blue_) { | |
| 1101 cur_diff -= 3; // favor keeping the areas locally similar | |
| 1102 } | |
| 1103 if ((uint8_t)red_to_blue == prev_y.red_to_blue_) { | |
| 1104 cur_diff -= 3; // favor keeping the areas locally similar | |
| 1105 } | |
| 1106 if (green_to_blue == 0) { | |
| 1107 cur_diff -= 3; | |
| 1108 } | |
| 1109 if (red_to_blue == 0) { | |
| 1110 cur_diff -= 3; | |
| 1111 } | |
| 1112 return cur_diff; | |
| 1113 } | |
| 1114 | |
| 1115 #define kGreenRedToBlueNumAxis 8 | |
| 1116 #define kGreenRedToBlueMaxIters 7 | |
| 1117 static void GetBestGreenRedToBlue( | |
| 1118 const uint32_t* argb, int stride, int tile_width, int tile_height, | |
| 1119 VP8LMultipliers prev_x, VP8LMultipliers prev_y, int quality, | |
| 1120 const int accumulated_blue_histo[256], | |
| 1121 VP8LMultipliers* const best_tx) { | |
| 1122 const int8_t offset[kGreenRedToBlueNumAxis][2] = | |
| 1123 {{0, -1}, {0, 1}, {-1, 0}, {1, 0}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}}; | |
| 1124 const int8_t delta_lut[kGreenRedToBlueMaxIters] = { 16, 16, 8, 4, 2, 2, 2 }; | |
| 1125 const int iters = | |
| 1126 (quality < 25) ? 1 : (quality > 50) ? kGreenRedToBlueMaxIters : 4; | |
| 1127 int green_to_blue_best = 0; | |
| 1128 int red_to_blue_best = 0; | |
| 1129 int iter; | |
| 1130 // Initial value at origin: | |
| 1131 float best_diff = GetPredictionCostCrossColorBlue( | |
| 1132 argb, stride, tile_width, tile_height, prev_x, prev_y, | |
| 1133 green_to_blue_best, red_to_blue_best, accumulated_blue_histo); | |
| 1134 for (iter = 0; iter < iters; ++iter) { | |
| 1135 const int delta = delta_lut[iter]; | |
| 1136 int axis; | |
| 1137 for (axis = 0; axis < kGreenRedToBlueNumAxis; ++axis) { | |
| 1138 const int green_to_blue_cur = | |
| 1139 offset[axis][0] * delta + green_to_blue_best; | |
| 1140 const int red_to_blue_cur = offset[axis][1] * delta + red_to_blue_best; | |
| 1141 const float cur_diff = GetPredictionCostCrossColorBlue( | |
| 1142 argb, stride, tile_width, tile_height, prev_x, prev_y, | |
| 1143 green_to_blue_cur, red_to_blue_cur, accumulated_blue_histo); | |
| 1144 if (cur_diff < best_diff) { | |
| 1145 best_diff = cur_diff; | |
| 1146 green_to_blue_best = green_to_blue_cur; | |
| 1147 red_to_blue_best = red_to_blue_cur; | |
| 1148 } | |
| 1149 if (quality < 25 && iter == 4) { | |
| 1150 // Only axis aligned diffs for lower quality. | |
| 1151 break; // next iter. | |
| 1152 } | |
| 1153 } | |
| 1154 if (delta == 2 && green_to_blue_best == 0 && red_to_blue_best == 0) { | |
| 1155 // Further iterations would not help. | |
| 1156 break; // out of iter-loop. | |
| 1157 } | |
| 1158 } | |
| 1159 best_tx->green_to_blue_ = green_to_blue_best; | |
| 1160 best_tx->red_to_blue_ = red_to_blue_best; | |
| 1161 } | |
| 1162 #undef kGreenRedToBlueMaxIters | |
| 1163 #undef kGreenRedToBlueNumAxis | |
| 1164 | |
| 1165 static VP8LMultipliers GetBestColorTransformForTile( | |
| 1166 int tile_x, int tile_y, int bits, | |
| 1167 VP8LMultipliers prev_x, | |
| 1168 VP8LMultipliers prev_y, | |
| 1169 int quality, int xsize, int ysize, | |
| 1170 const int accumulated_red_histo[256], | |
| 1171 const int accumulated_blue_histo[256], | |
| 1172 const uint32_t* const argb) { | |
| 1173 const int max_tile_size = 1 << bits; | |
| 1174 const int tile_y_offset = tile_y * max_tile_size; | |
| 1175 const int tile_x_offset = tile_x * max_tile_size; | |
| 1176 const int all_x_max = GetMin(tile_x_offset + max_tile_size, xsize); | |
| 1177 const int all_y_max = GetMin(tile_y_offset + max_tile_size, ysize); | |
| 1178 const int tile_width = all_x_max - tile_x_offset; | |
| 1179 const int tile_height = all_y_max - tile_y_offset; | |
| 1180 const uint32_t* const tile_argb = argb + tile_y_offset * xsize | |
| 1181 + tile_x_offset; | |
| 1182 VP8LMultipliers best_tx; | |
| 1183 MultipliersClear(&best_tx); | |
| 1184 | |
| 1185 GetBestGreenToRed(tile_argb, xsize, tile_width, tile_height, | |
| 1186 prev_x, prev_y, quality, accumulated_red_histo, &best_tx); | |
| 1187 GetBestGreenRedToBlue(tile_argb, xsize, tile_width, tile_height, | |
| 1188 prev_x, prev_y, quality, accumulated_blue_histo, | |
| 1189 &best_tx); | |
| 1190 return best_tx; | |
| 1191 } | |
| 1192 | |
| 1193 static void CopyTileWithColorTransform(int xsize, int ysize, | |
| 1194 int tile_x, int tile_y, | |
| 1195 int max_tile_size, | |
| 1196 VP8LMultipliers color_transform, | |
| 1197 uint32_t* argb) { | |
| 1198 const int xscan = GetMin(max_tile_size, xsize - tile_x); | |
| 1199 int yscan = GetMin(max_tile_size, ysize - tile_y); | |
| 1200 argb += tile_y * xsize + tile_x; | |
| 1201 while (yscan-- > 0) { | |
| 1202 VP8LTransformColor(&color_transform, argb, xscan); | |
| 1203 argb += xsize; | |
| 1204 } | |
| 1205 } | |
| 1206 | |
| 1207 void VP8LColorSpaceTransform(int width, int height, int bits, int quality, | |
| 1208 uint32_t* const argb, uint32_t* image) { | |
| 1209 const int max_tile_size = 1 << bits; | |
| 1210 const int tile_xsize = VP8LSubSampleSize(width, bits); | |
| 1211 const int tile_ysize = VP8LSubSampleSize(height, bits); | |
| 1212 int accumulated_red_histo[256] = { 0 }; | |
| 1213 int accumulated_blue_histo[256] = { 0 }; | |
| 1214 int tile_x, tile_y; | |
| 1215 VP8LMultipliers prev_x, prev_y; | |
| 1216 MultipliersClear(&prev_y); | |
| 1217 MultipliersClear(&prev_x); | |
| 1218 for (tile_y = 0; tile_y < tile_ysize; ++tile_y) { | |
| 1219 for (tile_x = 0; tile_x < tile_xsize; ++tile_x) { | |
| 1220 int y; | |
| 1221 const int tile_x_offset = tile_x * max_tile_size; | |
| 1222 const int tile_y_offset = tile_y * max_tile_size; | |
| 1223 const int all_x_max = GetMin(tile_x_offset + max_tile_size, width); | |
| 1224 const int all_y_max = GetMin(tile_y_offset + max_tile_size, height); | |
| 1225 const int offset = tile_y * tile_xsize + tile_x; | |
| 1226 if (tile_y != 0) { | |
| 1227 ColorCodeToMultipliers(image[offset - tile_xsize], &prev_y); | |
| 1228 } | |
| 1229 prev_x = GetBestColorTransformForTile(tile_x, tile_y, bits, | |
| 1230 prev_x, prev_y, | |
| 1231 quality, width, height, | |
| 1232 accumulated_red_histo, | |
| 1233 accumulated_blue_histo, | |
| 1234 argb); | |
| 1235 image[offset] = MultipliersToColorCode(&prev_x); | |
| 1236 CopyTileWithColorTransform(width, height, tile_x_offset, tile_y_offset, | |
| 1237 max_tile_size, prev_x, argb); | |
| 1238 | |
| 1239 // Gather accumulated histogram data. | |
| 1240 for (y = tile_y_offset; y < all_y_max; ++y) { | |
| 1241 int ix = y * width + tile_x_offset; | |
| 1242 const int ix_end = ix + all_x_max - tile_x_offset; | |
| 1243 for (; ix < ix_end; ++ix) { | |
| 1244 const uint32_t pix = argb[ix]; | |
| 1245 if (ix >= 2 && | |
| 1246 pix == argb[ix - 2] && | |
| 1247 pix == argb[ix - 1]) { | |
| 1248 continue; // repeated pixels are handled by backward references | |
| 1249 } | |
| 1250 if (ix >= width + 2 && | |
| 1251 argb[ix - 2] == argb[ix - width - 2] && | |
| 1252 argb[ix - 1] == argb[ix - width - 1] && | |
| 1253 pix == argb[ix - width]) { | |
| 1254 continue; // repeated pixels are handled by backward references | |
| 1255 } | |
| 1256 ++accumulated_red_histo[(pix >> 16) & 0xff]; | |
| 1257 ++accumulated_blue_histo[(pix >> 0) & 0xff]; | |
| 1258 } | |
| 1259 } | |
| 1260 } | |
| 1261 } | |
| 1262 } | |
| 1263 | |
| 1264 //------------------------------------------------------------------------------ | 578 //------------------------------------------------------------------------------ |
| 1265 | 579 |
| 1266 static int VectorMismatch(const uint32_t* const array1, | 580 static int VectorMismatch(const uint32_t* const array1, |
| 1267 const uint32_t* const array2, int length) { | 581 const uint32_t* const array2, int length) { |
| 1268 int match_len = 0; | 582 int match_len = 0; |
| 1269 | 583 |
| 1270 while (match_len < length && array1[match_len] == array2[match_len]) { | 584 while (match_len < length && array1[match_len] == array2[match_len]) { |
| 1271 ++match_len; | 585 ++match_len; |
| 1272 } | 586 } |
| 1273 return match_len; | 587 return match_len; |
| 1274 } | 588 } |
| 1275 | 589 |
| 1276 // Bundles multiple (1, 2, 4 or 8) pixels into a single pixel. | 590 // Bundles multiple (1, 2, 4 or 8) pixels into a single pixel. |
| 1277 void VP8LBundleColorMap(const uint8_t* const row, int width, | 591 void VP8LBundleColorMap_C(const uint8_t* const row, int width, int xbits, |
| 1278 int xbits, uint32_t* const dst) { | 592 uint32_t* dst) { |
| 1279 int x; | 593 int x; |
| 1280 if (xbits > 0) { | 594 if (xbits > 0) { |
| 1281 const int bit_depth = 1 << (3 - xbits); | 595 const int bit_depth = 1 << (3 - xbits); |
| 1282 const int mask = (1 << xbits) - 1; | 596 const int mask = (1 << xbits) - 1; |
| 1283 uint32_t code = 0xff000000; | 597 uint32_t code = 0xff000000; |
| 1284 for (x = 0; x < width; ++x) { | 598 for (x = 0; x < width; ++x) { |
| 1285 const int xsub = x & mask; | 599 const int xsub = x & mask; |
| 1286 if (xsub == 0) { | 600 if (xsub == 0) { |
| 1287 code = 0xff000000; | 601 code = 0xff000000; |
| 1288 } | 602 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1343 } | 657 } |
| 1344 for (i = 0; i < NUM_LITERAL_CODES; ++i) { | 658 for (i = 0; i < NUM_LITERAL_CODES; ++i) { |
| 1345 out->red_[i] += a->red_[i]; | 659 out->red_[i] += a->red_[i]; |
| 1346 out->blue_[i] += a->blue_[i]; | 660 out->blue_[i] += a->blue_[i]; |
| 1347 out->alpha_[i] += a->alpha_[i]; | 661 out->alpha_[i] += a->alpha_[i]; |
| 1348 } | 662 } |
| 1349 } | 663 } |
| 1350 } | 664 } |
| 1351 | 665 |
| 1352 //------------------------------------------------------------------------------ | 666 //------------------------------------------------------------------------------ |
| 667 // Image transforms. |
| 668 |
| 669 static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) { |
| 670 return (((a0 ^ a1) & 0xfefefefeu) >> 1) + (a0 & a1); |
| 671 } |
| 672 |
| 673 static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) { |
| 674 return Average2(Average2(a0, a2), a1); |
| 675 } |
| 676 |
| 677 static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1, |
| 678 uint32_t a2, uint32_t a3) { |
| 679 return Average2(Average2(a0, a1), Average2(a2, a3)); |
| 680 } |
| 681 |
| 682 static WEBP_INLINE uint32_t Clip255(uint32_t a) { |
| 683 if (a < 256) { |
| 684 return a; |
| 685 } |
| 686 // return 0, when a is a negative integer. |
| 687 // return 255, when a is positive. |
| 688 return ~a >> 24; |
| 689 } |
| 690 |
| 691 static WEBP_INLINE int AddSubtractComponentFull(int a, int b, int c) { |
| 692 return Clip255(a + b - c); |
| 693 } |
| 694 |
| 695 static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1, |
| 696 uint32_t c2) { |
| 697 const int a = AddSubtractComponentFull(c0 >> 24, c1 >> 24, c2 >> 24); |
| 698 const int r = AddSubtractComponentFull((c0 >> 16) & 0xff, |
| 699 (c1 >> 16) & 0xff, |
| 700 (c2 >> 16) & 0xff); |
| 701 const int g = AddSubtractComponentFull((c0 >> 8) & 0xff, |
| 702 (c1 >> 8) & 0xff, |
| 703 (c2 >> 8) & 0xff); |
| 704 const int b = AddSubtractComponentFull(c0 & 0xff, c1 & 0xff, c2 & 0xff); |
| 705 return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b; |
| 706 } |
| 707 |
| 708 static WEBP_INLINE int AddSubtractComponentHalf(int a, int b) { |
| 709 return Clip255(a + (a - b) / 2); |
| 710 } |
| 711 |
| 712 static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1, |
| 713 uint32_t c2) { |
| 714 const uint32_t ave = Average2(c0, c1); |
| 715 const int a = AddSubtractComponentHalf(ave >> 24, c2 >> 24); |
| 716 const int r = AddSubtractComponentHalf((ave >> 16) & 0xff, (c2 >> 16) & 0xff); |
| 717 const int g = AddSubtractComponentHalf((ave >> 8) & 0xff, (c2 >> 8) & 0xff); |
| 718 const int b = AddSubtractComponentHalf((ave >> 0) & 0xff, (c2 >> 0) & 0xff); |
| 719 return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b; |
| 720 } |
| 721 |
| 722 // gcc-4.9 on ARM generates incorrect code in Select() when Sub3() is inlined. |
| 723 #if defined(__arm__) && \ |
| 724 (LOCAL_GCC_VERSION == 0x409 || LOCAL_GCC_VERSION == 0x408) |
| 725 # define LOCAL_INLINE __attribute__ ((noinline)) |
| 726 #else |
| 727 # define LOCAL_INLINE WEBP_INLINE |
| 728 #endif |
| 729 |
| 730 static LOCAL_INLINE int Sub3(int a, int b, int c) { |
| 731 const int pb = b - c; |
| 732 const int pa = a - c; |
| 733 return abs(pb) - abs(pa); |
| 734 } |
| 735 |
| 736 #undef LOCAL_INLINE |
| 737 |
| 738 static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) { |
| 739 const int pa_minus_pb = |
| 740 Sub3((a >> 24) , (b >> 24) , (c >> 24) ) + |
| 741 Sub3((a >> 16) & 0xff, (b >> 16) & 0xff, (c >> 16) & 0xff) + |
| 742 Sub3((a >> 8) & 0xff, (b >> 8) & 0xff, (c >> 8) & 0xff) + |
| 743 Sub3((a ) & 0xff, (b ) & 0xff, (c ) & 0xff); |
| 744 return (pa_minus_pb <= 0) ? a : b; |
| 745 } |
| 746 |
| 747 //------------------------------------------------------------------------------ |
| 748 // Predictors |
| 749 |
| 750 static uint32_t Predictor2(uint32_t left, const uint32_t* const top) { |
| 751 (void)left; |
| 752 return top[0]; |
| 753 } |
| 754 static uint32_t Predictor3(uint32_t left, const uint32_t* const top) { |
| 755 (void)left; |
| 756 return top[1]; |
| 757 } |
| 758 static uint32_t Predictor4(uint32_t left, const uint32_t* const top) { |
| 759 (void)left; |
| 760 return top[-1]; |
| 761 } |
| 762 static uint32_t Predictor5(uint32_t left, const uint32_t* const top) { |
| 763 const uint32_t pred = Average3(left, top[0], top[1]); |
| 764 return pred; |
| 765 } |
| 766 static uint32_t Predictor6(uint32_t left, const uint32_t* const top) { |
| 767 const uint32_t pred = Average2(left, top[-1]); |
| 768 return pred; |
| 769 } |
| 770 static uint32_t Predictor7(uint32_t left, const uint32_t* const top) { |
| 771 const uint32_t pred = Average2(left, top[0]); |
| 772 return pred; |
| 773 } |
| 774 static uint32_t Predictor8(uint32_t left, const uint32_t* const top) { |
| 775 const uint32_t pred = Average2(top[-1], top[0]); |
| 776 (void)left; |
| 777 return pred; |
| 778 } |
| 779 static uint32_t Predictor9(uint32_t left, const uint32_t* const top) { |
| 780 const uint32_t pred = Average2(top[0], top[1]); |
| 781 (void)left; |
| 782 return pred; |
| 783 } |
| 784 static uint32_t Predictor10(uint32_t left, const uint32_t* const top) { |
| 785 const uint32_t pred = Average4(left, top[-1], top[0], top[1]); |
| 786 return pred; |
| 787 } |
| 788 static uint32_t Predictor11(uint32_t left, const uint32_t* const top) { |
| 789 const uint32_t pred = Select(top[0], left, top[-1]); |
| 790 return pred; |
| 791 } |
| 792 static uint32_t Predictor12(uint32_t left, const uint32_t* const top) { |
| 793 const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]); |
| 794 return pred; |
| 795 } |
| 796 static uint32_t Predictor13(uint32_t left, const uint32_t* const top) { |
| 797 const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]); |
| 798 return pred; |
| 799 } |
| 800 |
| 801 //------------------------------------------------------------------------------ |
| 1353 | 802 |
| 1354 VP8LProcessBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed; | 803 static void PredictorSub0_C(const uint32_t* in, const uint32_t* upper, |
| 804 int num_pixels, uint32_t* out) { |
| 805 int i; |
| 806 for (i = 0; i < num_pixels; ++i) out[i] = VP8LSubPixels(in[i], ARGB_BLACK); |
| 807 (void)upper; |
| 808 } |
| 809 |
| 810 static void PredictorSub1_C(const uint32_t* in, const uint32_t* upper, |
| 811 int num_pixels, uint32_t* out) { |
| 812 int i; |
| 813 for (i = 0; i < num_pixels; ++i) out[i] = VP8LSubPixels(in[i], in[i - 1]); |
| 814 (void)upper; |
| 815 } |
| 816 |
| 817 GENERATE_PREDICTOR_SUB(Predictor2, PredictorSub2_C) |
| 818 GENERATE_PREDICTOR_SUB(Predictor3, PredictorSub3_C) |
| 819 GENERATE_PREDICTOR_SUB(Predictor4, PredictorSub4_C) |
| 820 GENERATE_PREDICTOR_SUB(Predictor5, PredictorSub5_C) |
| 821 GENERATE_PREDICTOR_SUB(Predictor6, PredictorSub6_C) |
| 822 GENERATE_PREDICTOR_SUB(Predictor7, PredictorSub7_C) |
| 823 GENERATE_PREDICTOR_SUB(Predictor8, PredictorSub8_C) |
| 824 GENERATE_PREDICTOR_SUB(Predictor9, PredictorSub9_C) |
| 825 GENERATE_PREDICTOR_SUB(Predictor10, PredictorSub10_C) |
| 826 GENERATE_PREDICTOR_SUB(Predictor11, PredictorSub11_C) |
| 827 GENERATE_PREDICTOR_SUB(Predictor12, PredictorSub12_C) |
| 828 GENERATE_PREDICTOR_SUB(Predictor13, PredictorSub13_C) |
| 829 |
| 830 //------------------------------------------------------------------------------ |
| 831 |
| 832 VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed; |
| 1355 | 833 |
| 1356 VP8LTransformColorFunc VP8LTransformColor; | 834 VP8LTransformColorFunc VP8LTransformColor; |
| 1357 | 835 |
| 1358 VP8LCollectColorBlueTransformsFunc VP8LCollectColorBlueTransforms; | 836 VP8LCollectColorBlueTransformsFunc VP8LCollectColorBlueTransforms; |
| 1359 VP8LCollectColorRedTransformsFunc VP8LCollectColorRedTransforms; | 837 VP8LCollectColorRedTransformsFunc VP8LCollectColorRedTransforms; |
| 1360 | 838 |
| 1361 VP8LFastLog2SlowFunc VP8LFastLog2Slow; | 839 VP8LFastLog2SlowFunc VP8LFastLog2Slow; |
| 1362 VP8LFastLog2SlowFunc VP8LFastSLog2Slow; | 840 VP8LFastLog2SlowFunc VP8LFastSLog2Slow; |
| 1363 | 841 |
| 1364 VP8LCostFunc VP8LExtraCost; | 842 VP8LCostFunc VP8LExtraCost; |
| 1365 VP8LCostCombinedFunc VP8LExtraCostCombined; | 843 VP8LCostCombinedFunc VP8LExtraCostCombined; |
| 1366 VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy; | 844 VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy; |
| 1367 | 845 |
| 1368 GetEntropyUnrefinedHelperFunc VP8LGetEntropyUnrefinedHelper; | 846 VP8LGetEntropyUnrefinedFunc VP8LGetEntropyUnrefined; |
| 847 VP8LGetCombinedEntropyUnrefinedFunc VP8LGetCombinedEntropyUnrefined; |
| 1369 | 848 |
| 1370 VP8LHistogramAddFunc VP8LHistogramAdd; | 849 VP8LHistogramAddFunc VP8LHistogramAdd; |
| 1371 | 850 |
| 1372 VP8LVectorMismatchFunc VP8LVectorMismatch; | 851 VP8LVectorMismatchFunc VP8LVectorMismatch; |
| 852 VP8LBundleColorMapFunc VP8LBundleColorMap; |
| 853 |
| 854 VP8LPredictorAddSubFunc VP8LPredictorsSub[16]; |
| 855 VP8LPredictorAddSubFunc VP8LPredictorsSub_C[16]; |
| 1373 | 856 |
| 1374 extern void VP8LEncDspInitSSE2(void); | 857 extern void VP8LEncDspInitSSE2(void); |
| 1375 extern void VP8LEncDspInitSSE41(void); | 858 extern void VP8LEncDspInitSSE41(void); |
| 1376 extern void VP8LEncDspInitNEON(void); | 859 extern void VP8LEncDspInitNEON(void); |
| 1377 extern void VP8LEncDspInitMIPS32(void); | 860 extern void VP8LEncDspInitMIPS32(void); |
| 1378 extern void VP8LEncDspInitMIPSdspR2(void); | 861 extern void VP8LEncDspInitMIPSdspR2(void); |
| 862 extern void VP8LEncDspInitMSA(void); |
| 1379 | 863 |
| 1380 static volatile VP8CPUInfo lossless_enc_last_cpuinfo_used = | 864 static volatile VP8CPUInfo lossless_enc_last_cpuinfo_used = |
| 1381 (VP8CPUInfo)&lossless_enc_last_cpuinfo_used; | 865 (VP8CPUInfo)&lossless_enc_last_cpuinfo_used; |
| 1382 | 866 |
| 1383 WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInit(void) { | 867 WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInit(void) { |
| 1384 if (lossless_enc_last_cpuinfo_used == VP8GetCPUInfo) return; | 868 if (lossless_enc_last_cpuinfo_used == VP8GetCPUInfo) return; |
| 1385 | 869 |
| 1386 VP8LDspInit(); | 870 VP8LDspInit(); |
| 1387 | 871 |
| 1388 VP8LSubtractGreenFromBlueAndRed = VP8LSubtractGreenFromBlueAndRed_C; | 872 VP8LSubtractGreenFromBlueAndRed = VP8LSubtractGreenFromBlueAndRed_C; |
| 1389 | 873 |
| 1390 VP8LTransformColor = VP8LTransformColor_C; | 874 VP8LTransformColor = VP8LTransformColor_C; |
| 1391 | 875 |
| 1392 VP8LCollectColorBlueTransforms = VP8LCollectColorBlueTransforms_C; | 876 VP8LCollectColorBlueTransforms = VP8LCollectColorBlueTransforms_C; |
| 1393 VP8LCollectColorRedTransforms = VP8LCollectColorRedTransforms_C; | 877 VP8LCollectColorRedTransforms = VP8LCollectColorRedTransforms_C; |
| 1394 | 878 |
| 1395 VP8LFastLog2Slow = FastLog2Slow; | 879 VP8LFastLog2Slow = FastLog2Slow; |
| 1396 VP8LFastSLog2Slow = FastSLog2Slow; | 880 VP8LFastSLog2Slow = FastSLog2Slow; |
| 1397 | 881 |
| 1398 VP8LExtraCost = ExtraCost; | 882 VP8LExtraCost = ExtraCost; |
| 1399 VP8LExtraCostCombined = ExtraCostCombined; | 883 VP8LExtraCostCombined = ExtraCostCombined; |
| 1400 VP8LCombinedShannonEntropy = CombinedShannonEntropy; | 884 VP8LCombinedShannonEntropy = CombinedShannonEntropy; |
| 1401 | 885 |
| 1402 VP8LGetEntropyUnrefinedHelper = GetEntropyUnrefinedHelper; | 886 VP8LGetEntropyUnrefined = GetEntropyUnrefined; |
| 887 VP8LGetCombinedEntropyUnrefined = GetCombinedEntropyUnrefined; |
| 1403 | 888 |
| 1404 VP8LHistogramAdd = HistogramAdd; | 889 VP8LHistogramAdd = HistogramAdd; |
| 1405 | 890 |
| 1406 VP8LVectorMismatch = VectorMismatch; | 891 VP8LVectorMismatch = VectorMismatch; |
| 892 VP8LBundleColorMap = VP8LBundleColorMap_C; |
| 893 |
| 894 VP8LPredictorsSub[0] = PredictorSub0_C; |
| 895 VP8LPredictorsSub[1] = PredictorSub1_C; |
| 896 VP8LPredictorsSub[2] = PredictorSub2_C; |
| 897 VP8LPredictorsSub[3] = PredictorSub3_C; |
| 898 VP8LPredictorsSub[4] = PredictorSub4_C; |
| 899 VP8LPredictorsSub[5] = PredictorSub5_C; |
| 900 VP8LPredictorsSub[6] = PredictorSub6_C; |
| 901 VP8LPredictorsSub[7] = PredictorSub7_C; |
| 902 VP8LPredictorsSub[8] = PredictorSub8_C; |
| 903 VP8LPredictorsSub[9] = PredictorSub9_C; |
| 904 VP8LPredictorsSub[10] = PredictorSub10_C; |
| 905 VP8LPredictorsSub[11] = PredictorSub11_C; |
| 906 VP8LPredictorsSub[12] = PredictorSub12_C; |
| 907 VP8LPredictorsSub[13] = PredictorSub13_C; |
| 908 VP8LPredictorsSub[14] = PredictorSub0_C; // <- padding security sentinels |
| 909 VP8LPredictorsSub[15] = PredictorSub0_C; |
| 910 |
| 911 VP8LPredictorsSub_C[0] = PredictorSub0_C; |
| 912 VP8LPredictorsSub_C[1] = PredictorSub1_C; |
| 913 VP8LPredictorsSub_C[2] = PredictorSub2_C; |
| 914 VP8LPredictorsSub_C[3] = PredictorSub3_C; |
| 915 VP8LPredictorsSub_C[4] = PredictorSub4_C; |
| 916 VP8LPredictorsSub_C[5] = PredictorSub5_C; |
| 917 VP8LPredictorsSub_C[6] = PredictorSub6_C; |
| 918 VP8LPredictorsSub_C[7] = PredictorSub7_C; |
| 919 VP8LPredictorsSub_C[8] = PredictorSub8_C; |
| 920 VP8LPredictorsSub_C[9] = PredictorSub9_C; |
| 921 VP8LPredictorsSub_C[10] = PredictorSub10_C; |
| 922 VP8LPredictorsSub_C[11] = PredictorSub11_C; |
| 923 VP8LPredictorsSub_C[12] = PredictorSub12_C; |
| 924 VP8LPredictorsSub_C[13] = PredictorSub13_C; |
| 925 VP8LPredictorsSub_C[14] = PredictorSub0_C; // <- padding security sentinels |
| 926 VP8LPredictorsSub_C[15] = PredictorSub0_C; |
| 1407 | 927 |
| 1408 // If defined, use CPUInfo() to overwrite some pointers with faster versions. | 928 // If defined, use CPUInfo() to overwrite some pointers with faster versions. |
| 1409 if (VP8GetCPUInfo != NULL) { | 929 if (VP8GetCPUInfo != NULL) { |
| 1410 #if defined(WEBP_USE_SSE2) | 930 #if defined(WEBP_USE_SSE2) |
| 1411 if (VP8GetCPUInfo(kSSE2)) { | 931 if (VP8GetCPUInfo(kSSE2)) { |
| 1412 VP8LEncDspInitSSE2(); | 932 VP8LEncDspInitSSE2(); |
| 1413 #if defined(WEBP_USE_SSE41) | 933 #if defined(WEBP_USE_SSE41) |
| 1414 if (VP8GetCPUInfo(kSSE4_1)) { | 934 if (VP8GetCPUInfo(kSSE4_1)) { |
| 1415 VP8LEncDspInitSSE41(); | 935 VP8LEncDspInitSSE41(); |
| 1416 } | 936 } |
| 1417 #endif | 937 #endif |
| 1418 } | 938 } |
| 1419 #endif | 939 #endif |
| 1420 #if defined(WEBP_USE_NEON) | 940 #if defined(WEBP_USE_NEON) |
| 1421 if (VP8GetCPUInfo(kNEON)) { | 941 if (VP8GetCPUInfo(kNEON)) { |
| 1422 VP8LEncDspInitNEON(); | 942 VP8LEncDspInitNEON(); |
| 1423 } | 943 } |
| 1424 #endif | 944 #endif |
| 1425 #if defined(WEBP_USE_MIPS32) | 945 #if defined(WEBP_USE_MIPS32) |
| 1426 if (VP8GetCPUInfo(kMIPS32)) { | 946 if (VP8GetCPUInfo(kMIPS32)) { |
| 1427 VP8LEncDspInitMIPS32(); | 947 VP8LEncDspInitMIPS32(); |
| 1428 } | 948 } |
| 1429 #endif | 949 #endif |
| 1430 #if defined(WEBP_USE_MIPS_DSP_R2) | 950 #if defined(WEBP_USE_MIPS_DSP_R2) |
| 1431 if (VP8GetCPUInfo(kMIPSdspR2)) { | 951 if (VP8GetCPUInfo(kMIPSdspR2)) { |
| 1432 VP8LEncDspInitMIPSdspR2(); | 952 VP8LEncDspInitMIPSdspR2(); |
| 1433 } | 953 } |
| 1434 #endif | 954 #endif |
| 955 #if defined(WEBP_USE_MSA) |
| 956 if (VP8GetCPUInfo(kMSA)) { |
| 957 VP8LEncDspInitMSA(); |
| 958 } |
| 959 #endif |
| 1435 } | 960 } |
| 1436 lossless_enc_last_cpuinfo_used = VP8GetCPUInfo; | 961 lossless_enc_last_cpuinfo_used = VP8GetCPUInfo; |
| 1437 } | 962 } |
| 1438 | 963 |
| 1439 //------------------------------------------------------------------------------ | 964 //------------------------------------------------------------------------------ |
| OLD | NEW |