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_api.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 * 34 * @remarks 35 * None 36 * 37 ******************************************************************************* 38 */ 39 /*****************************************************************************/ 40 /* File Includes */ 41 /*****************************************************************************/ 42 /* System include files */ 43 #include <stdio.h> 44 #include <stdint.h> 45 #include <string.h> 46 #include <stdlib.h> 47 #include <assert.h> 48 49 /* User include files */ 50 #include "icv_datatypes.h" 51 #include "icv_macros.h" 52 #include "icv_platform_macros.h" 53 #include "icv.h" 54 #include "icv_variance.h" 55 #include "icv_sad.h" 56 #include "ideint.h" 57 58 #include "ideint_defs.h" 59 #include "ideint_structs.h" 60 61 #include "ideint_utils.h" 62 #include "ideint_cac.h" 63 #include "ideint_debug.h" 64 #include "ideint_function_selector.h" 65 66 /** 67 ******************************************************************************* 68 * 69 * @brief 70 * Return deinterlacer context size 71 * 72 * @par Description 73 * Return deinterlacer context size, application will allocate this memory 74 * and send it as context to process call 75 * 76 * @param[in] None 77 * 78 * @returns 79 * Size of deinterlacer context 80 * 81 * @remarks 82 * None 83 * 84 ******************************************************************************* 85 */ 86 WORD32 ideint_ctxt_size(void) 87 { 88 return sizeof(ctxt_t); 89 } 90 91 /** 92 ******************************************************************************* 93 * 94 * @brief 95 * Deinterlace given fields and produce a frame 96 * 97 * @par Description 98 * Deinterlacer function that deinterlaces given fields and produces a frame 99 * 100 * @param[in] pv_ctxt 101 * Deinterlacer context returned by ideint_create() 102 * 103 * @param[in] ps_prv_fld 104 * Previous field (can be null, in which case spatial filtering is done 105 * unconditionally) 106 * 107 * @param[in] ps_cur_fld 108 * Current field 109 * 110 * @param[in] ps_nxt_fld 111 * Next field 112 * 113 * @param[in] ps_out_frm 114 * Output frame 115 * 116 * @param[in] ps_params 117 * Parameters 118 * 119 * @param[in] start_row 120 * Start row 121 * 122 * @param[in] num_rows 123 * Number of rows to be processed 124 * 125 * @returns 126 * IDEINT_ERROR_T 127 * 128 * @remarks 129 * 130 ******************************************************************************* 131 */ 132 IDEINT_ERROR_T ideint_process(void *pv_ctxt, 133 icv_pic_t *ps_prv_fld, 134 icv_pic_t *ps_cur_fld, 135 icv_pic_t *ps_nxt_fld, 136 icv_pic_t *ps_out_frm, 137 ideint_params_t *ps_params, 138 WORD32 start_row, 139 WORD32 num_rows) 140 { 141 ctxt_t *ps_ctxt; 142 WORD32 num_blks_x, num_blks_y; 143 WORD32 num_comp; 144 WORD32 i, row, col; 145 WORD32 rows_remaining; 146 147 if(NULL == pv_ctxt) 148 return IDEINT_INVALID_CTXT; 149 150 ps_ctxt = (ctxt_t *)pv_ctxt; 151 152 /* Copy the parameters */ 153 if(ps_params) 154 { 155 ps_ctxt->s_params = *ps_params; 156 } 157 else 158 { 159 /* Use default params if ps_params is NULL */ 160 ps_ctxt->s_params.i4_cur_fld_top = 1; 161 ps_ctxt->s_params.e_mode = IDEINT_MODE_SPATIAL; 162 ps_ctxt->s_params.e_arch = ideint_default_arch(); 163 ps_ctxt->s_params.e_soc = ICV_SOC_GENERIC; 164 ps_ctxt->s_params.i4_disable_weave = 0; 165 ps_ctxt->s_params.pf_aligned_alloc = NULL; 166 ps_ctxt->s_params.pf_aligned_free = NULL; 167 } 168 169 /* Start row has to be multiple of 8 */ 170 if(start_row & 0x7) 171 { 172 return IDEINT_START_ROW_UNALIGNED; 173 } 174 175 /* Initialize variances */ 176 ps_ctxt->ai4_vrnc_avg_fb[0] = VAR_AVG_LUMA; 177 ps_ctxt->ai4_vrnc_avg_fb[1] = VAR_AVG_CHROMA; 178 ps_ctxt->ai4_vrnc_avg_fb[2] = VAR_AVG_CHROMA; 179 180 ideint_init_function_ptr(ps_ctxt); 181 182 rows_remaining = ps_out_frm->ai4_ht[0] - start_row; 183 num_rows = MIN(num_rows, 184 rows_remaining); 185 186 IDEINT_CORRUPT_PIC(ps_out_frm, 0xCD); 187 188 //Weave two fields to get a frame 189 if(IDEINT_MODE_WEAVE == ps_ctxt->s_params.e_mode) 190 { 191 if(0 == ps_ctxt->s_params.i4_disable_weave) 192 { 193 if(ps_ctxt->s_params.i4_cur_fld_top) 194 ideint_weave_pic(ps_cur_fld, ps_nxt_fld, ps_out_frm, 195 start_row, 196 num_rows); 197 else 198 ideint_weave_pic(ps_nxt_fld, ps_cur_fld, ps_out_frm, 199 start_row, 200 num_rows); 201 } 202 return IDEINT_ERROR_NONE; 203 } 204 205 num_comp = 3; 206 207 for(i = 0; i < num_comp; i++) 208 { 209 UWORD8 *pu1_prv, *pu1_out; 210 UWORD8 *pu1_top, *pu1_bot, *pu1_dst; 211 WORD32 cur_strd, out_strd, dst_strd; 212 213 WORD32 st_thresh; 214 WORD32 vrnc_avg_st; 215 WORD32 disable_cac_sad; 216 WORD32 comp_row_start, comp_row_end; 217 num_blks_x = ALIGN8(ps_out_frm->ai4_wd[i]) >> 3; 218 num_blks_y = ALIGN8(ps_out_frm->ai4_ht[i]) >> 3; 219 comp_row_start = start_row; 220 comp_row_end = comp_row_start + num_rows; 221 222 if(i) 223 { 224 comp_row_start >>= 1; 225 comp_row_end >>= 1; 226 } 227 228 comp_row_end = MIN(comp_row_end, ps_out_frm->ai4_ht[i]); 229 230 comp_row_start = ALIGN8(comp_row_start) >> 3; 231 comp_row_end = ALIGN8(comp_row_end) >> 3; 232 st_thresh = ST_THRESH; 233 vrnc_avg_st = VAR_AVG_LUMA; 234 235 if(i) 236 { 237 st_thresh = ST_THRESH >> 1; 238 vrnc_avg_st = VAR_AVG_CHROMA; 239 } 240 241 out_strd = ps_out_frm->ai4_strd[i]; 242 if(ps_ctxt->s_params.i4_cur_fld_top) 243 { 244 cur_strd = ps_cur_fld->ai4_strd[i]; 245 } 246 else 247 { 248 cur_strd = ps_nxt_fld->ai4_strd[i]; 249 } 250 251 252 disable_cac_sad = 0; 253 /* If previous field is not provided, then change to SPATIAL mode */ 254 if(ps_prv_fld->apu1_buf[i] == NULL) 255 { 256 disable_cac_sad = 1; 257 } 258 259 for(row = comp_row_start; row < comp_row_end; row++) 260 { 261 pu1_out = ps_out_frm->apu1_buf[i]; 262 pu1_out += (ps_out_frm->ai4_strd[i] * row << 3); 263 264 pu1_prv = ps_prv_fld->apu1_buf[i]; 265 pu1_prv += (ps_prv_fld->ai4_strd[i] * row << 2); 266 267 if(ps_ctxt->s_params.i4_cur_fld_top) 268 { 269 pu1_top = ps_cur_fld->apu1_buf[i]; 270 pu1_bot = ps_nxt_fld->apu1_buf[i]; 271 } 272 else 273 { 274 pu1_top = ps_nxt_fld->apu1_buf[i]; 275 pu1_bot = ps_cur_fld->apu1_buf[i]; 276 } 277 pu1_top += (cur_strd * row << 2); 278 pu1_bot += (cur_strd * row << 2); 279 280 for(col = 0; col < num_blks_x; col++) 281 { 282 WORD32 cac, sad, vrnc; 283 WORD32 th_num, th_den; 284 UWORD8 au1_dst[BLK_WD * BLK_HT]; 285 WORD32 blk_wd, blk_ht; 286 WORD32 input_boundary; 287 cac = 0; 288 sad = 0; 289 th_den = 0; 290 th_num = st_thresh; 291 vrnc = 0; 292 293 disable_cac_sad = 0; 294 /* If previous field is not provided, then change to SPATIAL mode */ 295 if(ps_prv_fld->apu1_buf[i] == NULL) 296 { 297 disable_cac_sad = 1; 298 } 299 /* For boundary blocks when input dimensions are not multiple of 8, 300 * then change to spatial mode */ 301 input_boundary = 0; 302 303 blk_wd = BLK_WD; 304 blk_ht = BLK_HT; 305 306 if((((num_blks_x - 1) == col) && (ps_out_frm->ai4_wd[i] & 0x7)) || 307 (((num_blks_y - 1) == row) && (ps_out_frm->ai4_ht[i] & 0x7))) 308 { 309 disable_cac_sad = 1; 310 input_boundary = 1; 311 312 if(((num_blks_x - 1) == col) && (ps_out_frm->ai4_wd[i] & 0x7)) 313 blk_wd = (ps_out_frm->ai4_wd[i] & 0x7); 314 315 if(((num_blks_y - 1) == row) && (ps_out_frm->ai4_ht[i] & 0x7)) 316 blk_ht = (ps_out_frm->ai4_ht[i] & 0x7); 317 318 } 319 320 if(0 == disable_cac_sad) 321 { 322 /* Compute SAD */ 323 PROFILE_DISABLE_SAD 324 sad = ps_ctxt->pf_sad_8x4(pu1_prv, pu1_bot, cur_strd, 325 cur_strd, 326 BLK_WD, 327 BLK_HT >> 1); 328 /* Compute Variance */ 329 PROFILE_DISABLE_VARIANCE 330 vrnc = ps_ctxt->pf_variance_8x4(pu1_top, cur_strd, BLK_WD, 331 BLK_HT >> 1); 332 333 th_num = st_thresh; 334 335 th_num *= vrnc_avg_st + 336 ((MOD_IDX_ST_NUM * vrnc) >> MOD_IDX_ST_SHIFT); 337 338 th_den = vrnc + 339 ((MOD_IDX_ST_NUM * vrnc_avg_st) >> MOD_IDX_ST_SHIFT); 340 341 if((sad * th_den) <= th_num) 342 { 343 /* Calculate Combing Artifact if SAD test fails */ 344 PROFILE_DISABLE_CAC 345 cac = ps_ctxt->pf_cac_8x8(pu1_top, pu1_bot, cur_strd, cur_strd); 346 } 347 } 348 349 pu1_dst = pu1_out; 350 dst_strd = out_strd; 351 352 /* In case boundary blocks are not complete (dimensions non-multiple of 8) 353 * Use intermediate buffer as destination and copy required pixels to output 354 * buffer later 355 */ 356 if(input_boundary) 357 { 358 pu1_dst = au1_dst; 359 dst_strd = BLK_WD; 360 ideint_weave_blk(pu1_top, pu1_bot, pu1_dst, dst_strd, 361 cur_strd, blk_wd, blk_ht); 362 } 363 364 /* Weave the two fields unconditionally */ 365 if(0 == ps_ctxt->s_params.i4_disable_weave) 366 { 367 ideint_weave_blk(pu1_top, pu1_bot, pu1_dst, dst_strd, 368 cur_strd, blk_wd, blk_ht); 369 } 370 371 if(disable_cac_sad || cac || (sad * th_den > th_num)) 372 { 373 /* Pad the input fields in an intermediate buffer if required */ 374 if((0 == row) || (0 == col) || 375 ((num_blks_x - 1) == col) || ((num_blks_y - 1) == row)) 376 { 377 UWORD8 *pu1_dst_top; 378 UWORD8 au1_pad[(BLK_HT + 4) * (BLK_WD + 4)]; 379 380 ideint_pad_blk(pu1_top, pu1_bot, au1_pad, cur_strd, row, 381 col, num_blks_y, num_blks_x, blk_wd, blk_ht); 382 383 pu1_dst_top = au1_pad + 2 * (BLK_WD + 4) + 2; 384 385 PROFILE_DISABLE_SPATIAL 386 ps_ctxt->pf_spatial_filter(pu1_dst_top, pu1_dst + dst_strd, 387 (BLK_WD + 4) * 2, 388 dst_strd * 2); 389 } 390 else 391 { 392 PROFILE_DISABLE_SPATIAL 393 ps_ctxt->pf_spatial_filter(pu1_top, pu1_dst + dst_strd, 394 cur_strd, dst_strd * 2); 395 396 } 397 } 398 399 /* copy required pixels to output buffer for boundary blocks 400 * when dimensions are not multiple of 8 401 */ 402 if(input_boundary) 403 { 404 WORD32 j; 405 406 for(j = 0; j < blk_ht; j++) 407 { 408 memcpy(pu1_out + j * out_strd, au1_dst + j * BLK_WD, blk_wd); 409 } 410 } 411 pu1_prv += 8; 412 pu1_top += 8; 413 pu1_bot += 8; 414 pu1_out += 8; 415 } 416 } 417 } 418 return IDEINT_ERROR_NONE; 419 } 420