• 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->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 #if CONFIG_POSTPROC
vp8_post_proc_frame(VP8_COMMON * oci,YV12_BUFFER_CONFIG * dest,vp8_ppflags_t * ppflags)155 int vp8_post_proc_frame(VP8_COMMON *oci, YV12_BUFFER_CONFIG *dest,
156                         vp8_ppflags_t *ppflags) {
157   int q = oci->filter_level * 10 / 6;
158   int flags = ppflags->post_proc_flag;
159   int deblock_level = ppflags->deblocking_level;
160   int noise_level = ppflags->noise_level;
161 
162   if (!oci->frame_to_show) return -1;
163 
164   if (q > 63) q = 63;
165 
166   if (!flags) {
167     *dest = *oci->frame_to_show;
168 
169     /* handle problem with extending borders */
170     dest->y_width = oci->Width;
171     dest->y_height = oci->Height;
172     dest->uv_height = dest->y_height / 2;
173     oci->postproc_state.last_base_qindex = oci->base_qindex;
174     oci->postproc_state.last_frame_valid = 1;
175     return 0;
176   }
177   if (flags & VP8D_ADDNOISE) {
178     if (!oci->postproc_state.generated_noise) {
179       oci->postproc_state.generated_noise = vpx_calloc(
180           oci->Width + 256, sizeof(*oci->postproc_state.generated_noise));
181       if (!oci->postproc_state.generated_noise) return 1;
182     }
183   }
184 
185   /* Allocate post_proc_buffer_int if needed */
186   if ((flags & VP8D_MFQE) && !oci->post_proc_buffer_int_used) {
187     if ((flags & VP8D_DEBLOCK) || (flags & VP8D_DEMACROBLOCK)) {
188       int width = (oci->Width + 15) & ~15;
189       int height = (oci->Height + 15) & ~15;
190 
191       if (vp8_yv12_alloc_frame_buffer(&oci->post_proc_buffer_int, width, height,
192                                       VP8BORDERINPIXELS)) {
193         vpx_internal_error(&oci->error, VPX_CODEC_MEM_ERROR,
194                            "Failed to allocate MFQE framebuffer");
195       }
196 
197       oci->post_proc_buffer_int_used = 1;
198 
199       /* insure that postproc is set to all 0's so that post proc
200        * doesn't pull random data in from edge
201        */
202       memset((&oci->post_proc_buffer_int)->buffer_alloc, 128,
203              (&oci->post_proc_buffer)->frame_size);
204     }
205   }
206 
207   vpx_clear_system_state();
208 
209   if ((flags & VP8D_MFQE) && oci->postproc_state.last_frame_valid &&
210       oci->current_video_frame > 10 &&
211       oci->postproc_state.last_base_qindex < 60 &&
212       oci->base_qindex - oci->postproc_state.last_base_qindex >= 20) {
213     vp8_multiframe_quality_enhance(oci);
214     if (((flags & VP8D_DEBLOCK) || (flags & VP8D_DEMACROBLOCK)) &&
215         oci->post_proc_buffer_int_used) {
216       vp8_yv12_copy_frame(&oci->post_proc_buffer, &oci->post_proc_buffer_int);
217       if (flags & VP8D_DEMACROBLOCK) {
218         vp8_deblock(oci, &oci->post_proc_buffer_int, &oci->post_proc_buffer,
219                     q + (deblock_level - 5) * 10, 1, 0);
220         vp8_de_mblock(&oci->post_proc_buffer, q + (deblock_level - 5) * 10);
221       } else if (flags & VP8D_DEBLOCK) {
222         vp8_deblock(oci, &oci->post_proc_buffer_int, &oci->post_proc_buffer, q,
223                     1, 0);
224       }
225     }
226     /* Move partially towards the base q of the previous frame */
227     oci->postproc_state.last_base_qindex =
228         (3 * oci->postproc_state.last_base_qindex + oci->base_qindex) >> 2;
229   } else if (flags & VP8D_DEMACROBLOCK) {
230     vp8_deblock(oci, oci->frame_to_show, &oci->post_proc_buffer,
231                 q + (deblock_level - 5) * 10, 1, 0);
232     vp8_de_mblock(&oci->post_proc_buffer, q + (deblock_level - 5) * 10);
233 
234     oci->postproc_state.last_base_qindex = oci->base_qindex;
235   } else if (flags & VP8D_DEBLOCK) {
236     vp8_deblock(oci, oci->frame_to_show, &oci->post_proc_buffer, q, 1, 0);
237     oci->postproc_state.last_base_qindex = oci->base_qindex;
238   } else {
239     vp8_yv12_copy_frame(oci->frame_to_show, &oci->post_proc_buffer);
240     oci->postproc_state.last_base_qindex = oci->base_qindex;
241   }
242   oci->postproc_state.last_frame_valid = 1;
243 
244   if (flags & VP8D_ADDNOISE) {
245     if (oci->postproc_state.last_q != q ||
246         oci->postproc_state.last_noise != noise_level) {
247       double sigma;
248       struct postproc_state *ppstate = &oci->postproc_state;
249       vpx_clear_system_state();
250       sigma = noise_level + .5 + .6 * q / 63.0;
251       ppstate->clamp =
252           vpx_setup_noise(sigma, ppstate->generated_noise, oci->Width + 256);
253       ppstate->last_q = q;
254       ppstate->last_noise = noise_level;
255     }
256 
257     vpx_plane_add_noise(
258         oci->post_proc_buffer.y_buffer, oci->postproc_state.generated_noise,
259         oci->postproc_state.clamp, oci->postproc_state.clamp,
260         oci->post_proc_buffer.y_width, oci->post_proc_buffer.y_height,
261         oci->post_proc_buffer.y_stride);
262   }
263 
264   *dest = oci->post_proc_buffer;
265 
266   /* handle problem with extending borders */
267   dest->y_width = oci->Width;
268   dest->y_height = oci->Height;
269   dest->uv_height = dest->y_height / 2;
270   return 0;
271 }
272 #endif
273