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