Home | History | Annotate | Download | only in generic
      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 /****************************************************************************
     13  *
     14  *   Module Title :     scale.c
     15  *
     16  *   Description  :     Image scaling functions.
     17  *
     18  ***************************************************************************/
     19 
     20 /****************************************************************************
     21 *  Header Files
     22 ****************************************************************************/
     23 #include "./vpx_scale_rtcd.h"
     24 #include "vpx_mem/vpx_mem.h"
     25 #include "vpx_scale/yv12config.h"
     26 
     27 typedef struct {
     28   int     expanded_frame_width;
     29   int     expanded_frame_height;
     30 
     31   int HScale;
     32   int HRatio;
     33   int VScale;
     34   int VRatio;
     35 
     36   YV12_BUFFER_CONFIG *src_yuv_config;
     37   YV12_BUFFER_CONFIG *dst_yuv_config;
     38 
     39 } SCALE_VARS;
     40 
     41 /****************************************************************************
     42  *
     43  *  ROUTINE       : scale1d_2t1_i
     44  *
     45  *  INPUTS        : const unsigned char *source : Pointer to data to be scaled.
     46  *                  int source_step              : Number of pixels to step on in source.
     47  *                  unsigned int source_scale    : Scale for source (UNUSED).
     48  *                  unsigned int source_length   : Length of source (UNUSED).
     49  *                  unsigned char *dest         : Pointer to output data array.
     50  *                  int dest_step                : Number of pixels to step on in destination.
     51  *                  unsigned int dest_scale      : Scale for destination (UNUSED).
     52  *                  unsigned int dest_length     : Length of destination.
     53  *
     54  *  OUTPUTS       : None.
     55  *
     56  *  RETURNS       : void
     57  *
     58  *  FUNCTION      : Performs 2-to-1 interpolated scaling.
     59  *
     60  *  SPECIAL NOTES : None.
     61  *
     62  ****************************************************************************/
     63 static
     64 void scale1d_2t1_i
     65 (
     66   const unsigned char *source,
     67   int source_step,
     68   unsigned int source_scale,
     69   unsigned int source_length,
     70   unsigned char *dest,
     71   int dest_step,
     72   unsigned int dest_scale,
     73   unsigned int dest_length
     74 ) {
     75   unsigned int i, j;
     76   unsigned int temp;
     77   int source_pitch = source_step;
     78   (void) source_length;
     79   (void) source_scale;
     80   (void) dest_scale;
     81 
     82   source_step *= 2;
     83   dest[0] = source[0];
     84 
     85   for (i = dest_step, j = source_step; i < dest_length * dest_step; i += dest_step, j += source_step) {
     86     temp = 8;
     87     temp += 3 * source[j - source_pitch];
     88     temp += 10 * source[j];
     89     temp += 3 * source[j + source_pitch];
     90     temp >>= 4;
     91     dest[i] = (char)(temp);
     92   }
     93 }
     94 
     95 /****************************************************************************
     96  *
     97  *  ROUTINE       : scale1d_2t1_ps
     98  *
     99  *  INPUTS        : const unsigned char *source : Pointer to data to be scaled.
    100  *                  int source_step              : Number of pixels to step on in source.
    101  *                  unsigned int source_scale    : Scale for source (UNUSED).
    102  *                  unsigned int source_length   : Length of source (UNUSED).
    103  *                  unsigned char *dest         : Pointer to output data array.
    104  *                  int dest_step                : Number of pixels to step on in destination.
    105  *                  unsigned int dest_scale      : Scale for destination (UNUSED).
    106  *                  unsigned int dest_length     : Length of destination.
    107  *
    108  *  OUTPUTS       : None.
    109  *
    110  *  RETURNS       : void
    111  *
    112  *  FUNCTION      : Performs 2-to-1 point subsampled scaling.
    113  *
    114  *  SPECIAL NOTES : None.
    115  *
    116  ****************************************************************************/
    117 static
    118 void scale1d_2t1_ps
    119 (
    120   const unsigned char *source,
    121   int source_step,
    122   unsigned int source_scale,
    123   unsigned int source_length,
    124   unsigned char *dest,
    125   int dest_step,
    126   unsigned int dest_scale,
    127   unsigned int dest_length
    128 ) {
    129   unsigned int i, j;
    130 
    131   (void) source_length;
    132   (void) source_scale;
    133   (void) dest_scale;
    134 
    135   source_step *= 2;
    136   j = 0;
    137 
    138   for (i = 0; i < dest_length * dest_step; i += dest_step, j += source_step)
    139     dest[i] = source[j];
    140 }
    141 /****************************************************************************
    142  *
    143  *  ROUTINE       : scale1d_c
    144  *
    145  *  INPUTS        : const unsigned char *source : Pointer to data to be scaled.
    146  *                  int source_step              : Number of pixels to step on in source.
    147  *                  unsigned int source_scale    : Scale for source.
    148  *                  unsigned int source_length   : Length of source (UNUSED).
    149  *                  unsigned char *dest         : Pointer to output data array.
    150  *                  int dest_step                : Number of pixels to step on in destination.
    151  *                  unsigned int dest_scale      : Scale for destination.
    152  *                  unsigned int dest_length     : Length of destination.
    153  *
    154  *  OUTPUTS       : None.
    155  *
    156  *  RETURNS       : void
    157  *
    158  *  FUNCTION      : Performs linear interpolation in one dimension.
    159  *
    160  *  SPECIAL NOTES : None.
    161  *
    162  ****************************************************************************/
    163 static
    164 void scale1d_c
    165 (
    166   const unsigned char *source,
    167   int source_step,
    168   unsigned int source_scale,
    169   unsigned int source_length,
    170   unsigned char *dest,
    171   int dest_step,
    172   unsigned int dest_scale,
    173   unsigned int dest_length
    174 ) {
    175   unsigned int i;
    176   unsigned int round_value = dest_scale / 2;
    177   unsigned int left_modifier = dest_scale;
    178   unsigned int right_modifier = 0;
    179   unsigned char left_pixel = *source;
    180   unsigned char right_pixel = *(source + source_step);
    181 
    182   (void) source_length;
    183 
    184   /* These asserts are needed if there are boundary issues... */
    185   /*assert ( dest_scale > source_scale );*/
    186   /*assert ( (source_length-1) * dest_scale >= (dest_length-1) * source_scale );*/
    187 
    188   for (i = 0; i < dest_length * dest_step; i += dest_step) {
    189     dest[i] = (char)((left_modifier * left_pixel + right_modifier * right_pixel + round_value) / dest_scale);
    190 
    191     right_modifier += source_scale;
    192 
    193     while (right_modifier > dest_scale) {
    194       right_modifier -= dest_scale;
    195       source += source_step;
    196       left_pixel = *source;
    197       right_pixel = *(source + source_step);
    198     }
    199 
    200     left_modifier = dest_scale - right_modifier;
    201   }
    202 }
    203 
    204 /****************************************************************************
    205  *
    206  *  ROUTINE       : Scale2D
    207  *
    208  *  INPUTS        : const unsigned char *source  : Pointer to data to be scaled.
    209  *                  int source_pitch              : Stride of source image.
    210  *                  unsigned int source_width     : Width of input image.
    211  *                  unsigned int source_height    : Height of input image.
    212  *                  unsigned char *dest          : Pointer to output data array.
    213  *                  int dest_pitch                : Stride of destination image.
    214  *                  unsigned int dest_width       : Width of destination image.
    215  *                  unsigned int dest_height      : Height of destination image.
    216  *                  unsigned char *temp_area      : Pointer to temp work area.
    217  *                  unsigned char temp_area_height : Height of temp work area.
    218  *                  unsigned int hscale          : Horizontal scale factor numerator.
    219  *                  unsigned int hratio          : Horizontal scale factor denominator.
    220  *                  unsigned int vscale          : Vertical scale factor numerator.
    221  *                  unsigned int vratio          : Vertical scale factor denominator.
    222  *                  unsigned int interlaced      : Interlace flag.
    223  *
    224  *  OUTPUTS       : None.
    225  *
    226  *  RETURNS       : void
    227  *
    228  *  FUNCTION      : Performs 2-tap linear interpolation in two dimensions.
    229  *
    230  *  SPECIAL NOTES : Expansion is performed one band at a time to help with
    231  *                  caching.
    232  *
    233  ****************************************************************************/
    234 static
    235 void Scale2D
    236 (
    237   /*const*/
    238   unsigned char *source,
    239   int source_pitch,
    240   unsigned int source_width,
    241   unsigned int source_height,
    242   unsigned char *dest,
    243   int dest_pitch,
    244   unsigned int dest_width,
    245   unsigned int dest_height,
    246   unsigned char *temp_area,
    247   unsigned char temp_area_height,
    248   unsigned int hscale,
    249   unsigned int hratio,
    250   unsigned int vscale,
    251   unsigned int vratio,
    252   unsigned int interlaced
    253 ) {
    254   /*unsigned*/
    255   int i, j, k;
    256   int bands;
    257   int dest_band_height;
    258   int source_band_height;
    259 
    260   typedef void (*Scale1D)(const unsigned char * source, int source_step, unsigned int source_scale, unsigned int source_length,
    261                           unsigned char * dest, int dest_step, unsigned int dest_scale, unsigned int dest_length);
    262 
    263   Scale1D Scale1Dv = scale1d_c;
    264   Scale1D Scale1Dh = scale1d_c;
    265 
    266   void (*horiz_line_scale)(const unsigned char *, unsigned int, unsigned char *, unsigned int) = NULL;
    267   void (*vert_band_scale)(unsigned char *, unsigned int, unsigned char *, unsigned int, unsigned int) = NULL;
    268 
    269   int ratio_scalable = 1;
    270   int interpolation = 0;
    271 
    272   unsigned char *source_base; /* = (unsigned char *) ((source_pitch >= 0) ? source : (source + ((source_height-1) * source_pitch))); */
    273   unsigned char *line_src;
    274 
    275 
    276   source_base = (unsigned char *)source;
    277 
    278   if (source_pitch < 0) {
    279     int offset;
    280 
    281     offset = (source_height - 1);
    282     offset *= source_pitch;
    283 
    284     source_base += offset;
    285   }
    286 
    287   /* find out the ratio for each direction */
    288   switch (hratio * 10 / hscale) {
    289     case 8:
    290       /* 4-5 Scale in Width direction */
    291       horiz_line_scale = vp8_horizontal_line_5_4_scale;
    292       break;
    293     case 6:
    294       /* 3-5 Scale in Width direction */
    295       horiz_line_scale = vp8_horizontal_line_5_3_scale;
    296       break;
    297     case 5:
    298       /* 1-2 Scale in Width direction */
    299       horiz_line_scale = vp8_horizontal_line_2_1_scale;
    300       break;
    301     default:
    302       /* The ratio is not acceptable now */
    303       /* throw("The ratio is not acceptable for now!"); */
    304       ratio_scalable = 0;
    305       break;
    306   }
    307 
    308   switch (vratio * 10 / vscale) {
    309     case 8:
    310       /* 4-5 Scale in vertical direction */
    311       vert_band_scale     = vp8_vertical_band_5_4_scale;
    312       source_band_height  = 5;
    313       dest_band_height    = 4;
    314       break;
    315     case 6:
    316       /* 3-5 Scale in vertical direction */
    317       vert_band_scale     = vp8_vertical_band_5_3_scale;
    318       source_band_height  = 5;
    319       dest_band_height    = 3;
    320       break;
    321     case 5:
    322       /* 1-2 Scale in vertical direction */
    323 
    324       if (interlaced) {
    325         /* if the content is interlaced, point sampling is used */
    326         vert_band_scale     = vp8_vertical_band_2_1_scale;
    327       } else {
    328 
    329         interpolation = 1;
    330         /* if the content is progressive, interplo */
    331         vert_band_scale     = vp8_vertical_band_2_1_scale_i;
    332 
    333       }
    334 
    335       source_band_height  = 2;
    336       dest_band_height    = 1;
    337       break;
    338     default:
    339       /* The ratio is not acceptable now */
    340       /* throw("The ratio is not acceptable for now!"); */
    341       ratio_scalable = 0;
    342       break;
    343   }
    344 
    345   if (ratio_scalable) {
    346     if (source_height == dest_height) {
    347       /* for each band of the image */
    348       for (k = 0; k < (int)dest_height; k++) {
    349         horiz_line_scale(source, source_width, dest, dest_width);
    350         source += source_pitch;
    351         dest   += dest_pitch;
    352       }
    353 
    354       return;
    355     }
    356 
    357     if (interpolation) {
    358       if (source < source_base)
    359         source = source_base;
    360 
    361       horiz_line_scale(source, source_width, temp_area, dest_width);
    362     }
    363 
    364     for (k = 0; k < (int)(dest_height + dest_band_height - 1) / dest_band_height; k++) {
    365       /* scale one band horizontally */
    366       for (i = 0; i < source_band_height; i++) {
    367         /* Trap case where we could read off the base of the source buffer */
    368 
    369         line_src = (unsigned char *)source + i * source_pitch;
    370 
    371         if (line_src < source_base)
    372           line_src = source_base;
    373 
    374         horiz_line_scale(line_src, source_width,
    375                          temp_area + (i + 1)*dest_pitch, dest_width);
    376       }
    377 
    378       /* Vertical scaling is in place */
    379       vert_band_scale(temp_area + dest_pitch, dest_pitch, dest, dest_pitch, dest_width);
    380 
    381       if (interpolation)
    382         vpx_memcpy(temp_area, temp_area + source_band_height * dest_pitch, dest_width);
    383 
    384       /* Next band... */
    385       source += (unsigned long) source_band_height  * source_pitch;
    386       dest   += (unsigned long) dest_band_height * dest_pitch;
    387     }
    388 
    389     return;
    390   }
    391 
    392   if (hscale == 2 && hratio == 1)
    393     Scale1Dh = scale1d_2t1_ps;
    394 
    395   if (vscale == 2 && vratio == 1) {
    396     if (interlaced)
    397       Scale1Dv = scale1d_2t1_ps;
    398     else
    399       Scale1Dv = scale1d_2t1_i;
    400   }
    401 
    402   if (source_height == dest_height) {
    403     /* for each band of the image */
    404     for (k = 0; k < (int)dest_height; k++) {
    405       Scale1Dh(source, 1, hscale, source_width + 1, dest, 1, hratio, dest_width);
    406       source += source_pitch;
    407       dest   += dest_pitch;
    408     }
    409 
    410     return;
    411   }
    412 
    413   if (dest_height > source_height) {
    414     dest_band_height   = temp_area_height - 1;
    415     source_band_height = dest_band_height * source_height / dest_height;
    416   } else {
    417     source_band_height = temp_area_height - 1;
    418     dest_band_height   = source_band_height * vratio / vscale;
    419   }
    420 
    421   /* first row needs to be done so that we can stay one row ahead for vertical zoom */
    422   Scale1Dh(source, 1, hscale, source_width + 1, temp_area, 1, hratio, dest_width);
    423 
    424   /* for each band of the image */
    425   bands = (dest_height + dest_band_height - 1) / dest_band_height;
    426 
    427   for (k = 0; k < bands; k++) {
    428     /* scale one band horizontally */
    429     for (i = 1; i < source_band_height + 1; i++) {
    430       if (k * source_band_height + i < (int) source_height) {
    431         Scale1Dh(source + i * source_pitch, 1, hscale, source_width + 1,
    432                  temp_area + i * dest_pitch, 1, hratio, dest_width);
    433       } else { /*  Duplicate the last row */
    434         /* copy temp_area row 0 over from last row in the past */
    435         vpx_memcpy(temp_area + i * dest_pitch, temp_area + (i - 1)*dest_pitch, dest_pitch);
    436       }
    437     }
    438 
    439     /* scale one band vertically */
    440     for (j = 0; j < (int)dest_width; j++) {
    441       Scale1Dv(&temp_area[j], dest_pitch, vscale, source_band_height + 1,
    442                &dest[j], dest_pitch, vratio, dest_band_height);
    443     }
    444 
    445     /* copy temp_area row 0 over from last row in the past */
    446     vpx_memcpy(temp_area, temp_area + source_band_height * dest_pitch, dest_pitch);
    447 
    448     /* move to the next band */
    449     source += source_band_height * source_pitch;
    450     dest   += dest_band_height * dest_pitch;
    451   }
    452 }
    453 
    454 /****************************************************************************
    455  *
    456  *  ROUTINE       : vpx_scale_frame
    457  *
    458  *  INPUTS        : YV12_BUFFER_CONFIG *src       : Pointer to frame to be scaled.
    459  *                  YV12_BUFFER_CONFIG *dst       : Pointer to buffer to hold scaled frame.
    460  *                  unsigned char *temp_area      : Pointer to temp work area.
    461  *                  unsigned char temp_area_height : Height of temp work area.
    462  *                  unsigned int hscale          : Horizontal scale factor numerator.
    463  *                  unsigned int hratio          : Horizontal scale factor denominator.
    464  *                  unsigned int vscale          : Vertical scale factor numerator.
    465  *                  unsigned int vratio          : Vertical scale factor denominator.
    466  *                  unsigned int interlaced      : Interlace flag.
    467  *
    468  *  OUTPUTS       : None.
    469  *
    470  *  RETURNS       : void
    471  *
    472  *  FUNCTION      : Performs 2-tap linear interpolation in two dimensions.
    473  *
    474  *  SPECIAL NOTES : Expansion is performed one band at a time to help with
    475  *                  caching.
    476  *
    477  ****************************************************************************/
    478 void vpx_scale_frame
    479 (
    480   YV12_BUFFER_CONFIG *src,
    481   YV12_BUFFER_CONFIG *dst,
    482   unsigned char *temp_area,
    483   unsigned char temp_height,
    484   unsigned int hscale,
    485   unsigned int hratio,
    486   unsigned int vscale,
    487   unsigned int vratio,
    488   unsigned int interlaced
    489 ) {
    490   int i;
    491   int dw = (hscale - 1 + src->y_width * hratio) / hscale;
    492   int dh = (vscale - 1 + src->y_height * vratio) / vscale;
    493 
    494   /* call our internal scaling routines!! */
    495   Scale2D((unsigned char *) src->y_buffer, src->y_stride, src->y_width, src->y_height,
    496           (unsigned char *) dst->y_buffer, dst->y_stride, dw, dh,
    497           temp_area, temp_height, hscale, hratio, vscale, vratio, interlaced);
    498 
    499   if (dw < (int)dst->y_width)
    500     for (i = 0; i < dh; i++)
    501       vpx_memset(dst->y_buffer + i * dst->y_stride + dw - 1, dst->y_buffer[i * dst->y_stride + dw - 2], dst->y_width - dw + 1);
    502 
    503   if (dh < (int)dst->y_height)
    504     for (i = dh - 1; i < (int)dst->y_height; i++)
    505       vpx_memcpy(dst->y_buffer + i * dst->y_stride, dst->y_buffer + (dh - 2) * dst->y_stride, dst->y_width + 1);
    506 
    507   Scale2D((unsigned char *) src->u_buffer, src->uv_stride, src->uv_width, src->uv_height,
    508           (unsigned char *) dst->u_buffer, dst->uv_stride, dw / 2, dh / 2,
    509           temp_area, temp_height, hscale, hratio, vscale, vratio, interlaced);
    510 
    511   if (dw / 2 < (int)dst->uv_width)
    512     for (i = 0; i < dst->uv_height; i++)
    513       vpx_memset(dst->u_buffer + i * dst->uv_stride + dw / 2 - 1, dst->u_buffer[i * dst->uv_stride + dw / 2 - 2], dst->uv_width - dw / 2 + 1);
    514 
    515   if (dh / 2 < (int)dst->uv_height)
    516     for (i = dh / 2 - 1; i < (int)dst->y_height / 2; i++)
    517       vpx_memcpy(dst->u_buffer + i * dst->uv_stride, dst->u_buffer + (dh / 2 - 2)*dst->uv_stride, dst->uv_width);
    518 
    519   Scale2D((unsigned char *) src->v_buffer, src->uv_stride, src->uv_width, src->uv_height,
    520           (unsigned char *) dst->v_buffer, dst->uv_stride, dw / 2, dh / 2,
    521           temp_area, temp_height, hscale, hratio, vscale, vratio, interlaced);
    522 
    523   if (dw / 2 < (int)dst->uv_width)
    524     for (i = 0; i < dst->uv_height; i++)
    525       vpx_memset(dst->v_buffer + i * dst->uv_stride + dw / 2 - 1, dst->v_buffer[i * dst->uv_stride + dw / 2 - 2], dst->uv_width - dw / 2 + 1);
    526 
    527   if (dh / 2 < (int) dst->uv_height)
    528     for (i = dh / 2 - 1; i < (int)dst->y_height / 2; i++)
    529       vpx_memcpy(dst->v_buffer + i * dst->uv_stride, dst->v_buffer + (dh / 2 - 2)*dst->uv_stride, dst->uv_width);
    530 }
    531