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 */
60typedef 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 */
73typedef 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 */
119M4OSA_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
160M4AIR_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 */
184M4OSA_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 */
221M4OSA_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 */
434M4OSA_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