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