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
27typedef 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 ****************************************************************************/
63static
64void 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 ****************************************************************************/
117static
118void 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 ****************************************************************************/
163static
164void 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 ****************************************************************************/
234static
235void 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 ****************************************************************************/
478void 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