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