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
12#include "vpx_ports/config.h"
13#include "vpx_scale/yv12config.h"
14#include "postproc.h"
15#include "vpx_scale/yv12extend.h"
16#include "vpx_scale/vpxscale.h"
17#include "systemdependent.h"
18
19#include <math.h>
20#include <stdlib.h>
21#include <stdio.h>
22
23#define RGB_TO_YUV(t)                                                                       \
24    ( (0.257*(float)(t>>16)) + (0.504*(float)(t>>8&0xff)) + (0.098*(float)(t&0xff)) + 16),  \
25    (-(0.148*(float)(t>>16)) - (0.291*(float)(t>>8&0xff)) + (0.439*(float)(t&0xff)) + 128), \
26    ( (0.439*(float)(t>>16)) - (0.368*(float)(t>>8&0xff)) - (0.071*(float)(t&0xff)) + 128)
27
28/* global constants */
29#if CONFIG_POSTPROC_VISUALIZER
30static const unsigned char MB_PREDICTION_MODE_colors[MB_MODE_COUNT][3] =
31{
32    { RGB_TO_YUV(0x98FB98) },   /* PaleGreen */
33    { RGB_TO_YUV(0x00FF00) },   /* Green */
34    { RGB_TO_YUV(0xADFF2F) },   /* GreenYellow */
35    { RGB_TO_YUV(0x228B22) },   /* ForestGreen */
36    { RGB_TO_YUV(0x006400) },   /* DarkGreen */
37    { RGB_TO_YUV(0x98F5FF) },   /* Cadet Blue */
38    { RGB_TO_YUV(0x6CA6CD) },   /* Sky Blue */
39    { RGB_TO_YUV(0x00008B) },   /* Dark blue */
40    { RGB_TO_YUV(0x551A8B) },   /* Purple */
41    { RGB_TO_YUV(0xFF0000) }    /* Red */
42};
43
44static const unsigned char B_PREDICTION_MODE_colors[B_MODE_COUNT][3] =
45{
46    { RGB_TO_YUV(0x6633ff) },   /* Purple */
47    { RGB_TO_YUV(0xcc33ff) },   /* Magenta */
48    { RGB_TO_YUV(0xff33cc) },   /* Pink */
49    { RGB_TO_YUV(0xff3366) },   /* Coral */
50    { RGB_TO_YUV(0x3366ff) },   /* Blue */
51    { RGB_TO_YUV(0xed00f5) },   /* Dark Blue */
52    { RGB_TO_YUV(0x2e00b8) },   /* Dark Purple */
53    { RGB_TO_YUV(0xff6633) },   /* Orange */
54    { RGB_TO_YUV(0x33ccff) },   /* Light Blue */
55    { RGB_TO_YUV(0x8ab800) },   /* Green */
56    { RGB_TO_YUV(0xffcc33) },   /* Light Orange */
57    { RGB_TO_YUV(0x33ffcc) },   /* Aqua */
58    { RGB_TO_YUV(0x66ff33) },   /* Light Green */
59    { RGB_TO_YUV(0xccff33) },   /* Yellow */
60};
61
62static const unsigned char MV_REFERENCE_FRAME_colors[MAX_REF_FRAMES][3] =
63{
64    { RGB_TO_YUV(0x00ff00) },   /* Blue */
65    { RGB_TO_YUV(0x0000ff) },   /* Green */
66    { RGB_TO_YUV(0xffff00) },   /* Yellow */
67    { RGB_TO_YUV(0xff0000) },   /* Red */
68};
69#endif
70
71static const short kernel5[] =
72{
73    1, 1, 4, 1, 1
74};
75
76const short vp8_rv[] =
77{
78    8, 5, 2, 2, 8, 12, 4, 9, 8, 3,
79    0, 3, 9, 0, 0, 0, 8, 3, 14, 4,
80    10, 1, 11, 14, 1, 14, 9, 6, 12, 11,
81    8, 6, 10, 0, 0, 8, 9, 0, 3, 14,
82    8, 11, 13, 4, 2, 9, 0, 3, 9, 6,
83    1, 2, 3, 14, 13, 1, 8, 2, 9, 7,
84    3, 3, 1, 13, 13, 6, 6, 5, 2, 7,
85    11, 9, 11, 8, 7, 3, 2, 0, 13, 13,
86    14, 4, 12, 5, 12, 10, 8, 10, 13, 10,
87    4, 14, 4, 10, 0, 8, 11, 1, 13, 7,
88    7, 14, 6, 14, 13, 2, 13, 5, 4, 4,
89    0, 10, 0, 5, 13, 2, 12, 7, 11, 13,
90    8, 0, 4, 10, 7, 2, 7, 2, 2, 5,
91    3, 4, 7, 3, 3, 14, 14, 5, 9, 13,
92    3, 14, 3, 6, 3, 0, 11, 8, 13, 1,
93    13, 1, 12, 0, 10, 9, 7, 6, 2, 8,
94    5, 2, 13, 7, 1, 13, 14, 7, 6, 7,
95    9, 6, 10, 11, 7, 8, 7, 5, 14, 8,
96    4, 4, 0, 8, 7, 10, 0, 8, 14, 11,
97    3, 12, 5, 7, 14, 3, 14, 5, 2, 6,
98    11, 12, 12, 8, 0, 11, 13, 1, 2, 0,
99    5, 10, 14, 7, 8, 0, 4, 11, 0, 8,
100    0, 3, 10, 5, 8, 0, 11, 6, 7, 8,
101    10, 7, 13, 9, 2, 5, 1, 5, 10, 2,
102    4, 3, 5, 6, 10, 8, 9, 4, 11, 14,
103    0, 10, 0, 5, 13, 2, 12, 7, 11, 13,
104    8, 0, 4, 10, 7, 2, 7, 2, 2, 5,
105    3, 4, 7, 3, 3, 14, 14, 5, 9, 13,
106    3, 14, 3, 6, 3, 0, 11, 8, 13, 1,
107    13, 1, 12, 0, 10, 9, 7, 6, 2, 8,
108    5, 2, 13, 7, 1, 13, 14, 7, 6, 7,
109    9, 6, 10, 11, 7, 8, 7, 5, 14, 8,
110    4, 4, 0, 8, 7, 10, 0, 8, 14, 11,
111    3, 12, 5, 7, 14, 3, 14, 5, 2, 6,
112    11, 12, 12, 8, 0, 11, 13, 1, 2, 0,
113    5, 10, 14, 7, 8, 0, 4, 11, 0, 8,
114    0, 3, 10, 5, 8, 0, 11, 6, 7, 8,
115    10, 7, 13, 9, 2, 5, 1, 5, 10, 2,
116    4, 3, 5, 6, 10, 8, 9, 4, 11, 14,
117    3, 8, 3, 7, 8, 5, 11, 4, 12, 3,
118    11, 9, 14, 8, 14, 13, 4, 3, 1, 2,
119    14, 6, 5, 4, 4, 11, 4, 6, 2, 1,
120    5, 8, 8, 12, 13, 5, 14, 10, 12, 13,
121    0, 9, 5, 5, 11, 10, 13, 9, 10, 13,
122};
123
124
125extern void vp8_blit_text(const char *msg, unsigned char *address, const int pitch);
126extern void vp8_blit_line(int x0, int x1, int y0, int y1, unsigned char *image, const int pitch);
127/***********************************************************************************************************
128 */
129void vp8_post_proc_down_and_across_c
130(
131    unsigned char *src_ptr,
132    unsigned char *dst_ptr,
133    int src_pixels_per_line,
134    int dst_pixels_per_line,
135    int rows,
136    int cols,
137    int flimit
138)
139{
140    unsigned char *p_src, *p_dst;
141    int row;
142    int col;
143    int i;
144    int v;
145    int pitch = src_pixels_per_line;
146    unsigned char d[8];
147    (void)dst_pixels_per_line;
148
149    for (row = 0; row < rows; row++)
150    {
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        {
157
158            int kernel = 4;
159            int v = p_src[col];
160
161            for (i = -2; i <= 2; i++)
162            {
163                if (abs(v - p_src[col+i*pitch]) > flimit)
164                    goto down_skip_convolve;
165
166                kernel += kernel5[2+i] * p_src[col+i*pitch];
167            }
168
169            v = (kernel >> 3);
170        down_skip_convolve:
171            p_dst[col] = v;
172        }
173
174        /* now post_proc_across */
175        p_src = dst_ptr;
176        p_dst = dst_ptr;
177
178        for (i = 0; i < 8; i++)
179            d[i] = p_src[i];
180
181        for (col = 0; col < cols; col++)
182        {
183            int kernel = 4;
184            v = p_src[col];
185
186            d[col&7] = v;
187
188            for (i = -2; i <= 2; i++)
189            {
190                if (abs(v - p_src[col+i]) > flimit)
191                    goto across_skip_convolve;
192
193                kernel += kernel5[2+i] * p_src[col+i];
194            }
195
196            d[col&7] = (kernel >> 3);
197        across_skip_convolve:
198
199            if (col >= 2)
200                p_dst[col-2] = d[(col-2)&7];
201        }
202
203        /* handle the last two pixels */
204        p_dst[col-2] = d[(col-2)&7];
205        p_dst[col-1] = d[(col-1)&7];
206
207
208        /* next row */
209        src_ptr += pitch;
210        dst_ptr += pitch;
211    }
212}
213
214static int q2mbl(int x)
215{
216    if (x < 20) x = 20;
217
218    x = 50 + (x - 50) * 10 / 8;
219    return x * x / 3;
220}
221void vp8_mbpost_proc_across_ip_c(unsigned char *src, int pitch, int rows, int cols, int flimit)
222{
223    int r, c, i;
224
225    unsigned char *s = src;
226    unsigned char d[16];
227
228
229    for (r = 0; r < rows; r++)
230    {
231        int sumsq = 0;
232        int sum   = 0;
233
234        for (i = -8; i <= 6; i++)
235        {
236            sumsq += s[i] * s[i];
237            sum   += s[i];
238            d[i+8] = 0;
239        }
240
241        for (c = 0; c < cols + 8; c++)
242        {
243            int x = s[c+7] - s[c-8];
244            int y = s[c+7] + s[c-8];
245
246            sum  += x;
247            sumsq += x * y;
248
249            d[c&15] = s[c];
250
251            if (sumsq * 15 - sum * sum < flimit)
252            {
253                d[c&15] = (8 + sum + s[c]) >> 4;
254            }
255
256            s[c-8] = d[(c-8)&15];
257        }
258
259        s += pitch;
260    }
261}
262
263
264
265
266
267void vp8_mbpost_proc_down_c(unsigned char *dst, int pitch, int rows, int cols, int flimit)
268{
269    int r, c, i;
270    const short *rv3 = &vp8_rv[63&rand()];
271
272    for (c = 0; c < cols; c++)
273    {
274        unsigned char *s = &dst[c];
275        int sumsq = 0;
276        int sum   = 0;
277        unsigned char d[16];
278        const short *rv2 = rv3 + ((c * 17) & 127);
279
280        for (i = -8; i <= 6; i++)
281        {
282            sumsq += s[i*pitch] * s[i*pitch];
283            sum   += s[i*pitch];
284        }
285
286        for (r = 0; r < rows + 8; r++)
287        {
288            sumsq += s[7*pitch] * s[ 7*pitch] - s[-8*pitch] * s[-8*pitch];
289            sum  += s[7*pitch] - s[-8*pitch];
290            d[r&15] = s[0];
291
292            if (sumsq * 15 - sum * sum < flimit)
293            {
294                d[r&15] = (rv2[r&127] + sum + s[0]) >> 4;
295            }
296
297            s[-8*pitch] = d[(r-8)&15];
298            s += pitch;
299        }
300    }
301}
302
303
304static void vp8_deblock_and_de_macro_block(YV12_BUFFER_CONFIG         *source,
305        YV12_BUFFER_CONFIG         *post,
306        int                         q,
307        int                         low_var_thresh,
308        int                         flag,
309        vp8_postproc_rtcd_vtable_t *rtcd)
310{
311    double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
312    int ppl = (int)(level + .5);
313    (void) low_var_thresh;
314    (void) flag;
315
316    POSTPROC_INVOKE(rtcd, downacross)(source->y_buffer, post->y_buffer, source->y_stride,  post->y_stride, source->y_height, source->y_width,  ppl);
317    POSTPROC_INVOKE(rtcd, across)(post->y_buffer, post->y_stride, post->y_height, post->y_width, q2mbl(q));
318    POSTPROC_INVOKE(rtcd, down)(post->y_buffer, post->y_stride, post->y_height, post->y_width, q2mbl(q));
319
320    POSTPROC_INVOKE(rtcd, downacross)(source->u_buffer, post->u_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl);
321    POSTPROC_INVOKE(rtcd, downacross)(source->v_buffer, post->v_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl);
322
323}
324
325void vp8_deblock(YV12_BUFFER_CONFIG         *source,
326                        YV12_BUFFER_CONFIG         *post,
327                        int                         q,
328                        int                         low_var_thresh,
329                        int                         flag,
330                        vp8_postproc_rtcd_vtable_t *rtcd)
331{
332    double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
333    int ppl = (int)(level + .5);
334    (void) low_var_thresh;
335    (void) flag;
336
337    POSTPROC_INVOKE(rtcd, downacross)(source->y_buffer, post->y_buffer, source->y_stride,  post->y_stride, source->y_height, source->y_width,   ppl);
338    POSTPROC_INVOKE(rtcd, downacross)(source->u_buffer, post->u_buffer, source->uv_stride, post->uv_stride,  source->uv_height, source->uv_width, ppl);
339    POSTPROC_INVOKE(rtcd, downacross)(source->v_buffer, post->v_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl);
340}
341
342void vp8_de_noise(YV12_BUFFER_CONFIG         *source,
343                  YV12_BUFFER_CONFIG         *post,
344                  int                         q,
345                  int                         low_var_thresh,
346                  int                         flag,
347                  vp8_postproc_rtcd_vtable_t *rtcd)
348{
349    double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
350    int ppl = (int)(level + .5);
351    (void) post;
352    (void) low_var_thresh;
353    (void) flag;
354
355    POSTPROC_INVOKE(rtcd, downacross)(
356        source->y_buffer + 2 * source->y_stride + 2,
357        source->y_buffer + 2 * source->y_stride + 2,
358        source->y_stride,
359        source->y_stride,
360        source->y_height - 4,
361        source->y_width - 4,
362        ppl);
363    POSTPROC_INVOKE(rtcd, downacross)(
364        source->u_buffer + 2 * source->uv_stride + 2,
365        source->u_buffer + 2 * source->uv_stride + 2,
366        source->uv_stride,
367        source->uv_stride,
368        source->uv_height - 4,
369        source->uv_width - 4, ppl);
370    POSTPROC_INVOKE(rtcd, downacross)(
371        source->v_buffer + 2 * source->uv_stride + 2,
372        source->v_buffer + 2 * source->uv_stride + 2,
373        source->uv_stride,
374        source->uv_stride,
375        source->uv_height - 4,
376        source->uv_width - 4, ppl);
377
378}
379
380double vp8_gaussian(double sigma, double mu, double x)
381{
382    return 1 / (sigma * sqrt(2.0 * 3.14159265)) *
383           (exp(-(x - mu) * (x - mu) / (2 * sigma * sigma)));
384}
385
386extern void (*vp8_clear_system_state)(void);
387
388
389static void fillrd(struct postproc_state *state, int q, int a)
390{
391    char char_dist[300];
392
393    double sigma;
394    int ai = a, qi = q, i;
395
396    vp8_clear_system_state();
397
398
399    sigma = ai + .5 + .6 * (63 - qi) / 63.0;
400
401    /* set up a lookup table of 256 entries that matches
402     * a gaussian distribution with sigma determined by q.
403     */
404    {
405        double i;
406        int next, j;
407
408        next = 0;
409
410        for (i = -32; i < 32; i++)
411        {
412            int a = (int)(.5 + 256 * vp8_gaussian(sigma, 0, i));
413
414            if (a)
415            {
416                for (j = 0; j < a; j++)
417                {
418                    char_dist[next+j] = (char) i;
419                }
420
421                next = next + j;
422            }
423
424        }
425
426        for (next = next; next < 256; next++)
427            char_dist[next] = 0;
428
429    }
430
431    for (i = 0; i < 3072; i++)
432    {
433        state->noise[i] = char_dist[rand() & 0xff];
434    }
435
436    for (i = 0; i < 16; i++)
437    {
438        state->blackclamp[i] = -char_dist[0];
439        state->whiteclamp[i] = -char_dist[0];
440        state->bothclamp[i] = -2 * char_dist[0];
441    }
442
443    state->last_q = q;
444    state->last_noise = a;
445}
446
447/****************************************************************************
448 *
449 *  ROUTINE       : plane_add_noise_c
450 *
451 *  INPUTS        : unsigned char *Start    starting address of buffer to add gaussian
452 *                                  noise to
453 *                  unsigned int Width    width of plane
454 *                  unsigned int Height   height of plane
455 *                  int  Pitch    distance between subsequent lines of frame
456 *                  int  q        quantizer used to determine amount of noise
457 *                                  to add
458 *
459 *  OUTPUTS       : None.
460 *
461 *  RETURNS       : void.
462 *
463 *  FUNCTION      : adds gaussian noise to a plane of pixels
464 *
465 *  SPECIAL NOTES : None.
466 *
467 ****************************************************************************/
468void vp8_plane_add_noise_c(unsigned char *Start, char *noise,
469                           char blackclamp[16],
470                           char whiteclamp[16],
471                           char bothclamp[16],
472                           unsigned int Width, unsigned int Height, int Pitch)
473{
474    unsigned int i, j;
475
476    for (i = 0; i < Height; i++)
477    {
478        unsigned char *Pos = Start + i * Pitch;
479        char  *Ref = (char *)(noise + (rand() & 0xff));
480
481        for (j = 0; j < Width; j++)
482        {
483            if (Pos[j] < blackclamp[0])
484                Pos[j] = blackclamp[0];
485
486            if (Pos[j] > 255 + whiteclamp[0])
487                Pos[j] = 255 + whiteclamp[0];
488
489            Pos[j] += Ref[j];
490        }
491    }
492}
493
494/* Blend the macro block with a solid colored square.  Leave the
495 * edges unblended to give distinction to macro blocks in areas
496 * filled with the same color block.
497 */
498void vp8_blend_mb_inner_c (unsigned char *y, unsigned char *u, unsigned char *v,
499                        int y1, int u1, int v1, int alpha, int stride)
500{
501    int i, j;
502    int y1_const = y1*((1<<16)-alpha);
503    int u1_const = u1*((1<<16)-alpha);
504    int v1_const = v1*((1<<16)-alpha);
505
506    y += 2*stride + 2;
507    for (i = 0; i < 12; i++)
508    {
509        for (j = 0; j < 12; j++)
510        {
511            y[j] = (y[j]*alpha + y1_const)>>16;
512        }
513        y += stride;
514    }
515
516    stride >>= 1;
517
518    u += stride + 1;
519    v += stride + 1;
520
521    for (i = 0; i < 6; i++)
522    {
523        for (j = 0; j < 6; j++)
524        {
525            u[j] = (u[j]*alpha + u1_const)>>16;
526            v[j] = (v[j]*alpha + v1_const)>>16;
527        }
528        u += stride;
529        v += stride;
530    }
531}
532
533/* Blend only the edge of the macro block.  Leave center
534 * unblended to allow for other visualizations to be layered.
535 */
536void vp8_blend_mb_outer_c (unsigned char *y, unsigned char *u, unsigned char *v,
537                        int y1, int u1, int v1, int alpha, int stride)
538{
539    int i, j;
540    int y1_const = y1*((1<<16)-alpha);
541    int u1_const = u1*((1<<16)-alpha);
542    int v1_const = v1*((1<<16)-alpha);
543
544    for (i = 0; i < 2; i++)
545    {
546        for (j = 0; j < 16; j++)
547        {
548            y[j] = (y[j]*alpha + y1_const)>>16;
549        }
550        y += stride;
551    }
552
553    for (i = 0; i < 12; i++)
554    {
555        y[0]  = (y[0]*alpha  + y1_const)>>16;
556        y[1]  = (y[1]*alpha  + y1_const)>>16;
557        y[14] = (y[14]*alpha + y1_const)>>16;
558        y[15] = (y[15]*alpha + y1_const)>>16;
559        y += stride;
560    }
561
562    for (i = 0; i < 2; i++)
563    {
564        for (j = 0; j < 16; j++)
565        {
566            y[j] = (y[j]*alpha + y1_const)>>16;
567        }
568        y += stride;
569    }
570
571    stride >>= 1;
572
573    for (j = 0; j < 8; j++)
574    {
575        u[j] = (u[j]*alpha + u1_const)>>16;
576        v[j] = (v[j]*alpha + v1_const)>>16;
577    }
578    u += stride;
579    v += stride;
580
581    for (i = 0; i < 6; i++)
582    {
583        u[0] = (u[0]*alpha + u1_const)>>16;
584        v[0] = (v[0]*alpha + v1_const)>>16;
585
586        u[7] = (u[7]*alpha + u1_const)>>16;
587        v[7] = (v[7]*alpha + v1_const)>>16;
588
589        u += stride;
590        v += stride;
591    }
592
593    for (j = 0; j < 8; j++)
594    {
595        u[j] = (u[j]*alpha + u1_const)>>16;
596        v[j] = (v[j]*alpha + v1_const)>>16;
597    }
598}
599
600void vp8_blend_b_c (unsigned char *y, unsigned char *u, unsigned char *v,
601                        int y1, int u1, int v1, int alpha, int stride)
602{
603    int i, j;
604    int y1_const = y1*((1<<16)-alpha);
605    int u1_const = u1*((1<<16)-alpha);
606    int v1_const = v1*((1<<16)-alpha);
607
608    for (i = 0; i < 4; i++)
609    {
610        for (j = 0; j < 4; j++)
611        {
612            y[j] = (y[j]*alpha + y1_const)>>16;
613        }
614        y += stride;
615    }
616
617    stride >>= 1;
618
619    for (i = 0; i < 2; i++)
620    {
621        for (j = 0; j < 2; j++)
622        {
623            u[j] = (u[j]*alpha + u1_const)>>16;
624            v[j] = (v[j]*alpha + v1_const)>>16;
625        }
626        u += stride;
627        v += stride;
628    }
629}
630
631static void constrain_line (int x0, int *x1, int y0, int *y1, int width, int height)
632{
633    int dx;
634    int dy;
635
636    if (*x1 > width)
637    {
638        dx = *x1 - x0;
639        dy = *y1 - y0;
640
641        *x1 = width;
642        if (dx)
643            *y1 = ((width-x0)*dy)/dx + y0;
644    }
645    if (*x1 < 0)
646    {
647        dx = *x1 - x0;
648        dy = *y1 - y0;
649
650        *x1 = 0;
651        if (dx)
652            *y1 = ((0-x0)*dy)/dx + y0;
653    }
654    if (*y1 > height)
655    {
656        dx = *x1 - x0;
657        dy = *y1 - y0;
658
659        *y1 = height;
660        if (dy)
661            *x1 = ((height-y0)*dx)/dy + x0;
662    }
663    if (*y1 < 0)
664    {
665        dx = *x1 - x0;
666        dy = *y1 - y0;
667
668        *y1 = 0;
669        if (dy)
670            *x1 = ((0-y0)*dx)/dy + x0;
671    }
672}
673
674
675#if CONFIG_RUNTIME_CPU_DETECT
676#define RTCD_VTABLE(oci) (&(oci)->rtcd.postproc)
677#else
678#define RTCD_VTABLE(oci) NULL
679#endif
680
681int vp8_post_proc_frame(VP8_COMMON *oci, YV12_BUFFER_CONFIG *dest, vp8_ppflags_t *ppflags)
682{
683    int q = oci->filter_level * 10 / 6;
684    int flags = ppflags->post_proc_flag;
685    int deblock_level = ppflags->deblocking_level;
686    int noise_level = ppflags->noise_level;
687
688    if (!oci->frame_to_show)
689        return -1;
690
691    if (q > 63)
692        q = 63;
693
694    if (!flags)
695    {
696        *dest = *oci->frame_to_show;
697
698        /* handle problem with extending borders */
699        dest->y_width = oci->Width;
700        dest->y_height = oci->Height;
701        dest->uv_height = dest->y_height / 2;
702        return 0;
703
704    }
705
706#if ARCH_X86||ARCH_X86_64
707    vpx_reset_mmx_state();
708#endif
709
710    if (flags & VP8D_DEMACROBLOCK)
711    {
712        vp8_deblock_and_de_macro_block(oci->frame_to_show, &oci->post_proc_buffer,
713                                       q + (deblock_level - 5) * 10, 1, 0, RTCD_VTABLE(oci));
714    }
715    else if (flags & VP8D_DEBLOCK)
716    {
717        vp8_deblock(oci->frame_to_show, &oci->post_proc_buffer,
718                    q, 1, 0, RTCD_VTABLE(oci));
719    }
720    else
721    {
722        vp8_yv12_copy_frame_ptr(oci->frame_to_show, &oci->post_proc_buffer);
723    }
724
725    if (flags & VP8D_ADDNOISE)
726    {
727        if (oci->postproc_state.last_q != q
728            || oci->postproc_state.last_noise != noise_level)
729        {
730            fillrd(&oci->postproc_state, 63 - q, noise_level);
731        }
732
733        POSTPROC_INVOKE(RTCD_VTABLE(oci), addnoise)
734        (oci->post_proc_buffer.y_buffer,
735         oci->postproc_state.noise,
736         oci->postproc_state.blackclamp,
737         oci->postproc_state.whiteclamp,
738         oci->postproc_state.bothclamp,
739         oci->post_proc_buffer.y_width, oci->post_proc_buffer.y_height,
740         oci->post_proc_buffer.y_stride);
741    }
742
743#if CONFIG_POSTPROC_VISUALIZER
744    if (flags & VP8D_DEBUG_TXT_FRAME_INFO)
745    {
746        char message[512];
747        sprintf(message, "F%1dG%1dQ%3dF%3dP%d_s%dx%d",
748                (oci->frame_type == KEY_FRAME),
749                oci->refresh_golden_frame,
750                oci->base_qindex,
751                oci->filter_level,
752                flags,
753                oci->mb_cols, oci->mb_rows);
754        vp8_blit_text(message, oci->post_proc_buffer.y_buffer, oci->post_proc_buffer.y_stride);
755    }
756
757    if (flags & VP8D_DEBUG_TXT_MBLK_MODES)
758    {
759        int i, j;
760        unsigned char *y_ptr;
761        YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
762        int mb_rows = post->y_height >> 4;
763        int mb_cols = post->y_width  >> 4;
764        int mb_index = 0;
765        MODE_INFO *mi = oci->mi;
766
767        y_ptr = post->y_buffer + 4 * post->y_stride + 4;
768
769        /* vp8_filter each macro block */
770        for (i = 0; i < mb_rows; i++)
771        {
772            for (j = 0; j < mb_cols; j++)
773            {
774                char zz[4];
775
776                sprintf(zz, "%c", mi[mb_index].mbmi.mode + 'a');
777
778                vp8_blit_text(zz, y_ptr, post->y_stride);
779                mb_index ++;
780                y_ptr += 16;
781            }
782
783            mb_index ++; /* border */
784            y_ptr += post->y_stride  * 16 - post->y_width;
785
786        }
787    }
788
789    if (flags & VP8D_DEBUG_TXT_DC_DIFF)
790    {
791        int i, j;
792        unsigned char *y_ptr;
793        YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
794        int mb_rows = post->y_height >> 4;
795        int mb_cols = post->y_width  >> 4;
796        int mb_index = 0;
797        MODE_INFO *mi = oci->mi;
798
799        y_ptr = post->y_buffer + 4 * post->y_stride + 4;
800
801        /* vp8_filter each macro block */
802        for (i = 0; i < mb_rows; i++)
803        {
804            for (j = 0; j < mb_cols; j++)
805            {
806                char zz[4];
807
808                if (oci->frame_type == KEY_FRAME)
809                    sprintf(zz, "a");
810                else
811                    sprintf(zz, "%c", mi[mb_index].mbmi.dc_diff + '0');
812
813                vp8_blit_text(zz, y_ptr, post->y_stride);
814                mb_index ++;
815                y_ptr += 16;
816            }
817
818            mb_index ++; /* border */
819            y_ptr += post->y_stride  * 16 - post->y_width;
820
821        }
822    }
823
824    if (flags & VP8D_DEBUG_TXT_RATE_INFO)
825    {
826        char message[512];
827        sprintf(message, "Bitrate: %10.2f frame_rate: %10.2f ", oci->bitrate, oci->framerate);
828        vp8_blit_text(message, oci->post_proc_buffer.y_buffer, oci->post_proc_buffer.y_stride);
829    }
830
831    /* Draw motion vectors */
832    if ((flags & VP8D_DEBUG_DRAW_MV) && ppflags->display_mv_flag)
833    {
834        YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
835        int width  = post->y_width;
836        int height = post->y_height;
837        int mb_cols = width  >> 4;
838        unsigned char *y_buffer = oci->post_proc_buffer.y_buffer;
839        int y_stride = oci->post_proc_buffer.y_stride;
840        MODE_INFO *mi = oci->mi;
841        int x0, y0;
842
843        for (y0 = 0; y0 < height; y0 += 16)
844        {
845            for (x0 = 0; x0 < width; x0 += 16)
846            {
847                int x1, y1;
848
849                if (!(ppflags->display_mv_flag & (1<<mi->mbmi.mode)))
850                {
851                    mi++;
852                    continue;
853                }
854
855                if (mi->mbmi.mode == SPLITMV)
856                {
857                    switch (mi->mbmi.partitioning)
858                    {
859                        case 0 :    /* mv_top_bottom */
860                        {
861                            B_MODE_INFO *bmi = &mi->bmi[0];
862                            MV *mv = &bmi->mv.as_mv;
863
864                            x1 = x0 + 8 + (mv->col >> 3);
865                            y1 = y0 + 4 + (mv->row >> 3);
866
867                            constrain_line (x0+8, &x1, y0+4, &y1, width, height);
868                            vp8_blit_line  (x0+8,  x1, y0+4,  y1, y_buffer, y_stride);
869
870                            bmi = &mi->bmi[8];
871
872                            x1 = x0 + 8 + (mv->col >> 3);
873                            y1 = y0 +12 + (mv->row >> 3);
874
875                            constrain_line (x0+8, &x1, y0+12, &y1, width, height);
876                            vp8_blit_line  (x0+8,  x1, y0+12,  y1, y_buffer, y_stride);
877
878                            break;
879                        }
880                        case 1 :    /* mv_left_right */
881                        {
882                            B_MODE_INFO *bmi = &mi->bmi[0];
883                            MV *mv = &bmi->mv.as_mv;
884
885                            x1 = x0 + 4 + (mv->col >> 3);
886                            y1 = y0 + 8 + (mv->row >> 3);
887
888                            constrain_line (x0+4, &x1, y0+8, &y1, width, height);
889                            vp8_blit_line  (x0+4,  x1, y0+8,  y1, y_buffer, y_stride);
890
891                            bmi = &mi->bmi[2];
892
893                            x1 = x0 +12 + (mv->col >> 3);
894                            y1 = y0 + 8 + (mv->row >> 3);
895
896                            constrain_line (x0+12, &x1, y0+8, &y1, width, height);
897                            vp8_blit_line  (x0+12,  x1, y0+8,  y1, y_buffer, y_stride);
898
899                            break;
900                        }
901                        case 2 :    /* mv_quarters   */
902                        {
903                            B_MODE_INFO *bmi = &mi->bmi[0];
904                            MV *mv = &bmi->mv.as_mv;
905
906                            x1 = x0 + 4 + (mv->col >> 3);
907                            y1 = y0 + 4 + (mv->row >> 3);
908
909                            constrain_line (x0+4, &x1, y0+4, &y1, width, height);
910                            vp8_blit_line  (x0+4,  x1, y0+4,  y1, y_buffer, y_stride);
911
912                            bmi = &mi->bmi[2];
913
914                            x1 = x0 +12 + (mv->col >> 3);
915                            y1 = y0 + 4 + (mv->row >> 3);
916
917                            constrain_line (x0+12, &x1, y0+4, &y1, width, height);
918                            vp8_blit_line  (x0+12,  x1, y0+4,  y1, y_buffer, y_stride);
919
920                            bmi = &mi->bmi[8];
921
922                            x1 = x0 + 4 + (mv->col >> 3);
923                            y1 = y0 +12 + (mv->row >> 3);
924
925                            constrain_line (x0+4, &x1, y0+12, &y1, width, height);
926                            vp8_blit_line  (x0+4,  x1, y0+12,  y1, y_buffer, y_stride);
927
928                            bmi = &mi->bmi[10];
929
930                            x1 = x0 +12 + (mv->col >> 3);
931                            y1 = y0 +12 + (mv->row >> 3);
932
933                            constrain_line (x0+12, &x1, y0+12, &y1, width, height);
934                            vp8_blit_line  (x0+12,  x1, y0+12,  y1, y_buffer, y_stride);
935                            break;
936                        }
937                        default :
938                        {
939                            B_MODE_INFO *bmi = mi->bmi;
940                            int bx0, by0;
941
942                            for (by0 = y0; by0 < (y0+16); by0 += 4)
943                            {
944                                for (bx0 = x0; bx0 < (x0+16); bx0 += 4)
945                                {
946                                    MV *mv = &bmi->mv.as_mv;
947
948                                    x1 = bx0 + 2 + (mv->col >> 3);
949                                    y1 = by0 + 2 + (mv->row >> 3);
950
951                                    constrain_line (bx0+2, &x1, by0+2, &y1, width, height);
952                                    vp8_blit_line  (bx0+2,  x1, by0+2,  y1, y_buffer, y_stride);
953
954                                    bmi++;
955                                }
956                            }
957                        }
958                    }
959                }
960                else if (mi->mbmi.mode >= NEARESTMV)
961                {
962                    MV *mv = &mi->mbmi.mv.as_mv;
963                    const int lx0 = x0 + 8;
964                    const int ly0 = y0 + 8;
965
966                    x1 = lx0 + (mv->col >> 3);
967                    y1 = ly0 + (mv->row >> 3);
968
969                    if (x1 != lx0 && y1 != ly0)
970                    {
971                        constrain_line (lx0, &x1, ly0-1, &y1, width, height);
972                        vp8_blit_line  (lx0,  x1, ly0-1,  y1, y_buffer, y_stride);
973
974                        constrain_line (lx0, &x1, ly0+1, &y1, width, height);
975                        vp8_blit_line  (lx0,  x1, ly0+1,  y1, y_buffer, y_stride);
976                    }
977                    else
978                        vp8_blit_line  (lx0,  x1, ly0,  y1, y_buffer, y_stride);
979                }
980
981                mi++;
982            }
983            mi++;
984        }
985    }
986
987    /* Color in block modes */
988    if ((flags & VP8D_DEBUG_CLR_BLK_MODES)
989        && (ppflags->display_mb_modes_flag || ppflags->display_b_modes_flag))
990    {
991        int y, x;
992        YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
993        int width  = post->y_width;
994        int height = post->y_height;
995        unsigned char *y_ptr = oci->post_proc_buffer.y_buffer;
996        unsigned char *u_ptr = oci->post_proc_buffer.u_buffer;
997        unsigned char *v_ptr = oci->post_proc_buffer.v_buffer;
998        int y_stride = oci->post_proc_buffer.y_stride;
999        MODE_INFO *mi = oci->mi;
1000
1001        for (y = 0; y < height; y += 16)
1002        {
1003            for (x = 0; x < width; x += 16)
1004            {
1005                int Y = 0, U = 0, V = 0;
1006
1007                if (mi->mbmi.mode == B_PRED &&
1008                    ((ppflags->display_mb_modes_flag & B_PRED) || ppflags->display_b_modes_flag))
1009                {
1010                    int by, bx;
1011                    unsigned char *yl, *ul, *vl;
1012                    B_MODE_INFO *bmi = mi->bmi;
1013
1014                    yl = y_ptr + x;
1015                    ul = u_ptr + (x>>1);
1016                    vl = v_ptr + (x>>1);
1017
1018                    for (by = 0; by < 16; by += 4)
1019                    {
1020                        for (bx = 0; bx < 16; bx += 4)
1021                        {
1022                            if ((ppflags->display_b_modes_flag & (1<<mi->mbmi.mode))
1023                                || (ppflags->display_mb_modes_flag & B_PRED))
1024                            {
1025                                Y = B_PREDICTION_MODE_colors[bmi->mode][0];
1026                                U = B_PREDICTION_MODE_colors[bmi->mode][1];
1027                                V = B_PREDICTION_MODE_colors[bmi->mode][2];
1028
1029                                POSTPROC_INVOKE(RTCD_VTABLE(oci), blend_b)
1030                                    (yl+bx, ul+(bx>>1), vl+(bx>>1), Y, U, V, 0xc000, y_stride);
1031                            }
1032                            bmi++;
1033                        }
1034
1035                        yl += y_stride*4;
1036                        ul += y_stride*1;
1037                        vl += y_stride*1;
1038                    }
1039                }
1040                else if (ppflags->display_mb_modes_flag & (1<<mi->mbmi.mode))
1041                {
1042                    Y = MB_PREDICTION_MODE_colors[mi->mbmi.mode][0];
1043                    U = MB_PREDICTION_MODE_colors[mi->mbmi.mode][1];
1044                    V = MB_PREDICTION_MODE_colors[mi->mbmi.mode][2];
1045
1046                    POSTPROC_INVOKE(RTCD_VTABLE(oci), blend_mb_inner)
1047                        (y_ptr+x, u_ptr+(x>>1), v_ptr+(x>>1), Y, U, V, 0xc000, y_stride);
1048                }
1049
1050                mi++;
1051            }
1052            y_ptr += y_stride*16;
1053            u_ptr += y_stride*4;
1054            v_ptr += y_stride*4;
1055
1056            mi++;
1057        }
1058    }
1059
1060    /* Color in frame reference blocks */
1061    if ((flags & VP8D_DEBUG_CLR_FRM_REF_BLKS) && ppflags->display_ref_frame_flag)
1062    {
1063        int y, x;
1064        YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
1065        int width  = post->y_width;
1066        int height = post->y_height;
1067        unsigned char *y_ptr = oci->post_proc_buffer.y_buffer;
1068        unsigned char *u_ptr = oci->post_proc_buffer.u_buffer;
1069        unsigned char *v_ptr = oci->post_proc_buffer.v_buffer;
1070        int y_stride = oci->post_proc_buffer.y_stride;
1071        MODE_INFO *mi = oci->mi;
1072
1073        for (y = 0; y < height; y += 16)
1074        {
1075            for (x = 0; x < width; x +=16)
1076            {
1077                int Y = 0, U = 0, V = 0;
1078
1079                if (ppflags->display_ref_frame_flag & (1<<mi->mbmi.ref_frame))
1080                {
1081                    Y = MV_REFERENCE_FRAME_colors[mi->mbmi.ref_frame][0];
1082                    U = MV_REFERENCE_FRAME_colors[mi->mbmi.ref_frame][1];
1083                    V = MV_REFERENCE_FRAME_colors[mi->mbmi.ref_frame][2];
1084
1085                    POSTPROC_INVOKE(RTCD_VTABLE(oci), blend_mb_outer)
1086                        (y_ptr+x, u_ptr+(x>>1), v_ptr+(x>>1), Y, U, V, 0xc000, y_stride);
1087                }
1088
1089                mi++;
1090            }
1091            y_ptr += y_stride*16;
1092            u_ptr += y_stride*4;
1093            v_ptr += y_stride*4;
1094
1095            mi++;
1096        }
1097    }
1098#endif
1099
1100    *dest = oci->post_proc_buffer;
1101
1102    /* handle problem with extending borders */
1103    dest->y_width = oci->Width;
1104    dest->y_height = oci->Height;
1105    dest->uv_height = dest->y_height / 2;
1106    return 0;
1107}
1108