M4VIFI_ResizeRGB565toRGB565.c revision 0078736220b9372f2c82eb258ceca3dbd6c358ef
1/*
2 * Copyright (C) 2004-2011 NXP Software
3 * Copyright (C) 2011 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/**
19 ******************************************************************************
20 * @file     M4VIFI_ResizeRGB565toRGB565.c
21 * @brief    Contain video library function
22 * @note     This file has a Resize filter function
23 *           Generic resizing of RGB565 (Planar) image
24 ******************************************************************************
25*/
26/* Prototypes of functions, and type definitions */
27#include    "M4VIFI_FiltersAPI.h"
28/* Macro definitions */
29#include    "M4VIFI_Defines.h"
30/* Clip table declaration */
31#include    "M4VIFI_Clip.h"
32
33/**
34 ***********************************************************************************************
35 * M4VIFI_UInt8 M4VIFI_ResizeBilinearRGB565toRGB565(void *pUserData, M4VIFI_ImagePlane *pPlaneIn,
36 *                                                                   M4VIFI_ImagePlane *pPlaneOut)
37 * @brief   Resizes RGB565 Planar plane.
38 * @param   pUserData: (IN) User Data
39 * @param   pPlaneIn: (IN) Pointer to RGB565 (Planar) plane buffer
40 * @param   pPlaneOut: (OUT) Pointer to RGB565 (Planar) plane
41 * @return  M4VIFI_OK: there is no error
42 * @return  M4VIFI_ILLEGAL_FRAME_HEIGHT: Error in height
43 * @return  M4VIFI_ILLEGAL_FRAME_WIDTH:  Error in width
44 ***********************************************************************************************
45*/
46M4VIFI_UInt8    M4VIFI_ResizeBilinearRGB565toRGB565(void *pUserData,
47                                                    M4VIFI_ImagePlane *pPlaneIn,
48                                                    M4VIFI_ImagePlane *pPlaneOut)
49{
50    M4VIFI_UInt16   *pu16_data_in;
51    M4VIFI_UInt16   *pu16_data_out;
52    M4VIFI_UInt32   u32_width_in, u32_width_out, u32_height_in, u32_height_out;
53    M4VIFI_UInt32   u32_stride_in, u32_stride_out;
54    M4VIFI_UInt32   u32_x_inc, u32_y_inc;
55    M4VIFI_UInt32   u32_x_accum, u32_y_accum, u32_x_accum_start;
56    M4VIFI_UInt32   u32_width, u32_height;
57    M4VIFI_UInt32   u32_y_frac;
58    M4VIFI_UInt32   u32_x_frac;
59    M4VIFI_UInt32   u32_Rtemp_value,u32_Gtemp_value,u32_Btemp_value;
60    M4VIFI_UInt16   *pu16_src_top;
61    M4VIFI_UInt16   *pu16_src_bottom;
62    M4VIFI_UInt32   i32_b00, i32_g00, i32_r00;
63    M4VIFI_UInt32   i32_b01, i32_g01, i32_r01;
64    M4VIFI_UInt32   i32_b02, i32_g02, i32_r02;
65    M4VIFI_UInt32   i32_b03, i32_g03, i32_r03;
66    M4VIFI_UInt8    count_trans=0;
67
68    /* Check for the RGB width and height are even */
69    if ((IS_EVEN(pPlaneIn->u_height) == FALSE) ||
70        (IS_EVEN(pPlaneOut->u_height) == FALSE)) {
71        return M4VIFI_ILLEGAL_FRAME_HEIGHT;
72    }
73
74    if ((IS_EVEN(pPlaneIn->u_width) == FALSE) ||
75        (IS_EVEN(pPlaneOut->u_width) == FALSE)) {
76        return M4VIFI_ILLEGAL_FRAME_WIDTH;
77    }
78
79    /* Set the working pointers at the beginning of the input/output data field */
80    pu16_data_in    = (M4VIFI_UInt16*)(pPlaneIn->pac_data + pPlaneIn->u_topleft);
81    pu16_data_out   = (M4VIFI_UInt16*)(pPlaneOut->pac_data + pPlaneOut->u_topleft);
82
83    /* Get the memory jump corresponding to a row jump */
84    u32_stride_in   = pPlaneIn->u_stride;
85    u32_stride_out  = pPlaneOut->u_stride;
86
87    /* Set the bounds of the active image */
88    u32_width_in    = pPlaneIn->u_width;
89    u32_height_in   = pPlaneIn->u_height;
90
91    u32_width_out   = pPlaneOut->u_width;
92    u32_height_out  = pPlaneOut->u_height;
93
94    /* Compute horizontal ratio between src and destination width.*/
95    if (u32_width_out >= u32_width_in) {
96        u32_x_inc   = ((u32_width_in-1) * MAX_SHORT) / (u32_width_out-1);
97    } else {
98        u32_x_inc   = (u32_width_in * MAX_SHORT) / (u32_width_out);
99    }
100
101    /* Compute vertical ratio between src and destination height.*/
102    if (u32_height_out >= u32_height_in) {
103        u32_y_inc   = ((u32_height_in - 1) * MAX_SHORT) / (u32_height_out-1);
104    } else {
105        u32_y_inc = (u32_height_in * MAX_SHORT) / (u32_height_out);
106    }
107
108    /*
109    Calculate initial accumulator value : u32_y_accum_start.
110    u32_y_accum_start is coded on 15 bits, and represents a value between 0 and 0.5
111    */
112    if (u32_y_inc >= MAX_SHORT) {
113        /*
114            Keep the fractional part, integer  part is coded
115            on the 16 high bits and the fractionnal on the 15 low bits
116        */
117        u32_y_accum = u32_y_inc & 0xffff;
118
119        if (!u32_y_accum)
120        {
121            u32_y_accum = MAX_SHORT;
122        }
123
124        u32_y_accum >>= 1;
125    } else {
126        u32_y_accum = 0;
127    }
128
129    /*
130        Calculate initial accumulator value : u32_x_accum_start.
131        u32_x_accum_start is coded on 15 bits, and represents a value between 0 and 0.5
132    */
133    if (u32_x_inc >= MAX_SHORT) {
134        u32_x_accum_start = u32_x_inc & 0xffff;
135
136        if (!u32_x_accum_start) {
137            u32_x_accum_start = MAX_SHORT;
138        }
139
140        u32_x_accum_start >>= 1;
141    } else {
142        u32_x_accum_start = 0;
143    }
144
145    u32_height = u32_height_out;
146
147    /*
148    Bilinear interpolation linearly interpolates along each row, and then uses that
149    result in a linear interpolation donw each column. Each estimated pixel in the
150    output image is a weighted combination of its four neighbours according to the formula:
151    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)
152    with  R(x) = / x+1  -1 =< x =< 0 \ 1-x  0 =< x =< 1 and a (resp. b)weighting coefficient
153    is the distance from the nearest neighbor in the p (resp. q) direction
154    */
155
156    do { /* Scan all the row */
157
158        /* Vertical weight factor */
159        u32_y_frac = (u32_y_accum>>12)&15;
160
161        /* Reinit accumulator */
162        u32_x_accum = u32_x_accum_start;
163
164        u32_width = u32_width_out;
165
166        do { /* Scan along each row */
167            pu16_src_top = pu16_data_in + (u32_x_accum >> 16);
168            pu16_src_bottom = pu16_src_top + (u32_stride_in>>1);
169            u32_x_frac = (u32_x_accum >> 12)&15; /* Horizontal weight factor */
170
171            /* Weighted combination */
172            if ((u32_height == 1) && (u32_height_in == u32_height_out)) {
173                GET_RGB565(i32_b00,i32_g00,i32_r00,(M4VIFI_UInt16)pu16_src_top[0]);
174                GET_RGB565(i32_b01,i32_g01,i32_r01,(M4VIFI_UInt16)pu16_src_top[1]);
175                GET_RGB565(i32_b02,i32_g02,i32_r02,(M4VIFI_UInt16)pu16_src_top[0]);
176                GET_RGB565(i32_b03,i32_g03,i32_r03,(M4VIFI_UInt16)pu16_src_top[1]);
177            } else {
178                GET_RGB565(i32_b00,i32_g00,i32_r00,(M4VIFI_UInt16)pu16_src_top[0]);
179                GET_RGB565(i32_b01,i32_g01,i32_r01,(M4VIFI_UInt16)pu16_src_top[1]);
180                GET_RGB565(i32_b02,i32_g02,i32_r02,(M4VIFI_UInt16)pu16_src_bottom[0]);
181                GET_RGB565(i32_b03,i32_g03,i32_r03,(M4VIFI_UInt16)pu16_src_bottom[1]);
182
183            }
184
185            /* Solution to avoid green effects due to transparency */
186            count_trans = 0;
187
188            /* If RGB is transparent color (0, 63, 0), we transform it to white (31,63,31) */
189            if (i32_b00 == 0 && i32_g00 == 63 && i32_r00 == 0)
190            {
191                i32_b00 = 31;
192                i32_r00 = 31;
193                count_trans++;
194            }
195            if (i32_b01 == 0 && i32_g01 == 63 && i32_r01 == 0)
196            {
197                i32_b01 = 31;
198                i32_r01 = 31;
199                count_trans++;
200            }
201            if (i32_b02 == 0 && i32_g02 == 63 && i32_r02 == 0)
202            {
203                i32_b02 = 31;
204                i32_r02 = 31;
205                count_trans++;
206            }
207            if (i32_b03 == 0 && i32_g03 == 63 && i32_r03 == 0)
208            {
209                i32_b03 = 31;
210                i32_r03 = 31;
211                count_trans++;
212            }
213
214            if (count_trans > 2) {
215                /* pixel is transparent */
216                u32_Rtemp_value = 0;
217                u32_Gtemp_value = 63;
218                u32_Btemp_value = 0;
219            } else {
220                u32_Rtemp_value = (M4VIFI_UInt8)(((i32_r00*(16-u32_x_frac) +
221                                 i32_r01*u32_x_frac)*(16-u32_y_frac) +
222                                (i32_r02*(16-u32_x_frac) +
223                                 i32_r03*u32_x_frac)*u32_y_frac )>>8);
224
225                u32_Gtemp_value = (M4VIFI_UInt8)(((i32_g00*(16-u32_x_frac) +
226                                 i32_g01*u32_x_frac)*(16-u32_y_frac) +
227                                (i32_g02*(16-u32_x_frac) +
228                                 i32_g03*u32_x_frac)*u32_y_frac )>>8);
229
230                u32_Btemp_value =  (M4VIFI_UInt8)(((i32_b00*(16-u32_x_frac) +
231                                 i32_b01*u32_x_frac)*(16-u32_y_frac) +
232                                (i32_b02*(16-u32_x_frac) +
233                                 i32_b03*u32_x_frac)*u32_y_frac )>>8);
234            }
235
236            *pu16_data_out++ = (M4VIFI_UInt16)( (((u32_Gtemp_value & 0x38) >> 3) | (u32_Btemp_value << 3)) |\
237                                ( (((u32_Gtemp_value & 0x7) << 5 ) | u32_Rtemp_value)<<8 ));
238
239            /* Update horizontal accumulator */
240            u32_x_accum += u32_x_inc;
241
242        } while(--u32_width);
243
244
245        /* Update vertical accumulator */
246        u32_y_accum += u32_y_inc;
247        if (u32_y_accum>>16) {
248            pu16_data_in = pu16_data_in + (u32_y_accum >> 16) * (u32_stride_in>>1);
249            u32_y_accum &= 0xffff;
250        }
251
252    } while(--u32_height);
253
254    return M4VIFI_OK;
255}
256
257