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