1 /****************************************************************************** 2 * 3 * Copyright (C) 2015 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 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore 19 */ 20 /** 21 ******************************************************************************* 22 * @file 23 * ideint_utils.c 24 * 25 * @brief 26 * This file contains the definitions of the core processing of the de 27 * interlacer. 28 * 29 * @author 30 * Ittiam 31 * 32 * @par List of Functions: 33 * ideint_weave_pic() 34 * init_bob_indices() 35 * ideint_weave_blk() 36 * ideint_spatial_filter() 37 * 38 * @remarks 39 * None 40 * 41 ******************************************************************************* 42 */ 43 /*****************************************************************************/ 44 /* File Includes */ 45 /*****************************************************************************/ 46 /* System include files */ 47 #include <stdio.h> 48 #include <stdint.h> 49 #include <string.h> 50 #include <stdlib.h> 51 #include <assert.h> 52 53 54 /* User include files */ 55 #include "icv_datatypes.h" 56 #include "icv_macros.h" 57 #include "icv_platform_macros.h" 58 #include "icv.h" 59 #include "icv_variance.h" 60 #include "icv_sad.h" 61 #include "ideint.h" 62 #include "ideint_defs.h" 63 #include "ideint_structs.h" 64 #include "ideint_utils.h" 65 #include "ideint_cac.h" 66 67 /** 68 ******************************************************************************* 69 * 70 * @brief 71 * Weaves two fields to produce a frame 72 * 73 * @par Description 74 * Weaves two fields to produce a frame 75 * 76 * @param[in] ps_src_top 77 * Top field source 78 * 79 * @param[in] ps_src_bot 80 * Bottom field source 81 * 82 * @param[in] ps_dst_frm 83 * Destination frame 84 * 85 * @returns 86 * 0 on Success 87 * 88 * @remarks 89 * 90 ******************************************************************************* 91 */ 92 WORD32 ideint_weave_pic(icv_pic_t *ps_src_top, 93 icv_pic_t *ps_src_bot, 94 icv_pic_t *ps_dst_frm, 95 WORD32 start_row, 96 WORD32 num_rows) 97 { 98 UWORD8 *pu1_src, *pu1_dst; 99 WORD32 i, j, num_comp; 100 icv_pic_t *ps_src_fld; 101 WORD32 fld; 102 icv_pic_t *ps_src_flds[2]; 103 104 num_comp = 3; 105 ps_src_flds[0] = ps_src_top; 106 ps_src_flds[1] = ps_src_bot; 107 108 for(fld = 0; fld < 2; fld++) 109 { 110 ps_src_fld = ps_src_flds[fld]; 111 for(i = 0; i < num_comp; i++) 112 { 113 WORD32 src_strd; 114 WORD32 dst_strd; 115 WORD32 comp_row_start, comp_row_end; 116 comp_row_start = start_row; 117 comp_row_end = comp_row_start + num_rows; 118 if(i) 119 { 120 comp_row_start >>= 1; 121 comp_row_end >>= 1; 122 } 123 124 comp_row_end = MIN(comp_row_end, ps_dst_frm->ai4_ht[i]); 125 126 pu1_src = ps_src_fld->apu1_buf[i]; 127 pu1_dst = ps_dst_frm->apu1_buf[i]; 128 129 src_strd = ps_src_fld->ai4_strd[i]; 130 dst_strd = ps_dst_frm->ai4_strd[i]; 131 132 /* If source field is bottom, increment destination */ 133 pu1_dst += fld * dst_strd; 134 135 /* In case input and output are pointing to same buffer, then no need to copy */ 136 if((pu1_src != pu1_dst) || ((2 * dst_strd) != src_strd)) 137 { 138 pu1_dst += ps_dst_frm->ai4_strd[i] * comp_row_start; 139 pu1_src += ps_src_fld->ai4_strd[i] * comp_row_start / 2; 140 141 for(j = comp_row_start; j < comp_row_end; j += 2) 142 { 143 memcpy(pu1_dst, pu1_src, ps_dst_frm->ai4_wd[i]); 144 pu1_dst += ps_dst_frm->ai4_strd[i] * 2; 145 pu1_src += ps_src_fld->ai4_strd[i]; 146 } 147 } 148 } 149 } 150 return 0; 151 } 152 153 154 /** 155 ******************************************************************************* 156 * 157 * @brief 158 * Weaves a 8x8 block 159 * 160 * @par Description 161 * Weaves a 8x8 block from two fields 162 * 163 * @param[in] pu1_top 164 * Top field source 165 * 166 * @param[in] pu1_bot 167 * Bottom field source 168 * 169 * @param[in] pu1_dst 170 * Destination 171 * 172 * @param[in] dst_strd 173 * Destination stride 174 * 175 * @param[in] src_strd 176 * Source stride 177 * 178 * @returns 179 * 0 on success 180 * 181 * @remarks 182 * 183 ******************************************************************************* 184 */ 185 WORD32 ideint_weave_blk(UWORD8 *pu1_top, 186 UWORD8 *pu1_bot, 187 UWORD8 *pu1_dst, 188 WORD32 dst_strd, 189 WORD32 src_strd, 190 WORD32 wd, 191 WORD32 ht) 192 { 193 WORD32 j; 194 195 for(j = 0; j < ht; j += 2) 196 { 197 memcpy(pu1_dst, pu1_top, wd); 198 pu1_dst += dst_strd; 199 pu1_top += src_strd; 200 201 memcpy(pu1_dst, pu1_bot, wd); 202 pu1_dst += dst_strd; 203 pu1_bot += src_strd; 204 } 205 return 0; 206 } 207 208 /** 209 ******************************************************************************* 210 * 211 * @brief 212 * Copy a boundary block and pad 213 * 214 * @par Description 215 * Copies a block on one of the boundaries and pads 216 * 217 * @param[in] pu1_top 218 * Top field source 219 * 220 * @param[in] pu1_bot 221 * Bottom field source 222 * 223 * @param[in] pu1_pad 224 * Padded destination 225 * 226 * @param[in] cur_strd 227 * Stride for pu1_top and pu1_bot 228 * 229 * @param[in] row 230 * Current block's row 231 * 232 * @param[in] col 233 * Current block's column 234 * 235 * @param[in] num_blks_y 236 * Number of blocks in Y direction 237 * 238 * @param[in] num_blks_x 239 * Number of blocks in X direction 240 241 * @returns 242 * None 243 * 244 * @remarks 245 * 246 ******************************************************************************* 247 */ 248 void ideint_pad_blk(UWORD8 *pu1_top, 249 UWORD8 *pu1_bot, 250 UWORD8 *pu1_pad, 251 WORD32 cur_strd, 252 WORD32 row, 253 WORD32 col, 254 WORD32 num_blks_y, 255 WORD32 num_blks_x, 256 WORD32 blk_wd, 257 WORD32 blk_ht) 258 { 259 WORD32 i; 260 WORD32 num_cols, num_rows; 261 UWORD8 *pu1_dst; 262 UWORD8 *pu1_src_top; 263 UWORD8 *pu1_src_bot; 264 265 num_rows = blk_ht + 4; 266 num_cols = blk_wd + 4; 267 268 pu1_src_top = pu1_top - cur_strd - 2; 269 pu1_src_bot = pu1_bot - cur_strd - 2; 270 pu1_dst = pu1_pad; 271 272 if(0 == col) 273 { 274 num_cols -= 2; 275 pu1_dst += 2; 276 pu1_src_top += 2; 277 pu1_src_bot += 2; 278 } 279 280 if(0 == row) 281 { 282 num_rows -= 2; 283 pu1_dst += 2 * (BLK_WD + 4); 284 pu1_src_top += cur_strd; 285 pu1_src_bot += cur_strd; 286 } 287 288 if((num_blks_x - 1) == col) 289 num_cols -= 2; 290 291 if((num_blks_y - 1) == row) 292 num_rows -= 2; 293 294 for(i = 0; i < num_rows; i += 2) 295 { 296 memcpy(pu1_dst, pu1_src_top, num_cols); 297 pu1_dst += (BLK_WD + 4); 298 299 memcpy(pu1_dst, pu1_src_bot, num_cols); 300 pu1_dst += (BLK_WD + 4); 301 302 pu1_src_top += cur_strd; 303 pu1_src_bot += cur_strd; 304 } 305 306 307 /* Pad Left */ 308 if(0 == col) 309 { 310 for(i = 0; i < (BLK_HT + 4); i++) 311 { 312 WORD32 ofst = i * (BLK_WD + 4) + 2; 313 pu1_pad[ofst - 1] = pu1_pad[ofst]; 314 pu1_pad[ofst - 2] = pu1_pad[ofst]; 315 } 316 } 317 318 /* Pad right */ 319 if((num_blks_x - 1) == col) 320 { 321 for(i = 0; i < (BLK_HT + 4); i++) 322 { 323 WORD32 ofst = i * (BLK_WD + 4) + 2 + blk_wd - 1; 324 WORD32 size = (BLK_WD - blk_wd) + 2; 325 /* Padding on right should include padding for boundary 326 * blocks when width is non-multiple of 8 327 */ 328 memset(&pu1_pad[ofst + 1], pu1_pad[ofst], size); 329 } 330 } 331 332 /* Pad Top */ 333 if(0 == row) 334 { 335 WORD32 src_ofst = 2 * (BLK_WD + 4); 336 WORD32 dst_ofst = 0; 337 memcpy(pu1_pad + dst_ofst, pu1_pad + src_ofst, (BLK_WD + 4)); 338 src_ofst += (BLK_WD + 4); 339 dst_ofst += (BLK_WD + 4); 340 memcpy(pu1_pad + dst_ofst, pu1_pad + src_ofst, (BLK_WD + 4)); 341 } 342 343 /* Pad Bottom */ 344 if((num_blks_y - 1) == row) 345 { 346 WORD32 src_ofst = (0 + blk_ht) * (BLK_WD + 4); 347 WORD32 dst_ofst = (1 + blk_ht) * (BLK_WD + 4); 348 WORD32 size = (BLK_HT - blk_ht) + 2; 349 350 /* Padding on bottom should include padding for boundary 351 * blocks when height is non-multiple of 8 352 */ 353 for(i = 0; i < size; i++) 354 { 355 memcpy(pu1_pad + dst_ofst, pu1_pad + src_ofst, (BLK_WD + 4)); 356 dst_ofst += (BLK_WD + 4); 357 } 358 } 359 } 360 361 /** 362 ******************************************************************************* 363 * 364 * @brief 365 * Performs spatial edge adaptive filtering 366 * 367 * @par Description 368 * Performs spatial edge adaptive filtering by detecting edge direction 369 * 370 * @param[in] pu1_src 371 * Source buffer 372 * 373 * @param[in] pu1_out 374 * Destination buffer 375 * 376 * @param[in] src_strd 377 * Source stride 378 * 379 * @param[in] out_strd 380 * Destination stride 381 382 * @returns 383 * None 384 * 385 * @remarks 386 * 387 ******************************************************************************* 388 */ 389 void ideint_spatial_filter(UWORD8 *pu1_src, 390 UWORD8 *pu1_out, 391 WORD32 src_strd, 392 WORD32 out_strd) 393 { 394 WORD32 i; 395 WORD32 j; 396 WORD32 k; 397 398 /*********************************************************************/ 399 /* This loop is for the two halves inside the 8x4 block. */ 400 /*********************************************************************/ 401 for(k = 0; k < 2; k++) 402 { 403 WORD32 adiff[3] = {0, 0, 0}; 404 WORD32 shift; 405 WORD32 dir_45_le_90, dir_45_le_135, dir_135_le_90; 406 UWORD8 *pu1_row_1, *pu1_row_2, *pu1_dst; 407 408 /*****************************************************************/ 409 /* Direction detection */ 410 /*****************************************************************/ 411 pu1_row_1 = pu1_src; 412 pu1_row_2 = pu1_src + src_strd; 413 414 /*****************************************************************/ 415 /* Calculating the difference along each of the 3 directions. */ 416 /*****************************************************************/ 417 for(j = 0; j < SUB_BLK_HT; j ++) 418 { 419 for(i = 0; i < SUB_BLK_WD; i++) 420 { 421 adiff[0] += ABS_DIF(pu1_row_1[i], pu1_row_2[i]); /* 90 */ 422 423 adiff[1] += ABS_DIF(pu1_row_1[i - 1], pu1_row_2[i + 1]); /* 135 */ 424 425 adiff[2] += ABS_DIF(pu1_row_1[i + 1], pu1_row_2[i - 1]); /* 45 */ 426 } 427 pu1_row_1 += src_strd; 428 pu1_row_2 += src_strd; 429 } 430 431 /*****************************************************************/ 432 /* Applying bias, to make the diff comparision more robust. */ 433 /*****************************************************************/ 434 adiff[0] *= EDGE_BIAS_0; 435 adiff[1] *= EDGE_BIAS_1; 436 adiff[2] *= EDGE_BIAS_1; 437 438 /*****************************************************************/ 439 /* comapring the diffs */ 440 /*****************************************************************/ 441 dir_45_le_90 = (adiff[2] <= adiff[0]); 442 dir_45_le_135 = (adiff[2] <= adiff[1]); 443 dir_135_le_90 = (adiff[1] <= adiff[0]); 444 445 /*****************************************************************/ 446 /* Direction selection. */ 447 /*****************************************************************/ 448 shift = 0; 449 if(1 == dir_45_le_135) 450 { 451 if(1 == dir_45_le_90) 452 shift = 1; 453 } 454 else 455 { 456 if(1 == dir_135_le_90) 457 shift = -1; 458 } 459 460 /*****************************************************************/ 461 /* Directional interpolation */ 462 /*****************************************************************/ 463 pu1_row_1 = pu1_src + shift; 464 pu1_row_2 = pu1_src + src_strd - shift; 465 pu1_dst = pu1_out; 466 467 for(j = 0; j < SUB_BLK_HT; j++) 468 { 469 for(i = 0; i < SUB_BLK_WD; i++) 470 { 471 pu1_dst[i] = (UWORD8)AVG(pu1_row_1[i], pu1_row_2[i]); 472 } 473 pu1_row_1 += src_strd; 474 pu1_row_2 += src_strd; 475 pu1_dst += out_strd; 476 } 477 478 pu1_out += SUB_BLK_WD; 479 pu1_src += SUB_BLK_WD; 480 } 481 } 482 483