M4VIFI_ResizeRGB888toRGB888.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_ResizeYUV420toYUV420.c
19 * @brief    Contain video library function
20 * @note     This file has a Resize filter function
21 *           -# Generic resizing of YUV420 (Planar) image
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_ResizeBilinearRGB888toRGB888(void *pUserData, M4VIFI_ImagePlane *pPlaneIn,
35 *                                                                  M4VIFI_ImagePlane *pPlaneOut)
36 * @brief   Resizes YUV420 Planar plane.
37 * @note    Basic structure 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 *                  Place the YUV in the ouput plane
43 *              end loop column
44 *          end loop row
45 *          For resizing bilinear interpolation linearly interpolates along
46 *          each row, and then uses that result in a linear interpolation down each column.
47 *          Each estimated pixel in the output image is a weighted
48 *          combination of its four neighbours. The ratio of compression
49 *          or dilatation is estimated using input and output sizes.
50 * @param   pUserData: (IN) User Data
51 * @param   pPlaneIn: (IN) Pointer to YUV420 (Planar) plane buffer
52 * @param   pPlaneOut: (OUT) Pointer to YUV420 (Planar) plane
53 * @return  M4VIFI_OK: there is no error
54 * @return  M4VIFI_ILLEGAL_FRAME_HEIGHT: Error in height
55 * @return  M4VIFI_ILLEGAL_FRAME_WIDTH:  Error in width
56 ***********************************************************************************************
57*/
58M4VIFI_UInt8    M4VIFI_ResizeBilinearRGB888toRGB888(void *pUserData,
59                                                                M4VIFI_ImagePlane *pPlaneIn,
60                                                                M4VIFI_ImagePlane *pPlaneOut)
61{
62    M4VIFI_UInt8    *pu8_data_in;
63    M4VIFI_UInt8    *pu8_data_out;
64    M4VIFI_UInt32   u32_width_in, u32_width_out, u32_height_in, u32_height_out;
65    M4VIFI_UInt32   u32_stride_in, u32_stride_out;
66    M4VIFI_UInt32   u32_x_inc, u32_y_inc;
67    M4VIFI_UInt32   u32_x_accum, u32_y_accum, u32_x_accum_start;
68    M4VIFI_UInt32   u32_width, u32_height;
69    M4VIFI_UInt32   u32_y_frac;
70    M4VIFI_UInt32   u32_x_frac;
71    M4VIFI_UInt32   u32_Rtemp_value,u32_Gtemp_value,u32_Btemp_value;
72    M4VIFI_UInt8    *pu8_src_top;
73    M4VIFI_UInt8    *pu8_src_bottom;
74    M4VIFI_UInt32    i32_b00, i32_g00, i32_r00;
75    M4VIFI_UInt32    i32_b01, i32_g01, i32_r01;
76    M4VIFI_UInt32    i32_b02, i32_g02, i32_r02;
77    M4VIFI_UInt32    i32_b03, i32_g03, i32_r03;
78
79    /* Check for the YUV width and height are even */
80    if ((IS_EVEN(pPlaneIn->u_height) == FALSE)    ||
81        (IS_EVEN(pPlaneOut->u_height) == FALSE))
82    {
83        return M4VIFI_ILLEGAL_FRAME_HEIGHT;
84    }
85
86    if ((IS_EVEN(pPlaneIn->u_width) == FALSE) ||
87        (IS_EVEN(pPlaneOut->u_width) == FALSE))
88    {
89        return M4VIFI_ILLEGAL_FRAME_WIDTH;
90    }
91
92
93        /* Set the working pointers at the beginning of the input/output data field */
94        pu8_data_in     = (M4VIFI_UInt8*)(pPlaneIn->pac_data + pPlaneIn->u_topleft);
95        pu8_data_out    = (M4VIFI_UInt8*)(pPlaneOut->pac_data + pPlaneOut->u_topleft);
96
97        /* Get the memory jump corresponding to a row jump */
98        u32_stride_in   = pPlaneIn->u_stride;
99        u32_stride_out  = pPlaneOut->u_stride;
100
101        /* Set the bounds of the active image */
102        u32_width_in    = pPlaneIn->u_width;
103        u32_height_in   = pPlaneIn->u_height;
104
105        u32_width_out   = pPlaneOut->u_width;
106        u32_height_out  = pPlaneOut->u_height;
107
108        /* Compute horizontal ratio between src and destination width.*/
109        if (u32_width_out >= u32_width_in)
110        {
111            u32_x_inc   = ((u32_width_in-1) * MAX_SHORT) / (u32_width_out-1);
112        }
113        else
114        {
115            u32_x_inc   = (u32_width_in * MAX_SHORT) / (u32_width_out);
116        }
117
118        /* Compute vertical ratio between src and destination height.*/
119        if (u32_height_out >= u32_height_in)
120        {
121            u32_y_inc   = ((u32_height_in - 1) * MAX_SHORT) / (u32_height_out-1);
122        }
123        else
124        {
125            u32_y_inc = (u32_height_in * MAX_SHORT) / (u32_height_out);
126        }
127
128        /*
129        Calculate initial accumulator value : u32_y_accum_start.
130        u32_y_accum_start is coded on 15 bits, and represents a value between 0 and 0.5
131        */
132        if (u32_y_inc >= MAX_SHORT)
133        {
134            /*
135                Keep the fractionnal part, assimung that integer  part is coded
136                on the 16 high bits and the fractionnal on the 15 low bits
137            */
138            u32_y_accum = u32_y_inc & 0xffff;
139
140            if (!u32_y_accum)
141            {
142                u32_y_accum = MAX_SHORT;
143            }
144
145            u32_y_accum >>= 1;
146        }
147        else
148        {
149            u32_y_accum = 0;
150        }
151
152
153        /*
154            Calculate initial accumulator value : u32_x_accum_start.
155            u32_x_accum_start is coded on 15 bits, and represents a value between 0 and 0.5
156        */
157        if (u32_x_inc >= MAX_SHORT)
158        {
159            u32_x_accum_start = u32_x_inc & 0xffff;
160
161            if (!u32_x_accum_start)
162            {
163                u32_x_accum_start = MAX_SHORT;
164            }
165
166            u32_x_accum_start >>= 1;
167        }
168        else
169        {
170            u32_x_accum_start = 0;
171        }
172
173        u32_height = u32_height_out;
174
175        /*
176        Bilinear interpolation linearly interpolates along each row, and then uses that
177        result in a linear interpolation donw each column. Each estimated pixel in the
178        output image is a weighted combination of its four neighbours according to the formula:
179        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)
180        with  R(x) = / x+1  -1 =< x =< 0 \ 1-x  0 =< x =< 1 and a (resp. b)weighting coefficient
181        is the distance from the nearest neighbor in the p (resp. q) direction
182        */
183
184        do { /* Scan all the row */
185
186            /* Vertical weight factor */
187            u32_y_frac = (u32_y_accum>>12)&15;
188
189            /* Reinit accumulator */
190            u32_x_accum = u32_x_accum_start;
191
192            u32_width = u32_width_out;
193
194            do { /* Scan along each row */
195                pu8_src_top = pu8_data_in + (u32_x_accum >> 16)*3;
196                pu8_src_bottom = pu8_src_top + (u32_stride_in);
197                u32_x_frac = (u32_x_accum >> 12)&15; /* Horizontal weight factor */
198
199                if ((u32_width == 1) && (u32_width_in == u32_width_out)) {
200                    /*
201                       When input height is equal to output height and input width
202                       equal to output width, replicate the corner pixels for
203                       interpolation
204                    */
205                    if ((u32_height == 1) && (u32_height_in == u32_height_out)) {
206                        GET_RGB24(i32_b00,i32_g00,i32_r00,pu8_src_top,0);
207                        GET_RGB24(i32_b01,i32_g01,i32_r01,pu8_src_top,0);
208                        GET_RGB24(i32_b02,i32_g02,i32_r02,pu8_src_top,0);
209                        GET_RGB24(i32_b03,i32_g03,i32_r03,pu8_src_top,0);
210                    }
211                    /*
212                       When input height is not equal to output height and
213                       input width equal to output width, replicate the
214                       column for interpolation
215                    */
216                    else {
217                        GET_RGB24(i32_b00,i32_g00,i32_r00,pu8_src_top,0);
218                        GET_RGB24(i32_b01,i32_g01,i32_r01,pu8_src_top,0);
219                        GET_RGB24(i32_b02,i32_g02,i32_r02,pu8_src_bottom,0);
220                        GET_RGB24(i32_b03,i32_g03,i32_r03,pu8_src_bottom,0);
221                    }
222                } else {
223                    /*
224                       When input height is equal to output height and
225                       input width not equal to output width, replicate the
226                       row for interpolation
227                    */
228                    if ((u32_height == 1) && (u32_height_in == u32_height_out)) {
229                        GET_RGB24(i32_b00,i32_g00,i32_r00,pu8_src_top,0);
230                        GET_RGB24(i32_b01,i32_g01,i32_r01,pu8_src_top,3);
231                        GET_RGB24(i32_b02,i32_g02,i32_r02,pu8_src_top,0);
232                        GET_RGB24(i32_b03,i32_g03,i32_r03,pu8_src_top,3);
233                    } else {
234                        GET_RGB24(i32_b00,i32_g00,i32_r00,pu8_src_top,0);
235                        GET_RGB24(i32_b01,i32_g01,i32_r01,pu8_src_top,3);
236                        GET_RGB24(i32_b02,i32_g02,i32_r02,pu8_src_bottom,0);
237                        GET_RGB24(i32_b03,i32_g03,i32_r03,pu8_src_bottom,3);
238                    }
239                }
240                u32_Rtemp_value = (M4VIFI_UInt8)(((i32_r00*(16-u32_x_frac) +
241                                 i32_r01*u32_x_frac)*(16-u32_y_frac) +
242                                (i32_r02*(16-u32_x_frac) +
243                                 i32_r03*u32_x_frac)*u32_y_frac )>>8);
244
245                u32_Gtemp_value = (M4VIFI_UInt8)(((i32_g00*(16-u32_x_frac) +
246                                 i32_g01*u32_x_frac)*(16-u32_y_frac) +
247                                (i32_g02*(16-u32_x_frac) +
248                                 i32_g03*u32_x_frac)*u32_y_frac )>>8);
249
250                u32_Btemp_value =  (M4VIFI_UInt8)(((i32_b00*(16-u32_x_frac) +
251                                 i32_b01*u32_x_frac)*(16-u32_y_frac) +
252                                (i32_b02*(16-u32_x_frac) +
253                                 i32_b03*u32_x_frac)*u32_y_frac )>>8);
254
255                *pu8_data_out++ = u32_Btemp_value ;
256                *pu8_data_out++ = u32_Gtemp_value ;
257                *pu8_data_out++ = u32_Rtemp_value ;
258
259                /* Update horizontal accumulator */
260                u32_x_accum += u32_x_inc;
261
262            } while(--u32_width);
263
264            //pu16_data_out = pu16_data_out + (u32_stride_out>>1) - (u32_width_out);
265
266            /* Update vertical accumulator */
267            u32_y_accum += u32_y_inc;
268            if (u32_y_accum>>16)
269            {
270                pu8_data_in = pu8_data_in + (u32_y_accum >> 16) * (u32_stride_in) ;
271                u32_y_accum &= 0xffff;
272            }
273        } while(--u32_height);
274
275    return M4VIFI_OK;
276}
277/* End of file M4VIFI_ResizeRGB565toRGB565.c */
278
279