Home | History | Annotate | Download | only in src
      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