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 
28 typedef 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  ****************************************************************************/
64 static
65 void 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  ****************************************************************************/
118 static
119 void 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  ****************************************************************************/
164 static
165 void 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  ****************************************************************************/
235 static
236 void 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  ****************************************************************************/
479 void 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