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
scale1d_2t1_i(const unsigned char * source,int source_step,unsigned int source_scale,unsigned int source_length,unsigned char * dest,int dest_step,unsigned int dest_scale,unsigned int dest_length)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
scale1d_2t1_ps(const unsigned char * source,int source_step,unsigned int source_scale,unsigned int source_length,unsigned char * dest,int dest_step,unsigned int dest_scale,unsigned int dest_length)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
scale1d_c(const unsigned char * source,int source_step,unsigned int source_scale,unsigned int source_length,unsigned char * dest,int dest_step,unsigned int dest_scale,unsigned int dest_length)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
Scale2D(unsigned char * source,int source_pitch,unsigned int source_width,unsigned int source_height,unsigned char * dest,int dest_pitch,unsigned int dest_width,unsigned int dest_height,unsigned char * temp_area,unsigned char temp_area_height,unsigned int hscale,unsigned int hratio,unsigned int vscale,unsigned int vratio,unsigned int interlaced)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  ****************************************************************************/
vpx_scale_frame(YV12_BUFFER_CONFIG * src,YV12_BUFFER_CONFIG * dst,unsigned char * temp_area,unsigned char temp_height,unsigned int hscale,unsigned int hratio,unsigned int vscale,unsigned int vratio,unsigned int interlaced)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