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

Side by Side Diff: third_party/libwebp/enc/frame.c

Issue 116213006: Update libwebp to 0.4.0 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: After Blink Roll Created 6 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 | Annotate | Revision Log
« no previous file with comments | « third_party/libwebp/enc/filter.c ('k') | third_party/libwebp/enc/histogram.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 Google Inc. All Rights Reserved. 1 // Copyright 2011 Google Inc. All Rights Reserved.
2 // 2 //
3 // Use of this source code is governed by a BSD-style license 3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the COPYING file in the root of the source 4 // that can be found in the COPYING file in the root of the source
5 // tree. An additional intellectual property rights grant can be found 5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may 6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree. 7 // be found in the AUTHORS file in the root of the source tree.
8 // ----------------------------------------------------------------------------- 8 // -----------------------------------------------------------------------------
9 // 9 //
10 // frame coding and analysis 10 // frame coding and analysis
11 // 11 //
12 // Author: Skal (pascal.massimino@gmail.com) 12 // Author: Skal (pascal.massimino@gmail.com)
13 13
14 #include <assert.h> 14 #include <assert.h>
15 #include <stdlib.h> 15 #include <stdlib.h>
16 #include <string.h> 16 #include <string.h>
17 #include <math.h> 17 #include <math.h>
18 18
19 #include "./vp8enci.h" 19 #include "./vp8enci.h"
20 #include "./cost.h" 20 #include "./cost.h"
21 21 #include "../webp/format_constants.h" // RIFF constants
22 #if defined(__cplusplus) || defined(c_plusplus)
23 extern "C" {
24 #endif
25 22
26 #define SEGMENT_VISU 0 23 #define SEGMENT_VISU 0
27 #define DEBUG_SEARCH 0 // useful to track search convergence 24 #define DEBUG_SEARCH 0 // useful to track search convergence
28 25
29 // On-the-fly info about the current set of residuals. Handy to avoid 26 // On-the-fly info about the current set of residuals. Handy to avoid
30 // passing zillions of params. 27 // passing zillions of params.
31 typedef struct { 28 typedef struct {
32 int first; 29 int first;
33 int last; 30 int last;
34 const int16_t* coeffs; 31 const int16_t* coeffs;
35 32
36 int coeff_type; 33 int coeff_type;
37 ProbaArray* prob; 34 ProbaArray* prob;
38 StatsArray* stats; 35 StatsArray* stats;
39 CostArray* cost; 36 CostArray* cost;
40 } VP8Residual; 37 } VP8Residual;
41 38
42 //------------------------------------------------------------------------------ 39 //------------------------------------------------------------------------------
40 // multi-pass convergence
41
42 #define HEADER_SIZE_ESTIMATE (RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + \
43 VP8_FRAME_HEADER_SIZE)
44 #define DQ_LIMIT 0.4 // convergence is considered reached if dq < DQ_LIMIT
45 // we allow 2k of extra head-room in PARTITION0 limit.
46 #define PARTITION0_SIZE_LIMIT ((VP8_MAX_PARTITION0_SIZE - 2048ULL) << 11)
47
48 typedef struct { // struct for organizing convergence in either size or PSNR
49 int is_first;
50 float dq;
51 float q, last_q;
52 double value, last_value; // PSNR or size
53 double target;
54 int do_size_search;
55 } PassStats;
56
57 static int InitPassStats(const VP8Encoder* const enc, PassStats* const s) {
58 const uint64_t target_size = (uint64_t)enc->config_->target_size;
59 const int do_size_search = (target_size != 0);
60 const float target_PSNR = enc->config_->target_PSNR;
61
62 s->is_first = 1;
63 s->dq = 10.f;
64 s->q = s->last_q = enc->config_->quality;
65 s->target = do_size_search ? (double)target_size
66 : (target_PSNR > 0.) ? target_PSNR
67 : 40.; // default, just in case
68 s->value = s->last_value = 0.;
69 s->do_size_search = do_size_search;
70 return do_size_search;
71 }
72
73 static float Clamp(float v, float min, float max) {
74 return (v < min) ? min : (v > max) ? max : v;
75 }
76
77 static float ComputeNextQ(PassStats* const s) {
78 float dq;
79 if (s->is_first) {
80 dq = (s->value > s->target) ? -s->dq : s->dq;
81 s->is_first = 0;
82 } else if (s->value != s->last_value) {
83 const double slope = (s->target - s->value) / (s->last_value - s->value);
84 dq = (float)(slope * (s->last_q - s->q));
85 } else {
86 dq = 0.; // we're done?!
87 }
88 // Limit variable to avoid large swings.
89 s->dq = Clamp(dq, -30.f, 30.f);
90 s->last_q = s->q;
91 s->last_value = s->value;
92 s->q = Clamp(s->q + s->dq, 0.f, 100.f);
93 return s->q;
94 }
95
96 //------------------------------------------------------------------------------
43 // Tables for level coding 97 // Tables for level coding
44 98
45 const uint8_t VP8EncBands[16 + 1] = { 99 const uint8_t VP8EncBands[16 + 1] = {
46 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 100 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7,
47 0 // sentinel 101 0 // sentinel
48 }; 102 };
49 103
50 const uint8_t VP8Cat3[] = { 173, 148, 140 }; 104 const uint8_t VP8Cat3[] = { 173, 148, 140 };
51 const uint8_t VP8Cat4[] = { 176, 155, 140, 135 }; 105 const uint8_t VP8Cat4[] = { 176, 155, 140, 135 };
52 const uint8_t VP8Cat5[] = { 180, 157, 141, 134, 130 }; 106 const uint8_t VP8Cat5[] = { 180, 157, 141, 134, 130 };
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 static int GetResidualCost(int ctx0, const VP8Residual* const res) { 339 static int GetResidualCost(int ctx0, const VP8Residual* const res) {
286 int n = res->first; 340 int n = res->first;
287 // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1 341 // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1
288 int p0 = res->prob[n][ctx0][0]; 342 int p0 = res->prob[n][ctx0][0];
289 const uint16_t* t = res->cost[n][ctx0]; 343 const uint16_t* t = res->cost[n][ctx0];
290 int cost; 344 int cost;
291 345
292 if (res->last < 0) { 346 if (res->last < 0) {
293 return VP8BitCost(0, p0); 347 return VP8BitCost(0, p0);
294 } 348 }
295 cost = 0; 349 cost = VP8BitCost(1, p0);
296 while (n < res->last) { 350 for (; n < res->last; ++n) {
297 int v = res->coeffs[n]; 351 const int v = abs(res->coeffs[n]);
298 const int b = VP8EncBands[n + 1]; 352 const int b = VP8EncBands[n + 1];
299 ++n; 353 const int ctx = (v >= 2) ? 2 : v;
300 if (v == 0) {
301 // short-case for VP8LevelCost(t, 0) (note: VP8LevelFixedCosts[0] == 0):
302 cost += t[0];
303 t = res->cost[b][0];
304 continue;
305 }
306 v = abs(v);
307 cost += VP8BitCost(1, p0);
308 cost += VP8LevelCost(t, v); 354 cost += VP8LevelCost(t, v);
309 { 355 t = res->cost[b][ctx];
310 const int ctx = (v == 1) ? 1 : 2; 356 // the masking trick is faster than "if (v) cost += ..." with clang
311 p0 = res->prob[b][ctx][0]; 357 cost += (v ? ~0U : 0) & VP8BitCost(1, res->prob[b][ctx][0]);
312 t = res->cost[b][ctx];
313 }
314 } 358 }
315 // Last coefficient is always non-zero 359 // Last coefficient is always non-zero
316 { 360 {
317 const int v = abs(res->coeffs[n]); 361 const int v = abs(res->coeffs[n]);
318 assert(v != 0); 362 assert(v != 0);
319 cost += VP8BitCost(1, p0);
320 cost += VP8LevelCost(t, v); 363 cost += VP8LevelCost(t, v);
321 if (n < 15) { 364 if (n < 15) {
322 const int b = VP8EncBands[n + 1]; 365 const int b = VP8EncBands[n + 1];
323 const int ctx = (v == 1) ? 1 : 2; 366 const int ctx = (v == 1) ? 1 : 2;
324 const int last_p0 = res->prob[b][ctx][0]; 367 const int last_p0 = res->prob[b][ctx][0];
325 cost += VP8BitCost(0, last_p0); 368 cost += VP8BitCost(0, last_p0);
326 } 369 }
327 } 370 }
328 return cost; 371 return cost;
329 } 372 }
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after
678 default: *info = 0; break; 721 default: *info = 0; break;
679 }; 722 };
680 } 723 }
681 #if SEGMENT_VISU // visualize segments and prediction modes 724 #if SEGMENT_VISU // visualize segments and prediction modes
682 SetBlock(it->yuv_out_ + Y_OFF, mb->segment_ * 64, 16); 725 SetBlock(it->yuv_out_ + Y_OFF, mb->segment_ * 64, 16);
683 SetBlock(it->yuv_out_ + U_OFF, it->preds_[0] * 64, 8); 726 SetBlock(it->yuv_out_ + U_OFF, it->preds_[0] * 64, 8);
684 SetBlock(it->yuv_out_ + V_OFF, mb->uv_mode_ * 64, 8); 727 SetBlock(it->yuv_out_ + V_OFF, mb->uv_mode_ * 64, 8);
685 #endif 728 #endif
686 } 729 }
687 730
731 static double GetPSNR(uint64_t mse, uint64_t size) {
732 return (mse > 0 && size > 0) ? 10. * log10(255. * 255. * size / mse) : 99;
733 }
734
688 //------------------------------------------------------------------------------ 735 //------------------------------------------------------------------------------
689 // StatLoop(): only collect statistics (number of skips, token usage, ...). 736 // StatLoop(): only collect statistics (number of skips, token usage, ...).
690 // This is used for deciding optimal probabilities. It also modifies the 737 // This is used for deciding optimal probabilities. It also modifies the
691 // quantizer value if some target (size, PNSR) was specified. 738 // quantizer value if some target (size, PSNR) was specified.
692
693 #define kHeaderSizeEstimate (15 + 20 + 10) // TODO: fix better
694 739
695 static void SetLoopParams(VP8Encoder* const enc, float q) { 740 static void SetLoopParams(VP8Encoder* const enc, float q) {
696 // Make sure the quality parameter is inside valid bounds 741 // Make sure the quality parameter is inside valid bounds
697 if (q < 0.) { 742 q = Clamp(q, 0.f, 100.f);
698 q = 0;
699 } else if (q > 100.) {
700 q = 100;
701 }
702 743
703 VP8SetSegmentParams(enc, q); // setup segment quantizations and filters 744 VP8SetSegmentParams(enc, q); // setup segment quantizations and filters
704 SetSegmentProbas(enc); // compute segment probabilities 745 SetSegmentProbas(enc); // compute segment probabilities
705 746
706 ResetStats(enc); 747 ResetStats(enc);
707 ResetTokenStats(enc);
708
709 ResetSSE(enc); 748 ResetSSE(enc);
710 } 749 }
711 750
712 static int OneStatPass(VP8Encoder* const enc, float q, VP8RDLevel rd_opt, 751 static uint64_t OneStatPass(VP8Encoder* const enc, VP8RDLevel rd_opt,
713 int nb_mbs, float* const PSNR, int percent_delta) { 752 int nb_mbs, int percent_delta,
753 PassStats* const s) {
714 VP8EncIterator it; 754 VP8EncIterator it;
715 uint64_t size = 0; 755 uint64_t size = 0;
756 uint64_t size_p0 = 0;
716 uint64_t distortion = 0; 757 uint64_t distortion = 0;
717 const uint64_t pixel_count = nb_mbs * 384; 758 const uint64_t pixel_count = nb_mbs * 384;
718 759
719 SetLoopParams(enc, q);
720
721 VP8IteratorInit(enc, &it); 760 VP8IteratorInit(enc, &it);
761 SetLoopParams(enc, s->q);
722 do { 762 do {
723 VP8ModeScore info; 763 VP8ModeScore info;
724 VP8IteratorImport(&it); 764 VP8IteratorImport(&it, NULL);
725 if (VP8Decimate(&it, &info, rd_opt)) { 765 if (VP8Decimate(&it, &info, rd_opt)) {
726 // Just record the number of skips and act like skip_proba is not used. 766 // Just record the number of skips and act like skip_proba is not used.
727 enc->proba_.nb_skip_++; 767 enc->proba_.nb_skip_++;
728 } 768 }
729 RecordResiduals(&it, &info); 769 RecordResiduals(&it, &info);
730 size += info.R; 770 size += info.R + info.H;
771 size_p0 += info.H;
731 distortion += info.D; 772 distortion += info.D;
732 if (percent_delta && !VP8IteratorProgress(&it, percent_delta)) 773 if (percent_delta && !VP8IteratorProgress(&it, percent_delta))
733 return 0; 774 return 0;
734 } while (VP8IteratorNext(&it, it.yuv_out_) && --nb_mbs > 0); 775 VP8IteratorSaveBoundary(&it);
735 size += FinalizeSkipProba(enc); 776 } while (VP8IteratorNext(&it) && --nb_mbs > 0);
736 size += FinalizeTokenProbas(&enc->proba_);
737 size += enc->segment_hdr_.size_;
738 size = ((size + 1024) >> 11) + kHeaderSizeEstimate;
739 777
740 if (PSNR) { 778 size_p0 += enc->segment_hdr_.size_;
741 *PSNR = (float)(10.* log10(255. * 255. * pixel_count / distortion)); 779 if (s->do_size_search) {
780 size += FinalizeSkipProba(enc);
781 size += FinalizeTokenProbas(&enc->proba_);
782 size = ((size + size_p0 + 1024) >> 11) + HEADER_SIZE_ESTIMATE;
783 s->value = (double)size;
784 } else {
785 s->value = GetPSNR(distortion, pixel_count);
742 } 786 }
743 return (int)size; 787 return size_p0;
744 } 788 }
745 789
746 // successive refinement increments.
747 static const int dqs[] = { 20, 15, 10, 8, 6, 4, 2, 1, 0 };
748
749 static int StatLoop(VP8Encoder* const enc) { 790 static int StatLoop(VP8Encoder* const enc) {
750 const int method = enc->method_; 791 const int method = enc->method_;
751 const int do_search = enc->do_search_; 792 const int do_search = enc->do_search_;
752 const int fast_probe = ((method == 0 || method == 3) && !do_search); 793 const int fast_probe = ((method == 0 || method == 3) && !do_search);
753 float q = enc->config_->quality; 794 int num_pass_left = enc->config_->pass;
754 const int max_passes = enc->config_->pass;
755 const int task_percent = 20; 795 const int task_percent = 20;
756 const int percent_per_pass = (task_percent + max_passes / 2) / max_passes; 796 const int percent_per_pass =
797 (task_percent + num_pass_left / 2) / num_pass_left;
757 const int final_percent = enc->percent_ + task_percent; 798 const int final_percent = enc->percent_ + task_percent;
758 int pass; 799 const VP8RDLevel rd_opt =
759 int nb_mbs; 800 (method >= 3 || do_search) ? RD_OPT_BASIC : RD_OPT_NONE;
801 int nb_mbs = enc->mb_w_ * enc->mb_h_;
802 PassStats stats;
803
804 InitPassStats(enc, &stats);
805 ResetTokenStats(enc);
760 806
761 // Fast mode: quick analysis pass over few mbs. Better than nothing. 807 // Fast mode: quick analysis pass over few mbs. Better than nothing.
762 nb_mbs = enc->mb_w_ * enc->mb_h_;
763 if (fast_probe) { 808 if (fast_probe) {
764 if (method == 3) { // we need more stats for method 3 to be reliable. 809 if (method == 3) { // we need more stats for method 3 to be reliable.
765 nb_mbs = (nb_mbs > 200) ? nb_mbs >> 1 : 100; 810 nb_mbs = (nb_mbs > 200) ? nb_mbs >> 1 : 100;
766 } else { 811 } else {
767 nb_mbs = (nb_mbs > 200) ? nb_mbs >> 2 : 50; 812 nb_mbs = (nb_mbs > 200) ? nb_mbs >> 2 : 50;
768 } 813 }
769 } 814 }
770 815
771 // No target size: just do several pass without changing 'q' 816 while (num_pass_left-- > 0) {
772 if (!do_search) { 817 const int is_last_pass = (fabs(stats.dq) <= DQ_LIMIT) ||
773 for (pass = 0; pass < max_passes; ++pass) { 818 (num_pass_left == 0) ||
774 const VP8RDLevel rd_opt = (method >= 3) ? RD_OPT_BASIC : RD_OPT_NONE; 819 (enc->max_i4_header_bits_ == 0);
775 if (!OneStatPass(enc, q, rd_opt, nb_mbs, NULL, percent_per_pass)) { 820 const uint64_t size_p0 =
776 return 0; 821 OneStatPass(enc, rd_opt, nb_mbs, percent_per_pass, &stats);
777 } 822 if (size_p0 == 0) return 0;
823 #if (DEBUG_SEARCH > 0)
824 printf("#%d value:%.1lf -> %.1lf q:%.2f -> %.2f\n",
825 num_pass_left, stats.last_value, stats.value, stats.last_q, stats.q);
826 #endif
827 if (enc->max_i4_header_bits_ > 0 && size_p0 > PARTITION0_SIZE_LIMIT) {
828 ++num_pass_left;
829 enc->max_i4_header_bits_ >>= 1; // strengthen header bit limitation...
830 continue; // ...and start over
778 } 831 }
779 } else { 832 if (is_last_pass) {
780 // binary search for a size close to target 833 break;
781 for (pass = 0; pass < max_passes && (dqs[pass] > 0); ++pass) {
782 float PSNR;
783 int criterion;
784 const int size = OneStatPass(enc, q, RD_OPT_BASIC, nb_mbs, &PSNR,
785 percent_per_pass);
786 #if DEBUG_SEARCH
787 printf("#%d size=%d PSNR=%.2f q=%.2f\n", pass, size, PSNR, q);
788 #endif
789 if (size == 0) return 0;
790 if (enc->config_->target_PSNR > 0) {
791 criterion = (PSNR < enc->config_->target_PSNR);
792 } else {
793 criterion = (size < enc->config_->target_size);
794 }
795 // dichotomize
796 if (criterion) {
797 q += dqs[pass];
798 } else {
799 q -= dqs[pass];
800 }
801 } 834 }
835 // If no target size: just do several pass without changing 'q'
836 if (do_search) {
837 ComputeNextQ(&stats);
838 if (fabs(stats.dq) <= DQ_LIMIT) break;
839 }
840 }
841 if (!do_search || !stats.do_size_search) {
842 // Need to finalize probas now, since it wasn't done during the search.
843 FinalizeSkipProba(enc);
844 FinalizeTokenProbas(&enc->proba_);
802 } 845 }
803 VP8CalculateLevelCosts(&enc->proba_); // finalize costs 846 VP8CalculateLevelCosts(&enc->proba_); // finalize costs
804 return WebPReportProgress(enc->pic_, final_percent, &enc->percent_); 847 return WebPReportProgress(enc->pic_, final_percent, &enc->percent_);
805 } 848 }
806 849
807 //------------------------------------------------------------------------------ 850 //------------------------------------------------------------------------------
808 // Main loops 851 // Main loops
809 // 852 //
810 853
811 static const int kAverageBytesPerMB[8] = { 50, 24, 16, 9, 7, 5, 3, 2 }; 854 static const int kAverageBytesPerMB[8] = { 50, 24, 16, 9, 7, 5, 3, 2 };
(...skipping 16 matching lines...) Expand all
828 VP8Encoder* const enc = it->enc_; 871 VP8Encoder* const enc = it->enc_;
829 if (ok) { // Finalize the partitions, check for extra errors. 872 if (ok) { // Finalize the partitions, check for extra errors.
830 int p; 873 int p;
831 for (p = 0; p < enc->num_parts_; ++p) { 874 for (p = 0; p < enc->num_parts_; ++p) {
832 VP8BitWriterFinish(enc->parts_ + p); 875 VP8BitWriterFinish(enc->parts_ + p);
833 ok &= !enc->parts_[p].error_; 876 ok &= !enc->parts_[p].error_;
834 } 877 }
835 } 878 }
836 879
837 if (ok) { // All good. Finish up. 880 if (ok) { // All good. Finish up.
838 if (enc->pic_->stats) { // finalize byte counters... 881 if (enc->pic_->stats != NULL) { // finalize byte counters...
839 int i, s; 882 int i, s;
840 for (i = 0; i <= 2; ++i) { 883 for (i = 0; i <= 2; ++i) {
841 for (s = 0; s < NUM_MB_SEGMENTS; ++s) { 884 for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
842 enc->residual_bytes_[i][s] = (int)((it->bit_count_[s][i] + 7) >> 3); 885 enc->residual_bytes_[i][s] = (int)((it->bit_count_[s][i] + 7) >> 3);
843 } 886 }
844 } 887 }
845 } 888 }
846 VP8AdjustFilterStrength(it); // ...and store filter stats. 889 VP8AdjustFilterStrength(it); // ...and store filter stats.
847 } else { 890 } else {
848 // Something bad happened -> need to do some memory cleanup. 891 // Something bad happened -> need to do some memory cleanup.
(...skipping 21 matching lines...) Expand all
870 913
871 StatLoop(enc); // stats-collection loop 914 StatLoop(enc); // stats-collection loop
872 915
873 VP8IteratorInit(enc, &it); 916 VP8IteratorInit(enc, &it);
874 VP8InitFilter(&it); 917 VP8InitFilter(&it);
875 do { 918 do {
876 VP8ModeScore info; 919 VP8ModeScore info;
877 const int dont_use_skip = !enc->proba_.use_skip_proba_; 920 const int dont_use_skip = !enc->proba_.use_skip_proba_;
878 const VP8RDLevel rd_opt = enc->rd_opt_level_; 921 const VP8RDLevel rd_opt = enc->rd_opt_level_;
879 922
880 VP8IteratorImport(&it); 923 VP8IteratorImport(&it, NULL);
881 // Warning! order is important: first call VP8Decimate() and 924 // Warning! order is important: first call VP8Decimate() and
882 // *then* decide how to code the skip decision if there's one. 925 // *then* decide how to code the skip decision if there's one.
883 if (!VP8Decimate(&it, &info, rd_opt) || dont_use_skip) { 926 if (!VP8Decimate(&it, &info, rd_opt) || dont_use_skip) {
884 CodeResiduals(it.bw_, &it, &info); 927 CodeResiduals(it.bw_, &it, &info);
885 } else { // reset predictors after a skip 928 } else { // reset predictors after a skip
886 ResetAfterSkip(&it); 929 ResetAfterSkip(&it);
887 } 930 }
888 #ifdef WEBP_EXPERIMENTAL_FEATURES 931 #ifdef WEBP_EXPERIMENTAL_FEATURES
889 if (enc->use_layer_) { 932 if (enc->use_layer_) {
890 VP8EncCodeLayerBlock(&it); 933 VP8EncCodeLayerBlock(&it);
891 } 934 }
892 #endif 935 #endif
893 StoreSideInfo(&it); 936 StoreSideInfo(&it);
894 VP8StoreFilterStats(&it); 937 VP8StoreFilterStats(&it);
895 VP8IteratorExport(&it); 938 VP8IteratorExport(&it);
896 ok = VP8IteratorProgress(&it, 20); 939 ok = VP8IteratorProgress(&it, 20);
897 } while (ok && VP8IteratorNext(&it, it.yuv_out_)); 940 VP8IteratorSaveBoundary(&it);
941 } while (ok && VP8IteratorNext(&it));
898 942
899 return PostLoopFinalize(&it, ok); 943 return PostLoopFinalize(&it, ok);
900 } 944 }
901 945
902 //------------------------------------------------------------------------------ 946 //------------------------------------------------------------------------------
903 // Single pass using Token Buffer. 947 // Single pass using Token Buffer.
904 948
905 #if !defined(DISABLE_TOKEN_BUFFER) 949 #if !defined(DISABLE_TOKEN_BUFFER)
906 950
907 #define MIN_COUNT 96 // minimum number of macroblocks before updating stats 951 #define MIN_COUNT 96 // minimum number of macroblocks before updating stats
908 952
909 int VP8EncTokenLoop(VP8Encoder* const enc) { 953 int VP8EncTokenLoop(VP8Encoder* const enc) {
910 int ok; 954 // Roughly refresh the proba eight times per pass
911 // Roughly refresh the proba height times per pass
912 int max_count = (enc->mb_w_ * enc->mb_h_) >> 3; 955 int max_count = (enc->mb_w_ * enc->mb_h_) >> 3;
913 int cnt; 956 int num_pass_left = enc->config_->pass;
957 const int do_search = enc->do_search_;
914 VP8EncIterator it; 958 VP8EncIterator it;
915 VP8Proba* const proba = &enc->proba_; 959 VP8Proba* const proba = &enc->proba_;
916 const VP8RDLevel rd_opt = enc->rd_opt_level_; 960 const VP8RDLevel rd_opt = enc->rd_opt_level_;
961 const uint64_t pixel_count = enc->mb_w_ * enc->mb_h_ * 384;
962 PassStats stats;
963 int ok;
964
965 InitPassStats(enc, &stats);
966 ok = PreLoopInitialize(enc);
967 if (!ok) return 0;
917 968
918 if (max_count < MIN_COUNT) max_count = MIN_COUNT; 969 if (max_count < MIN_COUNT) max_count = MIN_COUNT;
919 cnt = max_count;
920 970
921 assert(enc->num_parts_ == 1); 971 assert(enc->num_parts_ == 1);
922 assert(enc->use_tokens_); 972 assert(enc->use_tokens_);
923 assert(proba->use_skip_proba_ == 0); 973 assert(proba->use_skip_proba_ == 0);
924 assert(rd_opt >= RD_OPT_BASIC); // otherwise, token-buffer won't be useful 974 assert(rd_opt >= RD_OPT_BASIC); // otherwise, token-buffer won't be useful
925 assert(!enc->do_search_); // TODO(skal): handle pass and dichotomy 975 assert(num_pass_left > 0);
926 976
927 SetLoopParams(enc, enc->config_->quality); 977 while (ok && num_pass_left-- > 0) {
978 const int is_last_pass = (fabs(stats.dq) <= DQ_LIMIT) ||
979 (num_pass_left == 0) ||
980 (enc->max_i4_header_bits_ == 0);
981 uint64_t size_p0 = 0;
982 uint64_t distortion = 0;
983 int cnt = max_count;
984 VP8IteratorInit(enc, &it);
985 SetLoopParams(enc, stats.q);
986 if (is_last_pass) {
987 ResetTokenStats(enc);
988 VP8InitFilter(&it); // don't collect stats until last pass (too costly)
989 }
990 VP8TBufferClear(&enc->tokens_);
991 do {
992 VP8ModeScore info;
993 VP8IteratorImport(&it, NULL);
994 if (--cnt < 0) {
995 FinalizeTokenProbas(proba);
996 VP8CalculateLevelCosts(proba); // refresh cost tables for rd-opt
997 cnt = max_count;
998 }
999 VP8Decimate(&it, &info, rd_opt);
1000 RecordTokens(&it, &info, &enc->tokens_);
1001 size_p0 += info.H;
1002 distortion += info.D;
1003 #ifdef WEBP_EXPERIMENTAL_FEATURES
1004 if (enc->use_layer_) {
1005 VP8EncCodeLayerBlock(&it);
1006 }
1007 #endif
1008 if (is_last_pass) {
1009 StoreSideInfo(&it);
1010 VP8StoreFilterStats(&it);
1011 VP8IteratorExport(&it);
1012 ok = VP8IteratorProgress(&it, 20);
1013 }
1014 VP8IteratorSaveBoundary(&it);
1015 } while (ok && VP8IteratorNext(&it));
1016 if (!ok) break;
928 1017
929 ok = PreLoopInitialize(enc); 1018 size_p0 += enc->segment_hdr_.size_;
930 if (!ok) return 0; 1019 if (stats.do_size_search) {
1020 uint64_t size = FinalizeTokenProbas(&enc->proba_);
1021 size += VP8EstimateTokenSize(&enc->tokens_,
1022 (const uint8_t*)proba->coeffs_);
1023 size = (size + size_p0 + 1024) >> 11; // -> size in bytes
1024 size += HEADER_SIZE_ESTIMATE;
1025 stats.value = (double)size;
1026 } else { // compute and store PSNR
1027 stats.value = GetPSNR(distortion, pixel_count);
1028 }
931 1029
932 VP8IteratorInit(enc, &it); 1030 #if (DEBUG_SEARCH > 0)
933 VP8InitFilter(&it); 1031 printf("#%2d metric:%.1lf -> %.1lf last_q=%.2lf q=%.2lf dq=%.2lf\n",
934 do { 1032 num_pass_left, stats.last_value, stats.value,
935 VP8ModeScore info; 1033 stats.last_q, stats.q, stats.dq);
936 VP8IteratorImport(&it); 1034 #endif
937 if (--cnt < 0) { 1035 if (size_p0 > PARTITION0_SIZE_LIMIT) {
938 FinalizeTokenProbas(proba); 1036 ++num_pass_left;
939 VP8CalculateLevelCosts(proba); // refresh cost tables for rd-opt 1037 enc->max_i4_header_bits_ >>= 1; // strengthen header bit limitation...
940 cnt = max_count; 1038 continue; // ...and start over
941 } 1039 }
942 VP8Decimate(&it, &info, rd_opt); 1040 if (is_last_pass) {
943 RecordTokens(&it, &info, &enc->tokens_); 1041 break; // done
944 #ifdef WEBP_EXPERIMENTAL_FEATURES
945 if (enc->use_layer_) {
946 VP8EncCodeLayerBlock(&it);
947 } 1042 }
948 #endif 1043 if (do_search) {
949 StoreSideInfo(&it); 1044 ComputeNextQ(&stats); // Adjust q
950 VP8StoreFilterStats(&it); 1045 }
951 VP8IteratorExport(&it); 1046 }
952 ok = VP8IteratorProgress(&it, 20);
953 } while (ok && VP8IteratorNext(&it, it.yuv_out_));
954
955 ok = ok && WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_);
956
957 if (ok) { 1047 if (ok) {
958 FinalizeTokenProbas(proba); 1048 if (!stats.do_size_search) {
1049 FinalizeTokenProbas(&enc->proba_);
1050 }
959 ok = VP8EmitTokens(&enc->tokens_, enc->parts_ + 0, 1051 ok = VP8EmitTokens(&enc->tokens_, enc->parts_ + 0,
960 (const uint8_t*)proba->coeffs_, 1); 1052 (const uint8_t*)proba->coeffs_, 1);
961 } 1053 }
962 1054 ok = ok && WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_);
963 return PostLoopFinalize(&it, ok); 1055 return PostLoopFinalize(&it, ok);
964 } 1056 }
965 1057
966 #else 1058 #else
967 1059
968 int VP8EncTokenLoop(VP8Encoder* const enc) { 1060 int VP8EncTokenLoop(VP8Encoder* const enc) {
969 (void)enc; 1061 (void)enc;
970 return 0; // we shouldn't be here. 1062 return 0; // we shouldn't be here.
971 } 1063 }
972 1064
973 #endif // DISABLE_TOKEN_BUFFER 1065 #endif // DISABLE_TOKEN_BUFFER
974 1066
975 //------------------------------------------------------------------------------ 1067 //------------------------------------------------------------------------------
976 1068
977 #if defined(__cplusplus) || defined(c_plusplus)
978 } // extern "C"
979 #endif
OLDNEW
« no previous file with comments | « third_party/libwebp/enc/filter.c ('k') | third_party/libwebp/enc/histogram.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698