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}
217void vp8_mbpost_proc_across_ip_c(unsigned char *src, int pitch, int rows, int cols, int flimit)
218{
219    int r, c, i;
220
221    unsigned char *s = src;
222    unsigned char d[16];
223
224    for (r = 0; r < rows; r++)
225    {
226        int sumsq = 0;
227        int sum   = 0;
228
229        for (i = -8; i<0; i++)
230          s[i]=s[0];
231
232        /* 17 avoids valgrind warning - we buffer values in c in d
233         * and only write them when we've read 8 ahead...
234         */
235        for (i = cols; i<cols+17; i++)
236          s[i]=s[cols-1];
237
238        for (i = -8; i <= 6; i++)
239        {
240            sumsq += s[i] * s[i];
241            sum   += s[i];
242            d[i+8] = 0;
243        }
244
245        for (c = 0; c < cols + 8; c++)
246        {
247            int x = s[c+7] - s[c-8];
248            int y = s[c+7] + s[c-8];
249
250            sum  += x;
251            sumsq += x * y;
252
253            d[c&15] = s[c];
254
255            if (sumsq * 15 - sum * sum < flimit)
256            {
257                d[c&15] = (8 + sum + s[c]) >> 4;
258            }
259
260            s[c-8] = d[(c-8)&15];
261        }
262
263        s += pitch;
264    }
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 = rows; i < rows+17; i++)
288          s[i*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
313static void vp8_de_mblock(YV12_BUFFER_CONFIG         *post,
314                          int                         q)
315{
316    vp8_mbpost_proc_across_ip(post->y_buffer, post->y_stride, post->y_height,
317                              post->y_width, q2mbl(q));
318    vp8_mbpost_proc_down(post->y_buffer, post->y_stride, post->y_height,
319                         post->y_width, q2mbl(q));
320}
321
322void vp8_deblock(VP8_COMMON                 *cm,
323                 YV12_BUFFER_CONFIG         *source,
324                 YV12_BUFFER_CONFIG         *post,
325                 int                         q,
326                 int                         low_var_thresh,
327                 int                         flag)
328{
329    double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
330    int ppl = (int)(level + .5);
331
332    const MODE_INFO *mode_info_context = cm->show_frame_mi;
333    int mbr, mbc;
334
335    /* The pixel thresholds are adjusted according to if or not the macroblock
336     * is a skipped block.  */
337    unsigned char *ylimits = cm->pp_limits_buffer;
338    unsigned char *uvlimits = cm->pp_limits_buffer + 16 * cm->mb_cols;
339    (void) low_var_thresh;
340    (void) flag;
341
342    if (ppl > 0)
343    {
344        for (mbr = 0; mbr < cm->mb_rows; mbr++)
345        {
346            unsigned char *ylptr = ylimits;
347            unsigned char *uvlptr = uvlimits;
348            for (mbc = 0; mbc < cm->mb_cols; mbc++)
349            {
350                unsigned char mb_ppl;
351
352                if (mode_info_context->mbmi.mb_skip_coeff)
353                    mb_ppl = (unsigned char)ppl >> 1;
354                else
355                    mb_ppl = (unsigned char)ppl;
356
357                vpx_memset(ylptr, mb_ppl, 16);
358                vpx_memset(uvlptr, mb_ppl, 8);
359
360                ylptr += 16;
361                uvlptr += 8;
362                mode_info_context++;
363            }
364            mode_info_context++;
365
366            vp8_post_proc_down_and_across_mb_row(
367                source->y_buffer + 16 * mbr * source->y_stride,
368                post->y_buffer + 16 * mbr * post->y_stride, source->y_stride,
369                post->y_stride, source->y_width, ylimits, 16);
370
371            vp8_post_proc_down_and_across_mb_row(
372                source->u_buffer + 8 * mbr * source->uv_stride,
373                post->u_buffer + 8 * mbr * post->uv_stride, source->uv_stride,
374                post->uv_stride, source->uv_width, uvlimits, 8);
375            vp8_post_proc_down_and_across_mb_row(
376                source->v_buffer + 8 * mbr * source->uv_stride,
377                post->v_buffer + 8 * mbr * post->uv_stride, source->uv_stride,
378                post->uv_stride, source->uv_width, uvlimits, 8);
379        }
380    } else
381    {
382        vp8_yv12_copy_frame(source, post);
383    }
384}
385
386#if !(CONFIG_TEMPORAL_DENOISING)
387void vp8_de_noise(VP8_COMMON                 *cm,
388                  YV12_BUFFER_CONFIG         *source,
389                  YV12_BUFFER_CONFIG         *post,
390                  int                         q,
391                  int                         low_var_thresh,
392                  int                         flag)
393{
394    double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
395    int ppl = (int)(level + .5);
396    int mb_rows = source->y_width >> 4;
397    int mb_cols = source->y_height >> 4;
398    unsigned char *limits = cm->pp_limits_buffer;;
399    int mbr, mbc;
400    (void) post;
401    (void) low_var_thresh;
402    (void) flag;
403
404    vpx_memset(limits, (unsigned char)ppl, 16 * mb_cols);
405
406    /* TODO: The original code don't filter the 2 outer rows and columns. */
407    for (mbr = 0; mbr < mb_rows; mbr++)
408    {
409        vp8_post_proc_down_and_across_mb_row(
410            source->y_buffer + 16 * mbr * source->y_stride,
411            source->y_buffer + 16 * mbr * source->y_stride,
412            source->y_stride, source->y_stride, source->y_width, limits, 16);
413
414        vp8_post_proc_down_and_across_mb_row(
415            source->u_buffer + 8 * mbr * source->uv_stride,
416            source->u_buffer + 8 * mbr * source->uv_stride,
417            source->uv_stride, source->uv_stride, source->uv_width, limits, 8);
418        vp8_post_proc_down_and_across_mb_row(
419            source->v_buffer + 8 * mbr * source->uv_stride,
420            source->v_buffer + 8 * mbr * source->uv_stride,
421            source->uv_stride, source->uv_stride, source->uv_width, limits, 8);
422    }
423}
424#endif
425
426double vp8_gaussian(double sigma, double mu, double x)
427{
428    return 1 / (sigma * sqrt(2.0 * 3.14159265)) *
429           (exp(-(x - mu) * (x - mu) / (2 * sigma * sigma)));
430}
431
432static void fillrd(struct postproc_state *state, int q, int a)
433{
434    char char_dist[300];
435
436    double sigma;
437    int i;
438
439    vp8_clear_system_state();
440
441
442    sigma = a + .5 + .6 * (63 - q) / 63.0;
443
444    /* set up a lookup table of 256 entries that matches
445     * a gaussian distribution with sigma determined by q.
446     */
447    {
448        int next, j;
449
450        next = 0;
451
452        for (i = -32; i < 32; i++)
453        {
454            const int v = (int)(.5 + 256 * vp8_gaussian(sigma, 0, i));
455
456            if (v)
457            {
458                for (j = 0; j < v; j++)
459                {
460                    char_dist[next+j] = (char) i;
461                }
462
463                next = next + j;
464            }
465
466        }
467
468        for (; next < 256; next++)
469            char_dist[next] = 0;
470
471    }
472
473    for (i = 0; i < 3072; i++)
474    {
475        state->noise[i] = char_dist[rand() & 0xff];
476    }
477
478    for (i = 0; i < 16; i++)
479    {
480        state->blackclamp[i] = -char_dist[0];
481        state->whiteclamp[i] = -char_dist[0];
482        state->bothclamp[i] = -2 * char_dist[0];
483    }
484
485    state->last_q = q;
486    state->last_noise = a;
487}
488
489/****************************************************************************
490 *
491 *  ROUTINE       : plane_add_noise_c
492 *
493 *  INPUTS        : unsigned char *Start    starting address of buffer to add gaussian
494 *                                  noise to
495 *                  unsigned int Width    width of plane
496 *                  unsigned int Height   height of plane
497 *                  int  Pitch    distance between subsequent lines of frame
498 *                  int  q        quantizer used to determine amount of noise
499 *                                  to add
500 *
501 *  OUTPUTS       : None.
502 *
503 *  RETURNS       : void.
504 *
505 *  FUNCTION      : adds gaussian noise to a plane of pixels
506 *
507 *  SPECIAL NOTES : None.
508 *
509 ****************************************************************************/
510void vp8_plane_add_noise_c(unsigned char *Start, char *noise,
511                           char blackclamp[16],
512                           char whiteclamp[16],
513                           char bothclamp[16],
514                           unsigned int Width, unsigned int Height, int Pitch)
515{
516    unsigned int i, j;
517
518    for (i = 0; i < Height; i++)
519    {
520        unsigned char *Pos = Start + i * Pitch;
521        char  *Ref = (char *)(noise + (rand() & 0xff));
522
523        for (j = 0; j < Width; j++)
524        {
525            if (Pos[j] < blackclamp[0])
526                Pos[j] = blackclamp[0];
527
528            if (Pos[j] > 255 + whiteclamp[0])
529                Pos[j] = 255 + whiteclamp[0];
530
531            Pos[j] += Ref[j];
532        }
533    }
534}
535
536/* Blend the macro block with a solid colored square.  Leave the
537 * edges unblended to give distinction to macro blocks in areas
538 * filled with the same color block.
539 */
540void vp8_blend_mb_inner_c (unsigned char *y, unsigned char *u, unsigned char *v,
541                        int y_1, int u_1, int v_1, int alpha, int stride)
542{
543    int i, j;
544    int y1_const = y_1*((1<<16)-alpha);
545    int u1_const = u_1*((1<<16)-alpha);
546    int v1_const = v_1*((1<<16)-alpha);
547
548    y += 2*stride + 2;
549    for (i = 0; i < 12; i++)
550    {
551        for (j = 0; j < 12; j++)
552        {
553            y[j] = (y[j]*alpha + y1_const)>>16;
554        }
555        y += stride;
556    }
557
558    stride >>= 1;
559
560    u += stride + 1;
561    v += stride + 1;
562
563    for (i = 0; i < 6; i++)
564    {
565        for (j = 0; j < 6; j++)
566        {
567            u[j] = (u[j]*alpha + u1_const)>>16;
568            v[j] = (v[j]*alpha + v1_const)>>16;
569        }
570        u += stride;
571        v += stride;
572    }
573}
574
575/* Blend only the edge of the macro block.  Leave center
576 * unblended to allow for other visualizations to be layered.
577 */
578void vp8_blend_mb_outer_c (unsigned char *y, unsigned char *u, unsigned char *v,
579                        int y_1, int u_1, int v_1, int alpha, int stride)
580{
581    int i, j;
582    int y1_const = y_1*((1<<16)-alpha);
583    int u1_const = u_1*((1<<16)-alpha);
584    int v1_const = v_1*((1<<16)-alpha);
585
586    for (i = 0; i < 2; i++)
587    {
588        for (j = 0; j < 16; j++)
589        {
590            y[j] = (y[j]*alpha + y1_const)>>16;
591        }
592        y += stride;
593    }
594
595    for (i = 0; i < 12; i++)
596    {
597        y[0]  = (y[0]*alpha  + y1_const)>>16;
598        y[1]  = (y[1]*alpha  + y1_const)>>16;
599        y[14] = (y[14]*alpha + y1_const)>>16;
600        y[15] = (y[15]*alpha + y1_const)>>16;
601        y += stride;
602    }
603
604    for (i = 0; i < 2; i++)
605    {
606        for (j = 0; j < 16; j++)
607        {
608            y[j] = (y[j]*alpha + y1_const)>>16;
609        }
610        y += stride;
611    }
612
613    stride >>= 1;
614
615    for (j = 0; j < 8; j++)
616    {
617        u[j] = (u[j]*alpha + u1_const)>>16;
618        v[j] = (v[j]*alpha + v1_const)>>16;
619    }
620    u += stride;
621    v += stride;
622
623    for (i = 0; i < 6; i++)
624    {
625        u[0] = (u[0]*alpha + u1_const)>>16;
626        v[0] = (v[0]*alpha + v1_const)>>16;
627
628        u[7] = (u[7]*alpha + u1_const)>>16;
629        v[7] = (v[7]*alpha + v1_const)>>16;
630
631        u += stride;
632        v += stride;
633    }
634
635    for (j = 0; j < 8; j++)
636    {
637        u[j] = (u[j]*alpha + u1_const)>>16;
638        v[j] = (v[j]*alpha + v1_const)>>16;
639    }
640}
641
642void vp8_blend_b_c (unsigned char *y, unsigned char *u, unsigned char *v,
643                        int y_1, int u_1, int v_1, int alpha, int stride)
644{
645    int i, j;
646    int y1_const = y_1*((1<<16)-alpha);
647    int u1_const = u_1*((1<<16)-alpha);
648    int v1_const = v_1*((1<<16)-alpha);
649
650    for (i = 0; i < 4; i++)
651    {
652        for (j = 0; j < 4; j++)
653        {
654            y[j] = (y[j]*alpha + y1_const)>>16;
655        }
656        y += stride;
657    }
658
659    stride >>= 1;
660
661    for (i = 0; i < 2; i++)
662    {
663        for (j = 0; j < 2; j++)
664        {
665            u[j] = (u[j]*alpha + u1_const)>>16;
666            v[j] = (v[j]*alpha + v1_const)>>16;
667        }
668        u += stride;
669        v += stride;
670    }
671}
672
673static void constrain_line (int x_0, int *x_1, int y_0, int *y_1, int width, int height)
674{
675    int dx;
676    int dy;
677
678    if (*x_1 > width)
679    {
680        dx = *x_1 - x_0;
681        dy = *y_1 - y_0;
682
683        *x_1 = width;
684        if (dx)
685            *y_1 = ((width-x_0)*dy)/dx + y_0;
686    }
687    if (*x_1 < 0)
688    {
689        dx = *x_1 - x_0;
690        dy = *y_1 - y_0;
691
692        *x_1 = 0;
693        if (dx)
694            *y_1 = ((0-x_0)*dy)/dx + y_0;
695    }
696    if (*y_1 > height)
697    {
698        dx = *x_1 - x_0;
699        dy = *y_1 - y_0;
700
701        *y_1 = height;
702        if (dy)
703            *x_1 = ((height-y_0)*dx)/dy + x_0;
704    }
705    if (*y_1 < 0)
706    {
707        dx = *x_1 - x_0;
708        dy = *y_1 - y_0;
709
710        *y_1 = 0;
711        if (dy)
712            *x_1 = ((0-y_0)*dx)/dy + x_0;
713    }
714}
715
716#if CONFIG_POSTPROC
717int vp8_post_proc_frame(VP8_COMMON *oci, YV12_BUFFER_CONFIG *dest, vp8_ppflags_t *ppflags)
718{
719    int q = oci->filter_level * 10 / 6;
720    int flags = ppflags->post_proc_flag;
721    int deblock_level = ppflags->deblocking_level;
722    int noise_level = ppflags->noise_level;
723
724    if (!oci->frame_to_show)
725        return -1;
726
727    if (q > 63)
728        q = 63;
729
730    if (!flags)
731    {
732        *dest = *oci->frame_to_show;
733
734        /* handle problem with extending borders */
735        dest->y_width = oci->Width;
736        dest->y_height = oci->Height;
737        dest->uv_height = dest->y_height / 2;
738        oci->postproc_state.last_base_qindex = oci->base_qindex;
739        oci->postproc_state.last_frame_valid = 1;
740        return 0;
741    }
742
743    /* Allocate post_proc_buffer_int if needed */
744    if ((flags & VP8D_MFQE) && !oci->post_proc_buffer_int_used)
745    {
746        if ((flags & VP8D_DEBLOCK) || (flags & VP8D_DEMACROBLOCK))
747        {
748            int width = (oci->Width + 15) & ~15;
749            int height = (oci->Height + 15) & ~15;
750
751            if (vp8_yv12_alloc_frame_buffer(&oci->post_proc_buffer_int,
752                                            width, height, VP8BORDERINPIXELS))
753                vpx_internal_error(&oci->error, VPX_CODEC_MEM_ERROR,
754                                   "Failed to allocate MFQE framebuffer");
755
756            oci->post_proc_buffer_int_used = 1;
757
758            /* insure that postproc is set to all 0's so that post proc
759             * doesn't pull random data in from edge
760             */
761            vpx_memset((&oci->post_proc_buffer_int)->buffer_alloc,128,(&oci->post_proc_buffer)->frame_size);
762
763        }
764    }
765
766    vp8_clear_system_state();
767
768    if ((flags & VP8D_MFQE) &&
769         oci->postproc_state.last_frame_valid &&
770         oci->current_video_frame >= 2 &&
771         oci->postproc_state.last_base_qindex < 60 &&
772         oci->base_qindex - oci->postproc_state.last_base_qindex >= 20)
773    {
774        vp8_multiframe_quality_enhance(oci);
775        if (((flags & VP8D_DEBLOCK) || (flags & VP8D_DEMACROBLOCK)) &&
776            oci->post_proc_buffer_int_used)
777        {
778            vp8_yv12_copy_frame(&oci->post_proc_buffer, &oci->post_proc_buffer_int);
779            if (flags & VP8D_DEMACROBLOCK)
780            {
781                vp8_deblock(oci, &oci->post_proc_buffer_int, &oci->post_proc_buffer,
782                                               q + (deblock_level - 5) * 10, 1, 0);
783                vp8_de_mblock(&oci->post_proc_buffer,
784                              q + (deblock_level - 5) * 10);
785            }
786            else if (flags & VP8D_DEBLOCK)
787            {
788                vp8_deblock(oci, &oci->post_proc_buffer_int, &oci->post_proc_buffer,
789                            q, 1, 0);
790            }
791        }
792        /* Move partially towards the base q of the previous frame */
793        oci->postproc_state.last_base_qindex = (3*oci->postproc_state.last_base_qindex + oci->base_qindex)>>2;
794    }
795    else if (flags & VP8D_DEMACROBLOCK)
796    {
797        vp8_deblock(oci, oci->frame_to_show, &oci->post_proc_buffer,
798                                     q + (deblock_level - 5) * 10, 1, 0);
799        vp8_de_mblock(&oci->post_proc_buffer, q + (deblock_level - 5) * 10);
800
801        oci->postproc_state.last_base_qindex = oci->base_qindex;
802    }
803    else if (flags & VP8D_DEBLOCK)
804    {
805        vp8_deblock(oci, oci->frame_to_show, &oci->post_proc_buffer,
806                    q, 1, 0);
807        oci->postproc_state.last_base_qindex = oci->base_qindex;
808    }
809    else
810    {
811        vp8_yv12_copy_frame(oci->frame_to_show, &oci->post_proc_buffer);
812        oci->postproc_state.last_base_qindex = oci->base_qindex;
813    }
814    oci->postproc_state.last_frame_valid = 1;
815
816    if (flags & VP8D_ADDNOISE)
817    {
818        if (oci->postproc_state.last_q != q
819            || oci->postproc_state.last_noise != noise_level)
820        {
821            fillrd(&oci->postproc_state, 63 - q, noise_level);
822        }
823
824        vp8_plane_add_noise
825        (oci->post_proc_buffer.y_buffer,
826         oci->postproc_state.noise,
827         oci->postproc_state.blackclamp,
828         oci->postproc_state.whiteclamp,
829         oci->postproc_state.bothclamp,
830         oci->post_proc_buffer.y_width, oci->post_proc_buffer.y_height,
831         oci->post_proc_buffer.y_stride);
832    }
833
834#if CONFIG_POSTPROC_VISUALIZER
835    if (flags & VP8D_DEBUG_TXT_FRAME_INFO)
836    {
837        char message[512];
838        sprintf(message, "F%1dG%1dQ%3dF%3dP%d_s%dx%d",
839                (oci->frame_type == KEY_FRAME),
840                oci->refresh_golden_frame,
841                oci->base_qindex,
842                oci->filter_level,
843                flags,
844                oci->mb_cols, oci->mb_rows);
845        vp8_blit_text(message, oci->post_proc_buffer.y_buffer, oci->post_proc_buffer.y_stride);
846    }
847
848    if (flags & VP8D_DEBUG_TXT_MBLK_MODES)
849    {
850        int i, j;
851        unsigned char *y_ptr;
852        YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
853        int mb_rows = post->y_height >> 4;
854        int mb_cols = post->y_width  >> 4;
855        int mb_index = 0;
856        MODE_INFO *mi = oci->mi;
857
858        y_ptr = post->y_buffer + 4 * post->y_stride + 4;
859
860        /* vp8_filter each macro block */
861        for (i = 0; i < mb_rows; i++)
862        {
863            for (j = 0; j < mb_cols; j++)
864            {
865                char zz[4];
866
867                sprintf(zz, "%c", mi[mb_index].mbmi.mode + 'a');
868
869                vp8_blit_text(zz, y_ptr, post->y_stride);
870                mb_index ++;
871                y_ptr += 16;
872            }
873
874            mb_index ++; /* border */
875            y_ptr += post->y_stride  * 16 - post->y_width;
876
877        }
878    }
879
880    if (flags & VP8D_DEBUG_TXT_DC_DIFF)
881    {
882        int i, j;
883        unsigned char *y_ptr;
884        YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
885        int mb_rows = post->y_height >> 4;
886        int mb_cols = post->y_width  >> 4;
887        int mb_index = 0;
888        MODE_INFO *mi = oci->mi;
889
890        y_ptr = post->y_buffer + 4 * post->y_stride + 4;
891
892        /* vp8_filter each macro block */
893        for (i = 0; i < mb_rows; i++)
894        {
895            for (j = 0; j < mb_cols; j++)
896            {
897                char zz[4];
898                int dc_diff = !(mi[mb_index].mbmi.mode != B_PRED &&
899                              mi[mb_index].mbmi.mode != SPLITMV &&
900                              mi[mb_index].mbmi.mb_skip_coeff);
901
902                if (oci->frame_type == KEY_FRAME)
903                    sprintf(zz, "a");
904                else
905                    sprintf(zz, "%c", dc_diff + '0');
906
907                vp8_blit_text(zz, y_ptr, post->y_stride);
908                mb_index ++;
909                y_ptr += 16;
910            }
911
912            mb_index ++; /* border */
913            y_ptr += post->y_stride  * 16 - post->y_width;
914
915        }
916    }
917
918    if (flags & VP8D_DEBUG_TXT_RATE_INFO)
919    {
920        char message[512];
921        sprintf(message, "Bitrate: %10.2f framerate: %10.2f ", oci->bitrate, oci->framerate);
922        vp8_blit_text(message, oci->post_proc_buffer.y_buffer, oci->post_proc_buffer.y_stride);
923    }
924
925    /* Draw motion vectors */
926    if ((flags & VP8D_DEBUG_DRAW_MV) && ppflags->display_mv_flag)
927    {
928        YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
929        int width  = post->y_width;
930        int height = post->y_height;
931        unsigned char *y_buffer = oci->post_proc_buffer.y_buffer;
932        int y_stride = oci->post_proc_buffer.y_stride;
933        MODE_INFO *mi = oci->mi;
934        int x0, y0;
935
936        for (y0 = 0; y0 < height; y0 += 16)
937        {
938            for (x0 = 0; x0 < width; x0 += 16)
939            {
940                int x1, y1;
941
942                if (!(ppflags->display_mv_flag & (1<<mi->mbmi.mode)))
943                {
944                    mi++;
945                    continue;
946                }
947
948                if (mi->mbmi.mode == SPLITMV)
949                {
950                    switch (mi->mbmi.partitioning)
951                    {
952                        case 0 :    /* mv_top_bottom */
953                        {
954                            union b_mode_info *bmi = &mi->bmi[0];
955                            MV *mv = &bmi->mv.as_mv;
956
957                            x1 = x0 + 8 + (mv->col >> 3);
958                            y1 = y0 + 4 + (mv->row >> 3);
959
960                            constrain_line (x0+8, &x1, y0+4, &y1, width, height);
961                            vp8_blit_line  (x0+8,  x1, y0+4,  y1, y_buffer, y_stride);
962
963                            bmi = &mi->bmi[8];
964
965                            x1 = x0 + 8 + (mv->col >> 3);
966                            y1 = y0 +12 + (mv->row >> 3);
967
968                            constrain_line (x0+8, &x1, y0+12, &y1, width, height);
969                            vp8_blit_line  (x0+8,  x1, y0+12,  y1, y_buffer, y_stride);
970
971                            break;
972                        }
973                        case 1 :    /* mv_left_right */
974                        {
975                            union b_mode_info *bmi = &mi->bmi[0];
976                            MV *mv = &bmi->mv.as_mv;
977
978                            x1 = x0 + 4 + (mv->col >> 3);
979                            y1 = y0 + 8 + (mv->row >> 3);
980
981                            constrain_line (x0+4, &x1, y0+8, &y1, width, height);
982                            vp8_blit_line  (x0+4,  x1, y0+8,  y1, y_buffer, y_stride);
983
984                            bmi = &mi->bmi[2];
985
986                            x1 = x0 +12 + (mv->col >> 3);
987                            y1 = y0 + 8 + (mv->row >> 3);
988
989                            constrain_line (x0+12, &x1, y0+8, &y1, width, height);
990                            vp8_blit_line  (x0+12,  x1, y0+8,  y1, y_buffer, y_stride);
991
992                            break;
993                        }
994                        case 2 :    /* mv_quarters   */
995                        {
996                            union b_mode_info *bmi = &mi->bmi[0];
997                            MV *mv = &bmi->mv.as_mv;
998
999                            x1 = x0 + 4 + (mv->col >> 3);
1000                            y1 = y0 + 4 + (mv->row >> 3);
1001
1002                            constrain_line (x0+4, &x1, y0+4, &y1, width, height);
1003                            vp8_blit_line  (x0+4,  x1, y0+4,  y1, y_buffer, y_stride);
1004
1005                            bmi = &mi->bmi[2];
1006
1007                            x1 = x0 +12 + (mv->col >> 3);
1008                            y1 = y0 + 4 + (mv->row >> 3);
1009
1010                            constrain_line (x0+12, &x1, y0+4, &y1, width, height);
1011                            vp8_blit_line  (x0+12,  x1, y0+4,  y1, y_buffer, y_stride);
1012
1013                            bmi = &mi->bmi[8];
1014
1015                            x1 = x0 + 4 + (mv->col >> 3);
1016                            y1 = y0 +12 + (mv->row >> 3);
1017
1018                            constrain_line (x0+4, &x1, y0+12, &y1, width, height);
1019                            vp8_blit_line  (x0+4,  x1, y0+12,  y1, y_buffer, y_stride);
1020
1021                            bmi = &mi->bmi[10];
1022
1023                            x1 = x0 +12 + (mv->col >> 3);
1024                            y1 = y0 +12 + (mv->row >> 3);
1025
1026                            constrain_line (x0+12, &x1, y0+12, &y1, width, height);
1027                            vp8_blit_line  (x0+12,  x1, y0+12,  y1, y_buffer, y_stride);
1028                            break;
1029                        }
1030                        default :
1031                        {
1032                            union b_mode_info *bmi = mi->bmi;
1033                            int bx0, by0;
1034
1035                            for (by0 = y0; by0 < (y0+16); by0 += 4)
1036                            {
1037                                for (bx0 = x0; bx0 < (x0+16); bx0 += 4)
1038                                {
1039                                    MV *mv = &bmi->mv.as_mv;
1040
1041                                    x1 = bx0 + 2 + (mv->col >> 3);
1042                                    y1 = by0 + 2 + (mv->row >> 3);
1043
1044                                    constrain_line (bx0+2, &x1, by0+2, &y1, width, height);
1045                                    vp8_blit_line  (bx0+2,  x1, by0+2,  y1, y_buffer, y_stride);
1046
1047                                    bmi++;
1048                                }
1049                            }
1050                        }
1051                    }
1052                }
1053                else if (mi->mbmi.mode >= NEARESTMV)
1054                {
1055                    MV *mv = &mi->mbmi.mv.as_mv;
1056                    const int lx0 = x0 + 8;
1057                    const int ly0 = y0 + 8;
1058
1059                    x1 = lx0 + (mv->col >> 3);
1060                    y1 = ly0 + (mv->row >> 3);
1061
1062                    if (x1 != lx0 && y1 != ly0)
1063                    {
1064                        constrain_line (lx0, &x1, ly0-1, &y1, width, height);
1065                        vp8_blit_line  (lx0,  x1, ly0-1,  y1, y_buffer, y_stride);
1066
1067                        constrain_line (lx0, &x1, ly0+1, &y1, width, height);
1068                        vp8_blit_line  (lx0,  x1, ly0+1,  y1, y_buffer, y_stride);
1069                    }
1070                    else
1071                        vp8_blit_line  (lx0,  x1, ly0,  y1, y_buffer, y_stride);
1072                }
1073
1074                mi++;
1075            }
1076            mi++;
1077        }
1078    }
1079
1080    /* Color in block modes */
1081    if ((flags & VP8D_DEBUG_CLR_BLK_MODES)
1082        && (ppflags->display_mb_modes_flag || ppflags->display_b_modes_flag))
1083    {
1084        int y, x;
1085        YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
1086        int width  = post->y_width;
1087        int height = post->y_height;
1088        unsigned char *y_ptr = oci->post_proc_buffer.y_buffer;
1089        unsigned char *u_ptr = oci->post_proc_buffer.u_buffer;
1090        unsigned char *v_ptr = oci->post_proc_buffer.v_buffer;
1091        int y_stride = oci->post_proc_buffer.y_stride;
1092        MODE_INFO *mi = oci->mi;
1093
1094        for (y = 0; y < height; y += 16)
1095        {
1096            for (x = 0; x < width; x += 16)
1097            {
1098                int Y = 0, U = 0, V = 0;
1099
1100                if (mi->mbmi.mode == B_PRED &&
1101                    ((ppflags->display_mb_modes_flag & B_PRED) || ppflags->display_b_modes_flag))
1102                {
1103                    int by, bx;
1104                    unsigned char *yl, *ul, *vl;
1105                    union b_mode_info *bmi = mi->bmi;
1106
1107                    yl = y_ptr + x;
1108                    ul = u_ptr + (x>>1);
1109                    vl = v_ptr + (x>>1);
1110
1111                    for (by = 0; by < 16; by += 4)
1112                    {
1113                        for (bx = 0; bx < 16; bx += 4)
1114                        {
1115                            if ((ppflags->display_b_modes_flag & (1<<mi->mbmi.mode))
1116                                || (ppflags->display_mb_modes_flag & B_PRED))
1117                            {
1118                                Y = B_PREDICTION_MODE_colors[bmi->as_mode][0];
1119                                U = B_PREDICTION_MODE_colors[bmi->as_mode][1];
1120                                V = B_PREDICTION_MODE_colors[bmi->as_mode][2];
1121
1122                                vp8_blend_b
1123                                    (yl+bx, ul+(bx>>1), vl+(bx>>1), Y, U, V, 0xc000, y_stride);
1124                            }
1125                            bmi++;
1126                        }
1127
1128                        yl += y_stride*4;
1129                        ul += y_stride*1;
1130                        vl += y_stride*1;
1131                    }
1132                }
1133                else if (ppflags->display_mb_modes_flag & (1<<mi->mbmi.mode))
1134                {
1135                    Y = MB_PREDICTION_MODE_colors[mi->mbmi.mode][0];
1136                    U = MB_PREDICTION_MODE_colors[mi->mbmi.mode][1];
1137                    V = MB_PREDICTION_MODE_colors[mi->mbmi.mode][2];
1138
1139                    vp8_blend_mb_inner
1140                        (y_ptr+x, u_ptr+(x>>1), v_ptr+(x>>1), Y, U, V, 0xc000, y_stride);
1141                }
1142
1143                mi++;
1144            }
1145            y_ptr += y_stride*16;
1146            u_ptr += y_stride*4;
1147            v_ptr += y_stride*4;
1148
1149            mi++;
1150        }
1151    }
1152
1153    /* Color in frame reference blocks */
1154    if ((flags & VP8D_DEBUG_CLR_FRM_REF_BLKS) && ppflags->display_ref_frame_flag)
1155    {
1156        int y, x;
1157        YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
1158        int width  = post->y_width;
1159        int height = post->y_height;
1160        unsigned char *y_ptr = oci->post_proc_buffer.y_buffer;
1161        unsigned char *u_ptr = oci->post_proc_buffer.u_buffer;
1162        unsigned char *v_ptr = oci->post_proc_buffer.v_buffer;
1163        int y_stride = oci->post_proc_buffer.y_stride;
1164        MODE_INFO *mi = oci->mi;
1165
1166        for (y = 0; y < height; y += 16)
1167        {
1168            for (x = 0; x < width; x +=16)
1169            {
1170                int Y = 0, U = 0, V = 0;
1171
1172                if (ppflags->display_ref_frame_flag & (1<<mi->mbmi.ref_frame))
1173                {
1174                    Y = MV_REFERENCE_FRAME_colors[mi->mbmi.ref_frame][0];
1175                    U = MV_REFERENCE_FRAME_colors[mi->mbmi.ref_frame][1];
1176                    V = MV_REFERENCE_FRAME_colors[mi->mbmi.ref_frame][2];
1177
1178                    vp8_blend_mb_outer
1179                        (y_ptr+x, u_ptr+(x>>1), v_ptr+(x>>1), Y, U, V, 0xc000, y_stride);
1180                }
1181
1182                mi++;
1183            }
1184            y_ptr += y_stride*16;
1185            u_ptr += y_stride*4;
1186            v_ptr += y_stride*4;
1187
1188            mi++;
1189        }
1190    }
1191#endif
1192
1193    *dest = oci->post_proc_buffer;
1194
1195    /* handle problem with extending borders */
1196    dest->y_width = oci->Width;
1197    dest->y_height = oci->Height;
1198    dest->uv_height = dest->y_height / 2;
1199    return 0;
1200}
1201#endif
1202