frame.c revision 88fe2b83c4b9232cd08729556fd0485d6a6a92cd
1// Copyright 2011 Google Inc.
2//
3// This code is licensed under the same terms as WebM:
4//  Software License Agreement:  http://www.webmproject.org/license/software/
5//  Additional IP Rights Grant:  http://www.webmproject.org/license/additional/
6// -----------------------------------------------------------------------------
7//
8//   frame coding and analysis
9//
10// Author: Skal (pascal.massimino@gmail.com)
11
12#include <stdlib.h>
13#include <string.h>
14#include <assert.h>
15#include <math.h>
16
17#include "vp8enci.h"
18#include "cost.h"
19
20#if defined(__cplusplus) || defined(c_plusplus)
21extern "C" {
22#endif
23
24#define SEGMENT_VISU 0
25#define DEBUG_SEARCH 0    // useful to track search convergence
26
27// On-the-fly info about the current set of residuals. Handy to avoid
28// passing zillions of params.
29typedef struct {
30  int first;
31  int last;
32  const int16_t* coeffs;
33
34  int coeff_type;
35  ProbaArray* prob;
36  StatsArray* stats;
37  CostArray*  cost;
38} VP8Residual;
39
40//-----------------------------------------------------------------------------
41// Tables for level coding
42
43const uint8_t VP8EncBands[16 + 1] = {
44  0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7,
45  0  // sentinel
46};
47
48static const uint8_t kCat3[] = { 173, 148, 140 };
49static const uint8_t kCat4[] = { 176, 155, 140, 135 };
50static const uint8_t kCat5[] = { 180, 157, 141, 134, 130 };
51static const uint8_t kCat6[] =
52    { 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129 };
53
54//-----------------------------------------------------------------------------
55// Reset the statistics about: number of skips, token proba, level cost,...
56
57static void ResetStats(VP8Encoder* const enc, int precalc_cost) {
58  VP8Proba* const proba = &enc->proba_;
59  if (precalc_cost) VP8CalculateLevelCosts(proba);
60  proba->nb_skip_ = 0;
61}
62
63//-----------------------------------------------------------------------------
64// Skip decision probability
65
66static int CalcSkipProba(uint64_t nb, uint64_t total) {
67  return (int)(total ? (total - nb) * 255 / total : 255);
68}
69
70// Returns the bit-cost for coding the skip probability.
71static int FinalizeSkipProba(VP8Encoder* const enc) {
72  VP8Proba* const proba = &enc->proba_;
73  const int nb_mbs = enc->mb_w_ * enc->mb_h_;
74  const int nb_events = proba->nb_skip_;
75  int size;
76  proba->skip_proba_ = CalcSkipProba(nb_events, nb_mbs);
77  proba->use_skip_proba_ = (proba->skip_proba_ < 250);
78  size = 256;   // 'use_skip_proba' bit
79  if (proba->use_skip_proba_) {
80    size +=  nb_events * VP8BitCost(1, proba->skip_proba_)
81         + (nb_mbs - nb_events) * VP8BitCost(0, proba->skip_proba_);
82    size += 8 * 256;   // cost of signaling the skip_proba_ itself.
83  }
84  return size;
85}
86
87//-----------------------------------------------------------------------------
88// Recording of token probabilities.
89
90static void ResetTokenStats(VP8Encoder* const enc) {
91  VP8Proba* const proba = &enc->proba_;
92  memset(proba->stats_, 0, sizeof(proba->stats_));
93}
94
95// Record proba context used
96static int Record(int bit, uint64_t* const stats) {
97  stats[0] += bit;
98  stats[1] += 1;
99  return bit;
100}
101
102// We keep the table free variant around for reference, in case.
103#define USE_LEVEL_CODE_TABLE
104
105// Simulate block coding, but only record statistics.
106// Note: no need to record the fixed probas.
107static int RecordCoeffs(int ctx, VP8Residual* res) {
108  int n = res->first;
109  uint64_t (*s)[2] = res->stats[VP8EncBands[n]][ctx];
110  if (!Record(res->last >= 0, s[0])) {
111    return 0;
112  }
113
114  while (1) {
115    int v = res->coeffs[n++];
116    if (!Record(v != 0, s[1])) {
117      s = res->stats[VP8EncBands[n]][0];
118      continue;
119    }
120    if (!Record(2u < (unsigned int)(v + 1), s[2])) {  // v = -1 or 1
121      s = res->stats[VP8EncBands[n]][1];
122    } else {
123      v = abs(v);
124#if !defined(USE_LEVEL_CODE_TABLE)
125      if (!Record(v > 4, s[3])) {
126        if (Record(v != 2, s[4]))
127          Record(v == 4, s[5]);
128      } else if (!Record(v > 10, s[6])) {
129        Record(v > 6, s[7]);
130      } else if (!Record((v >= 3 + (8 << 2)), s[8])) {
131        Record((v >= 3 + (8 << 1)), s[9]);
132      } else {
133        Record((v >= 3 + (8 << 3)), s[10]);
134      }
135#else
136      if (v > MAX_VARIABLE_LEVEL)
137        v = MAX_VARIABLE_LEVEL;
138
139      {
140        const int bits = VP8LevelCodes[v - 1][1];
141        int pattern = VP8LevelCodes[v - 1][0];
142        int i;
143        for (i = 0; (pattern >>= 1) != 0; ++i) {
144          const int mask = 2 << i;
145          if (pattern & 1) Record(!!(bits & mask), s[3 + i]);
146        }
147      }
148#endif
149      s = res->stats[VP8EncBands[n]][2];
150    }
151    if (n == 16 || !Record(n <= res->last, s[0])) {
152      return 1;
153    }
154  }
155}
156
157// Collect statistics and deduce probabilities for next coding pass.
158// Return the total bit-cost for coding the probability updates.
159static int CalcTokenProba(uint64_t nb, uint64_t total) {
160  return (int)(nb ? ((total - nb) * 255 + total / 2) / total : 255);
161}
162
163static int FinalizeTokenProbas(VP8Encoder* const enc) {
164  VP8Proba* const proba = &enc->proba_;
165  int size = 0;
166  int t, b, c, p;
167  for (t = 0; t < NUM_TYPES; ++t) {
168    for (b = 0; b < NUM_BANDS; ++b) {
169      for (c = 0; c < NUM_CTX; ++c) {
170        for (p = 0; p < NUM_PROBAS; ++p) {
171          const uint64_t* const cnt = proba->stats_[t][b][c][p];
172          const int update_proba = VP8CoeffsUpdateProba[t][b][c][p];
173          const int old_p = VP8CoeffsProba0[t][b][c][p];
174          const int new_p = CalcTokenProba(cnt[0], cnt[1]);
175          const uint64_t old_cost = VP8BranchCost(cnt[0], cnt[1], old_p)
176                                  + VP8BitCost(0, update_proba);
177          const uint64_t new_cost = VP8BranchCost(cnt[0], cnt[1], new_p)
178                                  + VP8BitCost(1, update_proba) + 8 * 256;
179          const int use_new_p = (old_cost > new_cost);
180          size += VP8BitCost(use_new_p, update_proba);
181          if (use_new_p) {  // only use proba that seem meaningful enough.
182            proba->coeffs_[t][b][c][p] = new_p;
183            size += 8 * 256;
184          } else {
185            proba->coeffs_[t][b][c][p] = old_p;
186          }
187        }
188      }
189    }
190  }
191  return size;
192}
193
194//-----------------------------------------------------------------------------
195// helper functions for residuals struct VP8Residual.
196
197static void InitResidual(int first, int coeff_type,
198                         VP8Encoder* const enc, VP8Residual* const res) {
199  res->coeff_type = coeff_type;
200  res->prob  = enc->proba_.coeffs_[coeff_type];
201  res->stats = enc->proba_.stats_[coeff_type];
202  res->cost  = enc->proba_.level_cost_[coeff_type];
203  res->first = first;
204}
205
206static void SetResidualCoeffs(const int16_t* const coeffs,
207                              VP8Residual* const res) {
208  int n;
209  res->last = -1;
210  for (n = 15; n >= res->first; --n) {
211    if (coeffs[n]) {
212      res->last = n;
213      break;
214    }
215  }
216  res->coeffs = coeffs;
217}
218
219//-----------------------------------------------------------------------------
220// Mode costs
221
222static int GetResidualCost(int ctx, const VP8Residual* const res) {
223  int n = res->first;
224  const uint8_t* p = res->prob[VP8EncBands[n]][ctx];
225  const uint16_t *t = res->cost[VP8EncBands[n]][ctx];
226  int cost;
227
228  cost = VP8BitCost(res->last >= 0, p[0]);
229  if (res->last < 0) {
230    return cost;
231  }
232  while (n <= res->last) {
233    const int v = res->coeffs[n++];
234    if (v == 0) {
235      cost += VP8LevelCost(t, 0);
236      p = res->prob[VP8EncBands[n]][0];
237      t = res->cost[VP8EncBands[n]][0];
238      continue;
239    } else if (2u >= (unsigned int)(v + 1)) {   // v = -1 or 1
240      cost += VP8LevelCost(t, 1);
241      p = res->prob[VP8EncBands[n]][1];
242      t = res->cost[VP8EncBands[n]][1];
243    } else {
244      cost += VP8LevelCost(t, abs(v));
245      p = res->prob[VP8EncBands[n]][2];
246      t = res->cost[VP8EncBands[n]][2];
247    }
248    if (n < 16) {
249      cost += VP8BitCost(n <= res->last, p[0]);
250    }
251  }
252  return cost;
253}
254
255int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]) {
256  const int x = (it->i4_ & 3), y = (it->i4_ >> 2);
257  VP8Residual res;
258  int R = 0;
259  int ctx;
260
261  InitResidual(0, 3, it->enc_, &res);
262  ctx = it->top_nz_[x] + it->left_nz_[y];
263  SetResidualCoeffs(levels, &res);
264  R += GetResidualCost(ctx, &res);
265  return R;
266}
267
268int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd) {
269  VP8Residual res;
270  int x, y;
271  int R = 0;
272
273  VP8IteratorNzToBytes(it);   // re-import the non-zero context
274
275  // DC
276  InitResidual(0, 1, it->enc_, &res);
277  SetResidualCoeffs(rd->y_dc_levels, &res);
278  R += GetResidualCost(it->top_nz_[8] + it->left_nz_[8], &res);
279
280  // AC
281  InitResidual(1, 0, it->enc_, &res);
282  for (y = 0; y < 4; ++y) {
283    for (x = 0; x < 4; ++x) {
284      const int ctx = it->top_nz_[x] + it->left_nz_[y];
285      SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
286      R += GetResidualCost(ctx, &res);
287      it->top_nz_[x] = it->left_nz_[y] = (res.last >= 0);
288    }
289  }
290  return R;
291}
292
293int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd) {
294  VP8Residual res;
295  int ch, x, y;
296  int R = 0;
297
298  VP8IteratorNzToBytes(it);  // re-import the non-zero context
299
300  InitResidual(0, 2, it->enc_, &res);
301  for (ch = 0; ch <= 2; ch += 2) {
302    for (y = 0; y < 2; ++y) {
303      for (x = 0; x < 2; ++x) {
304        const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
305        SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
306        R += GetResidualCost(ctx, &res);
307        it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = (res.last >= 0);
308      }
309    }
310  }
311  return R;
312}
313
314//-----------------------------------------------------------------------------
315// Coefficient coding
316
317static int PutCoeffs(VP8BitWriter* const bw, int ctx, const VP8Residual* res) {
318  int n = res->first;
319  const uint8_t* p = res->prob[VP8EncBands[n]][ctx];
320  if (!VP8PutBit(bw, res->last >= 0, p[0])) {
321    return 0;
322  }
323
324  while (n < 16) {
325    const int c = res->coeffs[n++];
326    const int sign = c < 0;
327    int v = sign ? -c : c;
328    if (!VP8PutBit(bw, v != 0, p[1])) {
329      p = res->prob[VP8EncBands[n]][0];
330      continue;
331    }
332    if (!VP8PutBit(bw, v > 1, p[2])) {
333      p = res->prob[VP8EncBands[n]][1];
334    } else {
335      if (!VP8PutBit(bw, v > 4, p[3])) {
336        if (VP8PutBit(bw, v != 2, p[4]))
337          VP8PutBit(bw, v == 4, p[5]);
338      } else if (!VP8PutBit(bw, v > 10, p[6])) {
339        if (!VP8PutBit(bw, v > 6, p[7])) {
340          VP8PutBit(bw, v == 6, 159);
341        } else {
342          VP8PutBit(bw, v >= 9, 165);
343          VP8PutBit(bw, !(v & 1), 145);
344        }
345      } else {
346        int mask;
347        const uint8_t* tab;
348        if (v < 3 + (8 << 1)) {          // kCat3  (3b)
349          VP8PutBit(bw, 0, p[8]);
350          VP8PutBit(bw, 0, p[9]);
351          v -= 3 + (8 << 0);
352          mask = 1 << 2;
353          tab = kCat3;
354        } else if (v < 3 + (8 << 2)) {   // kCat4  (4b)
355          VP8PutBit(bw, 0, p[8]);
356          VP8PutBit(bw, 1, p[9]);
357          v -= 3 + (8 << 1);
358          mask = 1 << 3;
359          tab = kCat4;
360        } else if (v < 3 + (8 << 3)) {   // kCat5  (5b)
361          VP8PutBit(bw, 1, p[8]);
362          VP8PutBit(bw, 0, p[10]);
363          v -= 3 + (8 << 2);
364          mask = 1 << 4;
365          tab = kCat5;
366        } else {                         // kCat6 (11b)
367          VP8PutBit(bw, 1, p[8]);
368          VP8PutBit(bw, 1, p[10]);
369          v -= 3 + (8 << 3);
370          mask = 1 << 10;
371          tab = kCat6;
372        }
373        while (mask) {
374          VP8PutBit(bw, !!(v & mask), *tab++);
375          mask >>= 1;
376        }
377      }
378      p = res->prob[VP8EncBands[n]][2];
379    }
380    VP8PutBitUniform(bw, sign);
381    if (n == 16 || !VP8PutBit(bw, n <= res->last, p[0])) {
382      return 1;   // EOB
383    }
384  }
385  return 1;
386}
387
388static void CodeResiduals(VP8BitWriter* const bw,
389                          VP8EncIterator* const it,
390                          const VP8ModeScore* const rd) {
391  int x, y, ch;
392  VP8Residual res;
393  uint64_t pos1, pos2, pos3;
394  const int i16 = (it->mb_->type_ == 1);
395  const int segment = it->mb_->segment_;
396
397  VP8IteratorNzToBytes(it);
398
399  pos1 = VP8BitWriterPos(bw);
400  if (i16) {
401    InitResidual(0, 1, it->enc_, &res);
402    SetResidualCoeffs(rd->y_dc_levels, &res);
403    it->top_nz_[8] = it->left_nz_[8] =
404      PutCoeffs(bw, it->top_nz_[8] + it->left_nz_[8], &res);
405    InitResidual(1, 0, it->enc_, &res);
406  } else {
407    InitResidual(0, 3, it->enc_, &res);
408  }
409
410  // luma-AC
411  for (y = 0; y < 4; ++y) {
412    for (x = 0; x < 4; ++x) {
413      const int ctx = it->top_nz_[x] + it->left_nz_[y];
414      SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
415      it->top_nz_[x] = it->left_nz_[y] = PutCoeffs(bw, ctx, &res);
416    }
417  }
418  pos2 = VP8BitWriterPos(bw);
419
420  // U/V
421  InitResidual(0, 2, it->enc_, &res);
422  for (ch = 0; ch <= 2; ch += 2) {
423    for (y = 0; y < 2; ++y) {
424      for (x = 0; x < 2; ++x) {
425        const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
426        SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
427        it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] =
428            PutCoeffs(bw, ctx, &res);
429      }
430    }
431  }
432  pos3 = VP8BitWriterPos(bw);
433  it->luma_bits_ = pos2 - pos1;
434  it->uv_bits_ = pos3 - pos2;
435  it->bit_count_[segment][i16] += it->luma_bits_;
436  it->bit_count_[segment][2] += it->uv_bits_;
437  VP8IteratorBytesToNz(it);
438}
439
440// Same as CodeResiduals, but doesn't actually write anything.
441// Instead, it just records the event distribution.
442static void RecordResiduals(VP8EncIterator* const it,
443                            const VP8ModeScore* const rd) {
444  int x, y, ch;
445  VP8Residual res;
446
447  VP8IteratorNzToBytes(it);
448
449  if (it->mb_->type_ == 1) {   // i16x16
450    InitResidual(0, 1, it->enc_, &res);
451    SetResidualCoeffs(rd->y_dc_levels, &res);
452    it->top_nz_[8] = it->left_nz_[8] =
453      RecordCoeffs(it->top_nz_[8] + it->left_nz_[8], &res);
454    InitResidual(1, 0, it->enc_, &res);
455  } else {
456    InitResidual(0, 3, it->enc_, &res);
457  }
458
459  // luma-AC
460  for (y = 0; y < 4; ++y) {
461    for (x = 0; x < 4; ++x) {
462      const int ctx = it->top_nz_[x] + it->left_nz_[y];
463      SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
464      it->top_nz_[x] = it->left_nz_[y] = RecordCoeffs(ctx, &res);
465    }
466  }
467
468  // U/V
469  InitResidual(0, 2, it->enc_, &res);
470  for (ch = 0; ch <= 2; ch += 2) {
471    for (y = 0; y < 2; ++y) {
472      for (x = 0; x < 2; ++x) {
473        const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
474        SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
475        it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] =
476            RecordCoeffs(ctx, &res);
477      }
478    }
479  }
480
481  VP8IteratorBytesToNz(it);
482}
483
484//-----------------------------------------------------------------------------
485// ExtraInfo map / Debug function
486
487#if SEGMENT_VISU
488static void SetBlock(uint8_t* p, int value, int size) {
489  int y;
490  for (y = 0; y < size; ++y) {
491    memset(p, value, size);
492    p += BPS;
493  }
494}
495#endif
496
497static void ResetSSE(VP8Encoder* const enc) {
498  memset(enc->sse_, 0, sizeof(enc->sse_));
499  enc->sse_count_ = 0;
500}
501
502static void StoreSSE(const VP8EncIterator* const it) {
503  VP8Encoder* const enc = it->enc_;
504  const uint8_t* const in = it->yuv_in_;
505  const uint8_t* const out = it->yuv_out_;
506  // Note: not totally accurate at boundary. And doesn't include in-loop filter.
507  enc->sse_[0] += VP8SSE16x16(in + Y_OFF, out + Y_OFF);
508  enc->sse_[1] += VP8SSE8x8(in + U_OFF, out + U_OFF);
509  enc->sse_[2] += VP8SSE8x8(in + V_OFF, out + V_OFF);
510  enc->sse_count_ += 16 * 16;
511}
512
513static void StoreSideInfo(const VP8EncIterator* const it) {
514  VP8Encoder* const enc = it->enc_;
515  const VP8MBInfo* const mb = it->mb_;
516  WebPPicture* const pic = enc->pic_;
517
518  if (pic->stats) {
519    StoreSSE(it);
520    enc->block_count_[0] += (mb->type_ == 0);
521    enc->block_count_[1] += (mb->type_ == 1);
522    enc->block_count_[2] += (mb->skip_ != 0);
523  }
524
525  if (pic->extra_info) {
526    uint8_t* const info = &pic->extra_info[it->x_ + it->y_ * enc->mb_w_];
527    switch(pic->extra_info_type) {
528      case 1: *info = mb->type_; break;
529      case 2: *info = mb->segment_; break;
530      case 3: *info = enc->dqm_[mb->segment_].quant_; break;
531      case 4: *info = (mb->type_ == 1) ? it->preds_[0] : 0xff; break;
532      case 5: *info = mb->uv_mode_; break;
533      case 6: {
534        const int b = (int)((it->luma_bits_ + it->uv_bits_ + 7) >> 3);
535        *info = (b > 255) ? 255 : b; break;
536      }
537      default: *info = 0; break;
538    };
539  }
540#if SEGMENT_VISU  // visualize segments and prediction modes
541  SetBlock(it->yuv_out_ + Y_OFF, mb->segment_ * 64, 16);
542  SetBlock(it->yuv_out_ + U_OFF, it->preds_[0] * 64, 8);
543  SetBlock(it->yuv_out_ + V_OFF, mb->uv_mode_ * 64, 8);
544#endif
545}
546
547//-----------------------------------------------------------------------------
548// Main loops
549//
550//  VP8EncLoop(): does the final bitstream coding.
551
552static void ResetAfterSkip(VP8EncIterator* const it) {
553  if (it->mb_->type_ == 1) {
554    *it->nz_ = 0;  // reset all predictors
555    it->left_nz_[8] = 0;
556  } else {
557    *it->nz_ &= (1 << 24);  // preserve the dc_nz bit
558  }
559}
560
561int VP8EncLoop(VP8Encoder* const enc) {
562  int i, s, p;
563  VP8EncIterator it;
564  VP8ModeScore info;
565  const int dont_use_skip = !enc->proba_.use_skip_proba_;
566  const int rd_opt = enc->rd_opt_level_;
567  const int kAverageBytesPerMB = 5;     // TODO: have a kTable[quality/10]
568  const int bytes_per_parts =
569    enc->mb_w_ * enc->mb_h_ * kAverageBytesPerMB / enc->num_parts_;
570
571  // Initialize the bit-writers
572  for (p = 0; p < enc->num_parts_; ++p) {
573    VP8BitWriterInit(enc->parts_ + p, bytes_per_parts);
574  }
575
576  ResetStats(enc, rd_opt != 0);
577  ResetSSE(enc);
578
579  VP8IteratorInit(enc, &it);
580  VP8InitFilter(&it);
581  do {
582    VP8IteratorImport(&it);
583    // Warning! order is important: first call VP8Decimate() and
584    // *then* decide how to code the skip decision if there's one.
585    if (!VP8Decimate(&it, &info, rd_opt) || dont_use_skip) {
586      CodeResiduals(it.bw_, &it, &info);
587    } else {   // reset predictors after a skip
588      ResetAfterSkip(&it);
589    }
590#ifdef WEBP_EXPERIMENTAL_FEATURES
591    if (enc->has_alpha_) {
592      VP8EncCodeAlphaBlock(&it);
593    }
594    if (enc->use_layer_) {
595      VP8EncCodeLayerBlock(&it);
596    }
597#endif
598    StoreSideInfo(&it);
599    VP8StoreFilterStats(&it);
600    VP8IteratorExport(&it);
601  } while (VP8IteratorNext(&it, it.yuv_out_));
602  VP8AdjustFilterStrength(&it);
603
604  // Finalize the partitions
605  for (p = 0; p < enc->num_parts_; ++p) {
606    VP8BitWriterFinish(enc->parts_ + p);
607  }
608  // and byte counters
609  if (enc->pic_->stats) {
610    for (i = 0; i <= 2; ++i) {
611      for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
612        enc->residual_bytes_[i][s] = (int)((it.bit_count_[s][i] + 7) >> 3);
613      }
614    }
615  }
616  return 1;
617}
618
619//-----------------------------------------------------------------------------
620//  VP8StatLoop(): only collect statistics (number of skips, token usage, ...)
621//                 This is used for deciding optimal probabilities. It also
622//                 modifies the quantizer value if some target (size, PNSR)
623//                 was specified.
624
625#define kHeaderSizeEstimate (15 + 20 + 10)      // TODO: fix better
626
627static int OneStatPass(VP8Encoder* const enc, float q, int rd_opt, int nb_mbs,
628                       float* const PSNR) {
629  VP8EncIterator it;
630  uint64_t size = 0;
631  uint64_t distortion = 0;
632  const uint64_t pixel_count = nb_mbs * 384;
633
634  // Make sure the quality parameter is inside valid bounds
635  if (q < 0.) {
636    q = 0;
637  } else if (q > 100.) {
638    q = 100;
639  }
640
641  VP8SetSegmentParams(enc, q);      // setup segment quantizations and filters
642
643  ResetStats(enc, rd_opt != 0);
644  ResetTokenStats(enc);
645
646  VP8IteratorInit(enc, &it);
647  do {
648    VP8ModeScore info;
649    VP8IteratorImport(&it);
650    if (VP8Decimate(&it, &info, rd_opt)) {
651      // Just record the number of skips and act like skip_proba is not used.
652      enc->proba_.nb_skip_++;
653    }
654    RecordResiduals(&it, &info);
655    size += info.R;
656    distortion += info.D;
657  } while (VP8IteratorNext(&it, it.yuv_out_) && --nb_mbs > 0);
658  size += FinalizeSkipProba(enc);
659  size += FinalizeTokenProbas(enc);
660  size += enc->segment_hdr_.size_;
661  size = ((size + 1024) >> 11) + kHeaderSizeEstimate;
662
663  if (PSNR) {
664    *PSNR = (float)(10.* log10(255. * 255. * pixel_count / distortion));
665  }
666  return (int)size;
667}
668
669// successive refinement increments.
670static const int dqs[] = { 20, 15, 10, 8, 6, 4, 2, 1, 0 };
671
672int VP8StatLoop(VP8Encoder* const enc) {
673  const int do_search =
674    (enc->config_->target_size > 0 || enc->config_->target_PSNR > 0);
675  const int fast_probe = (enc->method_ < 2 && !do_search);
676  float q = enc->config_->quality;
677  int pass;
678  int nb_mbs;
679
680  // Fast mode: quick analysis pass over few mbs. Better than nothing.
681  nb_mbs = enc->mb_w_ * enc->mb_h_;
682  if (fast_probe && nb_mbs > 100) nb_mbs = 100;
683
684  // No target size: just do several pass without changing 'q'
685  if (!do_search) {
686    for (pass = 0; pass < enc->config_->pass; ++pass) {
687      const int rd_opt = (enc->method_ > 2);
688      OneStatPass(enc, q, rd_opt, nb_mbs, NULL);
689    }
690    return 1;
691  }
692
693  // binary search for a size close to target
694  for (pass = 0; pass < enc->config_->pass && (dqs[pass] > 0); ++pass) {
695    const int rd_opt = 1;
696    float PSNR;
697    int criterion;
698    const int size = OneStatPass(enc, q, rd_opt, nb_mbs, &PSNR);
699#if DEBUG_SEARCH
700    printf("#%d size=%d PSNR=%.2f q=%.2f\n", pass, size, PSNR, q);
701#endif
702
703    if (enc->config_->target_PSNR > 0) {
704      criterion = (PSNR < enc->config_->target_PSNR);
705    } else {
706      criterion = (size < enc->config_->target_size);
707    }
708    // dichotomize
709    if (criterion) {
710      q += dqs[pass];
711    } else {
712      q -= dqs[pass];
713    }
714  }
715  return 1;
716}
717
718//-----------------------------------------------------------------------------
719
720#if defined(__cplusplus) || defined(c_plusplus)
721}    // extern "C"
722#endif
723