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