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 ****************************************************************************** 19 * @file M4VIFI_ResizeRGB565toRGB565.c 20 * @brief Contain video library function 21 * @note This file has a Resize filter function 22 * Generic resizing of RGB565 (Planar) image 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_ResizeBilinearRGB565toRGB565(void *pUserData, M4VIFI_ImagePlane *pPlaneIn, 35 * M4VIFI_ImagePlane *pPlaneOut) 36 * @brief Resizes RGB565 Planar plane. 37 * @param pUserData: (IN) User Data 38 * @param pPlaneIn: (IN) Pointer to RGB565 (Planar) plane buffer 39 * @param pPlaneOut: (OUT) Pointer to RGB565 (Planar) plane 40 * @return M4VIFI_OK: there is no error 41 * @return M4VIFI_ILLEGAL_FRAME_HEIGHT: Error in height 42 * @return M4VIFI_ILLEGAL_FRAME_WIDTH: Error in width 43 *********************************************************************************************** 44 */ 45 M4VIFI_UInt8 M4VIFI_ResizeBilinearRGB565toRGB565(void *pUserData, 46 M4VIFI_ImagePlane *pPlaneIn, 47 M4VIFI_ImagePlane *pPlaneOut) 48 { 49 M4VIFI_UInt16 *pu16_data_in; 50 M4VIFI_UInt16 *pu16_data_out; 51 M4VIFI_UInt32 u32_width_in, u32_width_out, u32_height_in, u32_height_out; 52 M4VIFI_UInt32 u32_stride_in, u32_stride_out; 53 M4VIFI_UInt32 u32_x_inc, u32_y_inc; 54 M4VIFI_UInt32 u32_x_accum, u32_y_accum, u32_x_accum_start; 55 M4VIFI_UInt32 u32_width, u32_height; 56 M4VIFI_UInt32 u32_y_frac; 57 M4VIFI_UInt32 u32_x_frac; 58 M4VIFI_UInt32 u32_Rtemp_value,u32_Gtemp_value,u32_Btemp_value; 59 M4VIFI_UInt16 *pu16_src_top; 60 M4VIFI_UInt16 *pu16_src_bottom; 61 M4VIFI_UInt32 i32_b00, i32_g00, i32_r00; 62 M4VIFI_UInt32 i32_b01, i32_g01, i32_r01; 63 M4VIFI_UInt32 i32_b02, i32_g02, i32_r02; 64 M4VIFI_UInt32 i32_b03, i32_g03, i32_r03; 65 M4VIFI_UInt8 count_trans=0; 66 67 /* Check for the RGB width and height are even */ 68 if ((IS_EVEN(pPlaneIn->u_height) == FALSE) || 69 (IS_EVEN(pPlaneOut->u_height) == FALSE)) { 70 return M4VIFI_ILLEGAL_FRAME_HEIGHT; 71 } 72 73 if ((IS_EVEN(pPlaneIn->u_width) == FALSE) || 74 (IS_EVEN(pPlaneOut->u_width) == FALSE)) { 75 return M4VIFI_ILLEGAL_FRAME_WIDTH; 76 } 77 78 /* Set the working pointers at the beginning of the input/output data field */ 79 pu16_data_in = (M4VIFI_UInt16*)(pPlaneIn->pac_data + pPlaneIn->u_topleft); 80 pu16_data_out = (M4VIFI_UInt16*)(pPlaneOut->pac_data + pPlaneOut->u_topleft); 81 82 /* Get the memory jump corresponding to a row jump */ 83 u32_stride_in = pPlaneIn->u_stride; 84 u32_stride_out = pPlaneOut->u_stride; 85 86 /* Set the bounds of the active image */ 87 u32_width_in = pPlaneIn->u_width; 88 u32_height_in = pPlaneIn->u_height; 89 90 u32_width_out = pPlaneOut->u_width; 91 u32_height_out = pPlaneOut->u_height; 92 93 /* Compute horizontal ratio between src and destination width.*/ 94 if (u32_width_out >= u32_width_in) { 95 u32_x_inc = ((u32_width_in-1) * MAX_SHORT) / (u32_width_out-1); 96 } else { 97 u32_x_inc = (u32_width_in * MAX_SHORT) / (u32_width_out); 98 } 99 100 /* Compute vertical ratio between src and destination height.*/ 101 if (u32_height_out >= u32_height_in) { 102 u32_y_inc = ((u32_height_in - 1) * MAX_SHORT) / (u32_height_out-1); 103 } else { 104 u32_y_inc = (u32_height_in * MAX_SHORT) / (u32_height_out); 105 } 106 107 /* 108 Calculate initial accumulator value : u32_y_accum_start. 109 u32_y_accum_start is coded on 15 bits, and represents a value between 0 and 0.5 110 */ 111 if (u32_y_inc >= MAX_SHORT) { 112 /* 113 Keep the fractional part, integer part is coded 114 on the 16 high bits and the fractionnal on the 15 low bits 115 */ 116 u32_y_accum = u32_y_inc & 0xffff; 117 118 if (!u32_y_accum) 119 { 120 u32_y_accum = MAX_SHORT; 121 } 122 123 u32_y_accum >>= 1; 124 } else { 125 u32_y_accum = 0; 126 } 127 128 /* 129 Calculate initial accumulator value : u32_x_accum_start. 130 u32_x_accum_start is coded on 15 bits, and represents a value between 0 and 0.5 131 */ 132 if (u32_x_inc >= MAX_SHORT) { 133 u32_x_accum_start = u32_x_inc & 0xffff; 134 135 if (!u32_x_accum_start) { 136 u32_x_accum_start = MAX_SHORT; 137 } 138 139 u32_x_accum_start >>= 1; 140 } else { 141 u32_x_accum_start = 0; 142 } 143 144 u32_height = u32_height_out; 145 146 /* 147 Bilinear interpolation linearly interpolates along each row, and then uses that 148 result in a linear interpolation donw each column. Each estimated pixel in the 149 output image is a weighted combination of its four neighbours according to the formula: 150 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) 151 with R(x) = / x+1 -1 =< x =< 0 \ 1-x 0 =< x =< 1 and a (resp. b)weighting coefficient 152 is the distance from the nearest neighbor in the p (resp. q) direction 153 */ 154 155 do { /* Scan all the row */ 156 157 /* Vertical weight factor */ 158 u32_y_frac = (u32_y_accum>>12)&15; 159 160 /* Reinit accumulator */ 161 u32_x_accum = u32_x_accum_start; 162 163 u32_width = u32_width_out; 164 165 do { /* Scan along each row */ 166 pu16_src_top = pu16_data_in + (u32_x_accum >> 16); 167 pu16_src_bottom = pu16_src_top + (u32_stride_in>>1); 168 u32_x_frac = (u32_x_accum >> 12)&15; /* Horizontal weight factor */ 169 170 /* Weighted combination */ 171 if ((u32_height == 1) && (u32_height_in == u32_height_out)) { 172 GET_RGB565(i32_b00,i32_g00,i32_r00,(M4VIFI_UInt16)pu16_src_top[0]); 173 GET_RGB565(i32_b01,i32_g01,i32_r01,(M4VIFI_UInt16)pu16_src_top[1]); 174 GET_RGB565(i32_b02,i32_g02,i32_r02,(M4VIFI_UInt16)pu16_src_top[0]); 175 GET_RGB565(i32_b03,i32_g03,i32_r03,(M4VIFI_UInt16)pu16_src_top[1]); 176 } else { 177 GET_RGB565(i32_b00,i32_g00,i32_r00,(M4VIFI_UInt16)pu16_src_top[0]); 178 GET_RGB565(i32_b01,i32_g01,i32_r01,(M4VIFI_UInt16)pu16_src_top[1]); 179 GET_RGB565(i32_b02,i32_g02,i32_r02,(M4VIFI_UInt16)pu16_src_bottom[0]); 180 GET_RGB565(i32_b03,i32_g03,i32_r03,(M4VIFI_UInt16)pu16_src_bottom[1]); 181 182 } 183 184 /* Solution to avoid green effects due to transparency */ 185 count_trans = 0; 186 187 /* If RGB is transparent color (0, 63, 0), we transform it to white (31,63,31) */ 188 if (i32_b00 == 0 && i32_g00 == 63 && i32_r00 == 0) 189 { 190 i32_b00 = 31; 191 i32_r00 = 31; 192 count_trans++; 193 } 194 if (i32_b01 == 0 && i32_g01 == 63 && i32_r01 == 0) 195 { 196 i32_b01 = 31; 197 i32_r01 = 31; 198 count_trans++; 199 } 200 if (i32_b02 == 0 && i32_g02 == 63 && i32_r02 == 0) 201 { 202 i32_b02 = 31; 203 i32_r02 = 31; 204 count_trans++; 205 } 206 if (i32_b03 == 0 && i32_g03 == 63 && i32_r03 == 0) 207 { 208 i32_b03 = 31; 209 i32_r03 = 31; 210 count_trans++; 211 } 212 213 if (count_trans > 2) { 214 /* pixel is transparent */ 215 u32_Rtemp_value = 0; 216 u32_Gtemp_value = 63; 217 u32_Btemp_value = 0; 218 } else { 219 u32_Rtemp_value = (M4VIFI_UInt8)(((i32_r00*(16-u32_x_frac) + 220 i32_r01*u32_x_frac)*(16-u32_y_frac) + 221 (i32_r02*(16-u32_x_frac) + 222 i32_r03*u32_x_frac)*u32_y_frac )>>8); 223 224 u32_Gtemp_value = (M4VIFI_UInt8)(((i32_g00*(16-u32_x_frac) + 225 i32_g01*u32_x_frac)*(16-u32_y_frac) + 226 (i32_g02*(16-u32_x_frac) + 227 i32_g03*u32_x_frac)*u32_y_frac )>>8); 228 229 u32_Btemp_value = (M4VIFI_UInt8)(((i32_b00*(16-u32_x_frac) + 230 i32_b01*u32_x_frac)*(16-u32_y_frac) + 231 (i32_b02*(16-u32_x_frac) + 232 i32_b03*u32_x_frac)*u32_y_frac )>>8); 233 } 234 235 *pu16_data_out++ = (M4VIFI_UInt16)( (((u32_Gtemp_value & 0x38) >> 3) | (u32_Btemp_value << 3)) |\ 236 ( (((u32_Gtemp_value & 0x7) << 5 ) | u32_Rtemp_value)<<8 )); 237 238 /* Update horizontal accumulator */ 239 u32_x_accum += u32_x_inc; 240 241 } while(--u32_width); 242 243 244 /* Update vertical accumulator */ 245 u32_y_accum += u32_y_inc; 246 if (u32_y_accum>>16) { 247 pu16_data_in = pu16_data_in + (u32_y_accum >> 16) * (u32_stride_in>>1); 248 u32_y_accum &= 0xffff; 249 } 250 251 } while(--u32_height); 252 253 return M4VIFI_OK; 254 } 255 256