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