summaryrefslogtreecommitdiffstats
path: root/libvideoeditor/vss/video_filters/src/M4VIFI_ResizeRGB888toRGB888.c
blob: deb9d440ba0883bb5f605bf4df0ff7da58072066 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 ******************************************************************************
 * @file     M4VIFI_ResizeYUV420toYUV420.c
 * @brief    Contain video library function
 * @note     This file has a Resize filter function
 *           -# Generic resizing of YUV420 (Planar) image
 ******************************************************************************
*/

/* Prototypes of functions, and type definitions */
#include    "M4VIFI_FiltersAPI.h"
/* Macro definitions */
#include    "M4VIFI_Defines.h"
/* Clip table declaration */
#include    "M4VIFI_Clip.h"

/**
 ***********************************************************************************************
 * M4VIFI_UInt8 M4VIFI_ResizeBilinearRGB888toRGB888(void *pUserData, M4VIFI_ImagePlane *pPlaneIn,
 *                                                                  M4VIFI_ImagePlane *pPlaneOut)
 * @brief   Resizes YUV420 Planar plane.
 * @note    Basic structure of the function
 *          Loop on each row (step 2)
 *              Loop on each column (step 2)
 *                  Get four Y samples and 1 U & V sample
 *                  Resize the Y with corresponing U and V samples
 *                  Place the YUV in the ouput plane
 *              end loop column
 *          end loop row
 *          For resizing bilinear interpolation linearly interpolates along
 *          each row, and then uses that result in a linear interpolation down each column.
 *          Each estimated pixel in the output image is a weighted
 *          combination of its four neighbours. The ratio of compression
 *          or dilatation is estimated using input and output sizes.
 * @param   pUserData: (IN) User Data
 * @param   pPlaneIn: (IN) Pointer to YUV420 (Planar) plane buffer
 * @param   pPlaneOut: (OUT) Pointer to YUV420 (Planar) plane
 * @return  M4VIFI_OK: there is no error
 * @return  M4VIFI_ILLEGAL_FRAME_HEIGHT: Error in height
 * @return  M4VIFI_ILLEGAL_FRAME_WIDTH:  Error in width
 ***********************************************************************************************
*/
M4VIFI_UInt8    M4VIFI_ResizeBilinearRGB888toRGB888(void *pUserData,
                                                                M4VIFI_ImagePlane *pPlaneIn,
                                                                M4VIFI_ImagePlane *pPlaneOut)
{
    M4VIFI_UInt8    *pu8_data_in;
    M4VIFI_UInt8    *pu8_data_out;
    M4VIFI_UInt32   u32_width_in, u32_width_out, u32_height_in, u32_height_out;
    M4VIFI_UInt32   u32_stride_in, u32_stride_out;
    M4VIFI_UInt32   u32_x_inc, u32_y_inc;
    M4VIFI_UInt32   u32_x_accum, u32_y_accum, u32_x_accum_start;
    M4VIFI_UInt32   u32_width, u32_height;
    M4VIFI_UInt32   u32_y_frac;
    M4VIFI_UInt32   u32_x_frac;
    M4VIFI_UInt32   u32_Rtemp_value,u32_Gtemp_value,u32_Btemp_value;
    M4VIFI_UInt8    *pu8_src_top;
    M4VIFI_UInt8    *pu8_src_bottom;
    M4VIFI_UInt32    i32_b00, i32_g00, i32_r00;
    M4VIFI_UInt32    i32_b01, i32_g01, i32_r01;
    M4VIFI_UInt32    i32_b02, i32_g02, i32_r02;
    M4VIFI_UInt32    i32_b03, i32_g03, i32_r03;

    /* Check for the YUV width and height are even */
    if ((IS_EVEN(pPlaneIn->u_height) == FALSE)    ||
        (IS_EVEN(pPlaneOut->u_height) == FALSE))
    {
        return M4VIFI_ILLEGAL_FRAME_HEIGHT;
    }

    if ((IS_EVEN(pPlaneIn->u_width) == FALSE) ||
        (IS_EVEN(pPlaneOut->u_width) == FALSE))
    {
        return M4VIFI_ILLEGAL_FRAME_WIDTH;
    }


        /* Set the working pointers at the beginning of the input/output data field */
        pu8_data_in     = (M4VIFI_UInt8*)(pPlaneIn->pac_data + pPlaneIn->u_topleft);
        pu8_data_out    = (M4VIFI_UInt8*)(pPlaneOut->pac_data + pPlaneOut->u_topleft);

        /* Get the memory jump corresponding to a row jump */
        u32_stride_in   = pPlaneIn->u_stride;
        u32_stride_out  = pPlaneOut->u_stride;

        /* Set the bounds of the active image */
        u32_width_in    = pPlaneIn->u_width;
        u32_height_in   = pPlaneIn->u_height;

        u32_width_out   = pPlaneOut->u_width;
        u32_height_out  = pPlaneOut->u_height;

        /* Compute horizontal ratio between src and destination width.*/
        if (u32_width_out >= u32_width_in)
        {
            u32_x_inc   = ((u32_width_in-1) * MAX_SHORT) / (u32_width_out-1);
        }
        else
        {
            u32_x_inc   = (u32_width_in * MAX_SHORT) / (u32_width_out);
        }

        /* Compute vertical ratio between src and destination height.*/
        if (u32_height_out >= u32_height_in)
        {
            u32_y_inc   = ((u32_height_in - 1) * MAX_SHORT) / (u32_height_out-1);
        }
        else
        {
            u32_y_inc = (u32_height_in * MAX_SHORT) / (u32_height_out);
        }

        /*
        Calculate initial accumulator value : u32_y_accum_start.
        u32_y_accum_start is coded on 15 bits, and represents a value between 0 and 0.5
        */
        if (u32_y_inc >= MAX_SHORT)
        {
            /*
                Keep the fractionnal part, assimung that integer  part is coded
                on the 16 high bits and the fractionnal on the 15 low bits
            */
            u32_y_accum = u32_y_inc & 0xffff;

            if (!u32_y_accum)
            {
                u32_y_accum = MAX_SHORT;
            }

            u32_y_accum >>= 1;
        }
        else
        {
            u32_y_accum = 0;
        }


        /*
            Calculate initial accumulator value : u32_x_accum_start.
            u32_x_accum_start is coded on 15 bits, and represents a value between 0 and 0.5
        */
        if (u32_x_inc >= MAX_SHORT)
        {
            u32_x_accum_start = u32_x_inc & 0xffff;

            if (!u32_x_accum_start)
            {
                u32_x_accum_start = MAX_SHORT;
            }

            u32_x_accum_start >>= 1;
        }
        else
        {
            u32_x_accum_start = 0;
        }

        u32_height = u32_height_out;

        /*
        Bilinear interpolation linearly interpolates along each row, and then uses that
        result in a linear interpolation donw each column. Each estimated pixel in the
        output image is a weighted combination of its four neighbours according to the formula:
        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)
        with  R(x) = / x+1  -1 =< x =< 0 \ 1-x  0 =< x =< 1 and a (resp. b)weighting coefficient
        is the distance from the nearest neighbor in the p (resp. q) direction
        */

        do { /* Scan all the row */

            /* Vertical weight factor */
            u32_y_frac = (u32_y_accum>>12)&15;

            /* Reinit accumulator */
            u32_x_accum = u32_x_accum_start;

            u32_width = u32_width_out;

            do { /* Scan along each row */
                pu8_src_top = pu8_data_in + (u32_x_accum >> 16)*3;
                pu8_src_bottom = pu8_src_top + (u32_stride_in);
                u32_x_frac = (u32_x_accum >> 12)&15; /* Horizontal weight factor */

                if ((u32_width == 1) && (u32_width_in == u32_width_out)) {
                    /*
                       When input height is equal to output height and input width
                       equal to output width, replicate the corner pixels for
                       interpolation
                    */
                    if ((u32_height == 1) && (u32_height_in == u32_height_out)) {
                        GET_RGB24(i32_b00,i32_g00,i32_r00,pu8_src_top,0);
                        GET_RGB24(i32_b01,i32_g01,i32_r01,pu8_src_top,0);
                        GET_RGB24(i32_b02,i32_g02,i32_r02,pu8_src_top,0);
                        GET_RGB24(i32_b03,i32_g03,i32_r03,pu8_src_top,0);
                    }
                    /*
                       When input height is not equal to output height and
                       input width equal to output width, replicate the
                       column for interpolation
                    */
                    else {
                        GET_RGB24(i32_b00,i32_g00,i32_r00,pu8_src_top,0);
                        GET_RGB24(i32_b01,i32_g01,i32_r01,pu8_src_top,0);
                        GET_RGB24(i32_b02,i32_g02,i32_r02,pu8_src_bottom,0);
                        GET_RGB24(i32_b03,i32_g03,i32_r03,pu8_src_bottom,0);
                    }
                } else {
                    /*
                       When input height is equal to output height and
                       input width not equal to output width, replicate the
                       row for interpolation
                    */
                    if ((u32_height == 1) && (u32_height_in == u32_height_out)) {
                        GET_RGB24(i32_b00,i32_g00,i32_r00,pu8_src_top,0);
                        GET_RGB24(i32_b01,i32_g01,i32_r01,pu8_src_top,3);
                        GET_RGB24(i32_b02,i32_g02,i32_r02,pu8_src_top,0);
                        GET_RGB24(i32_b03,i32_g03,i32_r03,pu8_src_top,3);
                    } else {
                        GET_RGB24(i32_b00,i32_g00,i32_r00,pu8_src_top,0);
                        GET_RGB24(i32_b01,i32_g01,i32_r01,pu8_src_top,3);
                        GET_RGB24(i32_b02,i32_g02,i32_r02,pu8_src_bottom,0);
                        GET_RGB24(i32_b03,i32_g03,i32_r03,pu8_src_bottom,3);
                    }
                }
                u32_Rtemp_value = (M4VIFI_UInt8)(((i32_r00*(16-u32_x_frac) +
                                 i32_r01*u32_x_frac)*(16-u32_y_frac) +
                                (i32_r02*(16-u32_x_frac) +
                                 i32_r03*u32_x_frac)*u32_y_frac )>>8);

                u32_Gtemp_value = (M4VIFI_UInt8)(((i32_g00*(16-u32_x_frac) +
                                 i32_g01*u32_x_frac)*(16-u32_y_frac) +
                                (i32_g02*(16-u32_x_frac) +
                                 i32_g03*u32_x_frac)*u32_y_frac )>>8);

                u32_Btemp_value =  (M4VIFI_UInt8)(((i32_b00*(16-u32_x_frac) +
                                 i32_b01*u32_x_frac)*(16-u32_y_frac) +
                                (i32_b02*(16-u32_x_frac) +
                                 i32_b03*u32_x_frac)*u32_y_frac )>>8);

                *pu8_data_out++ = u32_Btemp_value ;
                *pu8_data_out++ = u32_Gtemp_value ;
                *pu8_data_out++ = u32_Rtemp_value ;

                /* Update horizontal accumulator */
                u32_x_accum += u32_x_inc;

            } while(--u32_width);

            //pu16_data_out = pu16_data_out + (u32_stride_out>>1) - (u32_width_out);

            /* Update vertical accumulator */
            u32_y_accum += u32_y_inc;
            if (u32_y_accum>>16)
            {
                pu8_data_in = pu8_data_in + (u32_y_accum >> 16) * (u32_stride_in) ;
                u32_y_accum &= 0xffff;
            }
        } while(--u32_height);

    return M4VIFI_OK;
}
/* End of file M4VIFI_ResizeRGB565toRGB565.c */