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 <string.h> | 14 #include <string.h> |
15 #include <math.h> | 15 #include <math.h> |
16 | 16 |
| 17 #include "./cost.h" |
17 #include "./vp8enci.h" | 18 #include "./vp8enci.h" |
18 #include "./cost.h" | 19 #include "../dsp/dsp.h" |
19 #include "../webp/format_constants.h" // RIFF constants | 20 #include "../webp/format_constants.h" // RIFF constants |
20 | 21 |
21 #define SEGMENT_VISU 0 | 22 #define SEGMENT_VISU 0 |
22 #define DEBUG_SEARCH 0 // useful to track search convergence | 23 #define DEBUG_SEARCH 0 // useful to track search convergence |
23 | 24 |
24 //------------------------------------------------------------------------------ | 25 //------------------------------------------------------------------------------ |
25 // multi-pass convergence | 26 // multi-pass convergence |
26 | 27 |
27 #define HEADER_SIZE_ESTIMATE (RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + \ | 28 #define HEADER_SIZE_ESTIMATE (RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + \ |
28 VP8_FRAME_HEADER_SIZE) | 29 VP8_FRAME_HEADER_SIZE) |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 s->dq = Clamp(dq, -30.f, 30.f); | 75 s->dq = Clamp(dq, -30.f, 30.f); |
75 s->last_q = s->q; | 76 s->last_q = s->q; |
76 s->last_value = s->value; | 77 s->last_value = s->value; |
77 s->q = Clamp(s->q + s->dq, 0.f, 100.f); | 78 s->q = Clamp(s->q + s->dq, 0.f, 100.f); |
78 return s->q; | 79 return s->q; |
79 } | 80 } |
80 | 81 |
81 //------------------------------------------------------------------------------ | 82 //------------------------------------------------------------------------------ |
82 // Tables for level coding | 83 // Tables for level coding |
83 | 84 |
84 const uint8_t VP8EncBands[16 + 1] = { | |
85 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, | |
86 0 // sentinel | |
87 }; | |
88 | |
89 const uint8_t VP8Cat3[] = { 173, 148, 140 }; | 85 const uint8_t VP8Cat3[] = { 173, 148, 140 }; |
90 const uint8_t VP8Cat4[] = { 176, 155, 140, 135 }; | 86 const uint8_t VP8Cat4[] = { 176, 155, 140, 135 }; |
91 const uint8_t VP8Cat5[] = { 180, 157, 141, 134, 130 }; | 87 const uint8_t VP8Cat5[] = { 180, 157, 141, 134, 130 }; |
92 const uint8_t VP8Cat6[] = | 88 const uint8_t VP8Cat6[] = |
93 { 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129 }; | 89 { 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129 }; |
94 | 90 |
95 //------------------------------------------------------------------------------ | 91 //------------------------------------------------------------------------------ |
96 // Reset the statistics about: number of skips, token proba, level cost,... | 92 // Reset the statistics about: number of skips, token proba, level cost,... |
97 | 93 |
98 static void ResetStats(VP8Encoder* const enc) { | 94 static void ResetStats(VP8Encoder* const enc) { |
99 VP8Proba* const proba = &enc->proba_; | 95 VP8EncProba* const proba = &enc->proba_; |
100 VP8CalculateLevelCosts(proba); | 96 VP8CalculateLevelCosts(proba); |
101 proba->nb_skip_ = 0; | 97 proba->nb_skip_ = 0; |
102 } | 98 } |
103 | 99 |
104 //------------------------------------------------------------------------------ | 100 //------------------------------------------------------------------------------ |
105 // Skip decision probability | 101 // Skip decision probability |
106 | 102 |
107 #define SKIP_PROBA_THRESHOLD 250 // value below which using skip_proba is OK. | 103 #define SKIP_PROBA_THRESHOLD 250 // value below which using skip_proba is OK. |
108 | 104 |
109 static int CalcSkipProba(uint64_t nb, uint64_t total) { | 105 static int CalcSkipProba(uint64_t nb, uint64_t total) { |
110 return (int)(total ? (total - nb) * 255 / total : 255); | 106 return (int)(total ? (total - nb) * 255 / total : 255); |
111 } | 107 } |
112 | 108 |
113 // Returns the bit-cost for coding the skip probability. | 109 // Returns the bit-cost for coding the skip probability. |
114 static int FinalizeSkipProba(VP8Encoder* const enc) { | 110 static int FinalizeSkipProba(VP8Encoder* const enc) { |
115 VP8Proba* const proba = &enc->proba_; | 111 VP8EncProba* const proba = &enc->proba_; |
116 const int nb_mbs = enc->mb_w_ * enc->mb_h_; | 112 const int nb_mbs = enc->mb_w_ * enc->mb_h_; |
117 const int nb_events = proba->nb_skip_; | 113 const int nb_events = proba->nb_skip_; |
118 int size; | 114 int size; |
119 proba->skip_proba_ = CalcSkipProba(nb_events, nb_mbs); | 115 proba->skip_proba_ = CalcSkipProba(nb_events, nb_mbs); |
120 proba->use_skip_proba_ = (proba->skip_proba_ < SKIP_PROBA_THRESHOLD); | 116 proba->use_skip_proba_ = (proba->skip_proba_ < SKIP_PROBA_THRESHOLD); |
121 size = 256; // 'use_skip_proba' bit | 117 size = 256; // 'use_skip_proba' bit |
122 if (proba->use_skip_proba_) { | 118 if (proba->use_skip_proba_) { |
123 size += nb_events * VP8BitCost(1, proba->skip_proba_) | 119 size += nb_events * VP8BitCost(1, proba->skip_proba_) |
124 + (nb_mbs - nb_events) * VP8BitCost(0, proba->skip_proba_); | 120 + (nb_mbs - nb_events) * VP8BitCost(0, proba->skip_proba_); |
125 size += 8 * 256; // cost of signaling the skip_proba_ itself. | 121 size += 8 * 256; // cost of signaling the skip_proba_ itself. |
126 } | 122 } |
127 return size; | 123 return size; |
128 } | 124 } |
129 | 125 |
130 // Collect statistics and deduce probabilities for next coding pass. | 126 // Collect statistics and deduce probabilities for next coding pass. |
131 // Return the total bit-cost for coding the probability updates. | 127 // Return the total bit-cost for coding the probability updates. |
132 static int CalcTokenProba(int nb, int total) { | 128 static int CalcTokenProba(int nb, int total) { |
133 assert(nb <= total); | 129 assert(nb <= total); |
134 return nb ? (255 - nb * 255 / total) : 255; | 130 return nb ? (255 - nb * 255 / total) : 255; |
135 } | 131 } |
136 | 132 |
137 // Cost of coding 'nb' 1's and 'total-nb' 0's using 'proba' probability. | 133 // Cost of coding 'nb' 1's and 'total-nb' 0's using 'proba' probability. |
138 static int BranchCost(int nb, int total, int proba) { | 134 static int BranchCost(int nb, int total, int proba) { |
139 return nb * VP8BitCost(1, proba) + (total - nb) * VP8BitCost(0, proba); | 135 return nb * VP8BitCost(1, proba) + (total - nb) * VP8BitCost(0, proba); |
140 } | 136 } |
141 | 137 |
142 static void ResetTokenStats(VP8Encoder* const enc) { | 138 static void ResetTokenStats(VP8Encoder* const enc) { |
143 VP8Proba* const proba = &enc->proba_; | 139 VP8EncProba* const proba = &enc->proba_; |
144 memset(proba->stats_, 0, sizeof(proba->stats_)); | 140 memset(proba->stats_, 0, sizeof(proba->stats_)); |
145 } | 141 } |
146 | 142 |
147 static int FinalizeTokenProbas(VP8Proba* const proba) { | 143 static int FinalizeTokenProbas(VP8EncProba* const proba) { |
148 int has_changed = 0; | 144 int has_changed = 0; |
149 int size = 0; | 145 int size = 0; |
150 int t, b, c, p; | 146 int t, b, c, p; |
151 for (t = 0; t < NUM_TYPES; ++t) { | 147 for (t = 0; t < NUM_TYPES; ++t) { |
152 for (b = 0; b < NUM_BANDS; ++b) { | 148 for (b = 0; b < NUM_BANDS; ++b) { |
153 for (c = 0; c < NUM_CTX; ++c) { | 149 for (c = 0; c < NUM_CTX; ++c) { |
154 for (p = 0; p < NUM_PROBAS; ++p) { | 150 for (p = 0; p < NUM_PROBAS; ++p) { |
155 const proba_t stats = proba->stats_[t][b][c][p]; | 151 const proba_t stats = proba->stats_[t][b][c][p]; |
156 const int nb = (stats >> 0) & 0xffff; | 152 const int nb = (stats >> 0) & 0xffff; |
157 const int total = (stats >> 16) & 0xffff; | 153 const int total = (stats >> 16) & 0xffff; |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 enc->sse_[2] = 0; | 465 enc->sse_[2] = 0; |
470 // Note: enc->sse_[3] is managed by alpha.c | 466 // Note: enc->sse_[3] is managed by alpha.c |
471 enc->sse_count_ = 0; | 467 enc->sse_count_ = 0; |
472 } | 468 } |
473 | 469 |
474 static void StoreSSE(const VP8EncIterator* const it) { | 470 static void StoreSSE(const VP8EncIterator* const it) { |
475 VP8Encoder* const enc = it->enc_; | 471 VP8Encoder* const enc = it->enc_; |
476 const uint8_t* const in = it->yuv_in_; | 472 const uint8_t* const in = it->yuv_in_; |
477 const uint8_t* const out = it->yuv_out_; | 473 const uint8_t* const out = it->yuv_out_; |
478 // Note: not totally accurate at boundary. And doesn't include in-loop filter. | 474 // Note: not totally accurate at boundary. And doesn't include in-loop filter. |
479 enc->sse_[0] += VP8SSE16x16(in + Y_OFF, out + Y_OFF); | 475 enc->sse_[0] += VP8SSE16x16(in + Y_OFF_ENC, out + Y_OFF_ENC); |
480 enc->sse_[1] += VP8SSE8x8(in + U_OFF, out + U_OFF); | 476 enc->sse_[1] += VP8SSE8x8(in + U_OFF_ENC, out + U_OFF_ENC); |
481 enc->sse_[2] += VP8SSE8x8(in + V_OFF, out + V_OFF); | 477 enc->sse_[2] += VP8SSE8x8(in + V_OFF_ENC, out + V_OFF_ENC); |
482 enc->sse_count_ += 16 * 16; | 478 enc->sse_count_ += 16 * 16; |
483 } | 479 } |
484 | 480 |
485 static void StoreSideInfo(const VP8EncIterator* const it) { | 481 static void StoreSideInfo(const VP8EncIterator* const it) { |
486 VP8Encoder* const enc = it->enc_; | 482 VP8Encoder* const enc = it->enc_; |
487 const VP8MBInfo* const mb = it->mb_; | 483 const VP8MBInfo* const mb = it->mb_; |
488 WebPPicture* const pic = enc->pic_; | 484 WebPPicture* const pic = enc->pic_; |
489 | 485 |
490 if (pic->stats != NULL) { | 486 if (pic->stats != NULL) { |
491 StoreSSE(it); | 487 StoreSSE(it); |
(...skipping 12 matching lines...) Expand all Loading... |
504 case 5: *info = mb->uv_mode_; break; | 500 case 5: *info = mb->uv_mode_; break; |
505 case 6: { | 501 case 6: { |
506 const int b = (int)((it->luma_bits_ + it->uv_bits_ + 7) >> 3); | 502 const int b = (int)((it->luma_bits_ + it->uv_bits_ + 7) >> 3); |
507 *info = (b > 255) ? 255 : b; break; | 503 *info = (b > 255) ? 255 : b; break; |
508 } | 504 } |
509 case 7: *info = mb->alpha_; break; | 505 case 7: *info = mb->alpha_; break; |
510 default: *info = 0; break; | 506 default: *info = 0; break; |
511 } | 507 } |
512 } | 508 } |
513 #if SEGMENT_VISU // visualize segments and prediction modes | 509 #if SEGMENT_VISU // visualize segments and prediction modes |
514 SetBlock(it->yuv_out_ + Y_OFF, mb->segment_ * 64, 16); | 510 SetBlock(it->yuv_out_ + Y_OFF_ENC, mb->segment_ * 64, 16); |
515 SetBlock(it->yuv_out_ + U_OFF, it->preds_[0] * 64, 8); | 511 SetBlock(it->yuv_out_ + U_OFF_ENC, it->preds_[0] * 64, 8); |
516 SetBlock(it->yuv_out_ + V_OFF, mb->uv_mode_ * 64, 8); | 512 SetBlock(it->yuv_out_ + V_OFF_ENC, mb->uv_mode_ * 64, 8); |
517 #endif | 513 #endif |
518 } | 514 } |
519 | 515 |
520 static double GetPSNR(uint64_t mse, uint64_t size) { | 516 static double GetPSNR(uint64_t mse, uint64_t size) { |
521 return (mse > 0 && size > 0) ? 10. * log10(255. * 255. * size / mse) : 99; | 517 return (mse > 0 && size > 0) ? 10. * log10(255. * 255. * size / mse) : 99; |
522 } | 518 } |
523 | 519 |
524 //------------------------------------------------------------------------------ | 520 //------------------------------------------------------------------------------ |
525 // StatLoop(): only collect statistics (number of skips, token usage, ...). | 521 // StatLoop(): only collect statistics (number of skips, token usage, ...). |
526 // This is used for deciding optimal probabilities. It also modifies the | 522 // This is used for deciding optimal probabilities. It also modifies the |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
736 #if !defined(DISABLE_TOKEN_BUFFER) | 732 #if !defined(DISABLE_TOKEN_BUFFER) |
737 | 733 |
738 #define MIN_COUNT 96 // minimum number of macroblocks before updating stats | 734 #define MIN_COUNT 96 // minimum number of macroblocks before updating stats |
739 | 735 |
740 int VP8EncTokenLoop(VP8Encoder* const enc) { | 736 int VP8EncTokenLoop(VP8Encoder* const enc) { |
741 // Roughly refresh the proba eight times per pass | 737 // Roughly refresh the proba eight times per pass |
742 int max_count = (enc->mb_w_ * enc->mb_h_) >> 3; | 738 int max_count = (enc->mb_w_ * enc->mb_h_) >> 3; |
743 int num_pass_left = enc->config_->pass; | 739 int num_pass_left = enc->config_->pass; |
744 const int do_search = enc->do_search_; | 740 const int do_search = enc->do_search_; |
745 VP8EncIterator it; | 741 VP8EncIterator it; |
746 VP8Proba* const proba = &enc->proba_; | 742 VP8EncProba* const proba = &enc->proba_; |
747 const VP8RDLevel rd_opt = enc->rd_opt_level_; | 743 const VP8RDLevel rd_opt = enc->rd_opt_level_; |
748 const uint64_t pixel_count = enc->mb_w_ * enc->mb_h_ * 384; | 744 const uint64_t pixel_count = enc->mb_w_ * enc->mb_h_ * 384; |
749 PassStats stats; | 745 PassStats stats; |
750 int ok; | 746 int ok; |
751 | 747 |
752 InitPassStats(enc, &stats); | 748 InitPassStats(enc, &stats); |
753 ok = PreLoopInitialize(enc); | 749 ok = PreLoopInitialize(enc); |
754 if (!ok) return 0; | 750 if (!ok) return 0; |
755 | 751 |
756 if (max_count < MIN_COUNT) max_count = MIN_COUNT; | 752 if (max_count < MIN_COUNT) max_count = MIN_COUNT; |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
845 | 841 |
846 int VP8EncTokenLoop(VP8Encoder* const enc) { | 842 int VP8EncTokenLoop(VP8Encoder* const enc) { |
847 (void)enc; | 843 (void)enc; |
848 return 0; // we shouldn't be here. | 844 return 0; // we shouldn't be here. |
849 } | 845 } |
850 | 846 |
851 #endif // DISABLE_TOKEN_BUFFER | 847 #endif // DISABLE_TOKEN_BUFFER |
852 | 848 |
853 //------------------------------------------------------------------------------ | 849 //------------------------------------------------------------------------------ |
854 | 850 |
OLD | NEW |