Coverage Report

Created: 2024-09-06 07:53

/src/libvpx/vp8/common/postproc.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3
 *
4
 *  Use of this source code is governed by a BSD-style license
5
 *  that can be found in the LICENSE file in the root of the source
6
 *  tree. An additional intellectual property rights grant can be found
7
 *  in the file PATENTS.  All contributing project authors may
8
 *  be found in the AUTHORS file in the root of the source tree.
9
 */
10
11
#include "vpx_config.h"
12
#include "vpx_dsp_rtcd.h"
13
#include "vp8_rtcd.h"
14
#include "vpx_dsp/postproc.h"
15
#include "vpx_ports/system_state.h"
16
#include "vpx_scale_rtcd.h"
17
#include "vpx_scale/yv12config.h"
18
#include "postproc.h"
19
#include "common.h"
20
#include "vpx_scale/vpx_scale.h"
21
#include "systemdependent.h"
22
23
#include <limits.h>
24
#include <math.h>
25
#include <stdlib.h>
26
#include <stdio.h>
27
28
/* clang-format off */
29
#define RGB_TO_YUV(t)                                     \
30
  (unsigned char)((0.257 * (float)(t >> 16)) +            \
31
                  (0.504 * (float)(t >> 8 & 0xff)) +      \
32
                  (0.098 * (float)(t & 0xff)) + 16),      \
33
  (unsigned char)(-(0.148 * (float)(t >> 16)) -           \
34
                  (0.291 * (float)(t >> 8 & 0xff)) +      \
35
                  (0.439 * (float)(t & 0xff)) + 128),     \
36
  (unsigned char)((0.439 * (float)(t >> 16)) -            \
37
                  (0.368 * (float)(t >> 8 & 0xff)) -      \
38
                  (0.071 * (float)(t & 0xff)) + 128)
39
/* clang-format on */
40
41
extern void vp8_blit_text(const char *msg, unsigned char *address,
42
                          const int pitch);
43
extern void vp8_blit_line(int x0, int x1, int y0, int y1, unsigned char *image,
44
                          const int pitch);
45
/***********************************************************************************************************
46
 */
