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