Home | History | Annotate | Download | only in common
      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