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