OLD | NEW |
1 // Copyright 2012 Google Inc. All Rights Reserved. | 1 // Copyright 2012 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 // Author: Jyrki Alakuijala (jyrki@google.com) | 10 // Author: Jyrki Alakuijala (jyrki@google.com) |
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
379 alpha_cost + distance_cost; | 379 alpha_cost + distance_cost; |
380 if ((alpha_sym | red_sym | blue_sym) == VP8L_NON_TRIVIAL_SYM) { | 380 if ((alpha_sym | red_sym | blue_sym) == VP8L_NON_TRIVIAL_SYM) { |
381 h->trivial_symbol_ = VP8L_NON_TRIVIAL_SYM; | 381 h->trivial_symbol_ = VP8L_NON_TRIVIAL_SYM; |
382 } else { | 382 } else { |
383 h->trivial_symbol_ = | 383 h->trivial_symbol_ = |
384 ((uint32_t)alpha_sym << 24) | (red_sym << 16) | (blue_sym << 0); | 384 ((uint32_t)alpha_sym << 24) | (red_sym << 16) | (blue_sym << 0); |
385 } | 385 } |
386 } | 386 } |
387 | 387 |
388 static int GetBinIdForEntropy(double min, double max, double val) { | 388 static int GetBinIdForEntropy(double min, double max, double val) { |
389 const double range = max - min + 1e-6; | 389 const double range = max - min; |
390 const double delta = val - min; | 390 if (range > 0.) { |
391 return (int)(NUM_PARTITIONS * delta / range); | 391 const double delta = val - min; |
| 392 return (int)((NUM_PARTITIONS - 1e-6) * delta / range); |
| 393 } else { |
| 394 return 0; |
| 395 } |
392 } | 396 } |
393 | 397 |
394 static int GetHistoBinIndexLowEffort( | 398 static int GetHistoBinIndex(const VP8LHistogram* const h, |
395 const VP8LHistogram* const h, const DominantCostRange* const c) { | 399 const DominantCostRange* const c, int low_effort) { |
396 const int bin_id = GetBinIdForEntropy(c->literal_min_, c->literal_max_, | 400 int bin_id = GetBinIdForEntropy(c->literal_min_, c->literal_max_, |
397 h->literal_cost_); | 401 h->literal_cost_); |
398 assert(bin_id < NUM_PARTITIONS); | 402 assert(bin_id < NUM_PARTITIONS); |
| 403 if (!low_effort) { |
| 404 bin_id = bin_id * NUM_PARTITIONS |
| 405 + GetBinIdForEntropy(c->red_min_, c->red_max_, h->red_cost_); |
| 406 bin_id = bin_id * NUM_PARTITIONS |
| 407 + GetBinIdForEntropy(c->blue_min_, c->blue_max_, h->blue_cost_); |
| 408 assert(bin_id < BIN_SIZE); |
| 409 } |
399 return bin_id; | 410 return bin_id; |
400 } | 411 } |
401 | 412 |
402 static int GetHistoBinIndex( | |
403 const VP8LHistogram* const h, const DominantCostRange* const c) { | |
404 const int bin_id = | |
405 GetBinIdForEntropy(c->blue_min_, c->blue_max_, h->blue_cost_) + | |
406 NUM_PARTITIONS * GetBinIdForEntropy(c->red_min_, c->red_max_, | |
407 h->red_cost_) + | |
408 NUM_PARTITIONS * NUM_PARTITIONS * GetBinIdForEntropy(c->literal_min_, | |
409 c->literal_max_, | |
410 h->literal_cost_); | |
411 assert(bin_id < BIN_SIZE); | |
412 return bin_id; | |
413 } | |
414 | |
415 // Construct the histograms from backward references. | 413 // Construct the histograms from backward references. |
416 static void HistogramBuild( | 414 static void HistogramBuild( |
417 int xsize, int histo_bits, const VP8LBackwardRefs* const backward_refs, | 415 int xsize, int histo_bits, const VP8LBackwardRefs* const backward_refs, |
418 VP8LHistogramSet* const image_histo) { | 416 VP8LHistogramSet* const image_histo) { |
419 int x = 0, y = 0; | 417 int x = 0, y = 0; |
420 const int histo_xsize = VP8LSubSampleSize(xsize, histo_bits); | 418 const int histo_xsize = VP8LSubSampleSize(xsize, histo_bits); |
421 VP8LHistogram** const histograms = image_histo->histograms; | 419 VP8LHistogram** const histograms = image_histo->histograms; |
422 VP8LRefsCursor c = VP8LRefsCursorInit(backward_refs); | 420 VP8LRefsCursor c = VP8LRefsCursorInit(backward_refs); |
423 assert(histo_bits > 0); | 421 assert(histo_bits > 0); |
424 while (VP8LRefsCursorOk(&c)) { | 422 while (VP8LRefsCursorOk(&c)) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 | 460 |
463 // Analyze the dominant (literal, red and blue) entropy costs. | 461 // Analyze the dominant (literal, red and blue) entropy costs. |
464 for (i = 0; i < histo_size; ++i) { | 462 for (i = 0; i < histo_size; ++i) { |
465 VP8LHistogram* const histo = histograms[i]; | 463 VP8LHistogram* const histo = histograms[i]; |
466 UpdateDominantCostRange(histo, &cost_range); | 464 UpdateDominantCostRange(histo, &cost_range); |
467 } | 465 } |
468 | 466 |
469 // bin-hash histograms on three of the dominant (literal, red and blue) | 467 // bin-hash histograms on three of the dominant (literal, red and blue) |
470 // symbol costs. | 468 // symbol costs. |
471 for (i = 0; i < histo_size; ++i) { | 469 for (i = 0; i < histo_size; ++i) { |
472 int num_histos; | 470 const VP8LHistogram* const histo = histograms[i]; |
473 VP8LHistogram* const histo = histograms[i]; | 471 const int bin_id = GetHistoBinIndex(histo, &cost_range, low_effort); |
474 const int16_t bin_id = low_effort ? | |
475 (int16_t)GetHistoBinIndexLowEffort(histo, &cost_range) : | |
476 (int16_t)GetHistoBinIndex(histo, &cost_range); | |
477 const int bin_offset = bin_id * bin_depth; | 472 const int bin_offset = bin_id * bin_depth; |
478 // bin_map[n][0] for every bin 'n' maintains the counter for the number of | 473 // bin_map[n][0] for every bin 'n' maintains the counter for the number of |
479 // histograms in that bin. | 474 // histograms in that bin. |
480 // Get and increment the num_histos in that bin. | 475 // Get and increment the num_histos in that bin. |
481 num_histos = ++bin_map[bin_offset]; | 476 const int num_histos = ++bin_map[bin_offset]; |
482 assert(bin_offset + num_histos < bin_depth * BIN_SIZE); | 477 assert(bin_offset + num_histos < bin_depth * BIN_SIZE); |
483 // Add histogram i'th index at num_histos (last) position in the bin_map. | 478 // Add histogram i'th index at num_histos (last) position in the bin_map. |
484 bin_map[bin_offset + num_histos] = i; | 479 bin_map[bin_offset + num_histos] = i; |
485 } | 480 } |
486 } | 481 } |
487 | 482 |
488 // Compact the histogram set by removing unused entries. | 483 // Compact the histogram set by removing unused entries. |
489 static void HistogramCompactBins(VP8LHistogramSet* const image_histo) { | 484 static void HistogramCompactBins(VP8LHistogramSet* const image_histo) { |
490 VP8LHistogram** const histograms = image_histo->histograms; | 485 VP8LHistogram** const histograms = image_histo->histograms; |
491 int i, j; | 486 int i, j; |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
629 | 624 |
630 // We cannot add more elements than the capacity. | 625 // We cannot add more elements than the capacity. |
631 // The allocation adds an extra element to the official capacity so that | 626 // The allocation adds an extra element to the official capacity so that |
632 // histo_queue->queue[histo_queue->max_size] is read/written within bound. | 627 // histo_queue->queue[histo_queue->max_size] is read/written within bound. |
633 assert(histo_queue->size <= histo_queue->max_size); | 628 assert(histo_queue->size <= histo_queue->max_size); |
634 } | 629 } |
635 | 630 |
636 // ----------------------------------------------------------------------------- | 631 // ----------------------------------------------------------------------------- |
637 | 632 |
638 static void PreparePair(VP8LHistogram** histograms, int idx1, int idx2, | 633 static void PreparePair(VP8LHistogram** histograms, int idx1, int idx2, |
639 HistogramPair* const pair, | 634 HistogramPair* const pair) { |
640 VP8LHistogram* const histos) { | 635 VP8LHistogram* h1; |
| 636 VP8LHistogram* h2; |
| 637 double sum_cost; |
| 638 |
641 if (idx1 > idx2) { | 639 if (idx1 > idx2) { |
642 const int tmp = idx2; | 640 const int tmp = idx2; |
643 idx2 = idx1; | 641 idx2 = idx1; |
644 idx1 = tmp; | 642 idx1 = tmp; |
645 } | 643 } |
646 pair->idx1 = idx1; | 644 pair->idx1 = idx1; |
647 pair->idx2 = idx2; | 645 pair->idx2 = idx2; |
648 pair->cost_diff = | 646 h1 = histograms[idx1]; |
649 HistogramAddEval(histograms[idx1], histograms[idx2], histos, 0); | 647 h2 = histograms[idx2]; |
650 pair->cost_combo = histos->bit_cost_; | 648 sum_cost = h1->bit_cost_ + h2->bit_cost_; |
| 649 pair->cost_combo = 0.; |
| 650 GetCombinedHistogramEntropy(h1, h2, sum_cost, &pair->cost_combo); |
| 651 pair->cost_diff = pair->cost_combo - sum_cost; |
651 } | 652 } |
652 | 653 |
653 // Combines histograms by continuously choosing the one with the highest cost | 654 // Combines histograms by continuously choosing the one with the highest cost |
654 // reduction. | 655 // reduction. |
655 static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo, | 656 static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo) { |
656 VP8LHistogram* const histos) { | |
657 int ok = 0; | 657 int ok = 0; |
658 int image_histo_size = image_histo->size; | 658 int image_histo_size = image_histo->size; |
659 int i, j; | 659 int i, j; |
660 VP8LHistogram** const histograms = image_histo->histograms; | 660 VP8LHistogram** const histograms = image_histo->histograms; |
661 // Indexes of remaining histograms. | 661 // Indexes of remaining histograms. |
662 int* const clusters = WebPSafeMalloc(image_histo_size, sizeof(*clusters)); | 662 int* const clusters = WebPSafeMalloc(image_histo_size, sizeof(*clusters)); |
663 // Priority queue of histogram pairs. | 663 // Priority queue of histogram pairs. |
664 HistoQueue histo_queue; | 664 HistoQueue histo_queue; |
665 | 665 |
666 if (!HistoQueueInit(&histo_queue, image_histo_size) || clusters == NULL) { | 666 if (!HistoQueueInit(&histo_queue, image_histo_size) || clusters == NULL) { |
667 goto End; | 667 goto End; |
668 } | 668 } |
669 | 669 |
670 for (i = 0; i < image_histo_size; ++i) { | 670 for (i = 0; i < image_histo_size; ++i) { |
671 // Initialize clusters indexes. | 671 // Initialize clusters indexes. |
672 clusters[i] = i; | 672 clusters[i] = i; |
673 for (j = i + 1; j < image_histo_size; ++j) { | 673 for (j = i + 1; j < image_histo_size; ++j) { |
674 // Initialize positions array. | 674 // Initialize positions array. |
675 PreparePair(histograms, i, j, &histo_queue.queue[histo_queue.size], | 675 PreparePair(histograms, i, j, &histo_queue.queue[histo_queue.size]); |
676 histos); | |
677 UpdateQueueFront(&histo_queue); | 676 UpdateQueueFront(&histo_queue); |
678 } | 677 } |
679 } | 678 } |
680 | 679 |
681 while (image_histo_size > 1 && histo_queue.size > 0) { | 680 while (image_histo_size > 1 && histo_queue.size > 0) { |
682 HistogramPair* copy_to; | 681 HistogramPair* copy_to; |
683 const int idx1 = histo_queue.queue[0].idx1; | 682 const int idx1 = histo_queue.queue[0].idx1; |
684 const int idx2 = histo_queue.queue[0].idx2; | 683 const int idx2 = histo_queue.queue[0].idx2; |
685 VP8LHistogramAdd(histograms[idx2], histograms[idx1], histograms[idx1]); | 684 VP8LHistogramAdd(histograms[idx2], histograms[idx1], histograms[idx1]); |
686 histograms[idx1]->bit_cost_ = histo_queue.queue[0].cost_combo; | 685 histograms[idx1]->bit_cost_ = histo_queue.queue[0].cost_combo; |
(...skipping 21 matching lines...) Expand all Loading... |
708 } | 707 } |
709 SwapHistogramPairs(copy_to, p); | 708 SwapHistogramPairs(copy_to, p); |
710 ++copy_to; | 709 ++copy_to; |
711 } | 710 } |
712 histo_queue.size = (int)(copy_to - histo_queue.queue); | 711 histo_queue.size = (int)(copy_to - histo_queue.queue); |
713 | 712 |
714 // Push new pairs formed with combined histogram to the queue. | 713 // Push new pairs formed with combined histogram to the queue. |
715 for (i = 0; i < image_histo_size; ++i) { | 714 for (i = 0; i < image_histo_size; ++i) { |
716 if (clusters[i] != idx1) { | 715 if (clusters[i] != idx1) { |
717 PreparePair(histograms, idx1, clusters[i], | 716 PreparePair(histograms, idx1, clusters[i], |
718 &histo_queue.queue[histo_queue.size], histos); | 717 &histo_queue.queue[histo_queue.size]); |
719 UpdateQueueFront(&histo_queue); | 718 UpdateQueueFront(&histo_queue); |
720 } | 719 } |
721 } | 720 } |
722 } | 721 } |
723 // Move remaining histograms to the beginning of the array. | 722 // Move remaining histograms to the beginning of the array. |
724 for (i = 0; i < image_histo_size; ++i) { | 723 for (i = 0; i < image_histo_size; ++i) { |
725 if (i != clusters[i]) { // swap the two histograms | 724 if (i != clusters[i]) { // swap the two histograms |
726 HistogramSwap(&histograms[i], &histograms[clusters[i]]); | 725 HistogramSwap(&histograms[i], &histograms[clusters[i]]); |
727 } | 726 } |
728 } | 727 } |
729 | 728 |
730 image_histo->size = image_histo_size; | 729 image_histo->size = image_histo_size; |
731 ok = 1; | 730 ok = 1; |
732 | 731 |
733 End: | 732 End: |
734 WebPSafeFree(clusters); | 733 WebPSafeFree(clusters); |
735 HistoQueueClear(&histo_queue); | 734 HistoQueueClear(&histo_queue); |
736 return ok; | 735 return ok; |
737 } | 736 } |
738 | 737 |
739 static VP8LHistogram* HistogramCombineStochastic( | 738 static void HistogramCombineStochastic(VP8LHistogramSet* const image_histo, |
740 VP8LHistogramSet* const image_histo, | 739 VP8LHistogram* tmp_histo, |
741 VP8LHistogram* tmp_histo, | 740 VP8LHistogram* best_combo, |
742 VP8LHistogram* best_combo, | 741 int quality, int min_cluster_size) { |
743 int quality, int min_cluster_size) { | |
744 int iter; | 742 int iter; |
745 uint32_t seed = 0; | 743 uint32_t seed = 0; |
746 int tries_with_no_success = 0; | 744 int tries_with_no_success = 0; |
747 int image_histo_size = image_histo->size; | 745 int image_histo_size = image_histo->size; |
748 const int iter_mult = (quality < 25) ? 2 : 2 + (quality - 25) / 8; | 746 const int iter_mult = (quality < 25) ? 2 : 2 + (quality - 25) / 8; |
749 const int outer_iters = image_histo_size * iter_mult; | 747 const int outer_iters = image_histo_size * iter_mult; |
750 const int num_pairs = image_histo_size / 2; | 748 const int num_pairs = image_histo_size / 2; |
751 const int num_tries_no_success = outer_iters / 2; | 749 const int num_tries_no_success = outer_iters / 2; |
752 VP8LHistogram** const histograms = image_histo->histograms; | 750 VP8LHistogram** const histograms = image_histo->histograms; |
753 | 751 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
793 HistogramSwap(&histograms[image_histo_size], &histograms[best_idx2]); | 791 HistogramSwap(&histograms[image_histo_size], &histograms[best_idx2]); |
794 histograms[image_histo_size] = NULL; | 792 histograms[image_histo_size] = NULL; |
795 } | 793 } |
796 tries_with_no_success = 0; | 794 tries_with_no_success = 0; |
797 } | 795 } |
798 if (++tries_with_no_success >= num_tries_no_success) { | 796 if (++tries_with_no_success >= num_tries_no_success) { |
799 break; | 797 break; |
800 } | 798 } |
801 } | 799 } |
802 image_histo->size = image_histo_size; | 800 image_histo->size = image_histo_size; |
803 return best_combo; | |
804 } | 801 } |
805 | 802 |
806 // ----------------------------------------------------------------------------- | 803 // ----------------------------------------------------------------------------- |
807 // Histogram refinement | 804 // Histogram refinement |
808 | 805 |
809 // Find the best 'out' histogram for each of the 'in' histograms. | 806 // Find the best 'out' histogram for each of the 'in' histograms. |
810 // Note: we assume that out[]->bit_cost_ is already up-to-date. | 807 // Note: we assume that out[]->bit_cost_ is already up-to-date. |
811 static void HistogramRemap(const VP8LHistogramSet* const orig_histo, | 808 static void HistogramRemap(const VP8LHistogramSet* const in, |
812 const VP8LHistogramSet* const image_histo, | 809 const VP8LHistogramSet* const out, |
813 uint16_t* const symbols) { | 810 uint16_t* const symbols) { |
814 int i; | 811 int i; |
815 VP8LHistogram** const orig_histograms = orig_histo->histograms; | 812 VP8LHistogram** const in_histo = in->histograms; |
816 VP8LHistogram** const histograms = image_histo->histograms; | 813 VP8LHistogram** const out_histo = out->histograms; |
817 const int orig_histo_size = orig_histo->size; | 814 const int in_size = in->size; |
818 const int image_histo_size = image_histo->size; | 815 const int out_size = out->size; |
819 if (image_histo_size > 1) { | 816 if (out_size > 1) { |
820 for (i = 0; i < orig_histo_size; ++i) { | 817 for (i = 0; i < in_size; ++i) { |
821 int best_out = 0; | 818 int best_out = 0; |
822 double best_bits = | 819 double best_bits = MAX_COST; |
823 HistogramAddThresh(histograms[0], orig_histograms[i], MAX_COST); | |
824 int k; | 820 int k; |
825 for (k = 1; k < image_histo_size; ++k) { | 821 for (k = 0; k < out_size; ++k) { |
826 const double cur_bits = | 822 const double cur_bits = |
827 HistogramAddThresh(histograms[k], orig_histograms[i], best_bits); | 823 HistogramAddThresh(out_histo[k], in_histo[i], best_bits); |
828 if (cur_bits < best_bits) { | 824 if (k == 0 || cur_bits < best_bits) { |
829 best_bits = cur_bits; | 825 best_bits = cur_bits; |
830 best_out = k; | 826 best_out = k; |
831 } | 827 } |
832 } | 828 } |
833 symbols[i] = best_out; | 829 symbols[i] = best_out; |
834 } | 830 } |
835 } else { | 831 } else { |
836 assert(image_histo_size == 1); | 832 assert(out_size == 1); |
837 for (i = 0; i < orig_histo_size; ++i) { | 833 for (i = 0; i < in_size; ++i) { |
838 symbols[i] = 0; | 834 symbols[i] = 0; |
839 } | 835 } |
840 } | 836 } |
841 | 837 |
842 // Recompute each out based on raw and symbols. | 838 // Recompute each out based on raw and symbols. |
843 for (i = 0; i < image_histo_size; ++i) { | 839 for (i = 0; i < out_size; ++i) { |
844 HistogramClear(histograms[i]); | 840 HistogramClear(out_histo[i]); |
845 } | 841 } |
846 | 842 |
847 for (i = 0; i < orig_histo_size; ++i) { | 843 for (i = 0; i < in_size; ++i) { |
848 const int idx = symbols[i]; | 844 const int idx = symbols[i]; |
849 VP8LHistogramAdd(orig_histograms[i], histograms[idx], histograms[idx]); | 845 VP8LHistogramAdd(in_histo[i], out_histo[idx], out_histo[idx]); |
850 } | 846 } |
851 } | 847 } |
852 | 848 |
853 static double GetCombineCostFactor(int histo_size, int quality) { | 849 static double GetCombineCostFactor(int histo_size, int quality) { |
854 double combine_cost_factor = 0.16; | 850 double combine_cost_factor = 0.16; |
855 if (quality < 90) { | 851 if (quality < 90) { |
856 if (histo_size > 256) combine_cost_factor /= 2.; | 852 if (histo_size > 256) combine_cost_factor /= 2.; |
857 if (histo_size > 512) combine_cost_factor /= 2.; | 853 if (histo_size > 512) combine_cost_factor /= 2.; |
858 if (histo_size > 1024) combine_cost_factor /= 2.; | 854 if (histo_size > 1024) combine_cost_factor /= 2.; |
859 if (quality <= 50) combine_cost_factor /= 2.; | 855 if (quality <= 50) combine_cost_factor /= 2.; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
913 bin_depth, entropy_combine_num_bins, | 909 bin_depth, entropy_combine_num_bins, |
914 combine_cost_factor, low_effort); | 910 combine_cost_factor, low_effort); |
915 } | 911 } |
916 | 912 |
917 // Don't combine the histograms using stochastic and greedy heuristics for | 913 // Don't combine the histograms using stochastic and greedy heuristics for |
918 // low-effort compression mode. | 914 // low-effort compression mode. |
919 if (!low_effort || !entropy_combine) { | 915 if (!low_effort || !entropy_combine) { |
920 const float x = quality / 100.f; | 916 const float x = quality / 100.f; |
921 // cubic ramp between 1 and MAX_HISTO_GREEDY: | 917 // cubic ramp between 1 and MAX_HISTO_GREEDY: |
922 const int threshold_size = (int)(1 + (x * x * x) * (MAX_HISTO_GREEDY - 1)); | 918 const int threshold_size = (int)(1 + (x * x * x) * (MAX_HISTO_GREEDY - 1)); |
923 cur_combo = HistogramCombineStochastic(image_histo, | 919 HistogramCombineStochastic(image_histo, tmp_histos->histograms[0], |
924 tmp_histos->histograms[0], | 920 cur_combo, quality, threshold_size); |
925 cur_combo, quality, threshold_size); | |
926 if ((image_histo->size <= threshold_size) && | 921 if ((image_histo->size <= threshold_size) && |
927 !HistogramCombineGreedy(image_histo, cur_combo)) { | 922 !HistogramCombineGreedy(image_histo)) { |
928 goto Error; | 923 goto Error; |
929 } | 924 } |
930 } | 925 } |
931 | 926 |
932 // TODO(vikasa): Optimize HistogramRemap for low-effort compression mode also. | 927 // TODO(vikasa): Optimize HistogramRemap for low-effort compression mode also. |
933 // Find the optimal map from original histograms to the final ones. | 928 // Find the optimal map from original histograms to the final ones. |
934 HistogramRemap(orig_histo, image_histo, histogram_symbols); | 929 HistogramRemap(orig_histo, image_histo, histogram_symbols); |
935 | 930 |
936 ok = 1; | 931 ok = 1; |
937 | 932 |
938 Error: | 933 Error: |
939 WebPSafeFree(bin_map); | 934 WebPSafeFree(bin_map); |
940 VP8LFreeHistogramSet(orig_histo); | 935 VP8LFreeHistogramSet(orig_histo); |
941 return ok; | 936 return ok; |
942 } | 937 } |
OLD | NEW |