M4AIR_API.c revision 7c9d8018755adf1857571125ba1b3598c96ea506
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                        M4OSA_memcpy((M4OSA_MemAddr8)pu8_data_out, (M4OSA_MemAddr8)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