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 */ 58 M4VIFI_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