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     M4VIFI_ResizeYUV420toBGR565.c
19 * @brief    Contain video library function
20 * @note     This file has a Combo filter function
21 *           -# Resizes YUV420 and converts to RGR565 with rotation
22 ******************************************************************************
23*/
24
25/* Prototypes of functions, and type definitions */
26#include    "M4VIFI_FiltersAPI.h"
27/* Macro definitions */
28#include    "M4VIFI_Defines.h"
29/* Clip table declaration */
30#include    "M4VIFI_Clip.h"
31
32/**
33 *********************************************************************************************
34 * M4VIFI_UInt8 M4VIFI_ResizeBilinearYUV420toBGR565(void *pContext, M4VIFI_ImagePlane *pPlaneIn,
35 *                                                                  M4VIFI_ImagePlane *pPlaneOut)
36 * @brief   Resize YUV420 plane and converts to BGR565 with +90 rotation.
37 * @note    Basic sturture of the function
38 *          Loop on each row (step 2)
39 *              Loop on each column (step 2)
40 *                  Get four Y samples and 1 u & V sample
41 *                  Resize the Y with corresponing U and V samples
42 *                  Compute the four corresponding R G B values
43 *                  Place the R G B in the ouput plane in rotated fashion
44 *              end loop column
45 *          end loop row
46 *          For resizing bilinear interpolation linearly interpolates along
47 *          each row, and then uses that result in a linear interpolation down each column.
48 *          Each estimated pixel in the output image is a weighted
49 *          combination of its four neighbours. The ratio of compression
50 *          or dilatation is estimated using input and output sizes.
51 * @param   pPlaneIn: (IN) Pointer to YUV plane buffer
52 * @param   pContext: (IN) Context Pointer
53 * @param   pPlaneOut: (OUT) Pointer to BGR565 Plane
54 * @return  M4VIFI_OK: there is no error
55 * @return  M4VIFI_ILLEGAL_FRAME_HEIGHT: YUV Plane height is ODD
56 * @return  M4VIFI_ILLEGAL_FRAME_WIDTH:  YUV Plane width is ODD
57 *********************************************************************************************
58*/
59M4VIFI_UInt8    M4VIFI_ResizeBilinearYUV420toBGR565(void* pContext,
60                                                                 M4VIFI_ImagePlane *pPlaneIn,
61                                                                 M4VIFI_ImagePlane *pPlaneOut)
62{
63    M4VIFI_UInt8    *pu8_data_in[PLANES], *pu8_data_in1[PLANES],*pu8_data_out;
64    M4VIFI_UInt32   *pu32_rgb_data_current, *pu32_rgb_data_next, *pu32_rgb_data_start;
65
66    M4VIFI_UInt32   u32_width_in[PLANES], u32_width_out, u32_height_in[PLANES], u32_height_out;
67    M4VIFI_UInt32   u32_stride_in[PLANES];
68    M4VIFI_UInt32   u32_stride_out, u32_stride2_out, u32_width2_RGB, u32_height2_RGB;
69    M4VIFI_UInt32   u32_x_inc[PLANES], u32_y_inc[PLANES];
70    M4VIFI_UInt32   u32_x_accum_Y, u32_x_accum_U, u32_x_accum_start;
71    M4VIFI_UInt32   u32_y_accum_Y, u32_y_accum_U;
72    M4VIFI_UInt32   u32_x_frac_Y, u32_x_frac_U, u32_y_frac_Y,u32_y_frac_U;
73    M4VIFI_Int32    U_32, V_32, Y_32, Yval_32;
74    M4VIFI_UInt8    u8_Red, u8_Green, u8_Blue;
75    M4VIFI_UInt32   u32_row, u32_col;
76
77    M4VIFI_UInt32   u32_plane;
78    M4VIFI_UInt32   u32_rgb_temp1, u32_rgb_temp2;
79    M4VIFI_UInt32   u32_rgb_temp3,u32_rgb_temp4;
80    M4VIFI_UInt32   u32_check_size;
81
82    M4VIFI_UInt8    *pu8_src_top_Y,*pu8_src_top_U,*pu8_src_top_V ;
83    M4VIFI_UInt8    *pu8_src_bottom_Y, *pu8_src_bottom_U, *pu8_src_bottom_V;
84
85    /* Check for the YUV width and height are even */
86    u32_check_size = IS_EVEN(pPlaneIn[0].u_height);
87    if( u32_check_size == FALSE )
88    {
89        return M4VIFI_ILLEGAL_FRAME_HEIGHT;
90    }
91    u32_check_size = IS_EVEN(pPlaneIn[0].u_width);
92    if (u32_check_size == FALSE )
93    {
94        return M4VIFI_ILLEGAL_FRAME_WIDTH;
95
96    }
97    /* Make the ouput width and height as even */
98    pPlaneOut->u_height = pPlaneOut->u_height & 0xFFFFFFFE;
99    pPlaneOut->u_width = pPlaneOut->u_width & 0xFFFFFFFE;
100    pPlaneOut->u_stride = pPlaneOut->u_stride & 0xFFFFFFFC;
101
102    /* Assignment of output pointer */
103    pu8_data_out    = pPlaneOut->pac_data + pPlaneOut->u_topleft;
104    /* Assignment of output width(rotated) */
105    u32_width_out   = pPlaneOut->u_width;
106    /* Assignment of output height(rotated) */
107    u32_height_out  = pPlaneOut->u_height;
108
109    u32_width2_RGB  = pPlaneOut->u_width >> 1;
110    u32_height2_RGB = pPlaneOut->u_height >> 1;
111
112    u32_stride_out = pPlaneOut->u_stride >> 1;
113    u32_stride2_out = pPlaneOut->u_stride >> 2;
114
115    for(u32_plane = 0; u32_plane < PLANES; u32_plane++)
116    {
117        /* Set the working pointers at the beginning of the input/output data field */
118        pu8_data_in[u32_plane] = pPlaneIn[u32_plane].pac_data + pPlaneIn[u32_plane].u_topleft;
119
120        /* Get the memory jump corresponding to a row jump */
121        u32_stride_in[u32_plane] = pPlaneIn[u32_plane].u_stride;
122
123        /* Set the bounds of the active image */
124        u32_width_in[u32_plane] = pPlaneIn[u32_plane].u_width;
125        u32_height_in[u32_plane] = pPlaneIn[u32_plane].u_height;
126    }
127    /* Compute horizontal ratio between src and destination width for Y Plane. */
128    if (u32_width_out >= u32_width_in[YPlane])
129    {
130        u32_x_inc[YPlane]   = ((u32_width_in[YPlane]-1) * MAX_SHORT) / (u32_width_out-1);
131    }
132    else
133    {
134        u32_x_inc[YPlane]   = (u32_width_in[YPlane] * MAX_SHORT) / (u32_width_out);
135    }
136
137    /* Compute vertical ratio between src and destination height for Y Plane.*/
138    if (u32_height_out >= u32_height_in[YPlane])
139    {
140        u32_y_inc[YPlane]   = ((u32_height_in[YPlane]-1) * MAX_SHORT) / (u32_height_out-1);
141    }
142    else
143    {
144        u32_y_inc[YPlane] = (u32_height_in[YPlane] * MAX_SHORT) / (u32_height_out);
145    }
146
147    /* Compute horizontal ratio between src and destination width for U and V Planes. */
148    if (u32_width2_RGB >= u32_width_in[UPlane])
149    {
150        u32_x_inc[UPlane]   = ((u32_width_in[UPlane]-1) * MAX_SHORT) / (u32_width2_RGB-1);
151    }
152    else
153    {
154        u32_x_inc[UPlane]   = (u32_width_in[UPlane] * MAX_SHORT) / (u32_width2_RGB);
155    }
156
157    /* Compute vertical ratio between src and destination height for U and V Planes. */
158
159    if (u32_height2_RGB >= u32_height_in[UPlane])
160    {
161        u32_y_inc[UPlane]   = ((u32_height_in[UPlane]-1) * MAX_SHORT) / (u32_height2_RGB-1);
162    }
163    else
164    {
165        u32_y_inc[UPlane]  = (u32_height_in[UPlane] * MAX_SHORT) / (u32_height2_RGB);
166    }
167
168    u32_y_inc[VPlane] = u32_y_inc[UPlane];
169    u32_x_inc[VPlane] = u32_x_inc[UPlane];
170
171    /*
172        Calculate initial accumulator value : u32_y_accum_start.
173        u32_y_accum_start is coded on 15 bits,and represents a value between 0 and 0.5
174    */
175    if (u32_y_inc[YPlane] > MAX_SHORT)
176    {
177        /*
178            Keep the fractionnal part, assimung that integer  part is coded on the 16 high bits,
179            and the fractionnal on the 15 low bits
180        */
181        u32_y_accum_Y = u32_y_inc[YPlane] & 0xffff;
182        u32_y_accum_U = u32_y_inc[UPlane] & 0xffff;
183
184        if (!u32_y_accum_Y)
185        {
186            u32_y_accum_Y = MAX_SHORT;
187            u32_y_accum_U = MAX_SHORT;
188        }
189        u32_y_accum_Y >>= 1;
190        u32_y_accum_U >>= 1;
191    }
192    else
193    {
194        u32_y_accum_Y = 0;
195        u32_y_accum_U = 0;
196
197    }
198
199    /*
200        Calculate initial accumulator value : u32_x_accum_start.
201        u32_x_accum_start is coded on 15 bits, and represents a value between 0 and 0.5
202    */
203    if (u32_x_inc[YPlane] > MAX_SHORT)
204    {
205        u32_x_accum_start = u32_x_inc[YPlane] & 0xffff;
206
207        if (!u32_x_accum_start)
208        {
209            u32_x_accum_start = MAX_SHORT;
210        }
211
212        u32_x_accum_start >>= 1;
213    }
214    else
215    {
216        u32_x_accum_start = 0;
217    }
218
219    pu32_rgb_data_start = (M4VIFI_UInt32*)pu8_data_out;
220
221    /*
222        Bilinear interpolation linearly interpolates along each row, and then uses that
223        result in a linear interpolation donw each column. Each estimated pixel in the
224        output image is a weighted combination of its four neighbours according to the formula :
225        F(p',q')=f(p,q)R(-a)R(b)+f(p,q-1)R(-a)R(b-1)+f(p+1,q)R(1-a)R(b)+f(p+&,q+1)R(1-a)R(b-1)
226        with  R(x) = / x+1  -1 =< x =< 0 \ 1-x  0 =< x =< 1 and a (resp. b) weighting coefficient
227        is the distance from the nearest neighbor in the p (resp. q) direction
228    */
229    for (u32_row = u32_height_out; u32_row != 0; u32_row -= 2)
230    {
231        u32_x_accum_Y = u32_x_accum_start;
232        u32_x_accum_U = u32_x_accum_start;
233
234        /* Vertical weight factor */
235        u32_y_frac_Y = (u32_y_accum_Y >> 12) & 15;
236        u32_y_frac_U = (u32_y_accum_U >> 12) & 15;
237
238        /* RGB current line position pointer */
239        pu32_rgb_data_current = pu32_rgb_data_start ;
240
241        /* RGB next line position pointer */
242        pu32_rgb_data_next    = pu32_rgb_data_current + (u32_stride2_out);
243
244        /* Y Plane next row pointer */
245        pu8_data_in1[YPlane] = pu8_data_in[YPlane];
246
247        u32_rgb_temp3 = u32_y_accum_Y + (u32_y_inc[YPlane]);
248        if (u32_rgb_temp3 >> 16)
249        {
250            pu8_data_in1[YPlane] =  pu8_data_in[YPlane] +
251                                                (u32_rgb_temp3 >> 16) * (u32_stride_in[YPlane]);
252            u32_rgb_temp3 &= 0xffff;
253        }
254        u32_rgb_temp4 = (u32_rgb_temp3 >> 12) & 15;
255
256        for (u32_col = u32_width_out; u32_col != 0; u32_col -= 2)
257        {
258
259            /* Input Y plane elements */
260            pu8_src_top_Y = pu8_data_in[YPlane] + (u32_x_accum_Y >> 16);
261            pu8_src_bottom_Y = pu8_src_top_Y + u32_stride_in[YPlane];
262
263            /* Input U Plane elements */
264            pu8_src_top_U = pu8_data_in[UPlane] + (u32_x_accum_U >> 16);
265            pu8_src_bottom_U = pu8_src_top_U + u32_stride_in[UPlane];
266
267            pu8_src_top_V = pu8_data_in[VPlane] + (u32_x_accum_U >> 16);
268            pu8_src_bottom_V = pu8_src_top_V + u32_stride_in[VPlane];
269
270            /* Horizontal weight factor for Y plane */
271            u32_x_frac_Y = (u32_x_accum_Y >> 12)&15;
272            /* Horizontal weight factor for U and V planes */
273            u32_x_frac_U = (u32_x_accum_U >> 12)&15;
274
275            /* Weighted combination */
276            U_32 = (((pu8_src_top_U[0]*(16-u32_x_frac_U) + pu8_src_top_U[1]*u32_x_frac_U)
277                    *(16-u32_y_frac_U) + (pu8_src_bottom_U[0]*(16-u32_x_frac_U)
278                    + pu8_src_bottom_U[1]*u32_x_frac_U)*u32_y_frac_U ) >> 8);
279
280            V_32 = (((pu8_src_top_V[0]*(16-u32_x_frac_U) + pu8_src_top_V[1]*u32_x_frac_U)
281                    *(16-u32_y_frac_U)+ (pu8_src_bottom_V[0]*(16-u32_x_frac_U)
282                    + pu8_src_bottom_V[1]*u32_x_frac_U)*u32_y_frac_U ) >> 8);
283
284            Y_32 = (((pu8_src_top_Y[0]*(16-u32_x_frac_Y) + pu8_src_top_Y[1]*u32_x_frac_Y)
285                    *(16-u32_y_frac_Y) + (pu8_src_bottom_Y[0]*(16-u32_x_frac_Y)
286                    + pu8_src_bottom_Y[1]*u32_x_frac_Y)*u32_y_frac_Y ) >> 8);
287
288            u32_x_accum_U += (u32_x_inc[UPlane]);
289
290            /* YUV to RGB */
291            #ifdef __RGB_V1__
292                    Yval_32 = Y_32*37;
293            #else   /* __RGB_V1__v */
294                    Yval_32 = Y_32*0x2568;
295            #endif /* __RGB_V1__v */
296
297                    DEMATRIX(u8_Red,u8_Green,u8_Blue,Yval_32,U_32,V_32);
298
299            /* Pack 8 bit R,G,B to RGB565 */
300            #ifdef  LITTLE_ENDIAN
301                    u32_rgb_temp1 = PACK_BGR565(0,u8_Red,u8_Green,u8_Blue);
302            #else   /* LITTLE_ENDIAN */
303                    u32_rgb_temp1 = PACK_BGR565(16,u8_Red,u8_Green,u8_Blue);
304            #endif  /* LITTLE_ENDIAN */
305
306
307            pu8_src_top_Y = pu8_data_in1[YPlane]+(u32_x_accum_Y >> 16);
308            pu8_src_bottom_Y = pu8_src_top_Y + u32_stride_in[YPlane];
309
310            /* Weighted combination */
311            Y_32 = (((pu8_src_top_Y[0]*(16-u32_x_frac_Y) + pu8_src_top_Y[1]*u32_x_frac_Y)
312                    *(16-u32_rgb_temp4) + (pu8_src_bottom_Y[0]*(16-u32_x_frac_Y)
313                    + pu8_src_bottom_Y[1]*u32_x_frac_Y)*u32_rgb_temp4 ) >> 8);
314
315            u32_x_accum_Y += u32_x_inc[YPlane];
316
317            /* Horizontal weight factor */
318            u32_x_frac_Y = (u32_x_accum_Y >> 12)&15;
319
320            /* YUV to RGB */
321            #ifdef __RGB_V1__
322                    Yval_32 = Y_32*37;
323            #else   /* __RGB_V1__v */
324                    Yval_32 = Y_32*0x2568;
325            #endif  /* __RGB_V1__v */
326
327            DEMATRIX(u8_Red,u8_Green,u8_Blue,Yval_32,U_32,V_32);
328
329            /* Pack 8 bit R,G,B to RGB565 */
330            #ifdef  LITTLE_ENDIAN
331                    u32_rgb_temp2 = PACK_BGR565(0,u8_Red,u8_Green,u8_Blue);
332            #else   /* LITTLE_ENDIAN */
333                    u32_rgb_temp2 = PACK_BGR565(16,u8_Red,u8_Green,u8_Blue);
334            #endif  /* LITTLE_ENDIAN */
335
336
337            pu8_src_top_Y = pu8_data_in[YPlane] + (u32_x_accum_Y >> 16) ;
338            pu8_src_bottom_Y = pu8_src_top_Y + u32_stride_in[YPlane];
339
340            /* Weighted combination */
341            Y_32 = (((pu8_src_top_Y[0]*(16-u32_x_frac_Y) + pu8_src_top_Y[1]*u32_x_frac_Y)
342                    *(16-u32_y_frac_Y) + (pu8_src_bottom_Y[0]*(16-u32_x_frac_Y)
343                    + pu8_src_bottom_Y[1]*u32_x_frac_Y)*u32_y_frac_Y ) >> 8);
344
345            /* YUV to RGB */
346            #ifdef __RGB_V1__
347                    Yval_32 = Y_32*37;
348            #else   /* __RGB_V1__v */
349                    Yval_32 = Y_32*0x2568;
350            #endif  /* __RGB_V1__v */
351
352            DEMATRIX(u8_Red,u8_Green,u8_Blue,Yval_32,U_32,V_32);
353
354            /* Pack 8 bit R,G,B to RGB565 */
355            #ifdef  LITTLE_ENDIAN
356                    *(pu32_rgb_data_current)++ = u32_rgb_temp1 |
357                                                        PACK_BGR565(16,u8_Red,u8_Green,u8_Blue);
358            #else   /* LITTLE_ENDIAN */
359                    *(pu32_rgb_data_current)++ = u32_rgb_temp1 |
360                                                        PACK_BGR565(0,u8_Red,u8_Green,u8_Blue);
361            #endif  /* LITTLE_ENDIAN */
362
363
364            pu8_src_top_Y = pu8_data_in1[YPlane]+ (u32_x_accum_Y >> 16);
365            pu8_src_bottom_Y = pu8_src_top_Y + u32_stride_in[YPlane];
366
367            /* Weighted combination */
368            Y_32 = (((pu8_src_top_Y[0]*(16-u32_x_frac_Y) + pu8_src_top_Y[1]*u32_x_frac_Y)
369                    *(16-u32_rgb_temp4) + (pu8_src_bottom_Y[0]*(16-u32_x_frac_Y)
370                    + pu8_src_bottom_Y[1]*u32_x_frac_Y)*u32_rgb_temp4 )>>8);
371
372            u32_x_accum_Y += u32_x_inc[YPlane];
373            /* YUV to RGB */
374            #ifdef __RGB_V1__
375                    Yval_32=Y_32*37;
376            #else   /* __RGB_V1__v */
377                    Yval_32=Y_32*0x2568;
378            #endif  /* __RGB_V1__v */
379
380            DEMATRIX(u8_Red,u8_Green,u8_Blue,Yval_32,U_32,V_32);
381
382            /* Pack 8 bit R,G,B to RGB565 */
383            #ifdef  LITTLE_ENDIAN
384                    *(pu32_rgb_data_next)++ = u32_rgb_temp2 |
385                                                        PACK_BGR565(16,u8_Red,u8_Green,u8_Blue);
386            #else   /* LITTLE_ENDIAN */
387                    *(pu32_rgb_data_next)++ = u32_rgb_temp2 |
388                                                        PACK_BGR565(0,u8_Red,u8_Green,u8_Blue);
389            #endif  /* LITTLE_ENDIAN */
390
391        }   /* End of horizontal scanning */
392
393        u32_y_accum_Y  =  u32_rgb_temp3 + (u32_y_inc[YPlane]);
394        u32_y_accum_U += (u32_y_inc[UPlane]);
395
396        /* Y plane row update */
397        if (u32_y_accum_Y >> 16)
398        {
399            pu8_data_in[YPlane] =  pu8_data_in1[YPlane] +
400                                                ((u32_y_accum_Y >> 16) * (u32_stride_in[YPlane]));
401            u32_y_accum_Y &= 0xffff;
402        }
403        else
404        {
405            pu8_data_in[YPlane] = pu8_data_in1[YPlane];
406        }
407        /* U and V planes row update */
408        if (u32_y_accum_U >> 16)
409        {
410            pu8_data_in[UPlane] =  pu8_data_in[UPlane] +
411                                                (u32_y_accum_U >> 16) * (u32_stride_in[UPlane]);
412            pu8_data_in[VPlane] =  pu8_data_in[VPlane] +
413                                                (u32_y_accum_U >> 16) * (u32_stride_in[VPlane]);
414            u32_y_accum_U &= 0xffff;
415        }
416        /* BGR pointer Update */
417        pu32_rgb_data_start += u32_stride_out;
418
419    }   /* End of vertical scanning */
420    return M4VIFI_OK;
421}
422
423