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