Coverage Report

Created: 2026-07-25 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libvpx/vp8/common/postproc.c
Line
Count
Source
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
/***********************************************************************************************************
29
 */
30
#if CONFIG_POSTPROC
31
0
static int q2mbl(int x) {
32
0
  if (x < 20) x = 20;
33
34
0
  x = 50 + (x - 50) * 10 / 8;
35
0
  return x * x / 3;
36
0
}
37
38
0
static void vp8_de_mblock(YV12_BUFFER_CONFIG *post, int q) {
39
0
  vpx_mbpost_proc_across_ip(post->y_buffer, post->y_stride, post->y_height,
40
0
                            post->y_width, q2mbl(q));
41
0
  vpx_mbpost_proc_down(post->y_buffer, post->y_stride, post->y_height,
42
0
                       post->y_width, q2mbl(q));
43
0
}
44
45
void vp8_deblock(VP8_COMMON *cm, YV12_BUFFER_CONFIG *source,
46
0
                 YV12_BUFFER_CONFIG *post, int q) {
47
0
  vpx_clear_system_state();
48
0
  double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
49
0
  int ppl = (int)(level + .5);
50
51
0
  const MODE_INFO *mode_info_context = cm->mi;
52
0
  int mbr, mbc;
53
54
  /* The pixel thresholds are adjusted according to if or not the macroblock
55
   * is a skipped block.  */
56
0
  unsigned char *ylimits = cm->pp_limits_buffer;
57
0
  unsigned char *uvlimits = cm->pp_limits_buffer + 16 * cm->mb_cols;
58
59
0
  if (ppl > 0) {
60
0
    for (mbr = 0; mbr < cm->mb_rows; ++mbr) {
61
0
      unsigned char *ylptr = ylimits;
62
0
      unsigned char *uvlptr = uvlimits;
63
0
      for (mbc = 0; mbc < cm->mb_cols; ++mbc) {
64
0
        unsigned char mb_ppl;
65
66
0
        if (mode_info_context->mbmi.mb_skip_coeff) {
67
0
          mb_ppl = (unsigned char)ppl >> 1;
68
0
        } else {
69
0
          mb_ppl = (unsigned char)ppl;
70
0
        }
71
72
0
        memset(ylptr, mb_ppl, 16);
73
0
        memset(uvlptr, mb_ppl, 8);
74
75
0
        ylptr += 16;
76
0
        uvlptr += 8;
77
0
        mode_info_context++;
78
0
      }
79
0
      mode_info_context++;
80
81
0
      vpx_post_proc_down_and_across_mb_row(
82
0
          source->y_buffer + 16 * mbr * source->y_stride,
83
0
          post->y_buffer + 16 * mbr * post->y_stride, source->y_stride,
84
0
          post->y_stride, source->y_width, ylimits, 16);
85
86
0
      vpx_post_proc_down_and_across_mb_row(
87
0
          source->u_buffer + 8 * mbr * source->uv_stride,
88
0
          post->u_buffer + 8 * mbr * post->uv_stride, source->uv_stride,
89
0
          post->uv_stride, source->uv_width, uvlimits, 8);
90
0
      vpx_post_proc_down_and_across_mb_row(
91
0
          source->v_buffer + 8 * mbr * source->uv_stride,
92
0
          post->v_buffer + 8 * mbr * post->uv_stride, source->uv_stride,
93
0
          post->uv_stride, source->uv_width, uvlimits, 8);
94
0
    }
95
0
  } else {
96
0
    vp8_yv12_copy_frame(source, post);
97
0
  }
98
0
}
99
100
void vp8_de_noise(VP8_COMMON *cm, YV12_BUFFER_CONFIG *source, int q,
101
0
                  int uvfilter) {
102
0
  int mbr;
103
0
  vpx_clear_system_state();
104
0
  double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
105
0
  int ppl = (int)(level + .5);
106
0
  int mb_rows = cm->mb_rows;
107
0
  int mb_cols = cm->mb_cols;
108
0
  unsigned char *limits = cm->pp_limits_buffer;
109
110
0
  memset(limits, (unsigned char)ppl, 16 * mb_cols);
111
112
  /* TODO: The original code don't filter the 2 outer rows and columns. */
113
0
  for (mbr = 0; mbr < mb_rows; ++mbr) {
114
0
    vpx_post_proc_down_and_across_mb_row(
115
0
        source->y_buffer + 16 * mbr * source->y_stride,
116
0
        source->y_buffer + 16 * mbr * source->y_stride, source->y_stride,
117
0
        source->y_stride, source->y_width, limits, 16);
118
0
    if (uvfilter == 1) {
119
0
      vpx_post_proc_down_and_across_mb_row(
120
0
          source->u_buffer + 8 * mbr * source->uv_stride,
121
0
          source->u_buffer + 8 * mbr * source->uv_stride, source->uv_stride,
122
0
          source->uv_stride, source->uv_width, limits, 8);
123
0
      vpx_post_proc_down_and_across_mb_row(
124
0
          source->v_buffer + 8 * mbr * source->uv_stride,
125
0
          source->v_buffer + 8 * mbr * source->uv_stride, source->uv_stride,
126
0
          source->uv_stride, source->uv_width, limits, 8);
127
0
    }
128
0
  }
129
0
}
130
#endif  // CONFIG_POSTPROC
131
132
#if CONFIG_POSTPROC
133
int vp8_post_proc_frame(VP8_COMMON *oci, YV12_BUFFER_CONFIG *dest,
134
31.3k
                        vp8_ppflags_t *ppflags) {
135
31.3k
  int q = oci->filter_level * 10 / 6;
136
31.3k
  int flags = ppflags->post_proc_flag;
137
31.3k
  int deblock_level = ppflags->deblocking_level;
138
31.3k
  int noise_level = ppflags->noise_level;
139
31.3k
  const int generated_noise_size = ALIGN_POWER_OF_TWO(oci->Width, 4) + 256;
140
141
31.3k
  if (!oci->frame_to_show) return -1;
142
143
31.3k
  if (q > 63) q = 63;
144
145
31.3k
  if (!flags) {
146
31.3k
    *dest = *oci->frame_to_show;
147
148
    /* handle problem with extending borders */
149
31.3k
    dest->y_width = oci->Width;
150
31.3k
    dest->y_height = oci->Height;
151
31.3k
    dest->uv_height = dest->y_height / 2;
152
31.3k
    oci->postproc_state.last_base_qindex = oci->base_qindex;
153
31.3k
    oci->postproc_state.last_frame_valid = 1;
154
31.3k
    return 0;
155
31.3k
  }
156
0
  if (flags & VP8D_ADDNOISE) {
157
0
    if (!oci->postproc_state.generated_noise ||
158
0
        oci->postproc_state.generated_noise_size < generated_noise_size) {
159
0
      vpx_free(oci->postproc_state.generated_noise);
160
0
      oci->postproc_state.generated_noise = vpx_calloc(
161
0
          generated_noise_size, sizeof(*oci->postproc_state.generated_noise));
162
0
      if (!oci->postproc_state.generated_noise) return 1;
163
0
      oci->postproc_state.generated_noise_size = generated_noise_size;
164
0
    }
165
0
  }
166
167
  /* Allocate post_proc_buffer_int if needed */
168
0
  if ((flags & VP8D_MFQE) && !oci->post_proc_buffer_int_used) {
169
0
    if ((flags & VP8D_DEBLOCK) || (flags & VP8D_DEMACROBLOCK)) {
170
0
      int width = (oci->Width + 15) & ~15;
171
0
      int height = (oci->Height + 15) & ~15;
172
173
0
      if (vp8_yv12_alloc_frame_buffer(&oci->post_proc_buffer_int, width, height,
174
0
                                      VP8BORDERINPIXELS)) {
175
0
        vpx_internal_error(&oci->error, VPX_CODEC_MEM_ERROR,
176
0
                           "Failed to allocate MFQE framebuffer");
177
0
      }
178
179
0
      oci->post_proc_buffer_int_used = 1;
180
181
      /* insure that postproc is set to all 0's so that post proc
182
       * doesn't pull random data in from edge
183
       */
184
0
      memset((&oci->post_proc_buffer_int)->buffer_alloc, 128,
185
0
             (&oci->post_proc_buffer)->frame_size);
186
0
    }
187
0
  }
188
189
0
  vpx_clear_system_state();
190
191
0
  if ((flags & VP8D_MFQE) && oci->postproc_state.last_frame_valid &&
192
0
      oci->current_video_frame > 10 &&
193
0
      oci->postproc_state.last_base_qindex < 60 &&
194
0
      oci->base_qindex - oci->postproc_state.last_base_qindex >= 20) {
195
0
    vp8_multiframe_quality_enhance(oci);
196
0
    if (((flags & VP8D_DEBLOCK) || (flags & VP8D_DEMACROBLOCK)) &&
197
0
        oci->post_proc_buffer_int_used) {
198
0
      vp8_yv12_copy_frame(&oci->post_proc_buffer, &oci->post_proc_buffer_int);
199
0
      if (flags & VP8D_DEMACROBLOCK) {
200
0
        vp8_deblock(oci, &oci->post_proc_buffer_int, &oci->post_proc_buffer,
201
0
                    q + (deblock_level - 5) * 10);
202
0
        vp8_de_mblock(&oci->post_proc_buffer, q + (deblock_level - 5) * 10);
203
0
      } else if (flags & VP8D_DEBLOCK) {
204
0
        vp8_deblock(oci, &oci->post_proc_buffer_int, &oci->post_proc_buffer, q);
205
0
      }
206
0
    }
207
    /* Move partially towards the base q of the previous frame */
208
0
    oci->postproc_state.last_base_qindex =
209
0
        (3 * oci->postproc_state.last_base_qindex + oci->base_qindex) >> 2;
210
0
  } else if (flags & VP8D_DEMACROBLOCK) {
211
0
    vp8_deblock(oci, oci->frame_to_show, &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
215
0
    oci->postproc_state.last_base_qindex = oci->base_qindex;
216
0
  } else if (flags & VP8D_DEBLOCK) {
217
0
    vp8_deblock(oci, oci->frame_to_show, &oci->post_proc_buffer, q);
218
0
    oci->postproc_state.last_base_qindex = oci->base_qindex;
219
0
  } else {
220
0
    vp8_yv12_copy_frame(oci->frame_to_show, &oci->post_proc_buffer);
221
0
    oci->postproc_state.last_base_qindex = oci->base_qindex;
222
0
  }
223
0
  oci->postproc_state.last_frame_valid = 1;
224
225
0
  if (flags & VP8D_ADDNOISE) {
226
0
    if (oci->postproc_state.last_q != q ||
227
0
        oci->postproc_state.last_noise != noise_level) {
228
0
      double sigma;
229
0
      struct postproc_state *ppstate = &oci->postproc_state;
230
0
      vpx_clear_system_state();
231
0
      sigma = noise_level + .5 + .6 * q / 63.0;
232
0
      ppstate->clamp = vpx_setup_noise(sigma, ppstate->generated_noise,
233
0
                                       generated_noise_size);
234
0
      ppstate->last_q = q;
235
0
      ppstate->last_noise = noise_level;
236
0
    }
237
238
0
    vpx_plane_add_noise(
239
0
        oci->post_proc_buffer.y_buffer, oci->postproc_state.generated_noise,
240
0
        oci->postproc_state.clamp, oci->postproc_state.clamp,
241
0
        oci->post_proc_buffer.y_width, oci->post_proc_buffer.y_height,
242
0
        oci->post_proc_buffer.y_stride);
243
0
  }
244
245
0
  *dest = oci->post_proc_buffer;
246
247
  /* handle problem with extending borders */
248
0
  dest->y_width = oci->Width;
249
0
  dest->y_height = oci->Height;
250
0
  dest->uv_height = dest->y_height / 2;
251
0
  return 0;
252
0
}
253
#endif