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