Home | History | Annotate | Download | only in common
      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 // global constants
     23 
     24 static const short kernel5[] =
     25 {
     26     1, 1, 4, 1, 1
     27 };
     28 
     29 const short vp8_rv[] =
     30 {
     31     8, 5, 2, 2, 8, 12, 4, 9, 8, 3,
     32     0, 3, 9, 0, 0, 0, 8, 3, 14, 4,
     33     10, 1, 11, 14, 1, 14, 9, 6, 12, 11,
     34     8, 6, 10, 0, 0, 8, 9, 0, 3, 14,
     35     8, 11, 13, 4, 2, 9, 0, 3, 9, 6,
     36     1, 2, 3, 14, 13, 1, 8, 2, 9, 7,
     37     3, 3, 1, 13, 13, 6, 6, 5, 2, 7,
     38     11, 9, 11, 8, 7, 3, 2, 0, 13, 13,
     39     14, 4, 12, 5, 12, 10, 8, 10, 13, 10,
     40     4, 14, 4, 10, 0, 8, 11, 1, 13, 7,
     41     7, 14, 6, 14, 13, 2, 13, 5, 4, 4,
     42     0, 10, 0, 5, 13, 2, 12, 7, 11, 13,
     43     8, 0, 4, 10, 7, 2, 7, 2, 2, 5,
     44     3, 4, 7, 3, 3, 14, 14, 5, 9, 13,
     45     3, 14, 3, 6, 3, 0, 11, 8, 13, 1,
     46     13, 1, 12, 0, 10, 9, 7, 6, 2, 8,
     47     5, 2, 13, 7, 1, 13, 14, 7, 6, 7,
     48     9, 6, 10, 11, 7, 8, 7, 5, 14, 8,
     49     4, 4, 0, 8, 7, 10, 0, 8, 14, 11,
     50     3, 12, 5, 7, 14, 3, 14, 5, 2, 6,
     51     11, 12, 12, 8, 0, 11, 13, 1, 2, 0,
     52     5, 10, 14, 7, 8, 0, 4, 11, 0, 8,
     53     0, 3, 10, 5, 8, 0, 11, 6, 7, 8,
     54     10, 7, 13, 9, 2, 5, 1, 5, 10, 2,
     55     4, 3, 5, 6, 10, 8, 9, 4, 11, 14,
     56     0, 10, 0, 5, 13, 2, 12, 7, 11, 13,
     57     8, 0, 4, 10, 7, 2, 7, 2, 2, 5,
     58     3, 4, 7, 3, 3, 14, 14, 5, 9, 13,
     59     3, 14, 3, 6, 3, 0, 11, 8, 13, 1,
     60     13, 1, 12, 0, 10, 9, 7, 6, 2, 8,
     61     5, 2, 13, 7, 1, 13, 14, 7, 6, 7,
     62     9, 6, 10, 11, 7, 8, 7, 5, 14, 8,
     63     4, 4, 0, 8, 7, 10, 0, 8, 14, 11,
     64     3, 12, 5, 7, 14, 3, 14, 5, 2, 6,
     65     11, 12, 12, 8, 0, 11, 13, 1, 2, 0,
     66     5, 10, 14, 7, 8, 0, 4, 11, 0, 8,
     67     0, 3, 10, 5, 8, 0, 11, 6, 7, 8,
     68     10, 7, 13, 9, 2, 5, 1, 5, 10, 2,
     69     4, 3, 5, 6, 10, 8, 9, 4, 11, 14,
     70     3, 8, 3, 7, 8, 5, 11, 4, 12, 3,
     71     11, 9, 14, 8, 14, 13, 4, 3, 1, 2,
     72     14, 6, 5, 4, 4, 11, 4, 6, 2, 1,
     73     5, 8, 8, 12, 13, 5, 14, 10, 12, 13,
     74     0, 9, 5, 5, 11, 10, 13, 9, 10, 13,
     75 };
     76 
     77 
     78 extern void vp8_blit_text(const char *msg, unsigned char *address, const int pitch);
     79 
     80 /***********************************************************************************************************
     81  */
     82 void vp8_post_proc_down_and_across_c
     83 (
     84     unsigned char *src_ptr,
     85     unsigned char *dst_ptr,
     86     int src_pixels_per_line,
     87     int dst_pixels_per_line,
     88     int rows,
     89     int cols,
     90     int flimit
     91 )
     92 {
     93     unsigned char *p_src, *p_dst;
     94     int row;
     95     int col;
     96     int i;
     97     int v;
     98     int pitch = src_pixels_per_line;
     99     unsigned char d[8];
    100     (void)dst_pixels_per_line;
    101 
    102     for (row = 0; row < rows; row++)
    103     {
    104         // post_proc_down for one row
    105         p_src = src_ptr;
    106         p_dst = dst_ptr;
    107 
    108         for (col = 0; col < cols; col++)
    109         {
    110 
    111             int kernel = 4;
    112             int v = p_src[col];
    113 
    114             for (i = -2; i <= 2; i++)
    115             {
    116                 if (abs(v - p_src[col+i*pitch]) > flimit)
    117                     goto down_skip_convolve;
    118 
    119                 kernel += kernel5[2+i] * p_src[col+i*pitch];
    120             }
    121 
    122             v = (kernel >> 3);
    123         down_skip_convolve:
    124             p_dst[col] = v;
    125         }
    126 
    127         // now post_proc_across
    128         p_src = dst_ptr;
    129         p_dst = dst_ptr;
    130 
    131         for (i = 0; i < 8; i++)
    132             d[i] = p_src[i];
    133 
    134         for (col = 0; col < cols; col++)
    135         {
    136             int kernel = 4;
    137             v = p_src[col];
    138 
    139             d[col&7] = v;
    140 
    141             for (i = -2; i <= 2; i++)
    142             {
    143                 if (abs(v - p_src[col+i]) > flimit)
    144                     goto across_skip_convolve;
    145 
    146                 kernel += kernel5[2+i] * p_src[col+i];
    147             }
    148 
    149             d[col&7] = (kernel >> 3);
    150         across_skip_convolve:
    151 
    152             if (col >= 2)
    153                 p_dst[col-2] = d[(col-2)&7];
    154         }
    155 
    156         //handle the last two pixels
    157         p_dst[col-2] = d[(col-2)&7];
    158         p_dst[col-1] = d[(col-1)&7];
    159 
    160 
    161         //next row
    162         src_ptr += pitch;
    163         dst_ptr += pitch;
    164     }
    165 }
    166 
    167 int vp8_q2mbl(int x)
    168 {
    169     if (x < 20) x = 20;
    170 
    171     x = 50 + (x - 50) * 10 / 8;
    172     return x * x / 3;
    173 }
    174 void vp8_mbpost_proc_across_ip_c(unsigned char *src, int pitch, int rows, int cols, int flimit)
    175 {
    176     int r, c, i;
    177 
    178     unsigned char *s = src;
    179     unsigned char d[16];
    180 
    181 
    182     for (r = 0; r < rows; r++)
    183     {
    184         int sumsq = 0;
    185         int sum   = 0;
    186 
    187         for (i = -8; i <= 6; i++)
    188         {
    189             sumsq += s[i] * s[i];
    190             sum   += s[i];
    191             d[i+8] = 0;
    192         }
    193 
    194         for (c = 0; c < cols + 8; c++)
    195         {
    196             int x = s[c+7] - s[c-8];
    197             int y = s[c+7] + s[c-8];
    198 
    199             sum  += x;
    200             sumsq += x * y;
    201 
    202             d[c&15] = s[c];
    203 
    204             if (sumsq * 15 - sum * sum < flimit)
    205             {
    206                 d[c&15] = (8 + sum + s[c]) >> 4;
    207             }
    208 
    209             s[c-8] = d[(c-8)&15];
    210         }
    211 
    212         s += pitch;
    213     }
    214 }
    215 
    216 
    217 
    218 
    219 
    220 void vp8_mbpost_proc_down_c(unsigned char *dst, int pitch, int rows, int cols, int flimit)
    221 {
    222     int r, c, i;
    223     const short *rv3 = &vp8_rv[63&rand()];
    224 
    225     for (c = 0; c < cols; c++)
    226     {
    227         unsigned char *s = &dst[c];
    228         int sumsq = 0;
    229         int sum   = 0;
    230         unsigned char d[16];
    231         const short *rv2 = rv3 + ((c * 17) & 127);
    232 
    233         for (i = -8; i <= 6; i++)
    234         {
    235             sumsq += s[i*pitch] * s[i*pitch];
    236             sum   += s[i*pitch];
    237         }
    238 
    239         for (r = 0; r < rows + 8; r++)
    240         {
    241             sumsq += s[7*pitch] * s[ 7*pitch] - s[-8*pitch] * s[-8*pitch];
    242             sum  += s[7*pitch] - s[-8*pitch];
    243             d[r&15] = s[0];
    244 
    245             if (sumsq * 15 - sum * sum < flimit)
    246             {
    247                 d[r&15] = (rv2[r&127] + sum + s[0]) >> 4;
    248             }
    249 
    250             s[-8*pitch] = d[(r-8)&15];
    251             s += pitch;
    252         }
    253     }
    254 }
    255 
    256 
    257 static void vp8_deblock_and_de_macro_block(YV12_BUFFER_CONFIG         *source,
    258         YV12_BUFFER_CONFIG         *post,
    259         int                         q,
    260         int                         low_var_thresh,
    261         int                         flag,
    262         vp8_postproc_rtcd_vtable_t *rtcd)
    263 {
    264     double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
    265     int ppl = (int)(level + .5);
    266     (void) low_var_thresh;
    267     (void) flag;
    268 
    269     POSTPROC_INVOKE(rtcd, downacross)(source->y_buffer, post->y_buffer, source->y_stride,  post->y_stride, source->y_height, source->y_width,  ppl);
    270     POSTPROC_INVOKE(rtcd, across)(post->y_buffer, post->y_stride, post->y_height, post->y_width, vp8_q2mbl(q));
    271     POSTPROC_INVOKE(rtcd, down)(post->y_buffer, post->y_stride, post->y_height, post->y_width, vp8_q2mbl(q));
    272 
    273     POSTPROC_INVOKE(rtcd, downacross)(source->u_buffer, post->u_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl);
    274     POSTPROC_INVOKE(rtcd, downacross)(source->v_buffer, post->v_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl);
    275 
    276 }
    277 
    278 void vp8_deblock(YV12_BUFFER_CONFIG         *source,
    279                         YV12_BUFFER_CONFIG         *post,
    280                         int                         q,
    281                         int                         low_var_thresh,
    282                         int                         flag,
    283                         vp8_postproc_rtcd_vtable_t *rtcd)
    284 {
    285     double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
    286     int ppl = (int)(level + .5);
    287     (void) low_var_thresh;
    288     (void) flag;
    289 
    290     POSTPROC_INVOKE(rtcd, downacross)(source->y_buffer, post->y_buffer, source->y_stride,  post->y_stride, source->y_height, source->y_width,   ppl);
    291     POSTPROC_INVOKE(rtcd, downacross)(source->u_buffer, post->u_buffer, source->uv_stride, post->uv_stride,  source->uv_height, source->uv_width, ppl);
    292     POSTPROC_INVOKE(rtcd, downacross)(source->v_buffer, post->v_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl);
    293 }
    294 
    295 void vp8_de_noise(YV12_BUFFER_CONFIG         *source,
    296                   YV12_BUFFER_CONFIG         *post,
    297                   int                         q,
    298                   int                         low_var_thresh,
    299                   int                         flag,
    300                   vp8_postproc_rtcd_vtable_t *rtcd)
    301 {
    302     double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
    303     int ppl = (int)(level + .5);
    304     (void) post;
    305     (void) low_var_thresh;
    306     (void) flag;
    307 
    308     POSTPROC_INVOKE(rtcd, downacross)(
    309         source->y_buffer + 2 * source->y_stride + 2,
    310         source->y_buffer + 2 * source->y_stride + 2,
    311         source->y_stride,
    312         source->y_stride,
    313         source->y_height - 4,
    314         source->y_width - 4,
    315         ppl);
    316     POSTPROC_INVOKE(rtcd, downacross)(
    317         source->u_buffer + 2 * source->uv_stride + 2,
    318         source->u_buffer + 2 * source->uv_stride + 2,
    319         source->uv_stride,
    320         source->uv_stride,
    321         source->uv_height - 4,
    322         source->uv_width - 4, ppl);
    323     POSTPROC_INVOKE(rtcd, downacross)(
    324         source->v_buffer + 2 * source->uv_stride + 2,
    325         source->v_buffer + 2 * source->uv_stride + 2,
    326         source->uv_stride,
    327         source->uv_stride,
    328         source->uv_height - 4,
    329         source->uv_width - 4, ppl);
    330 
    331 }
    332 
    333 double vp8_gaussian(double sigma, double mu, double x)
    334 {
    335     return 1 / (sigma * sqrt(2.0 * 3.14159265)) *
    336            (exp(-(x - mu) * (x - mu) / (2 * sigma * sigma)));
    337 }
    338 
    339 extern void (*vp8_clear_system_state)(void);
    340 
    341 
    342 static void fillrd(struct postproc_state *state, int q, int a)
    343 {
    344     char char_dist[300];
    345 
    346     double sigma;
    347     int ai = a, qi = q, i;
    348 
    349     vp8_clear_system_state();
    350 
    351 
    352     sigma = ai + .5 + .6 * (63 - qi) / 63.0;
    353 
    354     // set up a lookup table of 256 entries that matches
    355     // a gaussian distribution with sigma determined by q.
    356     //
    357     {
    358         double i;
    359         int next, j;
    360 
    361         next = 0;
    362 
    363         for (i = -32; i < 32; i++)
    364         {
    365             int a = (int)(.5 + 256 * vp8_gaussian(sigma, 0, i));
    366 
    367             if (a)
    368             {
    369                 for (j = 0; j < a; j++)
    370                 {
    371                     char_dist[next+j] = (char) i;
    372                 }
    373 
    374                 next = next + j;
    375             }
    376 
    377         }
    378 
    379         for (next = next; next < 256; next++)
    380             char_dist[next] = 0;
    381 
    382     }
    383 
    384     for (i = 0; i < 3072; i++)
    385     {
    386         state->noise[i] = char_dist[rand() & 0xff];
    387     }
    388 
    389     for (i = 0; i < 16; i++)
    390     {
    391         state->blackclamp[i] = -char_dist[0];
    392         state->whiteclamp[i] = -char_dist[0];
    393         state->bothclamp[i] = -2 * char_dist[0];
    394     }
    395 
    396     state->last_q = q;
    397     state->last_noise = a;
    398 }
    399 
    400 /****************************************************************************
    401  *
    402  *  ROUTINE       : plane_add_noise_c
    403  *
    404  *  INPUTS        : unsigned char *Start    starting address of buffer to add gaussian
    405  *                                  noise to
    406  *                  unsigned int Width    width of plane
    407  *                  unsigned int Height   height of plane
    408  *                  int  Pitch    distance between subsequent lines of frame
    409  *                  int  q        quantizer used to determine amount of noise
    410  *                                  to add
    411  *
    412  *  OUTPUTS       : None.
    413  *
    414  *  RETURNS       : void.
    415  *
    416  *  FUNCTION      : adds gaussian noise to a plane of pixels
    417  *
    418  *  SPECIAL NOTES : None.
    419  *
    420  ****************************************************************************/
    421 void vp8_plane_add_noise_c(unsigned char *Start, char *noise,
    422                            char blackclamp[16],
    423                            char whiteclamp[16],
    424                            char bothclamp[16],
    425                            unsigned int Width, unsigned int Height, int Pitch)
    426 {
    427     unsigned int i, j;
    428 
    429     for (i = 0; i < Height; i++)
    430     {
    431         unsigned char *Pos = Start + i * Pitch;
    432         char  *Ref = (char *)(noise + (rand() & 0xff));
    433 
    434         for (j = 0; j < Width; j++)
    435         {
    436             if (Pos[j] < blackclamp[0])
    437                 Pos[j] = blackclamp[0];
    438 
    439             if (Pos[j] > 255 + whiteclamp[0])
    440                 Pos[j] = 255 + whiteclamp[0];
    441 
    442             Pos[j] += Ref[j];
    443         }
    444     }
    445 }
    446 
    447 #if CONFIG_RUNTIME_CPU_DETECT
    448 #define RTCD_VTABLE(oci) (&(oci)->rtcd.postproc)
    449 #else
    450 #define RTCD_VTABLE(oci) NULL
    451 #endif
    452 
    453 int vp8_post_proc_frame(VP8_COMMON *oci, YV12_BUFFER_CONFIG *dest, int deblock_level, int noise_level, int flags)
    454 {
    455     char message[512];
    456     int q = oci->filter_level * 10 / 6;
    457 
    458     if (!oci->frame_to_show)
    459         return -1;
    460 
    461     if (q > 63)
    462         q = 63;
    463 
    464     if (!flags)
    465     {
    466         *dest = *oci->frame_to_show;
    467 
    468         // handle problem with extending borders
    469         dest->y_width = oci->Width;
    470         dest->y_height = oci->Height;
    471         dest->uv_height = dest->y_height / 2;
    472         return 0;
    473 
    474     }
    475 
    476 #if ARCH_X86||ARCH_X86_64
    477     vpx_reset_mmx_state();
    478 #endif
    479 
    480     if (flags & VP8D_DEMACROBLOCK)
    481     {
    482         vp8_deblock_and_de_macro_block(oci->frame_to_show, &oci->post_proc_buffer,
    483                                        q + (deblock_level - 5) * 10, 1, 0, RTCD_VTABLE(oci));
    484     }
    485     else if (flags & VP8D_DEBLOCK)
    486     {
    487         vp8_deblock(oci->frame_to_show, &oci->post_proc_buffer,
    488                     q, 1, 0, RTCD_VTABLE(oci));
    489     }
    490     else
    491     {
    492         vp8_yv12_copy_frame_ptr(oci->frame_to_show, &oci->post_proc_buffer);
    493     }
    494 
    495     if (flags & VP8D_ADDNOISE)
    496     {
    497         if (oci->postproc_state.last_q != q
    498             || oci->postproc_state.last_noise != noise_level)
    499         {
    500             fillrd(&oci->postproc_state, 63 - q, noise_level);
    501         }
    502 
    503         POSTPROC_INVOKE(RTCD_VTABLE(oci), addnoise)
    504         (oci->post_proc_buffer.y_buffer,
    505          oci->postproc_state.noise,
    506          oci->postproc_state.blackclamp,
    507          oci->postproc_state.whiteclamp,
    508          oci->postproc_state.bothclamp,
    509          oci->post_proc_buffer.y_width, oci->post_proc_buffer.y_height,
    510          oci->post_proc_buffer.y_stride);
    511     }
    512 
    513     if (flags & VP8D_DEBUG_LEVEL1)
    514     {
    515         sprintf(message, "F%1dG%1dQ%3dF%3dP%d_s%dx%d",
    516                 (oci->frame_type == KEY_FRAME),
    517                 oci->refresh_golden_frame,
    518                 oci->base_qindex,
    519                 oci->filter_level,
    520                 flags,
    521                 oci->mb_cols, oci->mb_rows);
    522         vp8_blit_text(message, oci->post_proc_buffer.y_buffer, oci->post_proc_buffer.y_stride);
    523     }
    524     else if (flags & VP8D_DEBUG_LEVEL2)
    525     {
    526         int i, j;
    527         unsigned char *y_ptr;
    528         YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
    529         int mb_rows = post->y_height >> 4;
    530         int mb_cols = post->y_width  >> 4;
    531         int mb_index = 0;
    532         MODE_INFO *mi = oci->mi;
    533 
    534         y_ptr = post->y_buffer + 4 * post->y_stride + 4;
    535 
    536         // vp8_filter each macro block
    537         for (i = 0; i < mb_rows; i++)
    538         {
    539             for (j = 0; j < mb_cols; j++)
    540             {
    541                 char zz[4];
    542 
    543                 sprintf(zz, "%c", mi[mb_index].mbmi.mode + 'a');
    544 
    545                 vp8_blit_text(zz, y_ptr, post->y_stride);
    546                 mb_index ++;
    547                 y_ptr += 16;
    548             }
    549 
    550             mb_index ++; //border
    551             y_ptr += post->y_stride  * 16 - post->y_width;
    552 
    553         }
    554     }
    555     else if (flags & VP8D_DEBUG_LEVEL3)
    556     {
    557         int i, j;
    558         unsigned char *y_ptr;
    559         YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
    560         int mb_rows = post->y_height >> 4;
    561         int mb_cols = post->y_width  >> 4;
    562         int mb_index = 0;
    563         MODE_INFO *mi = oci->mi;
    564 
    565         y_ptr = post->y_buffer + 4 * post->y_stride + 4;
    566 
    567         // vp8_filter each macro block
    568         for (i = 0; i < mb_rows; i++)
    569         {
    570             for (j = 0; j < mb_cols; j++)
    571             {
    572                 char zz[4];
    573 
    574                 if (oci->frame_type == KEY_FRAME)
    575                     sprintf(zz, "a");
    576                 else
    577                     sprintf(zz, "%c", mi[mb_index].mbmi.dc_diff + '0');
    578 
    579                 vp8_blit_text(zz, y_ptr, post->y_stride);
    580                 mb_index ++;
    581                 y_ptr += 16;
    582             }
    583 
    584             mb_index ++; //border
    585             y_ptr += post->y_stride  * 16 - post->y_width;
    586 
    587         }
    588     }
    589     else if (flags & VP8D_DEBUG_LEVEL4)
    590     {
    591         sprintf(message, "Bitrate: %10.2f frame_rate: %10.2f ", oci->bitrate, oci->framerate);
    592         vp8_blit_text(message, oci->post_proc_buffer.y_buffer, oci->post_proc_buffer.y_stride);
    593 #if 0
    594         int i, j;
    595         unsigned char *y_ptr;
    596         YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
    597         int mb_rows = post->y_height >> 4;
    598         int mb_cols = post->y_width  >> 4;
    599         int mb_index = 0;
    600         MODE_INFO *mi = oci->mi;
    601 
    602         y_ptr = post->y_buffer + 4 * post->y_stride + 4;
    603 
    604         // vp8_filter each macro block
    605         for (i = 0; i < mb_rows; i++)
    606         {
    607             for (j = 0; j < mb_cols; j++)
    608             {
    609                 char zz[4];
    610 
    611                 sprintf(zz, "%c", mi[mb_index].mbmi.dc_diff + '0');
    612                 vp8_blit_text(zz, y_ptr, post->y_stride);
    613                 mb_index ++;
    614                 y_ptr += 16;
    615             }
    616 
    617             mb_index ++; //border
    618             y_ptr += post->y_stride  * 16 - post->y_width;
    619 
    620         }
    621 
    622 #endif
    623 
    624     }
    625 
    626 
    627 
    628     *dest = oci->post_proc_buffer;
    629 
    630     // handle problem with extending borders
    631     dest->y_width = oci->Width;
    632     dest->y_height = oci->Height;
    633     dest->uv_height = dest->y_height / 2;
    634     return 0;
    635 }
    636