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