Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: third_party/libwebp/dsp/lossless_enc.c

Issue 2651883004: libwebp-0.6.0-rc1 (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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 //------------------------------------------------------------------------------
OLDNEW
« no previous file with comments | « third_party/libwebp/dsp/lossless_common.h ('k') | third_party/libwebp/dsp/lossless_enc_mips32.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698