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