• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
q2mbl(int x)48 static int q2mbl(int x) {
49   if (x < 20) x = 20;
50 
51   x = 50 + (x - 50) * 10 / 8;
52   return x * x / 3;
53 }
54 
vp8_de_mblock(YV12_BUFFER_CONFIG * post,int q)55 static void vp8_de_mblock(YV12_BUFFER_CONFIG *post, int q) {
56   vpx_mbpost_proc_across_ip(post->y_buffer, post->y_stride, post->y_height,
57                             post->y_width, q2mbl(q));
58   vpx_mbpost_proc_down(post->y_buffer, post->y_stride, post->y_height,
59                        post->y_width, q2mbl(q));
60 }
61 
vp8_deblock(VP8_COMMON * cm,YV12_BUFFER_CONFIG * source,YV12_BUFFER_CONFIG * post,int q,int low_var_thresh,int flag)62 void vp8_deblock(VP8_COMMON *cm, YV12_BUFFER_CONFIG *source,
63                  YV12_BUFFER_CONFIG *post, int q, int low_var_thresh,
64                  int flag) {
65   double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
66   int ppl = (int)(level + .5);
67 
68   const MODE_INFO *mode_info_context = cm->show_frame_mi;
69   int mbr, mbc;
70 
71   /* The pixel thresholds are adjusted according to if or not the macroblock
72    * is a skipped block.  */
73   unsigned char *ylimits = cm->pp_limits_buffer;
74   unsigned char *uvlimits = cm->pp_limits_buffer + 16 * cm->mb_cols;
75   (void)low_var_thresh;
76   (void)flag;
77 
78   if (ppl > 0) {
79     for (mbr = 0; mbr < cm->mb_rows; ++mbr) {
80       unsigned char *ylptr = ylimits;
81       unsigned char *uvlptr = uvlimits;
82       for (mbc = 0; mbc < cm->mb_cols; ++mbc) {
83         unsigned char mb_ppl;
84 
85         if (mode_info_context->mbmi.mb_skip_coeff) {
86           mb_ppl = (unsigned char)ppl >> 1;
87         } else {
88           mb_ppl = (unsigned char)ppl;
89         }
90 
91         memset(ylptr, mb_ppl, 16);
92         memset(uvlptr, mb_ppl, 8);
93 
94         ylptr += 16;
95         uvlptr += 8;
96         mode_info_context++;
97       }
98       mode_info_context++;
99 
100       vpx_post_proc_down_and_across_mb_row(
101           source->y_buffer + 16 * mbr * source->y_stride,
102           post->y_buffer + 16 * mbr * post->y_stride, source->y_stride,
103           post->y_stride, source->y_width, ylimits, 16);
104 
105       vpx_post_proc_down_and_across_mb_row(
106           source->u_buffer + 8 * mbr * source->uv_stride,
107           post->u_buffer + 8 * mbr * post->uv_stride, source->uv_stride,
108           post->uv_stride, source->uv_width, uvlimits, 8);
109       vpx_post_proc_down_and_across_mb_row(
110           source->v_buffer + 8 * mbr * source->uv_stride,
111           post->v_buffer + 8 * mbr * post->uv_stride, source->uv_stride,
112           post->uv_stride, source->uv_width, uvlimits, 8);
113     }
114   } else {
115     vp8_yv12_copy_frame(source, post);
116   }
117 }
118 
vp8_de_noise(VP8_COMMON * cm,YV12_BUFFER_CONFIG * source,YV12_BUFFER_CONFIG * post,int q,int low_var_thresh,int flag,int uvfilter)119 void vp8_de_noise(VP8_COMMON *cm, YV12_BUFFER_CONFIG *source,
120                   YV12_BUFFER_CONFIG *post, int q, int low_var_thresh, int flag,
121                   int uvfilter) {
122   int mbr;
123   double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
124   int ppl = (int)(level + .5);
125   int mb_rows = cm->mb_rows;
126   int mb_cols = cm->mb_cols;
127   unsigned char *limits = cm->pp_limits_buffer;
128   (void)post;
129   (void)low_var_thresh;
130   (void)flag;
131 
132   memset(limits, (unsigned char)ppl, 16 * mb_cols);
133 
134   /* TODO: The original code don't filter the 2 outer rows and columns. */
135   for (mbr = 0; mbr < mb_rows; ++mbr) {
136     vpx_post_proc_down_and_across_mb_row(
137         source->y_buffer + 16 * mbr * source->y_stride,
138         source->y_buffer + 16 * mbr * source->y_stride, source->y_stride,
139         source->y_stride, source->y_width, limits, 16);
140     if (uvfilter == 1) {
141       vpx_post_proc_down_and_across_mb_row(
142           source->u_buffer + 8 * mbr * source->uv_stride,
143           source->u_buffer + 8 * mbr * source->uv_stride, source->uv_stride,
144           source->uv_stride, source->uv_width, limits, 8);
145       vpx_post_proc_down_and_across_mb_row(
146           source->v_buffer + 8 * mbr * source->uv_stride,
147           source->v_buffer + 8 * mbr * source->uv_stride, source->uv_stride,
148           source->uv_stride, source->uv_width, limits, 8);
149     }
150   }
151 }
152 #endif  // CONFIG_POSTPROC
153 
154 /* Blend the macro block with a solid colored square.  Leave the
155  * edges unblended to give distinction to macro blocks in areas
156  * filled with the same color block.
157  */
vp8_blend_mb_inner_c(unsigned char * y,unsigned char * u,unsigned char * v,int y_1,int u_1,int v_1,int alpha,int stride)158 void vp8_blend_mb_inner_c(unsigned char *y, unsigned char *u, unsigned char *v,
159                           int y_1, int u_1, int v_1, int alpha, int stride) {
160   int i, j;
161   int y1_const = y_1 * ((1 << 16) - alpha);
162   int u1_const = u_1 * ((1 << 16) - alpha);
163   int v1_const = v_1 * ((1 << 16) - alpha);
164 
165   y += 2 * stride + 2;
166   for (i = 0; i < 12; ++i) {
167     for (j = 0; j < 12; ++j) {
168       y[j] = (y[j] * alpha + y1_const) >> 16;
169     }
170     y += stride;
171   }
172 
173   stride >>= 1;
174 
175   u += stride + 1;
176   v += stride + 1;
177 
178   for (i = 0; i < 6; ++i) {
179     for (j = 0; j < 6; ++j) {
180       u[j] = (u[j] * alpha + u1_const) >> 16;
181       v[j] = (v[j] * alpha + v1_const) >> 16;
182     }
183     u += stride;
184     v += stride;
185   }
186 }
187 
188 /* Blend only the edge of the macro block.  Leave center
189  * unblended to allow for other visualizations to be layered.
190  */
vp8_blend_mb_outer_c(unsigned char * y,unsigned char * u,unsigned char * v,int y_1,int u_1,int v_1,int alpha,int stride)191 void vp8_blend_mb_outer_c(unsigned char *y, unsigned char *u, unsigned char *v,
192                           int y_1, int u_1, int v_1, int alpha, int stride) {
193   int i, j;
194   int y1_const = y_1 * ((1 << 16) - alpha);
195   int u1_const = u_1 * ((1 << 16) - alpha);
196   int v1_const = v_1 * ((1 << 16) - alpha);
197 
198   for (i = 0; i < 2; ++i) {
199     for (j = 0; j < 16; ++j) {
200       y[j] = (y[j] * alpha + y1_const) >> 16;
201     }
202     y += stride;
203   }
204 
205   for (i = 0; i < 12; ++i) {
206     y[0] = (y[0] * alpha + y1_const) >> 16;
207     y[1] = (y[1] * alpha + y1_const) >> 16;
208     y[14] = (y[14] * alpha + y1_const) >> 16;
209     y[15] = (y[15] * alpha + y1_const) >> 16;
210     y += stride;
211   }
212 
213   for (i = 0; i < 2; ++i) {
214     for (j = 0; j < 16; ++j) {
215       y[j] = (y[j] * alpha + y1_const) >> 16;
216     }
217     y += stride;
218   }
219 
220   stride >>= 1;
221 
222   for (j = 0; j < 8; ++j) {
223     u[j] = (u[j] * alpha + u1_const) >> 16;
224     v[j] = (v[j] * alpha + v1_const) >> 16;
225   }
226   u += stride;
227   v += stride;
228 
229   for (i = 0; i < 6; ++i) {
230     u[0] = (u[0] * alpha + u1_const) >> 16;
231     v[0] = (v[0] * alpha + v1_const) >> 16;
232 
233     u[7] = (u[7] * alpha + u1_const) >> 16;
234     v[7] = (v[7] * alpha + v1_const) >> 16;
235 
236     u += stride;
237     v += stride;
238   }
239 
240   for (j = 0; j < 8; ++j) {
241     u[j] = (u[j] * alpha + u1_const) >> 16;
242     v[j] = (v[j] * alpha + v1_const) >> 16;
243   }
244 }
245 
vp8_blend_b_c(unsigned char * y,unsigned char * u,unsigned char * v,int y_1,int u_1,int v_1,int alpha,int stride)246 void vp8_blend_b_c(unsigned char *y, unsigned char *u, unsigned char *v,
247                    int y_1, int u_1, int v_1, int alpha, int stride) {
248   int i, j;
249   int y1_const = y_1 * ((1 << 16) - alpha);
250   int u1_const = u_1 * ((1 << 16) - alpha);
251   int v1_const = v_1 * ((1 << 16) - alpha);
252 
253   for (i = 0; i < 4; ++i) {
254     for (j = 0; j < 4; ++j) {
255       y[j] = (y[j] * alpha + y1_const) >> 16;
256     }
257     y += stride;
258   }
259 
260   stride >>= 1;
261 
262   for (i = 0; i < 2; ++i) {
263     for (j = 0; j < 2; ++j) {
264       u[j] = (u[j] * alpha + u1_const) >> 16;
265       v[j] = (v[j] * alpha + v1_const) >> 16;
266     }
267     u += stride;
268     v += stride;
269   }
270 }
271 
272 #if CONFIG_POSTPROC
vp8_post_proc_frame(VP8_COMMON * oci,YV12_BUFFER_CONFIG * dest,vp8_ppflags_t * ppflags)273 int vp8_post_proc_frame(VP8_COMMON *oci, YV12_BUFFER_CONFIG *dest,
274                         vp8_ppflags_t *ppflags) {
275   int q = oci->filter_level * 10 / 6;
276   int flags = ppflags->post_proc_flag;
277   int deblock_level = ppflags->deblocking_level;
278   int noise_level = ppflags->noise_level;
279 
280   if (!oci->frame_to_show) return -1;
281 
282   if (q > 63) q = 63;
283 
284   if (!flags) {
285     *dest = *oci->frame_to_show;
286 
287     /* handle problem with extending borders */
288     dest->y_width = oci->Width;
289     dest->y_height = oci->Height;
290     dest->uv_height = dest->y_height / 2;
291     oci->postproc_state.last_base_qindex = oci->base_qindex;
292     oci->postproc_state.last_frame_valid = 1;
293     return 0;
294   }
295   if (flags & VP8D_ADDNOISE) {
296     if (!oci->postproc_state.generated_noise) {
297       oci->postproc_state.generated_noise = vpx_calloc(
298           oci->Width + 256, sizeof(*oci->postproc_state.generated_noise));
299       if (!oci->postproc_state.generated_noise) return 1;
300     }
301   }
302 
303   /* Allocate post_proc_buffer_int if needed */
304   if ((flags & VP8D_MFQE) && !oci->post_proc_buffer_int_used) {
305     if ((flags & VP8D_DEBLOCK) || (flags & VP8D_DEMACROBLOCK)) {
306       int width = (oci->Width + 15) & ~15;
307       int height = (oci->Height + 15) & ~15;
308 
309       if (vp8_yv12_alloc_frame_buffer(&oci->post_proc_buffer_int, width, height,
310                                       VP8BORDERINPIXELS)) {
311         vpx_internal_error(&oci->error, VPX_CODEC_MEM_ERROR,
312                            "Failed to allocate MFQE framebuffer");
313       }
314 
315       oci->post_proc_buffer_int_used = 1;
316 
317       /* insure that postproc is set to all 0's so that post proc
318        * doesn't pull random data in from edge
319        */
320       memset((&oci->post_proc_buffer_int)->buffer_alloc, 128,
321              (&oci->post_proc_buffer)->frame_size);
322     }
323   }
324 
325   vpx_clear_system_state();
326 
327   if ((flags & VP8D_MFQE) && oci->postproc_state.last_frame_valid &&
328       oci->current_video_frame >= 2 &&
329       oci->postproc_state.last_base_qindex < 60 &&
330       oci->base_qindex - oci->postproc_state.last_base_qindex >= 20) {
331     vp8_multiframe_quality_enhance(oci);
332     if (((flags & VP8D_DEBLOCK) || (flags & VP8D_DEMACROBLOCK)) &&
333         oci->post_proc_buffer_int_used) {
334       vp8_yv12_copy_frame(&oci->post_proc_buffer, &oci->post_proc_buffer_int);
335       if (flags & VP8D_DEMACROBLOCK) {
336         vp8_deblock(oci, &oci->post_proc_buffer_int, &oci->post_proc_buffer,
337                     q + (deblock_level - 5) * 10, 1, 0);
338         vp8_de_mblock(&oci->post_proc_buffer, q + (deblock_level - 5) * 10);
339       } else if (flags & VP8D_DEBLOCK) {
340         vp8_deblock(oci, &oci->post_proc_buffer_int, &oci->post_proc_buffer, q,
341                     1, 0);
342       }
343     }
344     /* Move partially towards the base q of the previous frame */
345     oci->postproc_state.last_base_qindex =
346         (3 * oci->postproc_state.last_base_qindex + oci->base_qindex) >> 2;
347   } else if (flags & VP8D_DEMACROBLOCK) {
348     vp8_deblock(oci, oci->frame_to_show, &oci->post_proc_buffer,
349                 q + (deblock_level - 5) * 10, 1, 0);
350     vp8_de_mblock(&oci->post_proc_buffer, q + (deblock_level - 5) * 10);
351 
352     oci->postproc_state.last_base_qindex = oci->base_qindex;
353   } else if (flags & VP8D_DEBLOCK) {
354     vp8_deblock(oci, oci->frame_to_show, &oci->post_proc_buffer, q, 1, 0);
355     oci->postproc_state.last_base_qindex = oci->base_qindex;
356   } else {
357     vp8_yv12_copy_frame(oci->frame_to_show, &oci->post_proc_buffer);
358     oci->postproc_state.last_base_qindex = oci->base_qindex;
359   }
360   oci->postproc_state.last_frame_valid = 1;
361 
362   if (flags & VP8D_ADDNOISE) {
363     if (oci->postproc_state.last_q != q ||
364         oci->postproc_state.last_noise != noise_level) {
365       double sigma;
366       struct postproc_state *ppstate = &oci->postproc_state;
367       vpx_clear_system_state();
368       sigma = noise_level + .5 + .6 * q / 63.0;
369       ppstate->clamp =
370           vpx_setup_noise(sigma, ppstate->generated_noise, oci->Width + 256);
371       ppstate->last_q = q;
372       ppstate->last_noise = noise_level;
373     }
374 
375     vpx_plane_add_noise(
376         oci->post_proc_buffer.y_buffer, oci->postproc_state.generated_noise,
377         oci->postproc_state.clamp, oci->postproc_state.clamp,
378         oci->post_proc_buffer.y_width, oci->post_proc_buffer.y_height,
379         oci->post_proc_buffer.y_stride);
380   }
381 
382   *dest = oci->post_proc_buffer;
383 
384   /* handle problem with extending borders */
385   dest->y_width = oci->Width;
386   dest->y_height = oci->Height;
387   dest->uv_height = dest->y_height / 2;
388   return 0;
389 }
390 #endif
391