1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 /** 17 ************************************************************************* 18 * @file M4AIR_API.c 19 * @brief Area of Interest Resizer API 20 ************************************************************************* 21 */ 22 23 #define M4AIR_YUV420_FORMAT_SUPPORTED 24 #define M4AIR_YUV420A_FORMAT_SUPPORTED 25 26 /************************* COMPILATION CHECKS ***************************/ 27 #ifndef M4AIR_YUV420_FORMAT_SUPPORTED 28 #ifndef M4AIR_BGR565_FORMAT_SUPPORTED 29 #ifndef M4AIR_RGB565_FORMAT_SUPPORTED 30 #ifndef M4AIR_BGR888_FORMAT_SUPPORTED 31 #ifndef M4AIR_RGB888_FORMAT_SUPPORTED 32 #ifndef M4AIR_JPG_FORMAT_SUPPORTED 33 34 #error "Please define at least one input format for the AIR component" 35 36 #endif 37 #endif 38 #endif 39 #endif 40 #endif 41 #endif 42 43 /******************************* INCLUDES *******************************/ 44 #include "M4OSA_Types.h" 45 #include "M4OSA_Error.h" 46 #include "M4OSA_CoreID.h" 47 #include "M4OSA_Mutex.h" 48 #include "M4OSA_Memory.h" 49 #include "M4VIFI_FiltersAPI.h" 50 #include "M4AIR_API.h" 51 52 /************************ M4AIR INTERNAL TYPES DEFINITIONS ***********************/ 53 54 /** 55 ****************************************************************************** 56 * enum M4AIR_States 57 * @brief The following enumeration defines the internal states of the AIR. 58 ****************************************************************************** 59 */ 60 typedef enum 61 { 62 M4AIR_kCreated, /**< State after M4AIR_create has been called */ 63 M4AIR_kConfigured /**< State after M4AIR_configure has been called */ 64 }M4AIR_States; 65 66 67 /** 68 ****************************************************************************** 69 * struct M4AIR_InternalContext 70 * @brief The following structure is the internal context of the AIR. 71 ****************************************************************************** 72 */ 73 typedef struct 74 { 75 M4AIR_States m_state; /**< Internal state */ 76 M4AIR_InputFormatType m_inputFormat; /**< Input format like YUV420Planar, 77 RGB565, JPG, etc ... */ 78 M4AIR_Params m_params; /**< Current input Parameter of the processing */ 79 M4OSA_UInt32 u32_x_inc[4]; /**< ratio between input and ouput width for YUV */ 80 M4OSA_UInt32 u32_y_inc[4]; /**< ratio between input and ouput height for YUV */ 81 M4OSA_UInt32 u32_x_accum_start[4]; /**< horizontal initial accumulator value */ 82 M4OSA_UInt32 u32_y_accum_start[4]; /**< Vertical initial accumulator value */ 83 M4OSA_UInt32 u32_x_accum[4]; /**< save of horizontal accumulator value */ 84 M4OSA_UInt32 u32_y_accum[4]; /**< save of vertical accumulator value */ 85 M4OSA_UInt8* pu8_data_in[4]; /**< Save of input plane pointers 86 in case of stripe mode */ 87 M4OSA_UInt32 m_procRows; /**< Number of processed rows, 88 used in stripe mode only */ 89 M4OSA_Bool m_bOnlyCopy; /**< Flag to know if we just perform a copy 90 or a bilinear interpolation */ 91 M4OSA_Bool m_bFlipX; /**< Depend on output orientation, used during 92 processing to revert processing order in X 93 coordinates */ 94 M4OSA_Bool m_bFlipY; /**< Depend on output orientation, used during 95 processing to revert processing order in Y 96 coordinates */ 97 M4OSA_Bool m_bRevertXY; /**< Depend on output orientation, used during 98 processing to revert X and Y processing order 99 (+-90 rotation) */ 100 }M4AIR_InternalContext; 101 102 /********************************* MACROS *******************************/ 103 #define M4ERR_CHECK_NULL_RETURN_VALUE(retval, pointer)\ 104 if ((pointer) == M4OSA_NULL) return ((M4OSA_ERR)(retval)); 105 106 107 /********************** M4AIR PUBLIC API IMPLEMENTATION ********************/ 108 /** 109 ****************************************************************************** 110 * M4OSA_ERR M4AIR_create(M4OSA_Context* pContext,M4AIR_InputFormatType inputFormat) 111 * @brief This function initialize an instance of the AIR. 112 * @param pContext: (IN/OUT) Address of the context to create 113 * @param inputFormat: (IN) input format type. 114 * @return M4NO_ERROR: there is no error 115 * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only). Invalid formatType 116 * @return M4ERR_ALLOC: No more memory is available 117 ****************************************************************************** 118 */ 119 M4OSA_ERR M4AIR_create(M4OSA_Context* pContext,M4AIR_InputFormatType inputFormat) 120 { 121 M4OSA_ERR err = M4NO_ERROR ; 122 M4AIR_InternalContext* pC = M4OSA_NULL ; 123 124 /* Check that the address on the context is not NULL */ 125 M4ERR_CHECK_NULL_RETURN_VALUE(M4ERR_PARAMETER, pContext) ; 126 127 *pContext = M4OSA_NULL ; 128 129 /* Internal Context creation */ 130 pC = (M4AIR_InternalContext*)M4OSA_32bitAlignedMalloc(sizeof(M4AIR_InternalContext), 131 M4AIR,(M4OSA_Char *)"AIR internal context") ; 132 M4ERR_CHECK_NULL_RETURN_VALUE(M4ERR_ALLOC, pC) ; 133 134 135 /* Check if the input format is supported */ 136 switch(inputFormat) 137 { 138 #ifdef M4AIR_YUV420_FORMAT_SUPPORTED 139 case M4AIR_kYUV420P: 140 break ; 141 #endif 142 #ifdef M4AIR_YUV420A_FORMAT_SUPPORTED 143 case M4AIR_kYUV420AP: 144 break ; 145 #endif 146 default: 147 err = M4ERR_AIR_FORMAT_NOT_SUPPORTED; 148 goto M4AIR_create_cleanup ; 149 } 150 151 /**< Save input format and update state */ 152 pC->m_inputFormat = inputFormat; 153 pC->m_state = M4AIR_kCreated; 154 155 /* Return the context to the caller */ 156 *pContext = pC ; 157 158 return M4NO_ERROR ; 159 160 M4AIR_create_cleanup: 161 /* Error management : we destroy the context if needed */ 162 if(M4OSA_NULL != pC) 163 { 164 free(pC) ; 165 } 166 167 *pContext = M4OSA_NULL ; 168 169 return err ; 170 } 171 172 173 174 /** 175 ****************************************************************************** 176 * M4OSA_ERR M4AIR_cleanUp(M4OSA_Context pContext) 177 * @brief This function destroys an instance of the AIR component 178 * @param pContext: (IN) Context identifying the instance to destroy 179 * @return M4NO_ERROR: there is no error 180 * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only). 181 * @return M4ERR_STATE: Internal state is incompatible with this function call. 182 ****************************************************************************** 183 */ 184 M4OSA_ERR M4AIR_cleanUp(M4OSA_Context pContext) 185 { 186 M4AIR_InternalContext* pC = (M4AIR_InternalContext*)pContext ; 187 188 M4ERR_CHECK_NULL_RETURN_VALUE(M4ERR_PARAMETER, pContext) ; 189 190 /**< Check state */ 191 if((M4AIR_kCreated != pC->m_state)&&(M4AIR_kConfigured != pC->m_state)) 192 { 193 return M4ERR_STATE; 194 } 195 free(pC) ; 196 197 return M4NO_ERROR ; 198 199 } 200 201 202 /** 203 ****************************************************************************** 204 * M4OSA_ERR M4AIR_configure(M4OSA_Context pContext, M4AIR_Params* pParams) 205 * @brief This function will configure the AIR. 206 * @note It will set the input and output coordinates and sizes, 207 * and indicates if we will proceed in stripe or not. 208 * In case a M4AIR_get in stripe mode was on going, it will cancel this previous 209 * processing and reset the get process. 210 * @param pContext: (IN) Context identifying the instance 211 * @param pParams->m_bOutputStripe:(IN) Stripe mode. 212 * @param pParams->m_inputCoord: (IN) X,Y coordinates of the first valid pixel in input. 213 * @param pParams->m_inputSize: (IN) input ROI size. 214 * @param pParams->m_outputSize: (IN) output size. 215 * @return M4NO_ERROR: there is no error 216 * @return M4ERR_ALLOC: No more memory space to add a new effect. 217 * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only). 218 * @return M4ERR_AIR_FORMAT_NOT_SUPPORTED: the requested input format is not supported. 219 ****************************************************************************** 220 */ 221 M4OSA_ERR M4AIR_configure(M4OSA_Context pContext, M4AIR_Params* pParams) 222 { 223 M4AIR_InternalContext* pC = (M4AIR_InternalContext*)pContext ; 224 M4OSA_UInt32 i,u32_width_in, u32_width_out, u32_height_in, u32_height_out; 225 M4OSA_UInt32 nb_planes; 226 227 M4ERR_CHECK_NULL_RETURN_VALUE(M4ERR_PARAMETER, pContext) ; 228 229 if(M4AIR_kYUV420AP == pC->m_inputFormat) 230 { 231 nb_planes = 4; 232 } 233 else 234 { 235 nb_planes = 3; 236 } 237 238 /**< Check state */ 239 if((M4AIR_kCreated != pC->m_state)&&(M4AIR_kConfigured != pC->m_state)) 240 { 241 return M4ERR_STATE; 242 } 243 244 /** Save parameters */ 245 pC->m_params = *pParams; 246 247 /* Check for the input&output width and height are even */ 248 if( ((pC->m_params.m_inputSize.m_height)&0x1) || 249 ((pC->m_params.m_inputSize.m_height)&0x1)) 250 { 251 return M4ERR_AIR_ILLEGAL_FRAME_SIZE; 252 } 253 254 if( ((pC->m_params.m_inputSize.m_width)&0x1) || 255 ((pC->m_params.m_inputSize.m_width)&0x1)) 256 { 257 return M4ERR_AIR_ILLEGAL_FRAME_SIZE; 258 } 259 if(((pC->m_params.m_inputSize.m_width) == (pC->m_params.m_outputSize.m_width)) 260 &&((pC->m_params.m_inputSize.m_height) == (pC->m_params.m_outputSize.m_height))) 261 { 262 /**< No resize in this case, we will just copy input in output */ 263 pC->m_bOnlyCopy = M4OSA_TRUE; 264 } 265 else 266 { 267 pC->m_bOnlyCopy = M4OSA_FALSE; 268 269 /**< Initialize internal variables used for resize filter */ 270 for(i=0;i<nb_planes;i++) 271 { 272 273 u32_width_in = ((i==0)||(i==3))?pC->m_params.m_inputSize.m_width:\ 274 (pC->m_params.m_inputSize.m_width+1)>>1; 275 u32_height_in = ((i==0)||(i==3))?pC->m_params.m_inputSize.m_height:\ 276 (pC->m_params.m_inputSize.m_height+1)>>1; 277 u32_width_out = ((i==0)||(i==3))?pC->m_params.m_outputSize.m_width:\ 278 (pC->m_params.m_outputSize.m_width+1)>>1; 279 u32_height_out = ((i==0)||(i==3))?pC->m_params.m_outputSize.m_height:\ 280 (pC->m_params.m_outputSize.m_height+1)>>1; 281 282 /* Compute horizontal ratio between src and destination width.*/ 283 if (u32_width_out >= u32_width_in) 284 { 285 pC->u32_x_inc[i] = ((u32_width_in-1) * 0x10000) / (u32_width_out-1); 286 } 287 else 288 { 289 pC->u32_x_inc[i] = (u32_width_in * 0x10000) / (u32_width_out); 290 } 291 292 /* Compute vertical ratio between src and destination height.*/ 293 if (u32_height_out >= u32_height_in) 294 { 295 pC->u32_y_inc[i] = ((u32_height_in - 1) * 0x10000) / (u32_height_out-1); 296 } 297 else 298 { 299 pC->u32_y_inc[i] = (u32_height_in * 0x10000) / (u32_height_out); 300 } 301 302 /* 303 Calculate initial accumulator value : u32_y_accum_start. 304 u32_y_accum_start is coded on 15 bits, and represents a value between 0 and 0.5 305 */ 306 if (pC->u32_y_inc[i] >= 0x10000) 307 { 308 /* 309 Keep the fractionnal part, assimung that integer part is coded 310 on the 16 high bits and the fractionnal on the 15 low bits 311 */ 312 pC->u32_y_accum_start[i] = pC->u32_y_inc[i] & 0xffff; 313 314 if (!pC->u32_y_accum_start[i]) 315 { 316 pC->u32_y_accum_start[i] = 0x10000; 317 } 318 319 pC->u32_y_accum_start[i] >>= 1; 320 } 321 else 322 { 323 pC->u32_y_accum_start[i] = 0; 324 } 325 /**< Take into account that Y coordinate can be odd 326 in this case we have to put a 0.5 offset 327 for U and V plane as there a 2 times sub-sampled vs Y*/ 328 if((pC->m_params.m_inputCoord.m_y&0x1)&&((i==1)||(i==2))) 329 { 330 pC->u32_y_accum_start[i] += 0x8000; 331 } 332 333 /* 334 Calculate initial accumulator value : u32_x_accum_start. 335 u32_x_accum_start is coded on 15 bits, and represents a value between 336 0 and 0.5 337 */ 338 339 if (pC->u32_x_inc[i] >= 0x10000) 340 { 341 pC->u32_x_accum_start[i] = pC->u32_x_inc[i] & 0xffff; 342 343 if (!pC->u32_x_accum_start[i]) 344 { 345 pC->u32_x_accum_start[i] = 0x10000; 346 } 347 348 pC->u32_x_accum_start[i] >>= 1; 349 } 350 else 351 { 352 pC->u32_x_accum_start[i] = 0; 353 } 354 /**< Take into account that X coordinate can be odd 355 in this case we have to put a 0.5 offset 356 for U and V plane as there a 2 times sub-sampled vs Y*/ 357 if((pC->m_params.m_inputCoord.m_x&0x1)&&((i==1)||(i==2))) 358 { 359 pC->u32_x_accum_start[i] += 0x8000; 360 } 361 } 362 } 363 364 /**< Reset variable used for stripe mode */ 365 pC->m_procRows = 0; 366 367 /**< Initialize var for X/Y processing order according to orientation */ 368 pC->m_bFlipX = M4OSA_FALSE; 369 pC->m_bFlipY = M4OSA_FALSE; 370 pC->m_bRevertXY = M4OSA_FALSE; 371 switch(pParams->m_outputOrientation) 372 { 373 case M4COMMON_kOrientationTopLeft: 374 break; 375 case M4COMMON_kOrientationTopRight: 376 pC->m_bFlipX = M4OSA_TRUE; 377 break; 378 case M4COMMON_kOrientationBottomRight: 379 pC->m_bFlipX = M4OSA_TRUE; 380 pC->m_bFlipY = M4OSA_TRUE; 381 break; 382 case M4COMMON_kOrientationBottomLeft: 383 pC->m_bFlipY = M4OSA_TRUE; 384 break; 385 case M4COMMON_kOrientationLeftTop: 386 pC->m_bRevertXY = M4OSA_TRUE; 387 break; 388 case M4COMMON_kOrientationRightTop: 389 pC->m_bRevertXY = M4OSA_TRUE; 390 pC->m_bFlipY = M4OSA_TRUE; 391 break; 392 case M4COMMON_kOrientationRightBottom: 393 pC->m_bRevertXY = M4OSA_TRUE; 394 pC->m_bFlipX = M4OSA_TRUE; 395 pC->m_bFlipY = M4OSA_TRUE; 396 break; 397 case M4COMMON_kOrientationLeftBottom: 398 pC->m_bRevertXY = M4OSA_TRUE; 399 pC->m_bFlipX = M4OSA_TRUE; 400 break; 401 default: 402 return M4ERR_PARAMETER; 403 } 404 /**< Update state */ 405 pC->m_state = M4AIR_kConfigured; 406 407 return M4NO_ERROR ; 408 } 409 410 411 /** 412 ****************************************************************************** 413 * M4OSA_ERR M4AIR_get(M4OSA_Context pContext, M4VIFI_ImagePlane* pIn, M4VIFI_ImagePlane* pOut) 414 * @brief This function will provide the requested resized area of interest according to 415 * settings provided in M4AIR_configure. 416 * @note In case the input format type is JPEG, input plane(s) 417 * in pIn is not used. In normal mode, dimension specified in output plane(s) structure 418 * must be the same than the one specified in M4AIR_configure. In stripe mode, only the 419 * width will be the same, height will be taken as the stripe height (typically 16). 420 * In normal mode, this function is call once to get the full output picture. 421 * In stripe mode, it is called for each stripe till the whole picture has been 422 * retrieved,and the position of the output stripe in the output picture 423 * is internally incremented at each step. 424 * Any call to M4AIR_configure during stripe process will reset this one to the 425 * beginning of the output picture. 426 * @param pContext: (IN) Context identifying the instance 427 * @param pIn: (IN) Plane structure containing input Plane(s). 428 * @param pOut: (IN/OUT) Plane structure containing output Plane(s). 429 * @return M4NO_ERROR: there is no error 430 * @return M4ERR_ALLOC: No more memory space to add a new effect. 431 * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only). 432 ****************************************************************************** 433 */ 434 M4OSA_ERR M4AIR_get(M4OSA_Context pContext, M4VIFI_ImagePlane* pIn, M4VIFI_ImagePlane* pOut) 435 { 436 M4AIR_InternalContext* pC = (M4AIR_InternalContext*)pContext ; 437 M4OSA_UInt32 i,j,k,u32_x_frac,u32_y_frac,u32_x_accum,u32_y_accum,u32_shift; 438 M4OSA_UInt8 *pu8_data_in, *pu8_data_in_org, *pu8_data_in_tmp, *pu8_data_out; 439 M4OSA_UInt8 *pu8_src_top; 440 M4OSA_UInt8 *pu8_src_bottom; 441 M4OSA_UInt32 u32_temp_value; 442 M4OSA_Int32 i32_tmp_offset; 443 M4OSA_UInt32 nb_planes; 444 445 446 447 M4ERR_CHECK_NULL_RETURN_VALUE(M4ERR_PARAMETER, pContext) ; 448 449 /**< Check state */ 450 if(M4AIR_kConfigured != pC->m_state) 451 { 452 return M4ERR_STATE; 453 } 454 455 if(M4AIR_kYUV420AP == pC->m_inputFormat) 456 { 457 nb_planes = 4; 458 } 459 else 460 { 461 nb_planes = 3; 462 } 463 464 /**< Loop on each Plane */ 465 for(i=0;i<nb_planes;i++) 466 { 467 468 /* Set the working pointers at the beginning of the input/output data field */ 469 470 u32_shift = ((i==0)||(i==3))?0:1; /**< Depend on Luma or Chroma */ 471 472 if((M4OSA_FALSE == pC->m_params.m_bOutputStripe)\ 473 ||((M4OSA_TRUE == pC->m_params.m_bOutputStripe)&&(0 == pC->m_procRows))) 474 { 475 /**< For input, take care about ROI */ 476 pu8_data_in = pIn[i].pac_data + pIn[i].u_topleft \ 477 + (pC->m_params.m_inputCoord.m_x>>u32_shift) 478 + (pC->m_params.m_inputCoord.m_y >> u32_shift) * pIn[i].u_stride; 479 480 /** Go at end of line/column in case X/Y scanning is flipped */ 481 if(M4OSA_TRUE == pC->m_bFlipX) 482 { 483 pu8_data_in += ((pC->m_params.m_inputSize.m_width)>>u32_shift) -1 ; 484 } 485 if(M4OSA_TRUE == pC->m_bFlipY) 486 { 487 pu8_data_in += ((pC->m_params.m_inputSize.m_height>>u32_shift) -1)\ 488 * pIn[i].u_stride; 489 } 490 491 /**< Initialize accumulators in case we are using it (bilinear interpolation) */ 492 if( M4OSA_FALSE == pC->m_bOnlyCopy) 493 { 494 pC->u32_x_accum[i] = pC->u32_x_accum_start[i]; 495 pC->u32_y_accum[i] = pC->u32_y_accum_start[i]; 496 } 497 498 } 499 else 500 { 501 /**< In case of stripe mode for other than first stripe, we need to recover input 502 pointer from internal context */ 503 pu8_data_in = pC->pu8_data_in[i]; 504 } 505 506 /**< In every mode, output data are at the beginning of the output plane */ 507 pu8_data_out = pOut[i].pac_data + pOut[i].u_topleft; 508 509 /**< Initialize input offset applied after each pixel */ 510 if(M4OSA_FALSE == pC->m_bFlipY) 511 { 512 i32_tmp_offset = pIn[i].u_stride; 513 } 514 else 515 { 516 i32_tmp_offset = -pIn[i].u_stride; 517 } 518 519 /**< In this case, no bilinear interpolation is needed as input and output dimensions 520 are the same */ 521 if( M4OSA_TRUE == pC->m_bOnlyCopy) 522 { 523 /**< No +-90 rotation */ 524 if(M4OSA_FALSE == pC->m_bRevertXY) 525 { 526 /**< No flip on X abscissa */ 527 if(M4OSA_FALSE == pC->m_bFlipX) 528 { 529 /**< Loop on each row */ 530 for(j=0;j<pOut[i].u_height;j++) 531 { 532 /**< Copy one whole line */ 533 memcpy((void *)pu8_data_out, (void *)pu8_data_in, 534 pOut[i].u_width); 535 536 /**< Update pointers */ 537 pu8_data_out += pOut[i].u_stride; 538 if(M4OSA_FALSE == pC->m_bFlipY) 539 { 540 pu8_data_in += pIn[i].u_stride; 541 } 542 else 543 { 544 pu8_data_in -= pIn[i].u_stride; 545 } 546 } 547 } 548 else 549 { 550 /**< Loop on each row */ 551 for(j=0;j<pOut[i].u_height;j++) 552 { 553 /**< Loop on each pixel of 1 row */ 554 for(k=0;k<pOut[i].u_width;k++) 555 { 556 *pu8_data_out++ = *pu8_data_in--; 557 } 558 559 /**< Update pointers */ 560 pu8_data_out += (pOut[i].u_stride - pOut[i].u_width); 561 562 pu8_data_in += pOut[i].u_width + i32_tmp_offset; 563 564 } 565 } 566 } 567 /**< Here we have a +-90 rotation */ 568 else 569 { 570 571 /**< Loop on each row */ 572 for(j=0;j<pOut[i].u_height;j++) 573 { 574 pu8_data_in_tmp = pu8_data_in; 575 576 /**< Loop on each pixel of 1 row */ 577 for(k=0;k<pOut[i].u_width;k++) 578 { 579 *pu8_data_out++ = *pu8_data_in_tmp; 580 581 /**< Update input pointer in order to go to next/past line */ 582 pu8_data_in_tmp += i32_tmp_offset; 583 } 584 585 /**< Update pointers */ 586 pu8_data_out += (pOut[i].u_stride - pOut[i].u_width); 587 if(M4OSA_FALSE == pC->m_bFlipX) 588 { 589 pu8_data_in ++; 590 } 591 else 592 { 593 pu8_data_in --; 594 } 595 } 596 } 597 } 598 /**< Bilinear interpolation */ 599 else 600 { 601 602 if(3 != i) /**< other than alpha plane */ 603 { 604 /**No +-90 rotation */ 605 if(M4OSA_FALSE == pC->m_bRevertXY) 606 { 607 608 /**< Loop on each row */ 609 for(j=0;j<pOut[i].u_height;j++) 610 { 611 /* Vertical weight factor */ 612 u32_y_frac = (pC->u32_y_accum[i]>>12)&15; 613 614 /* Reinit horizontal weight factor */ 615 u32_x_accum = pC->u32_x_accum_start[i]; 616 617 618 619 if(M4OSA_TRUE == pC->m_bFlipX) 620 { 621 622 /**< Loop on each output pixel in a row */ 623 for(k=0;k<pOut[i].u_width;k++) 624 { 625 626 u32_x_frac = (u32_x_accum >> 12)&15; /* Fraction of Horizontal 627 weight factor */ 628 629 pu8_src_top = (pu8_data_in - (u32_x_accum >> 16)) -1 ; 630 631 pu8_src_bottom = pu8_src_top + i32_tmp_offset; 632 633 /* Weighted combination */ 634 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[1]*(16-u32_x_frac) + 635 pu8_src_top[0]*u32_x_frac)*(16-u32_y_frac) + 636 (pu8_src_bottom[1]*(16-u32_x_frac) + 637 pu8_src_bottom[0]*u32_x_frac)*u32_y_frac )>>8); 638 639 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value; 640 641 /* Update horizontal accumulator */ 642 u32_x_accum += pC->u32_x_inc[i]; 643 } 644 } 645 646 else 647 { 648 /**< Loop on each output pixel in a row */ 649 for(k=0;k<pOut[i].u_width;k++) 650 { 651 u32_x_frac = (u32_x_accum >> 12)&15; /* Fraction of Horizontal 652 weight factor */ 653 654 pu8_src_top = pu8_data_in + (u32_x_accum >> 16); 655 656 pu8_src_bottom = pu8_src_top + i32_tmp_offset; 657 658 /* Weighted combination */ 659 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[0]*(16-u32_x_frac) + 660 pu8_src_top[1]*u32_x_frac)*(16-u32_y_frac) + 661 (pu8_src_bottom[0]*(16-u32_x_frac) + 662 pu8_src_bottom[1]*u32_x_frac)*u32_y_frac )>>8); 663 664 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value; 665 666 /* Update horizontal accumulator */ 667 u32_x_accum += pC->u32_x_inc[i]; 668 } 669 670 } 671 672 pu8_data_out += pOut[i].u_stride - pOut[i].u_width; 673 674 /* Update vertical accumulator */ 675 pC->u32_y_accum[i] += pC->u32_y_inc[i]; 676 if (pC->u32_y_accum[i]>>16) 677 { 678 pu8_data_in = pu8_data_in + (pC->u32_y_accum[i] >> 16) * i32_tmp_offset; 679 pC->u32_y_accum[i] &= 0xffff; 680 } 681 } 682 } 683 /** +-90 rotation */ 684 else 685 { 686 pu8_data_in_org = pu8_data_in; 687 688 /**< Loop on each output row */ 689 for(j=0;j<pOut[i].u_height;j++) 690 { 691 /* horizontal weight factor */ 692 u32_x_frac = (pC->u32_x_accum[i]>>12)&15; 693 694 /* Reinit accumulator */ 695 u32_y_accum = pC->u32_y_accum_start[i]; 696 697 if(M4OSA_TRUE == pC->m_bFlipX) 698 { 699 700 /**< Loop on each output pixel in a row */ 701 for(k=0;k<pOut[i].u_width;k++) 702 { 703 704 u32_y_frac = (u32_y_accum >> 12)&15; /* Vertical weight factor */ 705 706 707 pu8_src_top = (pu8_data_in - (pC->u32_x_accum[i] >> 16)) - 1; 708 709 pu8_src_bottom = pu8_src_top + i32_tmp_offset; 710 711 /* Weighted combination */ 712 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[1]*(16-u32_x_frac) + 713 pu8_src_top[0]*u32_x_frac)*(16-u32_y_frac) + 714 (pu8_src_bottom[1]*(16-u32_x_frac) + 715 pu8_src_bottom[0]*u32_x_frac)*u32_y_frac )>>8); 716 717 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value; 718 719 /* Update vertical accumulator */ 720 u32_y_accum += pC->u32_y_inc[i]; 721 if (u32_y_accum>>16) 722 { 723 pu8_data_in = pu8_data_in + (u32_y_accum >> 16) * i32_tmp_offset; 724 u32_y_accum &= 0xffff; 725 } 726 727 } 728 } 729 else 730 { 731 /**< Loop on each output pixel in a row */ 732 for(k=0;k<pOut[i].u_width;k++) 733 { 734 735 u32_y_frac = (u32_y_accum >> 12)&15; /* Vertical weight factor */ 736 737 pu8_src_top = pu8_data_in + (pC->u32_x_accum[i] >> 16); 738 739 pu8_src_bottom = pu8_src_top + i32_tmp_offset; 740 741 /* Weighted combination */ 742 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[0]*(16-u32_x_frac) + 743 pu8_src_top[1]*u32_x_frac)*(16-u32_y_frac) + 744 (pu8_src_bottom[0]*(16-u32_x_frac) + 745 pu8_src_bottom[1]*u32_x_frac)*u32_y_frac )>>8); 746 747 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value; 748 749 /* Update vertical accumulator */ 750 u32_y_accum += pC->u32_y_inc[i]; 751 if (u32_y_accum>>16) 752 { 753 pu8_data_in = pu8_data_in + (u32_y_accum >> 16) * i32_tmp_offset; 754 u32_y_accum &= 0xffff; 755 } 756 } 757 } 758 pu8_data_out += pOut[i].u_stride - pOut[i].u_width; 759 760 /* Update horizontal accumulator */ 761 pC->u32_x_accum[i] += pC->u32_x_inc[i]; 762 763 pu8_data_in = pu8_data_in_org; 764 } 765 766 } 767 }/** 3 != i */ 768 else 769 { 770 /**No +-90 rotation */ 771 if(M4OSA_FALSE == pC->m_bRevertXY) 772 { 773 774 /**< Loop on each row */ 775 for(j=0;j<pOut[i].u_height;j++) 776 { 777 /* Vertical weight factor */ 778 u32_y_frac = (pC->u32_y_accum[i]>>12)&15; 779 780 /* Reinit horizontal weight factor */ 781 u32_x_accum = pC->u32_x_accum_start[i]; 782 783 784 785 if(M4OSA_TRUE == pC->m_bFlipX) 786 { 787 788 /**< Loop on each output pixel in a row */ 789 for(k=0;k<pOut[i].u_width;k++) 790 { 791 792 u32_x_frac = (u32_x_accum >> 12)&15; /* Fraction of Horizontal 793 weight factor */ 794 795 pu8_src_top = (pu8_data_in - (u32_x_accum >> 16)) -1 ; 796 797 pu8_src_bottom = pu8_src_top + i32_tmp_offset; 798 799 /* Weighted combination */ 800 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[1]*(16-u32_x_frac) + 801 pu8_src_top[0]*u32_x_frac)*(16-u32_y_frac) + 802 (pu8_src_bottom[1]*(16-u32_x_frac) + 803 pu8_src_bottom[0]*u32_x_frac)*u32_y_frac )>>8); 804 805 u32_temp_value= (u32_temp_value >> 7)*0xff; 806 807 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value; 808 809 /* Update horizontal accumulator */ 810 u32_x_accum += pC->u32_x_inc[i]; 811 } 812 } 813 814 else 815 { 816 /**< Loop on each output pixel in a row */ 817 for(k=0;k<pOut[i].u_width;k++) 818 { 819 u32_x_frac = (u32_x_accum >> 12)&15; /* Fraction of Horizontal 820 weight factor */ 821 822 pu8_src_top = pu8_data_in + (u32_x_accum >> 16); 823 824 pu8_src_bottom = pu8_src_top + i32_tmp_offset; 825 826 /* Weighted combination */ 827 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[0]*(16-u32_x_frac) + 828 pu8_src_top[1]*u32_x_frac)*(16-u32_y_frac) + 829 (pu8_src_bottom[0]*(16-u32_x_frac) + 830 pu8_src_bottom[1]*u32_x_frac)*u32_y_frac )>>8); 831 832 u32_temp_value= (u32_temp_value >> 7)*0xff; 833 834 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value; 835 836 /* Update horizontal accumulator */ 837 u32_x_accum += pC->u32_x_inc[i]; 838 } 839 840 } 841 842 pu8_data_out += pOut[i].u_stride - pOut[i].u_width; 843 844 /* Update vertical accumulator */ 845 pC->u32_y_accum[i] += pC->u32_y_inc[i]; 846 if (pC->u32_y_accum[i]>>16) 847 { 848 pu8_data_in = pu8_data_in + (pC->u32_y_accum[i] >> 16) * i32_tmp_offset; 849 pC->u32_y_accum[i] &= 0xffff; 850 } 851 } 852 853 } /**< M4OSA_FALSE == pC->m_bRevertXY */ 854 /** +-90 rotation */ 855 else 856 { 857 pu8_data_in_org = pu8_data_in; 858 859 /**< Loop on each output row */ 860 for(j=0;j<pOut[i].u_height;j++) 861 { 862 /* horizontal weight factor */ 863 u32_x_frac = (pC->u32_x_accum[i]>>12)&15; 864 865 /* Reinit accumulator */ 866 u32_y_accum = pC->u32_y_accum_start[i]; 867 868 if(M4OSA_TRUE == pC->m_bFlipX) 869 { 870 871 /**< Loop on each output pixel in a row */ 872 for(k=0;k<pOut[i].u_width;k++) 873 { 874 875 u32_y_frac = (u32_y_accum >> 12)&15; /* Vertical weight factor */ 876 877 878 pu8_src_top = (pu8_data_in - (pC->u32_x_accum[i] >> 16)) - 1; 879 880 pu8_src_bottom = pu8_src_top + i32_tmp_offset; 881 882 /* Weighted combination */ 883 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[1]*(16-u32_x_frac) + 884 pu8_src_top[0]*u32_x_frac)*(16-u32_y_frac) + 885 (pu8_src_bottom[1]*(16-u32_x_frac) + 886 pu8_src_bottom[0]*u32_x_frac)*u32_y_frac )>>8); 887 888 u32_temp_value= (u32_temp_value >> 7)*0xff; 889 890 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value; 891 892 /* Update vertical accumulator */ 893 u32_y_accum += pC->u32_y_inc[i]; 894 if (u32_y_accum>>16) 895 { 896 pu8_data_in = pu8_data_in + (u32_y_accum >> 16) * i32_tmp_offset; 897 u32_y_accum &= 0xffff; 898 } 899 900 } 901 } 902 else 903 { 904 /**< Loop on each output pixel in a row */ 905 for(k=0;k<pOut[i].u_width;k++) 906 { 907 908 u32_y_frac = (u32_y_accum >> 12)&15; /* Vertical weight factor */ 909 910 pu8_src_top = pu8_data_in + (pC->u32_x_accum[i] >> 16); 911 912 pu8_src_bottom = pu8_src_top + i32_tmp_offset; 913 914 /* Weighted combination */ 915 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[0]*(16-u32_x_frac) + 916 pu8_src_top[1]*u32_x_frac)*(16-u32_y_frac) + 917 (pu8_src_bottom[0]*(16-u32_x_frac) + 918 pu8_src_bottom[1]*u32_x_frac)*u32_y_frac )>>8); 919 920 u32_temp_value= (u32_temp_value >> 7)*0xff; 921 922 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value; 923 924 /* Update vertical accumulator */ 925 u32_y_accum += pC->u32_y_inc[i]; 926 if (u32_y_accum>>16) 927 { 928 pu8_data_in = pu8_data_in + (u32_y_accum >> 16) * i32_tmp_offset; 929 u32_y_accum &= 0xffff; 930 } 931 } 932 } 933 pu8_data_out += pOut[i].u_stride - pOut[i].u_width; 934 935 /* Update horizontal accumulator */ 936 pC->u32_x_accum[i] += pC->u32_x_inc[i]; 937 938 pu8_data_in = pu8_data_in_org; 939 940 } 941 } /**< M4OSA_TRUE == pC->m_bRevertXY */ 942 }/** 3 == i */ 943 } 944 /**< In case of stripe mode, save current input pointer */ 945 if(M4OSA_TRUE == pC->m_params.m_bOutputStripe) 946 { 947 pC->pu8_data_in[i] = pu8_data_in; 948 } 949 } 950 951 /**< Update number of processed rows, reset it if we have finished 952 with the whole processing */ 953 pC->m_procRows += pOut[0].u_height; 954 if(M4OSA_FALSE == pC->m_bRevertXY) 955 { 956 if(pC->m_params.m_outputSize.m_height <= pC->m_procRows) pC->m_procRows = 0; 957 } 958 else 959 { 960 if(pC->m_params.m_outputSize.m_width <= pC->m_procRows) pC->m_procRows = 0; 961 } 962 963 return M4NO_ERROR ; 964 965 } 966 967 968 969