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