1a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Copyright 2011 Google Inc. All Rights Reserved.
27c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//
30406ce1417f76f2034833414dcecc9f56253640cVikas Arora// Use of this source code is governed by a BSD-style license
40406ce1417f76f2034833414dcecc9f56253640cVikas Arora// that can be found in the COPYING file in the root of the source
50406ce1417f76f2034833414dcecc9f56253640cVikas Arora// tree. An additional intellectual property rights grant can be found
60406ce1417f76f2034833414dcecc9f56253640cVikas Arora// in the file PATENTS. All contributing project authors may
70406ce1417f76f2034833414dcecc9f56253640cVikas Arora// be found in the AUTHORS file in the root of the source tree.
87c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// -----------------------------------------------------------------------------
97c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//
107c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// Macroblock analysis
117c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//
127c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// Author: Skal (pascal.massimino@gmail.com)
137c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
147c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#include <stdlib.h>
157c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#include <string.h>
167c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#include <assert.h>
177c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
18a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern#include "src/enc/vp8i_enc.h"
19a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern#include "src/enc/cost_enc.h"
20a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern#include "src/utils/utils.h"
217c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
227c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#define MAX_ITERS_K_MEANS  6
237c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
24a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
257c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// Smooth the segment map by replacing isolated block by the majority of its
267c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// neighbours.
277c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
287c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arorastatic void SmoothSegmentMap(VP8Encoder* const enc) {
297c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  int n, x, y;
307c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const int w = enc->mb_w_;
317c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const int h = enc->mb_h_;
327c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const int majority_cnt_3_x_3_grid = 5;
3333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  uint8_t* const tmp = (uint8_t*)WebPSafeMalloc(w * h, sizeof(*tmp));
34a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  assert((uint64_t)(w * h) == (uint64_t)w * h);   // no overflow, as per spec
357c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
367c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  if (tmp == NULL) return;
377c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  for (y = 1; y < h - 1; ++y) {
387c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    for (x = 1; x < w - 1; ++x) {
397c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      int cnt[NUM_MB_SEGMENTS] = { 0 };
407c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      const VP8MBInfo* const mb = &enc->mb_info_[x + w * y];
417c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      int majority_seg = mb->segment_;
427c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      // Check the 8 neighbouring segment values.
437c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      cnt[mb[-w - 1].segment_]++;  // top-left
447c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      cnt[mb[-w + 0].segment_]++;  // top
457c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      cnt[mb[-w + 1].segment_]++;  // top-right
46466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      cnt[mb[   - 1].segment_]++;  // left
47466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      cnt[mb[   + 1].segment_]++;  // right
48466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      cnt[mb[ w - 1].segment_]++;  // bottom-left
49466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      cnt[mb[ w + 0].segment_]++;  // bottom
50466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      cnt[mb[ w + 1].segment_]++;  // bottom-right
517c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      for (n = 0; n < NUM_MB_SEGMENTS; ++n) {
527c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora        if (cnt[n] >= majority_cnt_3_x_3_grid) {
537c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora          majority_seg = n;
548b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora          break;
557c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora        }
567c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      }
577c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      tmp[x + y * w] = majority_seg;
587c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    }
597c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
607c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  for (y = 1; y < h - 1; ++y) {
617c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    for (x = 1; x < w - 1; ++x) {
627c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      VP8MBInfo* const mb = &enc->mb_info_[x + w * y];
637c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      mb->segment_ = tmp[x + y * w];
647c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    }
657c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
6633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  WebPSafeFree(tmp);
677c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
687c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
69a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
701e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// set segment susceptibility alpha_ / beta_
717c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
72a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic WEBP_INLINE int clip(int v, int m, int M) {
731e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  return (v < m) ? m : (v > M) ? M : v;
747c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
757c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
767c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arorastatic void SetSegmentAlphas(VP8Encoder* const enc,
777c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora                             const int centers[NUM_MB_SEGMENTS],
787c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora                             int mid) {
797c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const int nb = enc->segment_hdr_.num_segments_;
807c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  int min = centers[0], max = centers[0];
817c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  int n;
827c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
837c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  if (nb > 1) {
847c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    for (n = 0; n < nb; ++n) {
857c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      if (min > centers[n]) min = centers[n];
867c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      if (max < centers[n]) max = centers[n];
877c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    }
887c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
897c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  if (max == min) max = min + 1;
907c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  assert(mid <= max && mid >= min);
917c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  for (n = 0; n < nb; ++n) {
927c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    const int alpha = 255 * (centers[n] - mid) / (max - min);
937c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    const int beta = 255 * (centers[n] - min) / (max - min);
947c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    enc->dqm_[n].alpha_ = clip(alpha, -127, 127);
957c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    enc->dqm_[n].beta_ = clip(beta, 0, 255);
967c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
977c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
987c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
99a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
1001e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// Compute susceptibility based on DCT-coeff histograms:
1011e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// the higher, the "easier" the macroblock is to compress.
1021e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
1031e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora#define MAX_ALPHA 255                // 8b of precision for susceptibilities.
1041e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora#define ALPHA_SCALE (2 * MAX_ALPHA)  // scaling factor for alpha.
1051e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora#define DEFAULT_ALPHA (-1)
1061e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora#define IS_BETTER_ALPHA(alpha, best_alpha) ((alpha) > (best_alpha))
1071e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
1081e7bf8805bd030c19924a5306837ecd72c295751Vikas Arorastatic int FinalAlphaValue(int alpha) {
1091e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  alpha = MAX_ALPHA - alpha;
1101e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  return clip(alpha, 0, MAX_ALPHA);
1111e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora}
1121e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
1131e7bf8805bd030c19924a5306837ecd72c295751Vikas Arorastatic int GetAlpha(const VP8Histogram* const histo) {
1141e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  // 'alpha' will later be clipped to [0..MAX_ALPHA] range, clamping outer
1151e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  // values which happen to be mostly noise. This leaves the maximum precision
1161e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  // for handling the useful small values which contribute most.
1177c8da7ce66017295a65ec028084b90800be377f8James Zern  const int max_value = histo->max_value;
1187c8da7ce66017295a65ec028084b90800be377f8James Zern  const int last_non_zero = histo->last_non_zero;
1197c8da7ce66017295a65ec028084b90800be377f8James Zern  const int alpha =
1207c8da7ce66017295a65ec028084b90800be377f8James Zern      (max_value > 1) ? ALPHA_SCALE * last_non_zero / max_value : 0;
1211e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  return alpha;
1221e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora}
1231e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
1247c8da7ce66017295a65ec028084b90800be377f8James Zernstatic void InitHistogram(VP8Histogram* const histo) {
1257c8da7ce66017295a65ec028084b90800be377f8James Zern  histo->max_value = 0;
1267c8da7ce66017295a65ec028084b90800be377f8James Zern  histo->last_non_zero = 1;
1277c8da7ce66017295a65ec028084b90800be377f8James Zern}
1287c8da7ce66017295a65ec028084b90800be377f8James Zern
1291e7bf8805bd030c19924a5306837ecd72c295751Vikas Arorastatic void MergeHistograms(const VP8Histogram* const in,
1301e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                            VP8Histogram* const out) {
1317c8da7ce66017295a65ec028084b90800be377f8James Zern  if (in->max_value > out->max_value) {
1327c8da7ce66017295a65ec028084b90800be377f8James Zern    out->max_value = in->max_value;
1337c8da7ce66017295a65ec028084b90800be377f8James Zern  }
1347c8da7ce66017295a65ec028084b90800be377f8James Zern  if (in->last_non_zero > out->last_non_zero) {
1357c8da7ce66017295a65ec028084b90800be377f8James Zern    out->last_non_zero = in->last_non_zero;
1361e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  }
1371e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora}
1381e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
1391e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//------------------------------------------------------------------------------
1407c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// Simplified k-Means, to assign Nb segments based on alpha-histogram
1417c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
1421e7bf8805bd030c19924a5306837ecd72c295751Vikas Arorastatic void AssignSegments(VP8Encoder* const enc,
1431e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                           const int alphas[MAX_ALPHA + 1]) {
1448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // 'num_segments_' is previously validated and <= NUM_MB_SEGMENTS, but an
1458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // explicit check is needed to avoid spurious warning about 'n + 1' exceeding
1468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // array bounds of 'centers' with some compilers (noticed with gcc-4.9).
1478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int nb = (enc->segment_hdr_.num_segments_ < NUM_MB_SEGMENTS) ?
1488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                 enc->segment_hdr_.num_segments_ : NUM_MB_SEGMENTS;
1497c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  int centers[NUM_MB_SEGMENTS];
150a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int weighted_average = 0;
1511e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int map[MAX_ALPHA + 1];
1527c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  int a, n, k;
1531e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int min_a = 0, max_a = MAX_ALPHA, range_a;
1547c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  // 'int' type is ok for histo, and won't overflow
1557c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  int accum[NUM_MB_SEGMENTS], dist_accum[NUM_MB_SEGMENTS];
1567c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
1578b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  assert(nb >= 1);
15833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(nb <= NUM_MB_SEGMENTS);
1598b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
1607c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  // bracket the input
1611e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  for (n = 0; n <= MAX_ALPHA && alphas[n] == 0; ++n) {}
1627c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  min_a = n;
1631e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  for (n = MAX_ALPHA; n > min_a && alphas[n] == 0; --n) {}
1647c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  max_a = n;
1657c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  range_a = max_a - min_a;
1667c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
1677c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  // Spread initial centers evenly
1688b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  for (k = 0, n = 1; k < nb; ++k, n += 2) {
1698b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    assert(n < 2 * nb);
1708b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    centers[k] = min_a + (n * range_a) / (2 * nb);
1717c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
1727c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
1737c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  for (k = 0; k < MAX_ITERS_K_MEANS; ++k) {     // few iters are enough
1747c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    int total_weight;
1757c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    int displaced;
1767c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    // Reset stats
1777c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    for (n = 0; n < nb; ++n) {
1787c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      accum[n] = 0;
1797c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      dist_accum[n] = 0;
1807c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    }
1817c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    // Assign nearest center for each 'a'
1827c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    n = 0;    // track the nearest center for current 'a'
1837c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    for (a = min_a; a <= max_a; ++a) {
1847c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      if (alphas[a]) {
1858b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        while (n + 1 < nb && abs(a - centers[n + 1]) < abs(a - centers[n])) {
1867c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora          n++;
1877c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora        }
1887c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora        map[a] = n;
1897c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora        // accumulate contribution into best centroid
1907c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora        dist_accum[n] += a * alphas[a];
1917c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora        accum[n] += alphas[a];
1927c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      }
1937c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    }
1947c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    // All point are classified. Move the centroids to the
1957c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    // center of their respective cloud.
1967c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    displaced = 0;
1977c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    weighted_average = 0;
1987c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    total_weight = 0;
1997c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    for (n = 0; n < nb; ++n) {
2007c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      if (accum[n]) {
2017c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora        const int new_center = (dist_accum[n] + accum[n] / 2) / accum[n];
2027c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora        displaced += abs(centers[n] - new_center);
2037c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora        centers[n] = new_center;
2047c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora        weighted_average += new_center * accum[n];
2057c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora        total_weight += accum[n];
2067c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      }
2077c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    }
2087c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    weighted_average = (weighted_average + total_weight / 2) / total_weight;
2097c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    if (displaced < 5) break;   // no need to keep on looping...
2107c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
2117c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
2127c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  // Map each original value to the closest centroid
2137c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
2147c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    VP8MBInfo* const mb = &enc->mb_info_[n];
215a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    const int alpha = mb->alpha_;
216a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    mb->segment_ = map[alpha];
2171e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    mb->alpha_ = centers[map[alpha]];  // for the record.
2187c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
2197c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
2207c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  if (nb > 1) {
2217c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    const int smooth = (enc->config_->preprocessing & 1);
2227c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    if (smooth) SmoothSegmentMap(enc);
2237c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
2247c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
2257c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  SetSegmentAlphas(enc, centers, weighted_average);  // pick some alphas.
2267c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
2277c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
228a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
2297c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// Macroblock analysis: collect histogram for each mode, deduce the maximal
2307c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// susceptibility and set best modes for this macroblock.
2317c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// Segment assignment is done later.
2327c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
23333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Number of modes to inspect for alpha_ evaluation. We don't need to test all
23433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// the possible modes during the analysis phase: we risk falling into a local
23533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// optimum, or be subject to boundary effect
2367c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#define MAX_INTRA16_MODE 2
2377c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#define MAX_INTRA4_MODE  2
2387c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#define MAX_UV_MODE      2
2397c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
2407c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arorastatic int MBAnalyzeBestIntra16Mode(VP8EncIterator* const it) {
24133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int max_mode = MAX_INTRA16_MODE;
2427c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  int mode;
2431e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int best_alpha = DEFAULT_ALPHA;
2447c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  int best_mode = 0;
2457c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
2467c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  VP8MakeLuma16Preds(it);
2477c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  for (mode = 0; mode < max_mode; ++mode) {
2487c8da7ce66017295a65ec028084b90800be377f8James Zern    VP8Histogram histo;
2491e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    int alpha;
2501e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
2517c8da7ce66017295a65ec028084b90800be377f8James Zern    InitHistogram(&histo);
2527c8da7ce66017295a65ec028084b90800be377f8James Zern    VP8CollectHistogram(it->yuv_in_ + Y_OFF_ENC,
2531e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                        it->yuv_p_ + VP8I16ModeOffsets[mode],
2541e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                        0, 16, &histo);
2551e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    alpha = GetAlpha(&histo);
2561e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    if (IS_BETTER_ALPHA(alpha, best_alpha)) {
2577c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      best_alpha = alpha;
2587c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      best_mode = mode;
2597c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    }
2607c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
2617c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  VP8SetIntra16Mode(it, best_mode);
2627c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  return best_alpha;
2637c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
2647c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
265fa39824bb690c5806358871f46940d0450973d8aJames Zernstatic int FastMBAnalyze(VP8EncIterator* const it) {
266fa39824bb690c5806358871f46940d0450973d8aJames Zern  // Empirical cut-off value, should be around 16 (~=block size). We use the
267fa39824bb690c5806358871f46940d0450973d8aJames Zern  // [8-17] range and favor intra4 at high quality, intra16 for low quality.
268fa39824bb690c5806358871f46940d0450973d8aJames Zern  const int q = (int)it->enc_->config_->quality;
269fa39824bb690c5806358871f46940d0450973d8aJames Zern  const uint32_t kThreshold = 8 + (17 - 8) * q / 100;
270fa39824bb690c5806358871f46940d0450973d8aJames Zern  int k;
271fa39824bb690c5806358871f46940d0450973d8aJames Zern  uint32_t dc[16], m, m2;
272fa39824bb690c5806358871f46940d0450973d8aJames Zern  for (k = 0; k < 16; k += 4) {
273fa39824bb690c5806358871f46940d0450973d8aJames Zern    VP8Mean16x4(it->yuv_in_ + Y_OFF_ENC + k * BPS, &dc[k]);
274fa39824bb690c5806358871f46940d0450973d8aJames Zern  }
275fa39824bb690c5806358871f46940d0450973d8aJames Zern  for (m = 0, m2 = 0, k = 0; k < 16; ++k) {
276fa39824bb690c5806358871f46940d0450973d8aJames Zern    m += dc[k];
277fa39824bb690c5806358871f46940d0450973d8aJames Zern    m2 += dc[k] * dc[k];
278fa39824bb690c5806358871f46940d0450973d8aJames Zern  }
279fa39824bb690c5806358871f46940d0450973d8aJames Zern  if (kThreshold * m2 < m * m) {
280fa39824bb690c5806358871f46940d0450973d8aJames Zern    VP8SetIntra16Mode(it, 0);   // DC16
281fa39824bb690c5806358871f46940d0450973d8aJames Zern  } else {
282fa39824bb690c5806358871f46940d0450973d8aJames Zern    const uint8_t modes[16] = { 0 };  // DC4
283fa39824bb690c5806358871f46940d0450973d8aJames Zern    VP8SetIntra4Mode(it, modes);
284fa39824bb690c5806358871f46940d0450973d8aJames Zern  }
285fa39824bb690c5806358871f46940d0450973d8aJames Zern  return 0;
286fa39824bb690c5806358871f46940d0450973d8aJames Zern}
287fa39824bb690c5806358871f46940d0450973d8aJames Zern
2887c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arorastatic int MBAnalyzeBestIntra4Mode(VP8EncIterator* const it,
2897c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora                                   int best_alpha) {
290a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  uint8_t modes[16];
29133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int max_mode = MAX_INTRA4_MODE;
2921e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int i4_alpha;
2937c8da7ce66017295a65ec028084b90800be377f8James Zern  VP8Histogram total_histo;
2941e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int cur_histo = 0;
2957c8da7ce66017295a65ec028084b90800be377f8James Zern  InitHistogram(&total_histo);
2961e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
2977c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  VP8IteratorStartI4(it);
2987c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  do {
2997c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    int mode;
3001e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    int best_mode_alpha = DEFAULT_ALPHA;
3011e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    VP8Histogram histos[2];
3027c8da7ce66017295a65ec028084b90800be377f8James Zern    const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC + VP8Scan[it->i4_];
3037c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
3047c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    VP8MakeIntra4Preds(it);
3057c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    for (mode = 0; mode < max_mode; ++mode) {
3061e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora      int alpha;
3071e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
3087c8da7ce66017295a65ec028084b90800be377f8James Zern      InitHistogram(&histos[cur_histo]);
3091e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora      VP8CollectHistogram(src, it->yuv_p_ + VP8I4ModeOffsets[mode],
3101e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                          0, 1, &histos[cur_histo]);
3111e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora      alpha = GetAlpha(&histos[cur_histo]);
3121e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora      if (IS_BETTER_ALPHA(alpha, best_mode_alpha)) {
3137c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora        best_mode_alpha = alpha;
3147c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora        modes[it->i4_] = mode;
3151e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora        cur_histo ^= 1;   // keep track of best histo so far.
3167c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      }
3177c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    }
3181e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    // accumulate best histogram
3191e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    MergeHistograms(&histos[cur_histo ^ 1], &total_histo);
3207c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    // Note: we reuse the original samples for predictors
3217c8da7ce66017295a65ec028084b90800be377f8James Zern  } while (VP8IteratorRotateI4(it, it->yuv_in_ + Y_OFF_ENC));
3227c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
3231e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  i4_alpha = GetAlpha(&total_histo);
3241e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  if (IS_BETTER_ALPHA(i4_alpha, best_alpha)) {
3257c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    VP8SetIntra4Mode(it, modes);
3261e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    best_alpha = i4_alpha;
3277c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
3287c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  return best_alpha;
3297c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
3307c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
3317c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arorastatic int MBAnalyzeBestUVMode(VP8EncIterator* const it) {
3321e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int best_alpha = DEFAULT_ALPHA;
33398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  int smallest_alpha = 0;
3347c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  int best_mode = 0;
33533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int max_mode = MAX_UV_MODE;
3367c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  int mode;
33733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
3387c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  VP8MakeChroma8Preds(it);
3397c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  for (mode = 0; mode < max_mode; ++mode) {
3407c8da7ce66017295a65ec028084b90800be377f8James Zern    VP8Histogram histo;
3411e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    int alpha;
3427c8da7ce66017295a65ec028084b90800be377f8James Zern    InitHistogram(&histo);
3437c8da7ce66017295a65ec028084b90800be377f8James Zern    VP8CollectHistogram(it->yuv_in_ + U_OFF_ENC,
3441e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                        it->yuv_p_ + VP8UVModeOffsets[mode],
3451e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                        16, 16 + 4 + 4, &histo);
3461e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    alpha = GetAlpha(&histo);
3471e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    if (IS_BETTER_ALPHA(alpha, best_alpha)) {
3487c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      best_alpha = alpha;
34998a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    }
35098a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    // The best prediction mode tends to be the one with the smallest alpha.
35198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    if (mode == 0 || alpha < smallest_alpha) {
35298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      smallest_alpha = alpha;
3537c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      best_mode = mode;
3547c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    }
3557c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
3567c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  VP8SetIntraUVMode(it, best_mode);
3577c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  return best_alpha;
3587c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
3597c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
3607c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arorastatic void MBAnalyze(VP8EncIterator* const it,
3611e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                      int alphas[MAX_ALPHA + 1],
3621e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                      int* const alpha, int* const uv_alpha) {
3637c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const VP8Encoder* const enc = it->enc_;
3647c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  int best_alpha, best_uv_alpha;
3657c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
3667c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  VP8SetIntra16Mode(it, 0);  // default: Intra16, DC_PRED
3677c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  VP8SetSkip(it, 0);         // not skipped
3687c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  VP8SetSegment(it, 0);      // default segment, spec-wise.
3697c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
370fa39824bb690c5806358871f46940d0450973d8aJames Zern  if (enc->method_ <= 1) {
371fa39824bb690c5806358871f46940d0450973d8aJames Zern    best_alpha = FastMBAnalyze(it);
372fa39824bb690c5806358871f46940d0450973d8aJames Zern  } else {
373fa39824bb690c5806358871f46940d0450973d8aJames Zern    best_alpha = MBAnalyzeBestIntra16Mode(it);
374fa39824bb690c5806358871f46940d0450973d8aJames Zern    if (enc->method_ >= 5) {
375fa39824bb690c5806358871f46940d0450973d8aJames Zern      // We go and make a fast decision for intra4/intra16.
376fa39824bb690c5806358871f46940d0450973d8aJames Zern      // It's usually not a good and definitive pick, but helps seeding the
377fa39824bb690c5806358871f46940d0450973d8aJames Zern      // stats about level bit-cost.
378fa39824bb690c5806358871f46940d0450973d8aJames Zern      // TODO(skal): improve criterion.
379fa39824bb690c5806358871f46940d0450973d8aJames Zern      best_alpha = MBAnalyzeBestIntra4Mode(it, best_alpha);
380fa39824bb690c5806358871f46940d0450973d8aJames Zern    }
3817c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
3827c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  best_uv_alpha = MBAnalyzeBestUVMode(it);
3837c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
3847c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  // Final susceptibility mix
3851e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  best_alpha = (3 * best_alpha + best_uv_alpha + 2) >> 2;
3861e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  best_alpha = FinalAlphaValue(best_alpha);
3877c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  alphas[best_alpha]++;
3881e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  it->mb_->alpha_ = best_alpha;   // for later remapping.
3891e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
3901e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  // Accumulate for later complexity analysis.
3911e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  *alpha += best_alpha;   // mixed susceptibility (not just luma)
3927c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  *uv_alpha += best_uv_alpha;
3931e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora}
3941e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
3951e7bf8805bd030c19924a5306837ecd72c295751Vikas Arorastatic void DefaultMBInfo(VP8MBInfo* const mb) {
3961e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  mb->type_ = 1;     // I16x16
3971e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  mb->uv_mode_ = 0;
3981e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  mb->skip_ = 0;     // not skipped
3991e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  mb->segment_ = 0;  // default segment
4001e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  mb->alpha_ = 0;
4017c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
4027c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
403a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
4047c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// Main analysis loop:
4057c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// Collect all susceptibilities for each macroblock and record their
4067c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// distribution in alphas[]. Segments is assigned a-posteriori, based on
4077c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// this histogram.
4087c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// We also pick an intra16 prediction mode, which shouldn't be considered
4097c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// final except for fast-encode settings. We can also pick some intra4 modes
4107c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// and decide intra4/intra16, but that's usually almost always a bad choice at
4117c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// this stage.
4127c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
4131e7bf8805bd030c19924a5306837ecd72c295751Vikas Arorastatic void ResetAllMBInfo(VP8Encoder* const enc) {
4141e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int n;
4151e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
4161e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    DefaultMBInfo(&enc->mb_info_[n]);
4171e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  }
4181e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  // Default susceptibilities.
4191e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  enc->dqm_[0].alpha_ = 0;
4201e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  enc->dqm_[0].beta_ = 0;
4218b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  // Note: we can't compute this alpha_ / uv_alpha_ -> set to default value.
4228b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  enc->alpha_ = 0;
4238b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  enc->uv_alpha_ = 0;
4241e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_);
4251e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora}
4261e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
4278b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// struct used to collect job result
4288b720228d581a84fd173b6dcb2fa295b59db489aVikas Aroratypedef struct {
4298b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  WebPWorker worker;
4308b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  int alphas[MAX_ALPHA + 1];
4318b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  int alpha, uv_alpha;
4328b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  VP8EncIterator it;
4338b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  int delta_progress;
4348b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora} SegmentJob;
4358b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
4368b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// main work call
4378b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic int DoSegmentsJob(SegmentJob* const job, VP8EncIterator* const it) {
4388b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  int ok = 1;
4398b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  if (!VP8IteratorIsDone(it)) {
4407c8da7ce66017295a65ec028084b90800be377f8James Zern    uint8_t tmp[32 + WEBP_ALIGN_CST];
4417c8da7ce66017295a65ec028084b90800be377f8James Zern    uint8_t* const scratch = (uint8_t*)WEBP_ALIGN(tmp);
4428b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    do {
4438b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      // Let's pretend we have perfect lossless reconstruction.
4448b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      VP8IteratorImport(it, scratch);
4458b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      MBAnalyze(it, job->alphas, &job->alpha, &job->uv_alpha);
4468b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      ok = VP8IteratorProgress(it, job->delta_progress);
4478b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    } while (ok && VP8IteratorNext(it));
4488b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  }
4498b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return ok;
4508b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora}
4518b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
4528b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic void MergeJobs(const SegmentJob* const src, SegmentJob* const dst) {
4538b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  int i;
4548b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  for (i = 0; i <= MAX_ALPHA; ++i) dst->alphas[i] += src->alphas[i];
4558b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  dst->alpha += src->alpha;
4568b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  dst->uv_alpha += src->uv_alpha;
4578b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora}
4588b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
4598b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// initialize the job struct with some TODOs
4608b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic void InitSegmentJob(VP8Encoder* const enc, SegmentJob* const job,
4618b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora                           int start_row, int end_row) {
46233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  WebPGetWorkerInterface()->Init(&job->worker);
4638b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  job->worker.data1 = job;
4648b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  job->worker.data2 = &job->it;
4658b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  job->worker.hook = (WebPWorkerHook)DoSegmentsJob;
4668b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  VP8IteratorInit(enc, &job->it);
4678b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  VP8IteratorSetRow(&job->it, start_row);
4688b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  VP8IteratorSetCountDown(&job->it, (end_row - start_row) * enc->mb_w_);
4698b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  memset(job->alphas, 0, sizeof(job->alphas));
4708b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  job->alpha = 0;
4718b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  job->uv_alpha = 0;
4728b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  // only one of both jobs can record the progress, since we don't
4738b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  // expect the user's hook to be multi-thread safe
4748b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  job->delta_progress = (start_row == 0) ? 20 : 0;
4758b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora}
4768b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
4778b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// main entry point
4787c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Aroraint VP8EncAnalyze(VP8Encoder* const enc) {
479a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int ok = 1;
4801e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  const int do_segments =
4811e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora      enc->config_->emulate_jpeg_size ||   // We need the complexity evaluation.
4821e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora      (enc->segment_hdr_.num_segments_ > 1) ||
483fa39824bb690c5806358871f46940d0450973d8aJames Zern      (enc->method_ <= 1);  // for method 0 - 1, we need preds_[] to be filled.
4841e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  if (do_segments) {
4858b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    const int last_row = enc->mb_h_;
4868b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    // We give a little more than a half work to the main thread.
4878b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    const int split_row = (9 * last_row + 15) >> 4;
4888b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    const int total_mb = last_row * enc->mb_w_;
4898b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#ifdef WEBP_USE_THREAD
4908b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    const int kMinSplitRow = 2;  // minimal rows needed for mt to be worth it
4918b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    const int do_mt = (enc->thread_level_ > 0) && (split_row >= kMinSplitRow);
4928b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#else
4938b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    const int do_mt = 0;
4948b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#endif
49533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const WebPWorkerInterface* const worker_interface =
49633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        WebPGetWorkerInterface();
4978b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    SegmentJob main_job;
4988b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    if (do_mt) {
4998b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      SegmentJob side_job;
5008b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      // Note the use of '&' instead of '&&' because we must call the functions
5018b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      // no matter what.
5028b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      InitSegmentJob(enc, &main_job, 0, split_row);
5038b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      InitSegmentJob(enc, &side_job, split_row, last_row);
5048b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      // we don't need to call Reset() on main_job.worker, since we're calling
5058b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      // WebPWorkerExecute() on it
50633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      ok &= worker_interface->Reset(&side_job.worker);
5078b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      // launch the two jobs in parallel
5088b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      if (ok) {
50933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        worker_interface->Launch(&side_job.worker);
51033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        worker_interface->Execute(&main_job.worker);
51133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        ok &= worker_interface->Sync(&side_job.worker);
51233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        ok &= worker_interface->Sync(&main_job.worker);
5138b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      }
51433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      worker_interface->End(&side_job.worker);
5158b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      if (ok) MergeJobs(&side_job, &main_job);  // merge results together
5168b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    } else {
5178b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      // Even for single-thread case, we use the generic Worker tools.
5188b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      InitSegmentJob(enc, &main_job, 0, last_row);
51933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      worker_interface->Execute(&main_job.worker);
52033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      ok &= worker_interface->Sync(&main_job.worker);
5218b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    }
52233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    worker_interface->End(&main_job.worker);
5238b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    if (ok) {
5248b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      enc->alpha_ = main_job.alpha / total_mb;
5258b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      enc->uv_alpha_ = main_job.uv_alpha / total_mb;
5268b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      AssignSegments(enc, main_job.alphas);
5278b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    }
5281e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  } else {   // Use only one default segment.
5291e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    ResetAllMBInfo(enc);
5301e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  }
531a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return ok;
5327c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
5337c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
534