Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / libvpx / source / libvpx / vp9 / common / vp9_postproc.c
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 <math.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14
15 #include "./vpx_config.h"
16 #include "./vpx_scale_rtcd.h"
17 #include "./vp9_rtcd.h"
18
19 #include "vpx_scale/vpx_scale.h"
20 #include "vpx_scale/yv12config.h"
21
22 #include "vp9/common/vp9_onyxc_int.h"
23 #include "vp9/common/vp9_postproc.h"
24 #include "vp9/common/vp9_systemdependent.h"
25 #include "vp9/common/vp9_textblit.h"
26
27 #define RGB_TO_YUV(t)                                            \
28   ( (0.257*(float)(t >> 16))  + (0.504*(float)(t >> 8 & 0xff)) + \
29     (0.098*(float)(t & 0xff)) + 16),                             \
30   (-(0.148*(float)(t >> 16))  - (0.291*(float)(t >> 8 & 0xff)) + \
31     (0.439*(float)(t & 0xff)) + 128),                            \
32   ( (0.439*(float)(t >> 16))  - (0.368*(float)(t >> 8 & 0xff)) - \
33     (0.071*(float)(t & 0xff)) + 128)
34
35 /* global constants */
36 #if 0 && CONFIG_POSTPROC_VISUALIZER
37 static const unsigned char MB_PREDICTION_MODE_colors[MB_MODE_COUNT][3] = {
38   { RGB_TO_YUV(0x98FB98) },   /* PaleGreen */
39   { RGB_TO_YUV(0x00FF00) },   /* Green */
40   { RGB_TO_YUV(0xADFF2F) },   /* GreenYellow */
41   { RGB_TO_YUV(0x8F0000) },   /* Dark Red */
42   { RGB_TO_YUV(0x008F8F) },   /* Dark Cyan */
43   { RGB_TO_YUV(0x008F8F) },   /* Dark Cyan */
44   { RGB_TO_YUV(0x008F8F) },   /* Dark Cyan */
45   { RGB_TO_YUV(0x8F0000) },   /* Dark Red */
46   { RGB_TO_YUV(0x8F0000) },   /* Dark Red */
47   { RGB_TO_YUV(0x228B22) },   /* ForestGreen */
48   { RGB_TO_YUV(0x006400) },   /* DarkGreen */
49   { RGB_TO_YUV(0x98F5FF) },   /* Cadet Blue */
50   { RGB_TO_YUV(0x6CA6CD) },   /* Sky Blue */
51   { RGB_TO_YUV(0x00008B) },   /* Dark blue */
52   { RGB_TO_YUV(0x551A8B) },   /* Purple */
53   { RGB_TO_YUV(0xFF0000) }    /* Red */
54   { RGB_TO_YUV(0xCC33FF) },   /* Magenta */
55 };
56
57 static const unsigned char B_PREDICTION_MODE_colors[INTRA_MODES][3] = {
58   { RGB_TO_YUV(0x6633ff) },   /* Purple */
59   { RGB_TO_YUV(0xcc33ff) },   /* Magenta */
60   { RGB_TO_YUV(0xff33cc) },   /* Pink */
61   { RGB_TO_YUV(0xff3366) },   /* Coral */
62   { RGB_TO_YUV(0x3366ff) },   /* Blue */
63   { RGB_TO_YUV(0xed00f5) },   /* Dark Blue */
64   { RGB_TO_YUV(0x2e00b8) },   /* Dark Purple */
65   { RGB_TO_YUV(0xff6633) },   /* Orange */
66   { RGB_TO_YUV(0x33ccff) },   /* Light Blue */
67   { RGB_TO_YUV(0x8ab800) },   /* Green */
68   { RGB_TO_YUV(0xffcc33) },   /* Light Orange */
69   { RGB_TO_YUV(0x33ffcc) },   /* Aqua */
70   { RGB_TO_YUV(0x66ff33) },   /* Light Green */
71   { RGB_TO_YUV(0xccff33) },   /* Yellow */
72 };
73
74 static const unsigned char MV_REFERENCE_FRAME_colors[MAX_REF_FRAMES][3] = {
75   { RGB_TO_YUV(0x00ff00) },   /* Blue */
76   { RGB_TO_YUV(0x0000ff) },   /* Green */
77   { RGB_TO_YUV(0xffff00) },   /* Yellow */
78   { RGB_TO_YUV(0xff0000) },   /* Red */
79 };
80 #endif
81
82 static const short kernel5[] = {
83   1, 1, 4, 1, 1
84 };
85
86 const short vp9_rv[] = {
87   8, 5, 2, 2, 8, 12, 4, 9, 8, 3,
88   0, 3, 9, 0, 0, 0, 8, 3, 14, 4,
89   10, 1, 11, 14, 1, 14, 9, 6, 12, 11,
90   8, 6, 10, 0, 0, 8, 9, 0, 3, 14,
91   8, 11, 13, 4, 2, 9, 0, 3, 9, 6,
92   1, 2, 3, 14, 13, 1, 8, 2, 9, 7,
93   3, 3, 1, 13, 13, 6, 6, 5, 2, 7,
94   11, 9, 11, 8, 7, 3, 2, 0, 13, 13,
95   14, 4, 12, 5, 12, 10, 8, 10, 13, 10,
96   4, 14, 4, 10, 0, 8, 11, 1, 13, 7,
97   7, 14, 6, 14, 13, 2, 13, 5, 4, 4,
98   0, 10, 0, 5, 13, 2, 12, 7, 11, 13,
99   8, 0, 4, 10, 7, 2, 7, 2, 2, 5,
100   3, 4, 7, 3, 3, 14, 14, 5, 9, 13,
101   3, 14, 3, 6, 3, 0, 11, 8, 13, 1,
102   13, 1, 12, 0, 10, 9, 7, 6, 2, 8,
103   5, 2, 13, 7, 1, 13, 14, 7, 6, 7,
104   9, 6, 10, 11, 7, 8, 7, 5, 14, 8,
105   4, 4, 0, 8, 7, 10, 0, 8, 14, 11,
106   3, 12, 5, 7, 14, 3, 14, 5, 2, 6,
107   11, 12, 12, 8, 0, 11, 13, 1, 2, 0,
108   5, 10, 14, 7, 8, 0, 4, 11, 0, 8,
109   0, 3, 10, 5, 8, 0, 11, 6, 7, 8,
110   10, 7, 13, 9, 2, 5, 1, 5, 10, 2,
111   4, 3, 5, 6, 10, 8, 9, 4, 11, 14,
112   0, 10, 0, 5, 13, 2, 12, 7, 11, 13,
113   8, 0, 4, 10, 7, 2, 7, 2, 2, 5,
114   3, 4, 7, 3, 3, 14, 14, 5, 9, 13,
115   3, 14, 3, 6, 3, 0, 11, 8, 13, 1,
116   13, 1, 12, 0, 10, 9, 7, 6, 2, 8,
117   5, 2, 13, 7, 1, 13, 14, 7, 6, 7,
118   9, 6, 10, 11, 7, 8, 7, 5, 14, 8,
119   4, 4, 0, 8, 7, 10, 0, 8, 14, 11,
120   3, 12, 5, 7, 14, 3, 14, 5, 2, 6,
121   11, 12, 12, 8, 0, 11, 13, 1, 2, 0,
122   5, 10, 14, 7, 8, 0, 4, 11, 0, 8,
123   0, 3, 10, 5, 8, 0, 11, 6, 7, 8,
124   10, 7, 13, 9, 2, 5, 1, 5, 10, 2,
125   4, 3, 5, 6, 10, 8, 9, 4, 11, 14,
126   3, 8, 3, 7, 8, 5, 11, 4, 12, 3,
127   11, 9, 14, 8, 14, 13, 4, 3, 1, 2,
128   14, 6, 5, 4, 4, 11, 4, 6, 2, 1,
129   5, 8, 8, 12, 13, 5, 14, 10, 12, 13,
130   0, 9, 5, 5, 11, 10, 13, 9, 10, 13,
131 };
132
133 void vp9_post_proc_down_and_across_c(const uint8_t *src_ptr,
134                                      uint8_t *dst_ptr,
135                                      int src_pixels_per_line,
136                                      int dst_pixels_per_line,
137                                      int rows,
138                                      int cols,
139                                      int flimit) {
140   uint8_t const *p_src;
141   uint8_t *p_dst;
142   int row;
143   int col;
144   int i;
145   int v;
146   int pitch = src_pixels_per_line;
147   uint8_t d[8];
148   (void)dst_pixels_per_line;
149
150   for (row = 0; row < rows; row++) {
151     /* post_proc_down for one row */
152     p_src = src_ptr;
153     p_dst = dst_ptr;
154
155     for (col = 0; col < cols; col++) {
156       int kernel = 4;
157       int v = p_src[col];
158
159       for (i = -2; i <= 2; i++) {
160         if (abs(v - p_src[col + i * pitch]) > flimit)
161           goto down_skip_convolve;
162
163         kernel += kernel5[2 + i] * p_src[col + i * pitch];
164       }
165
166       v = (kernel >> 3);
167     down_skip_convolve:
168       p_dst[col] = v;
169     }
170
171     /* now post_proc_across */
172     p_src = dst_ptr;
173     p_dst = dst_ptr;
174
175     for (i = 0; i < 8; i++)
176       d[i] = p_src[i];
177
178     for (col = 0; col < cols; col++) {
179       int kernel = 4;
180       v = p_src[col];
181
182       d[col & 7] = v;
183
184       for (i = -2; i <= 2; i++) {
185         if (abs(v - p_src[col + i]) > flimit)
186           goto across_skip_convolve;
187
188         kernel += kernel5[2 + i] * p_src[col + i];
189       }
190
191       d[col & 7] = (kernel >> 3);
192     across_skip_convolve:
193
194       if (col >= 2)
195         p_dst[col - 2] = d[(col - 2) & 7];
196     }
197
198     /* handle the last two pixels */
199     p_dst[col - 2] = d[(col - 2) & 7];
200     p_dst[col - 1] = d[(col - 1) & 7];
201
202
203     /* next row */
204     src_ptr += pitch;
205     dst_ptr += pitch;
206   }
207 }
208
209 static int q2mbl(int x) {
210   if (x < 20) x = 20;
211
212   x = 50 + (x - 50) * 10 / 8;
213   return x * x / 3;
214 }
215
216 void vp9_mbpost_proc_across_ip_c(uint8_t *src, int pitch,
217                                  int rows, int cols, int flimit) {
218   int r, c, i;
219
220   uint8_t *s = src;
221   uint8_t d[16];
222
223
224   for (r = 0; r < rows; r++) {
225     int sumsq = 0;
226     int sum   = 0;
227
228     for (i = -8; i <= 6; i++) {
229       sumsq += s[i] * s[i];
230       sum   += s[i];
231       d[i + 8] = 0;
232     }
233
234     for (c = 0; c < cols + 8; c++) {
235       int x = s[c + 7] - s[c - 8];
236       int y = s[c + 7] + s[c - 8];
237
238       sum  += x;
239       sumsq += x * y;
240
241       d[c & 15] = s[c];
242
243       if (sumsq * 15 - sum * sum < flimit) {
244         d[c & 15] = (8 + sum + s[c]) >> 4;
245       }
246
247       s[c - 8] = d[(c - 8) & 15];
248     }
249
250     s += pitch;
251   }
252 }
253
254 void vp9_mbpost_proc_down_c(uint8_t *dst, int pitch,
255                             int rows, int cols, int flimit) {
256   int r, c, i;
257   const short *rv3 = &vp9_rv[63 & rand()]; // NOLINT
258
259   for (c = 0; c < cols; c++) {
260     uint8_t *s = &dst[c];
261     int sumsq = 0;
262     int sum   = 0;
263     uint8_t d[16];
264     const short *rv2 = rv3 + ((c * 17) & 127);
265
266     for (i = -8; i <= 6; i++) {
267       sumsq += s[i * pitch] * s[i * pitch];
268       sum   += s[i * pitch];
269     }
270
271     for (r = 0; r < rows + 8; r++) {
272       sumsq += s[7 * pitch] * s[ 7 * pitch] - s[-8 * pitch] * s[-8 * pitch];
273       sum  += s[7 * pitch] - s[-8 * pitch];
274       d[r & 15] = s[0];
275
276       if (sumsq * 15 - sum * sum < flimit) {
277         d[r & 15] = (rv2[r & 127] + sum + s[0]) >> 4;
278       }
279
280       s[-8 * pitch] = d[(r - 8) & 15];
281       s += pitch;
282     }
283   }
284 }
285
286 static void deblock_and_de_macro_block(YV12_BUFFER_CONFIG   *source,
287                                        YV12_BUFFER_CONFIG   *post,
288                                        int                   q,
289                                        int                   low_var_thresh,
290                                        int                   flag) {
291   double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
292   int ppl = (int)(level + .5);
293   (void) low_var_thresh;
294   (void) flag;
295
296   vp9_post_proc_down_and_across(source->y_buffer, post->y_buffer,
297                                 source->y_stride, post->y_stride,
298                                 source->y_height, source->y_width, ppl);
299
300   vp9_mbpost_proc_across_ip(post->y_buffer, post->y_stride, post->y_height,
301                             post->y_width, q2mbl(q));
302
303   vp9_mbpost_proc_down(post->y_buffer, post->y_stride, post->y_height,
304                        post->y_width, q2mbl(q));
305
306   vp9_post_proc_down_and_across(source->u_buffer, post->u_buffer,
307                                 source->uv_stride, post->uv_stride,
308                                 source->uv_height, source->uv_width, ppl);
309   vp9_post_proc_down_and_across(source->v_buffer, post->v_buffer,
310                                 source->uv_stride, post->uv_stride,
311                                 source->uv_height, source->uv_width, ppl);
312 }
313
314 void vp9_deblock(const YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *dst,
315                  int q) {
316   const int ppl = (int)(6.0e-05 * q * q * q - 0.0067 * q * q + 0.306 * q
317                         + 0.0065 + 0.5);
318   int i;
319
320   const uint8_t *const srcs[4] = {src->y_buffer, src->u_buffer, src->v_buffer,
321                                   src->alpha_buffer};
322   const int src_strides[4] = {src->y_stride, src->uv_stride, src->uv_stride,
323                               src->alpha_stride};
324   const int src_widths[4] = {src->y_width, src->uv_width, src->uv_width,
325                              src->alpha_width};
326   const int src_heights[4] = {src->y_height, src->uv_height, src->uv_height,
327                               src->alpha_height};
328
329   uint8_t *const dsts[4] = {dst->y_buffer, dst->u_buffer, dst->v_buffer,
330                             dst->alpha_buffer};
331   const int dst_strides[4] = {dst->y_stride, dst->uv_stride, dst->uv_stride,
332                               dst->alpha_stride};
333
334   for (i = 0; i < MAX_MB_PLANE; ++i)
335     vp9_post_proc_down_and_across(srcs[i], dsts[i],
336                                   src_strides[i], dst_strides[i],
337                                   src_heights[i], src_widths[i], ppl);
338 }
339
340 void vp9_denoise(const YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *dst,
341                  int q) {
342   const int ppl = (int)(6.0e-05 * q * q * q - 0.0067 * q * q + 0.306 * q
343                         + 0.0065 + 0.5);
344   int i;
345
346   const uint8_t *const srcs[4] = {src->y_buffer, src->u_buffer, src->v_buffer,
347                                   src->alpha_buffer};
348   const int src_strides[4] = {src->y_stride, src->uv_stride, src->uv_stride,
349                               src->alpha_stride};
350   const int src_widths[4] = {src->y_width, src->uv_width, src->uv_width,
351                              src->alpha_width};
352   const int src_heights[4] = {src->y_height, src->uv_height, src->uv_height,
353                               src->alpha_height};
354
355   uint8_t *const dsts[4] = {dst->y_buffer, dst->u_buffer, dst->v_buffer,
356                             dst->alpha_buffer};
357   const int dst_strides[4] = {dst->y_stride, dst->uv_stride, dst->uv_stride,
358                               dst->alpha_stride};
359
360   for (i = 0; i < MAX_MB_PLANE; ++i) {
361     const int src_stride = src_strides[i];
362     const uint8_t *const src = srcs[i] + 2 * src_stride + 2;
363     const int src_width = src_widths[i] - 4;
364     const int src_height = src_heights[i] - 4;
365
366     const int dst_stride = dst_strides[i];
367     uint8_t *const dst = dsts[i] + 2 * dst_stride + 2;
368
369     vp9_post_proc_down_and_across(src, dst, src_stride, dst_stride,
370                                   src_height, src_width, ppl);
371   }
372 }
373
374 static double gaussian(double sigma, double mu, double x) {
375   return 1 / (sigma * sqrt(2.0 * 3.14159265)) *
376          (exp(-(x - mu) * (x - mu) / (2 * sigma * sigma)));
377 }
378
379 static void fillrd(struct postproc_state *state, int q, int a) {
380   char char_dist[300];
381
382   double sigma;
383   int ai = a, qi = q, i;
384
385   vp9_clear_system_state();
386
387   sigma = ai + .5 + .6 * (63 - qi) / 63.0;
388
389   /* set up a lookup table of 256 entries that matches
390    * a gaussian distribution with sigma determined by q.
391    */
392   {
393     double i;
394     int next, j;
395
396     next = 0;
397
398     for (i = -32; i < 32; i++) {
399       int a = (int)(0.5 + 256 * gaussian(sigma, 0, i));
400
401       if (a) {
402         for (j = 0; j < a; j++) {
403           char_dist[next + j] = (char) i;
404         }
405
406         next = next + j;
407       }
408     }
409
410     for (; next < 256; next++)
411       char_dist[next] = 0;
412   }
413
414   for (i = 0; i < 3072; i++) {
415     state->noise[i] = char_dist[rand() & 0xff];  // NOLINT
416   }
417
418   for (i = 0; i < 16; i++) {
419     state->blackclamp[i] = -char_dist[0];
420     state->whiteclamp[i] = -char_dist[0];
421     state->bothclamp[i] = -2 * char_dist[0];
422   }
423
424   state->last_q = q;
425   state->last_noise = a;
426 }
427
428 void vp9_plane_add_noise_c(uint8_t *start, char *noise,
429                            char blackclamp[16],
430                            char whiteclamp[16],
431                            char bothclamp[16],
432                            unsigned int width, unsigned int height, int pitch) {
433   unsigned int i, j;
434
435   for (i = 0; i < height; i++) {
436     uint8_t *pos = start + i * pitch;
437     char  *ref = (char *)(noise + (rand() & 0xff));  // NOLINT
438
439     for (j = 0; j < width; j++) {
440       if (pos[j] < blackclamp[0])
441         pos[j] = blackclamp[0];
442
443       if (pos[j] > 255 + whiteclamp[0])
444         pos[j] = 255 + whiteclamp[0];
445
446       pos[j] += ref[j];
447     }
448   }
449 }
450
451 /* Blend the macro block with a solid colored square.  Leave the
452  * edges unblended to give distinction to macro blocks in areas
453  * filled with the same color block.
454  */
455 void vp9_blend_mb_inner_c(uint8_t *y, uint8_t *u, uint8_t *v,
456                           int y1, int u1, int v1, int alpha, int stride) {
457   int i, j;
458   int y1_const = y1 * ((1 << 16) - alpha);
459   int u1_const = u1 * ((1 << 16) - alpha);
460   int v1_const = v1 * ((1 << 16) - alpha);
461
462   y += 2 * stride + 2;
463   for (i = 0; i < 12; i++) {
464     for (j = 0; j < 12; j++) {
465       y[j] = (y[j] * alpha + y1_const) >> 16;
466     }
467     y += stride;
468   }
469
470   stride >>= 1;
471
472   u += stride + 1;
473   v += stride + 1;
474
475   for (i = 0; i < 6; i++) {
476     for (j = 0; j < 6; j++) {
477       u[j] = (u[j] * alpha + u1_const) >> 16;
478       v[j] = (v[j] * alpha + v1_const) >> 16;
479     }
480     u += stride;
481     v += stride;
482   }
483 }
484
485 /* Blend only the edge of the macro block.  Leave center
486  * unblended to allow for other visualizations to be layered.
487  */
488 void vp9_blend_mb_outer_c(uint8_t *y, uint8_t *u, uint8_t *v,
489                           int y1, int u1, int v1, int alpha, int stride) {
490   int i, j;
491   int y1_const = y1 * ((1 << 16) - alpha);
492   int u1_const = u1 * ((1 << 16) - alpha);
493   int v1_const = v1 * ((1 << 16) - alpha);
494
495   for (i = 0; i < 2; i++) {
496     for (j = 0; j < 16; j++) {
497       y[j] = (y[j] * alpha + y1_const) >> 16;
498     }
499     y += stride;
500   }
501
502   for (i = 0; i < 12; i++) {
503     y[0]  = (y[0] * alpha  + y1_const) >> 16;
504     y[1]  = (y[1] * alpha  + y1_const) >> 16;
505     y[14] = (y[14] * alpha + y1_const) >> 16;
506     y[15] = (y[15] * alpha + y1_const) >> 16;
507     y += stride;
508   }
509
510   for (i = 0; i < 2; i++) {
511     for (j = 0; j < 16; j++) {
512       y[j] = (y[j] * alpha + y1_const) >> 16;
513     }
514     y += stride;
515   }
516
517   stride >>= 1;
518
519   for (j = 0; j < 8; j++) {
520     u[j] = (u[j] * alpha + u1_const) >> 16;
521     v[j] = (v[j] * alpha + v1_const) >> 16;
522   }
523   u += stride;
524   v += stride;
525
526   for (i = 0; i < 6; i++) {
527     u[0] = (u[0] * alpha + u1_const) >> 16;
528     v[0] = (v[0] * alpha + v1_const) >> 16;
529
530     u[7] = (u[7] * alpha + u1_const) >> 16;
531     v[7] = (v[7] * alpha + v1_const) >> 16;
532
533     u += stride;
534     v += stride;
535   }
536
537   for (j = 0; j < 8; j++) {
538     u[j] = (u[j] * alpha + u1_const) >> 16;
539     v[j] = (v[j] * alpha + v1_const) >> 16;
540   }
541 }
542
543 void vp9_blend_b_c(uint8_t *y, uint8_t *u, uint8_t *v,
544                    int y1, int u1, int v1, int alpha, int stride) {
545   int i, j;
546   int y1_const = y1 * ((1 << 16) - alpha);
547   int u1_const = u1 * ((1 << 16) - alpha);
548   int v1_const = v1 * ((1 << 16) - alpha);
549
550   for (i = 0; i < 4; i++) {
551     for (j = 0; j < 4; j++) {
552       y[j] = (y[j] * alpha + y1_const) >> 16;
553     }
554     y += stride;
555   }
556
557   stride >>= 1;
558
559   for (i = 0; i < 2; i++) {
560     for (j = 0; j < 2; j++) {
561       u[j] = (u[j] * alpha + u1_const) >> 16;
562       v[j] = (v[j] * alpha + v1_const) >> 16;
563     }
564     u += stride;
565     v += stride;
566   }
567 }
568
569 static void constrain_line(int x0, int *x1, int y0, int *y1,
570                            int width, int height) {
571   int dx;
572   int dy;
573
574   if (*x1 > width) {
575     dx = *x1 - x0;
576     dy = *y1 - y0;
577
578     *x1 = width;
579     if (dx)
580       *y1 = ((width - x0) * dy) / dx + y0;
581   }
582   if (*x1 < 0) {
583     dx = *x1 - x0;
584     dy = *y1 - y0;
585
586     *x1 = 0;
587     if (dx)
588       *y1 = ((0 - x0) * dy) / dx + y0;
589   }
590   if (*y1 > height) {
591     dx = *x1 - x0;
592     dy = *y1 - y0;
593
594     *y1 = height;
595     if (dy)
596       *x1 = ((height - y0) * dx) / dy + x0;
597   }
598   if (*y1 < 0) {
599     dx = *x1 - x0;
600     dy = *y1 - y0;
601
602     *y1 = 0;
603     if (dy)
604       *x1 = ((0 - y0) * dx) / dy + x0;
605   }
606 }
607
608 int vp9_post_proc_frame(struct VP9Common *cm,
609                         YV12_BUFFER_CONFIG *dest, vp9_ppflags_t *ppflags) {
610   const int q = MIN(63, cm->lf.filter_level * 10 / 6);
611   const int flags = ppflags->post_proc_flag;
612   YV12_BUFFER_CONFIG *const ppbuf = &cm->post_proc_buffer;
613   struct postproc_state *const ppstate = &cm->postproc_state;
614
615   if (!cm->frame_to_show)
616     return -1;
617
618   if (!flags) {
619     *dest = *cm->frame_to_show;
620     return 0;
621   }
622
623   vp9_clear_system_state();
624
625   if (flags & VP9D_DEMACROBLOCK) {
626     deblock_and_de_macro_block(cm->frame_to_show, ppbuf,
627                                q + (ppflags->deblocking_level - 5) * 10, 1, 0);
628   } else if (flags & VP9D_DEBLOCK) {
629     vp9_deblock(cm->frame_to_show, ppbuf, q);
630   } else {
631     vp8_yv12_copy_frame(cm->frame_to_show, ppbuf);
632   }
633
634   if (flags & VP9D_ADDNOISE) {
635     const int noise_level = ppflags->noise_level;
636     if (ppstate->last_q != q ||
637         ppstate->last_noise != noise_level) {
638       fillrd(ppstate, 63 - q, noise_level);
639     }
640
641     vp9_plane_add_noise(ppbuf->y_buffer, ppstate->noise, ppstate->blackclamp,
642                         ppstate->whiteclamp, ppstate->bothclamp,
643                         ppbuf->y_width, ppbuf->y_height, ppbuf->y_stride);
644   }
645
646 #if 0 && CONFIG_POSTPROC_VISUALIZER
647   if (flags & VP9D_DEBUG_TXT_FRAME_INFO) {
648     char message[512];
649     snprintf(message, sizeof(message) -1,
650              "F%1dG%1dQ%3dF%3dP%d_s%dx%d",
651              (cm->frame_type == KEY_FRAME),
652              cm->refresh_golden_frame,
653              cm->base_qindex,
654              cm->filter_level,
655              flags,
656              cm->mb_cols, cm->mb_rows);
657     vp9_blit_text(message, ppbuf->y_buffer, ppbuf->y_stride);
658   }
659
660   if (flags & VP9D_DEBUG_TXT_MBLK_MODES) {
661     int i, j;
662     uint8_t *y_ptr;
663     int mb_rows = ppbuf->y_height >> 4;
664     int mb_cols = ppbuf->y_width  >> 4;
665     int mb_index = 0;
666     MODE_INFO *mi = cm->mi;
667
668     y_ptr = post->y_buffer + 4 * post->y_stride + 4;
669
670     /* vp9_filter each macro block */
671     for (i = 0; i < mb_rows; i++) {
672       for (j = 0; j < mb_cols; j++) {
673         char zz[4];
674
675         snprintf(zz, sizeof(zz) - 1, "%c", mi[mb_index].mbmi.mode + 'a');
676
677         vp9_blit_text(zz, y_ptr, post->y_stride);
678         mb_index++;
679         y_ptr += 16;
680       }
681
682       mb_index++; /* border */
683       y_ptr += post->y_stride  * 16 - post->y_width;
684     }
685   }
686
687   if (flags & VP9D_DEBUG_TXT_DC_DIFF) {
688     int i, j;
689     uint8_t *y_ptr;
690     int mb_rows = ppbuf->y_height >> 4;
691     int mb_cols = ppbuf->y_width  >> 4;
692     int mb_index = 0;
693     MODE_INFO *mi = cm->mi;
694
695     y_ptr = post->y_buffer + 4 * post->y_stride + 4;
696
697     /* vp9_filter each macro block */
698     for (i = 0; i < mb_rows; i++) {
699       for (j = 0; j < mb_cols; j++) {
700         char zz[4];
701         int dc_diff = !(mi[mb_index].mbmi.mode != I4X4_PRED &&
702                         mi[mb_index].mbmi.mode != SPLITMV &&
703                         mi[mb_index].mbmi.skip);
704
705         if (cm->frame_type == KEY_FRAME)
706           snprintf(zz, sizeof(zz) - 1, "a");
707         else
708           snprintf(zz, sizeof(zz) - 1, "%c", dc_diff + '0');
709
710         vp9_blit_text(zz, y_ptr, post->y_stride);
711         mb_index++;
712         y_ptr += 16;
713       }
714
715       mb_index++; /* border */
716       y_ptr += post->y_stride  * 16 - post->y_width;
717     }
718   }
719
720   if (flags & VP9D_DEBUG_TXT_RATE_INFO) {
721     char message[512];
722     snprintf(message, sizeof(message),
723              "Bitrate: %10.2f framerate: %10.2f ",
724              cm->bitrate, cm->framerate);
725     vp9_blit_text(message, ppbuf->y_buffer, ppbuf->y_stride);
726   }
727
728   /* Draw motion vectors */
729   if ((flags & VP9D_DEBUG_DRAW_MV) && ppflags->display_mv_flag) {
730     int width  = ppbuf->y_width;
731     int height = ppbuf->y_height;
732     uint8_t *y_buffer = ppbuf->y_buffer;
733     int y_stride = ppbuf->y_stride;
734     MODE_INFO *mi = cm->mi;
735     int x0, y0;
736
737     for (y0 = 0; y0 < height; y0 += 16) {
738       for (x0 = 0; x0 < width; x0 += 16) {
739         int x1, y1;
740
741         if (!(ppflags->display_mv_flag & (1 << mi->mbmi.mode))) {
742           mi++;
743           continue;
744         }
745
746         if (mi->mbmi.mode == SPLITMV) {
747           switch (mi->mbmi.partitioning) {
748             case PARTITIONING_16X8 : {  /* mv_top_bottom */
749               union b_mode_info *bmi = &mi->bmi[0];
750               MV *mv = &bmi->mv.as_mv;
751
752               x1 = x0 + 8 + (mv->col >> 3);
753               y1 = y0 + 4 + (mv->row >> 3);
754
755               constrain_line(x0 + 8, &x1, y0 + 4, &y1, width, height);
756               vp9_blit_line(x0 + 8,  x1, y0 + 4,  y1, y_buffer, y_stride);
757
758               bmi = &mi->bmi[8];
759
760               x1 = x0 + 8 + (mv->col >> 3);
761               y1 = y0 + 12 + (mv->row >> 3);
762
763               constrain_line(x0 + 8, &x1, y0 + 12, &y1, width, height);
764               vp9_blit_line(x0 + 8,  x1, y0 + 12,  y1, y_buffer, y_stride);
765
766               break;
767             }
768             case PARTITIONING_8X16 : {  /* mv_left_right */
769               union b_mode_info *bmi = &mi->bmi[0];
770               MV *mv = &bmi->mv.as_mv;
771
772               x1 = x0 + 4 + (mv->col >> 3);
773               y1 = y0 + 8 + (mv->row >> 3);
774
775               constrain_line(x0 + 4, &x1, y0 + 8, &y1, width, height);
776               vp9_blit_line(x0 + 4,  x1, y0 + 8,  y1, y_buffer, y_stride);
777
778               bmi = &mi->bmi[2];
779
780               x1 = x0 + 12 + (mv->col >> 3);
781               y1 = y0 + 8 + (mv->row >> 3);
782
783               constrain_line(x0 + 12, &x1, y0 + 8, &y1, width, height);
784               vp9_blit_line(x0 + 12,  x1, y0 + 8,  y1, y_buffer, y_stride);
785
786               break;
787             }
788             case PARTITIONING_8X8 : {  /* mv_quarters   */
789               union b_mode_info *bmi = &mi->bmi[0];
790               MV *mv = &bmi->mv.as_mv;
791
792               x1 = x0 + 4 + (mv->col >> 3);
793               y1 = y0 + 4 + (mv->row >> 3);
794
795               constrain_line(x0 + 4, &x1, y0 + 4, &y1, width, height);
796               vp9_blit_line(x0 + 4,  x1, y0 + 4,  y1, y_buffer, y_stride);
797
798               bmi = &mi->bmi[2];
799
800               x1 = x0 + 12 + (mv->col >> 3);
801               y1 = y0 + 4 + (mv->row >> 3);
802
803               constrain_line(x0 + 12, &x1, y0 + 4, &y1, width, height);
804               vp9_blit_line(x0 + 12,  x1, y0 + 4,  y1, y_buffer, y_stride);
805
806               bmi = &mi->bmi[8];
807
808               x1 = x0 + 4 + (mv->col >> 3);
809               y1 = y0 + 12 + (mv->row >> 3);
810
811               constrain_line(x0 + 4, &x1, y0 + 12, &y1, width, height);
812               vp9_blit_line(x0 + 4,  x1, y0 + 12,  y1, y_buffer, y_stride);
813
814               bmi = &mi->bmi[10];
815
816               x1 = x0 + 12 + (mv->col >> 3);
817               y1 = y0 + 12 + (mv->row >> 3);
818
819               constrain_line(x0 + 12, &x1, y0 + 12, &y1, width, height);
820               vp9_blit_line(x0 + 12,  x1, y0 + 12,  y1, y_buffer, y_stride);
821               break;
822             }
823             case PARTITIONING_4X4:
824             default : {
825               union b_mode_info *bmi = mi->bmi;
826               int bx0, by0;
827
828               for (by0 = y0; by0 < (y0 + 16); by0 += 4) {
829                 for (bx0 = x0; bx0 < (x0 + 16); bx0 += 4) {
830                   MV *mv = &bmi->mv.as_mv;
831
832                   x1 = bx0 + 2 + (mv->col >> 3);
833                   y1 = by0 + 2 + (mv->row >> 3);
834
835                   constrain_line(bx0 + 2, &x1, by0 + 2, &y1, width, height);
836                   vp9_blit_line(bx0 + 2,  x1, by0 + 2,  y1, y_buffer, y_stride);
837
838                   bmi++;
839                 }
840               }
841             }
842           }
843         } else if (is_inter_mode(mi->mbmi.mode)) {
844           MV *mv = &mi->mbmi.mv.as_mv;
845           const int lx0 = x0 + 8;
846           const int ly0 = y0 + 8;
847
848           x1 = lx0 + (mv->col >> 3);
849           y1 = ly0 + (mv->row >> 3);
850
851           if (x1 != lx0 && y1 != ly0) {
852             constrain_line(lx0, &x1, ly0 - 1, &y1, width, height);
853             vp9_blit_line(lx0,  x1, ly0 - 1,  y1, y_buffer, y_stride);
854
855             constrain_line(lx0, &x1, ly0 + 1, &y1, width, height);
856             vp9_blit_line(lx0,  x1, ly0 + 1,  y1, y_buffer, y_stride);
857           } else {
858             vp9_blit_line(lx0,  x1, ly0,  y1, y_buffer, y_stride);
859           }
860         }
861
862         mi++;
863       }
864       mi++;
865     }
866   }
867
868   /* Color in block modes */
869   if ((flags & VP9D_DEBUG_CLR_BLK_MODES)
870       && (ppflags->display_mb_modes_flag || ppflags->display_b_modes_flag)) {
871     int y, x;
872     int width  = ppbuf->y_width;
873     int height = ppbuf->y_height;
874     uint8_t *y_ptr = ppbuf->y_buffer;
875     uint8_t *u_ptr = ppbuf->u_buffer;
876     uint8_t *v_ptr = ppbuf->v_buffer;
877     int y_stride = ppbuf->y_stride;
878     MODE_INFO *mi = cm->mi;
879
880     for (y = 0; y < height; y += 16) {
881       for (x = 0; x < width; x += 16) {
882         int Y = 0, U = 0, V = 0;
883
884         if (mi->mbmi.mode == I4X4_PRED &&
885             ((ppflags->display_mb_modes_flag & I4X4_PRED) ||
886              ppflags->display_b_modes_flag)) {
887           int by, bx;
888           uint8_t *yl, *ul, *vl;
889           union b_mode_info *bmi = mi->bmi;
890
891           yl = y_ptr + x;
892           ul = u_ptr + (x >> 1);
893           vl = v_ptr + (x >> 1);
894
895           for (by = 0; by < 16; by += 4) {
896             for (bx = 0; bx < 16; bx += 4) {
897               if ((ppflags->display_b_modes_flag & (1 << mi->mbmi.mode))
898                   || (ppflags->display_mb_modes_flag & I4X4_PRED)) {
899                 Y = B_PREDICTION_MODE_colors[bmi->as_mode][0];
900                 U = B_PREDICTION_MODE_colors[bmi->as_mode][1];
901                 V = B_PREDICTION_MODE_colors[bmi->as_mode][2];
902
903                 vp9_blend_b(yl + bx, ul + (bx >> 1), vl + (bx >> 1), Y, U, V,
904                     0xc000, y_stride);
905               }
906               bmi++;
907             }
908
909             yl += y_stride * 4;
910             ul += y_stride * 1;
911             vl += y_stride * 1;
912           }
913         } else if (ppflags->display_mb_modes_flag & (1 << mi->mbmi.mode)) {
914           Y = MB_PREDICTION_MODE_colors[mi->mbmi.mode][0];
915           U = MB_PREDICTION_MODE_colors[mi->mbmi.mode][1];
916           V = MB_PREDICTION_MODE_colors[mi->mbmi.mode][2];
917
918           vp9_blend_mb_inner(y_ptr + x, u_ptr + (x >> 1), v_ptr + (x >> 1),
919                              Y, U, V, 0xc000, y_stride);
920         }
921
922         mi++;
923       }
924       y_ptr += y_stride * 16;
925       u_ptr += y_stride * 4;
926       v_ptr += y_stride * 4;
927
928       mi++;
929     }
930   }
931
932   /* Color in frame reference blocks */
933   if ((flags & VP9D_DEBUG_CLR_FRM_REF_BLKS) &&
934       ppflags->display_ref_frame_flag) {
935     int y, x;
936     int width  = ppbuf->y_width;
937     int height = ppbuf->y_height;
938     uint8_t *y_ptr = ppbuf->y_buffer;
939     uint8_t *u_ptr = ppbuf->u_buffer;
940     uint8_t *v_ptr = ppbuf->v_buffer;
941     int y_stride = ppbuf->y_stride;
942     MODE_INFO *mi = cm->mi;
943
944     for (y = 0; y < height; y += 16) {
945       for (x = 0; x < width; x += 16) {
946         int Y = 0, U = 0, V = 0;
947
948         if (ppflags->display_ref_frame_flag & (1 << mi->mbmi.ref_frame)) {
949           Y = MV_REFERENCE_FRAME_colors[mi->mbmi.ref_frame][0];
950           U = MV_REFERENCE_FRAME_colors[mi->mbmi.ref_frame][1];
951           V = MV_REFERENCE_FRAME_colors[mi->mbmi.ref_frame][2];
952
953           vp9_blend_mb_outer(y_ptr + x, u_ptr + (x >> 1), v_ptr + (x >> 1),
954                              Y, U, V, 0xc000, y_stride);
955         }
956
957         mi++;
958       }
959       y_ptr += y_stride * 16;
960       u_ptr += y_stride * 4;
961       v_ptr += y_stride * 4;
962
963       mi++;
964     }
965   }
966 #endif
967
968   *dest = *ppbuf;
969
970   /* handle problem with extending borders */
971   dest->y_width = cm->width;
972   dest->y_height = cm->height;
973   dest->uv_width = dest->y_width >> cm->subsampling_x;
974   dest->uv_height = dest->y_height >> cm->subsampling_y;
975
976   return 0;
977 }