• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
M4AIR_create(M4OSA_Context * pContext,M4AIR_InputFormatType inputFormat)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  */
M4AIR_cleanUp(M4OSA_Context pContext)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  */
M4AIR_configure(M4OSA_Context pContext,M4AIR_Params * pParams)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  */
M4AIR_get(M4OSA_Context pContext,M4VIFI_ImagePlane * pIn,M4VIFI_ImagePlane * pOut)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