47
#if CONFIG_POSTPROC
48
0
static int q2mbl(int x) {
49
0
  if (x < 20) x = 20;
50
51
0
  x = 50 + (x - 50) * 10 / 8;
52
0
  return x * x / 3;
53
0
}
54
55
0
static void vp8_de_mblock(YV12_BUFFER_CONFIG *post, int q) {
56
0
  vpx_mbpost_proc_across_ip(post->y_buffer, post->y_stride, post->y_height,
57
0
                            post->y_width, q2mbl(q));
58
0
  vpx_mbpost_proc_down(post->y_buffer, post->y_stride, post->y_height,
59
0
                       post->y_width, q2mbl(q));
60
0
}
61
62
void vp8_deblock(VP8_COMMON *cm, YV12_BUFFER_CONFIG *source,
63
0
                 YV12_BUFFER_CONFIG *post, int q) {
64
0
  double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
65
0
  int ppl = (int)(level + .5);
66
67
0
  const MODE_INFO *mode_info_context = cm->mi;
68
0
  int mbr, mbc;
69
70
  /* The pixel thresholds are adjusted according to if or not the macroblock
71
   * is a skipped block.  */
72
0
  unsigned char *ylimits = cm->pp_limits_buffer;
73
0
  unsigned char *uvlimits = cm->pp_limits_buffer + 16 * cm->mb_cols;
74
75
0
  if (ppl > 0) {
76
0
    for (mbr = 0; mbr < cm->mb_rows; ++mbr) {
77
0
      unsigned char *ylptr = ylimits;
78
0
      unsigned char *uvlptr = uvlimits;
79
0
      for (mbc = 0; mbc < cm->mb_cols; ++mbc) {
80
0
        unsigned char mb_ppl;
81
82
0
        if (mode_info_context->mbmi.mb_skip_coeff) {
83
0
          mb_ppl = (unsigned char)ppl >> 1;
84
0
        } else {
85
0
          mb_ppl = (unsigned char)ppl;
86
0
        }
87
88
0
        memset(ylptr, mb_ppl, 16);
89
0
        memset(uvlptr, mb_ppl, 8);
90
91
0
        ylptr += 16;
92
0
        uvlptr += 8;
93
0
        mode_info_context++;
94
0
      }
95
0
      mode_info_context++;
96
97
0
      vpx_post_proc_down_and_across_mb_row(
98
0
          source->y_buffer + 16 * mbr * source->y_stride,
99
0
          post->y_buffer + 16 * mbr * post->y_stride, source->y_stride,
100
0
          post->y_stride, source->y_width, ylimits, 16);
101
102
0
      vpx_post_proc_down_and_across_mb_row(
103
0
          source->u_buffer + 8 * mbr * source->uv_stride,
104
0
          post->u_buffer + 8 * mbr * post->uv_stride, source->uv_stride,
105
0
          post->uv_stride, source->uv_width, uvlimits, 8);
106
0
      vpx_post_proc_down_and_across_mb_row(
107
0
          source->v_buffer + 8 * mbr * source->uv_stride,
108
0
          post->v_buffer + 8 * mbr * post->uv_stride, source->uv_stride,
109
0
          post->uv_stride, source->uv_width, uvlimits, 8);
110
0
    }
111
0
  } else {
112
0
    vp8_yv12_copy_frame(source, post);
113
0
  }
114
0
}
115
116
void vp8_de_noise(VP8_COMMON *cm, YV12_BUFFER_CONFIG *source, int q,
117
0
                  int uvfilter) {
118
0
  int mbr;
119
0
  double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
120
0
  int ppl = (int)(level + .5);
121
0
  int mb_rows = cm->mb_rows;
122
0
  int mb_cols = cm->mb_cols;
123
0
  unsigned char *limits = cm->pp_limits_buffer;
124
125
0
  memset(limits, (unsigned char)ppl, 16 * mb_cols);
126
127
  /* TODO: The original code don't filter the 2 outer rows and columns. */
128
0
  for (mbr = 0; mbr < mb_rows; ++mbr) {
129
0
    vpx_post_proc_down_and_across_mb_row(
130
0
        source->y_buffer + 16 * mbr * source->y_stride,
131
0
        source->y_buffer + 16 * mbr * source->y_stride, source->y_stride,
132
0
        source->y_stride, source->y_width, limits, 16);
133
0
    if (uvfilter == 1) {
134
0
      vpx_post_proc_down_and_across_mb_row(
135
0
          source->u_buffer + 8 * mbr * source->uv_stride,
136
0
          source->u_buffer + 8 * mbr * source->uv_stride, source->uv_stride,
137
0
          source->uv_stride, source->uv_width, limits, 8);
138
0
      vpx_post_proc_down_and_across_mb_row(
139
0
          source->v_buffer + 8 * mbr * source->uv_stride,
140
0
          source->v_buffer + 8 * mbr * source->uv_stride, source->uv_stride,
141
0
          source->uv_stride, source->uv_width, limits, 8);
142
0
    }
143
0
  }
144
0
}
145
#endif  // CONFIG_POSTPROC
146
147
#if CONFIG_POSTPROC
148
int vp8_post_proc_frame(VP8_COMMON *oci, YV12_BUFFER_CONFIG *dest,
149
0
                        vp8_ppflags_t *ppflags) {
150
0
  int q = oci->filter_level * 10 / 6;
151
0
  int flags = ppflags->post_proc_flag;
152
0
  int deblock_level = ppflags->deblocking_level;
153
0
  int noise_level = ppflags->noise_level;
154
155
0
  if (!oci->frame_to_show) return -1;
156
157
0
  if (q > 63) q = 63;
158
159
0
  if (!flags) {
160
0
    *dest = *oci->frame_to_show;
161
162
    /* handle problem with extending borders */
163
0
    dest->y_width = oci->Width;
164
0
    dest->y_height = oci->Height;
165
0
    dest->uv_height = dest->y_height / 2;
166
0
    oci->postproc_state.last_base_qindex = oci->base_qindex;
167
0
    oci->postproc_state.last_frame_valid = 1;
168
0
    return 0;
169
0
  }
170
0
  if (flags & VP8D_ADDNOISE) {
171
0
    if (!oci->postproc_state.generated_noise) {
172
0
      oci->postproc_state.generated_noise = vpx_calloc(
173
0
          oci->Width + 256, sizeof(*oci->postproc_state.generated_noise));
174
0
      if (!oci->postproc_state.generated_noise) return 1;
175
0
    }
176
0
  }
177
178
  /* Allocate post_proc_buffer_int if needed */
179
0
  if ((flags & VP8D_MFQE) && !oci->post_proc_buffer_int_used) {
180
0
    if ((flags & VP8D_DEBLOCK) || (flags & VP8D_DEMACROBLOCK)) {
181
0
      int width = (oci->Width + 15) & ~15;
182
0
      int height = (oci->Height + 15) & ~15;
183
184
0
      if (vp8_yv12_alloc_frame_buffer(&oci->post_proc_buffer_int, width, height,
185
0
                                      VP8BORDERINPIXELS)) {
186
0
        vpx_internal_error(&oci->error, VPX_CODEC_MEM_ERROR,
187
0
                           "Failed to allocate MFQE framebuffer");
188
0
      }
189
190
0
      oci->post_proc_buffer_int_used = 1;
191
192
      /* insure that postproc is set to all 0's so that post proc
193
       * doesn't pull random data in from edge
194
       */
195
0
      memset((&oci->post_proc_buffer_int)->buffer_alloc, 128,
196
0
             (&oci->post_proc_buffer)->frame_size);
197
0
    }
198
0
  }
199
200
0
  vpx_clear_system_state();
201
202
0
  if ((flags & VP8D_MFQE) && oci->postproc_state.last_frame_valid &&
203
0
      oci->current_video_frame > 10 &&
204
0
      oci->postproc_state.last_base_qindex < 60 &&
205
0
      oci->base_qindex - oci->postproc_state.last_base_qindex >= 20) {
206
0
    vp8_multiframe_quality_enhance(oci);
207
0
    if (((flags & VP8D_DEBLOCK) || (flags & VP8D_DEMACROBLOCK)) &&
208
0
        oci->post_proc_buffer_int_used) {
209
0
      vp8_yv12_copy_frame(&oci->post_proc_buffer, &oci->post_proc_buffer_int);
210
0
      if (flags & VP8D_DEMACROBLOCK) {
211
0
        vp8_deblock(oci, &oci->post_proc_buffer_int, &oci->post_proc_buffer,
212
0
                    q + (deblock_level - 5) * 10);
213
0
        vp8_de_mblock(&oci->post_proc_buffer, q + (deblock_level - 5) * 10);
214
0
      } else if (flags & VP8D_DEBLOCK) {
215
0
        vp8_deblock(oci, &oci->post_proc_buffer_int, &oci->post_proc_buffer, q);
216
0
      }
217
0
    }
218
    /* Move partially towards the base q of the previous frame */
219
0
    oci->postproc_state.last_base_qindex =
220
0
        (3 * oci->postproc_state.last_base_qindex + oci->base_qindex) >> 2;
221
0
  } else if (flags & VP8D_DEMACROBLOCK) {
222
0
    vp8_deblock(oci, oci->frame_to_show, &oci->post_proc_buffer,
223
0
                q + (deblock_level - 5) * 10);
224
0
    vp8_de_mblock(&oci->post_proc_buffer, q + (deblock_level - 5) * 10);
225
226
0
    oci->postproc_state.last_base_qindex = oci->base_qindex;
227
0
  } else if (flags & VP8D_DEBLOCK) {
228
0
    vp8_deblock(oci, oci->frame_to_show, &oci->post_proc_buffer, q);
229
0
    oci->postproc_state.last_base_qindex = oci->base_qindex;
230
0
  } else {
231
0
    vp8_yv12_copy_frame(oci->frame_to_show, &oci->post_proc_buffer);
232
0
    oci->postproc_state.last_base_qindex = oci->base_qindex;
233
0
  }
234
0
  oci->postproc_state.last_frame_valid = 1;
235
236
0
  if (flags & VP8D_ADDNOISE) {
237
0
    if (oci->postproc_state.last_q != q ||
238
0
        oci->postproc_state.last_noise != noise_level) {
239
0
      double sigma;
240
0
      struct postproc_state *ppstate = &oci->postproc_state;
241
0
      vpx_clear_system_state();
242
0
      sigma = noise_level + .5 + .6 * q / 63.0;
243
0
      ppstate->clamp =
244
0
          vpx_setup_noise(sigma, ppstate->generated_noise, oci->Width + 256);
245
0
      ppstate->last_q = q;
246
0
      ppstate->last_noise = noise_level;
247
0
    }
248
249
0
    vpx_plane_add_noise(
250
0
        oci->post_proc_buffer.y_buffer, oci->postproc_state.generated_noise,
251
0
        oci->postproc_state.clamp, oci->postproc_state.clamp,
252
0
        oci->post_proc_buffer.y_width, oci->post_proc_buffer.y_height,
253
0
        oci->post_proc_buffer.y_stride);
254
0
  }
255
256
0
  *dest = oci->post_proc_buffer;
257
258
  /* handle problem with extending borders */
259
0
  dest->y_width = oci->Width;
260
0
  dest->y_height = oci->Height;
261
0
  dest->uv_height = dest->y_height / 2;
262
0
  return 0;
263
0
}
264
#endif