clpf.c 5.29 KB
Newer Older
1
/*
2
3
4
5
6
7
8
9
10
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
 */
Yaowu Xu's avatar
Yaowu Xu committed
11
#include "av1/common/clpf.h"
12
#include "./aom_dsp_rtcd.h"
13
#include "aom_dsp/aom_dsp_common.h"
14

15
int av1_clpf_maxbits(const AV1_COMMON *cm) {
Alex Converse's avatar
Alex Converse committed
16
17
18
19
20
  return get_msb(
             ALIGN_POWER_OF_TWO(cm->mi_cols * MAX_MIB_SIZE, cm->clpf_size + 4) *
                 ALIGN_POWER_OF_TWO(cm->mi_rows * MAX_MIB_SIZE,
                                    cm->clpf_size + 4) >>
             (cm->clpf_size * 2 + 8)) +
21
22
23
24
25
26
27
28
29
         1;
}

int av1_clpf_sample(int X, int A, int B, int C, int D, int E, int F, int b) {
  int delta = 4 * clamp(A - X, -b, b) + clamp(B - X, -b, b) +
              3 * clamp(C - X, -b, b) + 3 * clamp(D - X, -b, b) +
              clamp(E - X, -b, b) + 4 * clamp(F - X, -b, b);
  return (8 + delta - (delta < 0)) >> 4;
}
30

31
32
33
void aom_clpf_block_c(const uint8_t *src, uint8_t *dst, int stride, int x0,
                      int y0, int sizex, int sizey, int width, int height,
                      unsigned int strength) {
34
35
36
37
38
39
40
41
42
43
44
45
46
  int x, y;
  for (y = y0; y < y0 + sizey; y++) {
    for (x = x0; x < x0 + sizex; x++) {
      int X = src[y * stride + x];
      int A = src[AOMMAX(0, y - 1) * stride + x];
      int B = src[y * stride + AOMMAX(0, x - 2)];
      int C = src[y * stride + AOMMAX(0, x - 1)];
      int D = src[y * stride + AOMMIN(width - 1, x + 1)];
      int E = src[y * stride + AOMMIN(width - 1, x + 2)];
      int F = src[AOMMIN(height - 1, y + 1) * stride + x];
      int delta;
      delta = av1_clpf_sample(X, A, B, C, D, E, F, strength);
      dst[y * stride + x] = X + delta;
47
48
49
50
    }
  }
}

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// Return number of filtered blocks
int av1_clpf_frame(const YV12_BUFFER_CONFIG *dst, const YV12_BUFFER_CONFIG *rec,
                   const YV12_BUFFER_CONFIG *org, const AV1_COMMON *cm,
                   int enable_fb_flag, unsigned int strength,
                   unsigned int fb_size_log2, uint8_t *blocks,
                   int (*decision)(int, int, const YV12_BUFFER_CONFIG *,
                                   const YV12_BUFFER_CONFIG *,
                                   const AV1_COMMON *cm, int, int, int,
                                   unsigned int, unsigned int, uint8_t *)) {
  /* Constrained low-pass filter (CLPF) */
  int c, k, l, m, n;
  int width = rec->y_crop_width;
  int height = rec->y_crop_height;
  int xpos, ypos;
  int stride_y = rec->y_stride;
66
  const int bs = MAX_MIB_SIZE;
67
68
69
  int num_fb_hor = (width + (1 << fb_size_log2) - bs) >> fb_size_log2;
  int num_fb_ver = (height + (1 << fb_size_log2) - bs) >> fb_size_log2;
  int block_index = 0;
70

71
72
73
74
75
76
77
78
79
80
81
82
83
84
  // Iterate over all filter blocks
  for (k = 0; k < num_fb_ver; k++) {
    for (l = 0; l < num_fb_hor; l++) {
      int h, w;
      int allskip = 1;
      for (m = 0; allskip && m < (1 << fb_size_log2) / bs; m++) {
        for (n = 0; allskip && n < (1 << fb_size_log2) / bs; n++) {
          xpos = (l << fb_size_log2) + n * bs;
          ypos = (k << fb_size_log2) + m * bs;
          if (xpos < width && ypos < height) {
            allskip &=
                cm->mi_grid_visible[ypos / bs * cm->mi_stride + xpos / bs]
                    ->mbmi.skip;
          }
85
86
        }
      }
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

      // Calculate the actual filter block size near frame edges
      h = AOMMIN(height, (k + 1) << fb_size_log2) & ((1 << fb_size_log2) - 1);
      w = AOMMIN(width, (l + 1) << fb_size_log2) & ((1 << fb_size_log2) - 1);
      h += !h << fb_size_log2;
      w += !w << fb_size_log2;
      if (!allskip &&  // Do not filter the block if all is skip encoded
          (!enable_fb_flag ||
           decision(k, l, rec, org, cm, bs, w / bs, h / bs, strength,
                    fb_size_log2, blocks + block_index))) {
        // Iterate over all smaller blocks inside the filter block
        for (m = 0; m < (h + bs - 1) / bs; m++) {
          for (n = 0; n < (w + bs - 1) / bs; n++) {
            xpos = (l << fb_size_log2) + n * bs;
            ypos = (k << fb_size_log2) + m * bs;
            if (!cm->mi_grid_visible[ypos / bs * cm->mi_stride + xpos / bs]
                     ->mbmi.skip) {
              // Not skip block, apply the filter
105
106
              aom_clpf_block(rec->y_buffer, dst->y_buffer, stride_y, xpos, ypos,
                             bs, bs, width, height, strength);
107
108
109
110
111
112
            } else {  // Skip block, copy instead
              for (c = 0; c < bs; c++)
                *(uint64_t *)(dst->y_buffer + (ypos + c) * stride_y + xpos) =
                    *(uint64_t *)(rec->y_buffer + (ypos + c) * stride_y + xpos);
            }
          }
113
        }
114
115
116
117
118
119
120
      } else {  // Entire filter block is skip, copy
        for (m = 0; m < h; m++)
          memcpy(dst->y_buffer + ((k << fb_size_log2) + m) * stride_y +
                     (l << fb_size_log2),
                 rec->y_buffer + ((k << fb_size_log2) + m) * stride_y +
                     (l << fb_size_log2),
                 w);
121
      }
122
      block_index += !allskip;  // Count number of blocks filtered
123
124
125
    }
  }

126
  return block_index;
127
}