1// Copyright 2011 Google Inc. All Rights Reserved.
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// Macroblock analysis
9//
10// Author: Skal (pascal.massimino@gmail.com)
11
12#include <stdlib.h>
13#include <string.h>
14#include <assert.h>
15
16#include "./vp8enci.h"
17#include "./cost.h"
18#include "../utils/utils.h"
19
20#if defined(__cplusplus) || defined(c_plusplus)
21extern "C" {
22#endif
23
24#define MAX_ITERS_K_MEANS  6
25
26static int ClipAlpha(int alpha) {
27  return alpha < 0 ? 0 : alpha > 255 ? 255 : alpha;
28}
29
30//------------------------------------------------------------------------------
31// Smooth the segment map by replacing isolated block by the majority of its
32// neighbours.
33
34static void SmoothSegmentMap(VP8Encoder* const enc) {
35  int n, x, y;
36  const int w = enc->mb_w_;
37  const int h = enc->mb_h_;
38  const int majority_cnt_3_x_3_grid = 5;
39  uint8_t* const tmp = (uint8_t*)WebPSafeMalloc((uint64_t)w * h, sizeof(*tmp));
40  assert((uint64_t)(w * h) == (uint64_t)w * h);   // no overflow, as per spec
41
42  if (tmp == NULL) return;
43  for (y = 1; y < h - 1; ++y) {
44    for (x = 1; x < w - 1; ++x) {
45      int cnt[NUM_MB_SEGMENTS] = { 0 };
46      const VP8MBInfo* const mb = &enc->mb_info_[x + w * y];
47      int majority_seg = mb->segment_;
48      // Check the 8 neighbouring segment values.
49      cnt[mb[-w - 1].segment_]++;  // top-left
50      cnt[mb[-w + 0].segment_]++;  // top
51      cnt[mb[-w + 1].segment_]++;  // top-right
52      cnt[mb[   - 1].segment_]++;  // left
53      cnt[mb[   + 1].segment_]++;  // right
54      cnt[mb[ w - 1].segment_]++;  // bottom-left
55      cnt[mb[ w + 0].segment_]++;  // bottom
56      cnt[mb[ w + 1].segment_]++;  // bottom-right
57      for (n = 0; n < NUM_MB_SEGMENTS; ++n) {
58        if (cnt[n] >= majority_cnt_3_x_3_grid) {
59          majority_seg = n;
60        }
61      }
62      tmp[x + y * w] = majority_seg;
63    }
64  }
65  for (y = 1; y < h - 1; ++y) {
66    for (x = 1; x < w - 1; ++x) {
67      VP8MBInfo* const mb = &enc->mb_info_[x + w * y];
68      mb->segment_ = tmp[x + y * w];
69    }
70  }
71  free(tmp);
72}
73
74//------------------------------------------------------------------------------
75// Finalize Segment probability based on the coding tree
76
77static int GetProba(int a, int b) {
78  int proba;
79  const int total = a + b;
80  if (total == 0) return 255;  // that's the default probability.
81  proba = (255 * a + total / 2) / total;
82  return proba;
83}
84
85static void SetSegmentProbas(VP8Encoder* const enc) {
86  int p[NUM_MB_SEGMENTS] = { 0 };
87  int n;
88
89  for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
90    const VP8MBInfo* const mb = &enc->mb_info_[n];
91    p[mb->segment_]++;
92  }
93  if (enc->pic_->stats) {
94    for (n = 0; n < NUM_MB_SEGMENTS; ++n) {
95      enc->pic_->stats->segment_size[n] = p[n];
96    }
97  }
98  if (enc->segment_hdr_.num_segments_ > 1) {
99    uint8_t* const probas = enc->proba_.segments_;
100    probas[0] = GetProba(p[0] + p[1], p[2] + p[3]);
101    probas[1] = GetProba(p[0], p[1]);
102    probas[2] = GetProba(p[2], p[3]);
103
104    enc->segment_hdr_.update_map_ =
105        (probas[0] != 255) || (probas[1] != 255) || (probas[2] != 255);
106    enc->segment_hdr_.size_ =
107      p[0] * (VP8BitCost(0, probas[0]) + VP8BitCost(0, probas[1])) +
108      p[1] * (VP8BitCost(0, probas[0]) + VP8BitCost(1, probas[1])) +
109      p[2] * (VP8BitCost(1, probas[0]) + VP8BitCost(0, probas[2])) +
110      p[3] * (VP8BitCost(1, probas[0]) + VP8BitCost(1, probas[2]));
111  } else {
112    enc->segment_hdr_.update_map_ = 0;
113    enc->segment_hdr_.size_ = 0;
114  }
115}
116
117static WEBP_INLINE int clip(int v, int m, int M) {
118  return v < m ? m : v > M ? M : v;
119}
120
121static void SetSegmentAlphas(VP8Encoder* const enc,
122                             const int centers[NUM_MB_SEGMENTS],
123                             int mid) {
124  const int nb = enc->segment_hdr_.num_segments_;
125  int min = centers[0], max = centers[0];
126  int n;
127
128  if (nb > 1) {
129    for (n = 0; n < nb; ++n) {
130      if (min > centers[n]) min = centers[n];
131      if (max < centers[n]) max = centers[n];
132    }
133  }
134  if (max == min) max = min + 1;
135  assert(mid <= max && mid >= min);
136  for (n = 0; n < nb; ++n) {
137    const int alpha = 255 * (centers[n] - mid) / (max - min);
138    const int beta = 255 * (centers[n] - min) / (max - min);
139    enc->dqm_[n].alpha_ = clip(alpha, -127, 127);
140    enc->dqm_[n].beta_ = clip(beta, 0, 255);
141  }
142}
143
144//------------------------------------------------------------------------------
145// Simplified k-Means, to assign Nb segments based on alpha-histogram
146
147static void AssignSegments(VP8Encoder* const enc, const int alphas[256]) {
148  const int nb = enc->segment_hdr_.num_segments_;
149  int centers[NUM_MB_SEGMENTS];
150  int weighted_average = 0;
151  int map[256];
152  int a, n, k;
153  int min_a = 0, max_a = 255, range_a;
154  // 'int' type is ok for histo, and won't overflow
155  int accum[NUM_MB_SEGMENTS], dist_accum[NUM_MB_SEGMENTS];
156
157  // bracket the input
158  for (n = 0; n < 256 && alphas[n] == 0; ++n) {}
159  min_a = n;
160  for (n = 255; n > min_a && alphas[n] == 0; --n) {}
161  max_a = n;
162  range_a = max_a - min_a;
163
164  // Spread initial centers evenly
165  for (n = 1, k = 0; n < 2 * nb; n += 2) {
166    centers[k++] = min_a + (n * range_a) / (2 * nb);
167  }
168
169  for (k = 0; k < MAX_ITERS_K_MEANS; ++k) {     // few iters are enough
170    int total_weight;
171    int displaced;
172    // Reset stats
173    for (n = 0; n < nb; ++n) {
174      accum[n] = 0;
175      dist_accum[n] = 0;
176    }
177    // Assign nearest center for each 'a'
178    n = 0;    // track the nearest center for current 'a'
179    for (a = min_a; a <= max_a; ++a) {
180      if (alphas[a]) {
181        while (n < nb - 1 && abs(a - centers[n + 1]) < abs(a - centers[n])) {
182          n++;
183        }
184        map[a] = n;
185        // accumulate contribution into best centroid
186        dist_accum[n] += a * alphas[a];
187        accum[n] += alphas[a];
188      }
189    }
190    // All point are classified. Move the centroids to the
191    // center of their respective cloud.
192    displaced = 0;
193    weighted_average = 0;
194    total_weight = 0;
195    for (n = 0; n < nb; ++n) {
196      if (accum[n]) {
197        const int new_center = (dist_accum[n] + accum[n] / 2) / accum[n];
198        displaced += abs(centers[n] - new_center);
199        centers[n] = new_center;
200        weighted_average += new_center * accum[n];
201        total_weight += accum[n];
202      }
203    }
204    weighted_average = (weighted_average + total_weight / 2) / total_weight;
205    if (displaced < 5) break;   // no need to keep on looping...
206  }
207
208  // Map each original value to the closest centroid
209  for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
210    VP8MBInfo* const mb = &enc->mb_info_[n];
211    const int alpha = mb->alpha_;
212    mb->segment_ = map[alpha];
213    mb->alpha_ = centers[map[alpha]];     // just for the record.
214  }
215
216  if (nb > 1) {
217    const int smooth = (enc->config_->preprocessing & 1);
218    if (smooth) SmoothSegmentMap(enc);
219  }
220
221  SetSegmentProbas(enc);                             // Assign final proba
222  SetSegmentAlphas(enc, centers, weighted_average);  // pick some alphas.
223}
224
225//------------------------------------------------------------------------------
226// Macroblock analysis: collect histogram for each mode, deduce the maximal
227// susceptibility and set best modes for this macroblock.
228// Segment assignment is done later.
229
230// Number of modes to inspect for alpha_ evaluation. For high-quality settings,
231// we don't need to test all the possible modes during the analysis phase.
232#define MAX_INTRA16_MODE 2
233#define MAX_INTRA4_MODE  2
234#define MAX_UV_MODE      2
235
236static int MBAnalyzeBestIntra16Mode(VP8EncIterator* const it) {
237  const int max_mode = (it->enc_->method_ >= 3) ? MAX_INTRA16_MODE : 4;
238  int mode;
239  int best_alpha = -1;
240  int best_mode = 0;
241
242  VP8MakeLuma16Preds(it);
243  for (mode = 0; mode < max_mode; ++mode) {
244    const int alpha = VP8CollectHistogram(it->yuv_in_ + Y_OFF,
245                                          it->yuv_p_ + VP8I16ModeOffsets[mode],
246                                          0, 16);
247    if (alpha > best_alpha) {
248      best_alpha = alpha;
249      best_mode = mode;
250    }
251  }
252  VP8SetIntra16Mode(it, best_mode);
253  return best_alpha;
254}
255
256static int MBAnalyzeBestIntra4Mode(VP8EncIterator* const it,
257                                   int best_alpha) {
258  uint8_t modes[16];
259  const int max_mode = (it->enc_->method_ >= 3) ? MAX_INTRA4_MODE : NUM_BMODES;
260  int i4_alpha = 0;
261  VP8IteratorStartI4(it);
262  do {
263    int mode;
264    int best_mode_alpha = -1;
265    const uint8_t* const src = it->yuv_in_ + Y_OFF + VP8Scan[it->i4_];
266
267    VP8MakeIntra4Preds(it);
268    for (mode = 0; mode < max_mode; ++mode) {
269      const int alpha = VP8CollectHistogram(src,
270                                            it->yuv_p_ + VP8I4ModeOffsets[mode],
271                                            0, 1);
272      if (alpha > best_mode_alpha) {
273        best_mode_alpha = alpha;
274        modes[it->i4_] = mode;
275      }
276    }
277    i4_alpha += best_mode_alpha;
278    // Note: we reuse the original samples for predictors
279  } while (VP8IteratorRotateI4(it, it->yuv_in_ + Y_OFF));
280
281  if (i4_alpha > best_alpha) {
282    VP8SetIntra4Mode(it, modes);
283    best_alpha = ClipAlpha(i4_alpha);
284  }
285  return best_alpha;
286}
287
288static int MBAnalyzeBestUVMode(VP8EncIterator* const it) {
289  int best_alpha = -1;
290  int best_mode = 0;
291  const int max_mode = (it->enc_->method_ >= 3) ? MAX_UV_MODE : 4;
292  int mode;
293  VP8MakeChroma8Preds(it);
294  for (mode = 0; mode < max_mode; ++mode) {
295    const int alpha = VP8CollectHistogram(it->yuv_in_ + U_OFF,
296                                          it->yuv_p_ + VP8UVModeOffsets[mode],
297                                          16, 16 + 4 + 4);
298    if (alpha > best_alpha) {
299      best_alpha = alpha;
300      best_mode = mode;
301    }
302  }
303  VP8SetIntraUVMode(it, best_mode);
304  return best_alpha;
305}
306
307static void MBAnalyze(VP8EncIterator* const it,
308                      int alphas[256], int* const uv_alpha) {
309  const VP8Encoder* const enc = it->enc_;
310  int best_alpha, best_uv_alpha;
311
312  VP8SetIntra16Mode(it, 0);  // default: Intra16, DC_PRED
313  VP8SetSkip(it, 0);         // not skipped
314  VP8SetSegment(it, 0);      // default segment, spec-wise.
315
316  best_alpha = MBAnalyzeBestIntra16Mode(it);
317  if (enc->method_ != 3) {
318    // We go and make a fast decision for intra4/intra16.
319    // It's usually not a good and definitive pick, but helps seeding the stats
320    // about level bit-cost.
321    // TODO(skal): improve criterion.
322    best_alpha = MBAnalyzeBestIntra4Mode(it, best_alpha);
323  }
324  best_uv_alpha = MBAnalyzeBestUVMode(it);
325
326  // Final susceptibility mix
327  best_alpha = (best_alpha + best_uv_alpha + 1) / 2;
328  alphas[best_alpha]++;
329  *uv_alpha += best_uv_alpha;
330  it->mb_->alpha_ = best_alpha;   // Informative only.
331}
332
333//------------------------------------------------------------------------------
334// Main analysis loop:
335// Collect all susceptibilities for each macroblock and record their
336// distribution in alphas[]. Segments is assigned a-posteriori, based on
337// this histogram.
338// We also pick an intra16 prediction mode, which shouldn't be considered
339// final except for fast-encode settings. We can also pick some intra4 modes
340// and decide intra4/intra16, but that's usually almost always a bad choice at
341// this stage.
342
343int VP8EncAnalyze(VP8Encoder* const enc) {
344  int ok = 1;
345  int alphas[256] = { 0 };
346  VP8EncIterator it;
347
348  VP8IteratorInit(enc, &it);
349  enc->uv_alpha_ = 0;
350  do {
351    VP8IteratorImport(&it);
352    MBAnalyze(&it, alphas, &enc->uv_alpha_);
353    ok = VP8IteratorProgress(&it, 20);
354    // Let's pretend we have perfect lossless reconstruction.
355  } while (ok && VP8IteratorNext(&it, it.yuv_in_));
356  enc->uv_alpha_ /= enc->mb_w_ * enc->mb_h_;
357  if (ok) AssignSegments(enc, alphas);
358
359  return ok;
360}
361
362#if defined(__cplusplus) || defined(c_plusplus)
363}    // extern "C"
364#endif
365