OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 | |
OLD | NEW |