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