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*/ 92WORD32 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*/ 185WORD32 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*/ 248void 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*/ 389void 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