| /****************************************************************************** |
| * |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at: |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| ***************************************************************************** |
| * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore |
| */ |
| /** |
| ******************************************************************************* |
| * @file |
| * ideint_utils.c |
| * |
| * @brief |
| * This file contains the definitions of the core processing of the de |
| * interlacer. |
| * |
| * @author |
| * Ittiam |
| * |
| * @par List of Functions: |
| * ideint_weave_pic() |
| * init_bob_indices() |
| * ideint_weave_blk() |
| * ideint_spatial_filter() |
| * |
| * @remarks |
| * None |
| * |
| ******************************************************************************* |
| */ |
| /*****************************************************************************/ |
| /* File Includes */ |
| /*****************************************************************************/ |
| /* System include files */ |
| #include <stdio.h> |
| #include <stdint.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <assert.h> |
| |
| |
| /* User include files */ |
| #include "icv_datatypes.h" |
| #include "icv_macros.h" |
| #include "icv_platform_macros.h" |
| #include "icv.h" |
| #include "icv_variance.h" |
| #include "icv_sad.h" |
| #include "ideint.h" |
| #include "ideint_defs.h" |
| #include "ideint_structs.h" |
| #include "ideint_utils.h" |
| #include "ideint_cac.h" |
| |
| /** |
| ******************************************************************************* |
| * |
| * @brief |
| * Weaves two fields to produce a frame |
| * |
| * @par Description |
| * Weaves two fields to produce a frame |
| * |
| * @param[in] ps_src_top |
| * Top field source |
| * |
| * @param[in] ps_src_bot |
| * Bottom field source |
| * |
| * @param[in] ps_dst_frm |
| * Destination frame |
| * |
| * @returns |
| * 0 on Success |
| * |
| * @remarks |
| * |
| ******************************************************************************* |
| */ |
| WORD32 ideint_weave_pic(icv_pic_t *ps_src_top, |
| icv_pic_t *ps_src_bot, |
| icv_pic_t *ps_dst_frm, |
| WORD32 start_row, |
| WORD32 num_rows) |
| { |
| UWORD8 *pu1_src, *pu1_dst; |
| WORD32 i, j, num_comp; |
| icv_pic_t *ps_src_fld; |
| WORD32 fld; |
| icv_pic_t *ps_src_flds[2]; |
| |
| num_comp = 3; |
| ps_src_flds[0] = ps_src_top; |
| ps_src_flds[1] = ps_src_bot; |
| |
| for(fld = 0; fld < 2; fld++) |
| { |
| ps_src_fld = ps_src_flds[fld]; |
| for(i = 0; i < num_comp; i++) |
| { |
| WORD32 src_strd; |
| WORD32 dst_strd; |
| WORD32 comp_row_start, comp_row_end; |
| comp_row_start = start_row; |
| comp_row_end = comp_row_start + num_rows; |
| if(i) |
| { |
| comp_row_start >>= 1; |
| comp_row_end >>= 1; |
| } |
| |
| comp_row_end = MIN(comp_row_end, ps_dst_frm->ai4_ht[i]); |
| |
| pu1_src = ps_src_fld->apu1_buf[i]; |
| pu1_dst = ps_dst_frm->apu1_buf[i]; |
| |
| src_strd = ps_src_fld->ai4_strd[i]; |
| dst_strd = ps_dst_frm->ai4_strd[i]; |
| |
| /* If source field is bottom, increment destination */ |
| pu1_dst += fld * dst_strd; |
| |
| /* In case input and output are pointing to same buffer, then no need to copy */ |
| if((pu1_src != pu1_dst) || ((2 * dst_strd) != src_strd)) |
| { |
| pu1_dst += ps_dst_frm->ai4_strd[i] * comp_row_start; |
| pu1_src += ps_src_fld->ai4_strd[i] * comp_row_start / 2; |
| |
| for(j = comp_row_start; j < comp_row_end; j += 2) |
| { |
| memcpy(pu1_dst, pu1_src, ps_dst_frm->ai4_wd[i]); |
| pu1_dst += ps_dst_frm->ai4_strd[i] * 2; |
| pu1_src += ps_src_fld->ai4_strd[i]; |
| } |
| } |
| } |
| } |
| return 0; |
| } |
| |
| |
| /** |
| ******************************************************************************* |
| * |
| * @brief |
| * Weaves a 8x8 block |
| * |
| * @par Description |
| * Weaves a 8x8 block from two fields |
| * |
| * @param[in] pu1_top |
| * Top field source |
| * |
| * @param[in] pu1_bot |
| * Bottom field source |
| * |
| * @param[in] pu1_dst |
| * Destination |
| * |
| * @param[in] dst_strd |
| * Destination stride |
| * |
| * @param[in] src_strd |
| * Source stride |
| * |
| * @returns |
| * 0 on success |
| * |
| * @remarks |
| * |
| ******************************************************************************* |
| */ |
| WORD32 ideint_weave_blk(UWORD8 *pu1_top, |
| UWORD8 *pu1_bot, |
| UWORD8 *pu1_dst, |
| WORD32 dst_strd, |
| WORD32 src_strd, |
| WORD32 wd, |
| WORD32 ht) |
| { |
| WORD32 j; |
| |
| for(j = 0; j < ht; j += 2) |
| { |
| memcpy(pu1_dst, pu1_top, wd); |
| pu1_dst += dst_strd; |
| pu1_top += src_strd; |
| |
| memcpy(pu1_dst, pu1_bot, wd); |
| pu1_dst += dst_strd; |
| pu1_bot += src_strd; |
| } |
| return 0; |
| } |
| |
| /** |
| ******************************************************************************* |
| * |
| * @brief |
| * Copy a boundary block and pad |
| * |
| * @par Description |
| * Copies a block on one of the boundaries and pads |
| * |
| * @param[in] pu1_top |
| * Top field source |
| * |
| * @param[in] pu1_bot |
| * Bottom field source |
| * |
| * @param[in] pu1_pad |
| * Padded destination |
| * |
| * @param[in] cur_strd |
| * Stride for pu1_top and pu1_bot |
| * |
| * @param[in] row |
| * Current block's row |
| * |
| * @param[in] col |
| * Current block's column |
| * |
| * @param[in] num_blks_y |
| * Number of blocks in Y direction |
| * |
| * @param[in] num_blks_x |
| * Number of blocks in X direction |
| |
| * @returns |
| * None |
| * |
| * @remarks |
| * |
| ******************************************************************************* |
| */ |
| void ideint_pad_blk(UWORD8 *pu1_top, |
| UWORD8 *pu1_bot, |
| UWORD8 *pu1_pad, |
| WORD32 cur_strd, |
| WORD32 row, |
| WORD32 col, |
| WORD32 num_blks_y, |
| WORD32 num_blks_x, |
| WORD32 blk_wd, |
| WORD32 blk_ht) |
| { |
| WORD32 i; |
| WORD32 num_cols, num_rows; |
| UWORD8 *pu1_dst; |
| UWORD8 *pu1_src_top; |
| UWORD8 *pu1_src_bot; |
| |
| num_rows = blk_ht + 4; |
| num_cols = blk_wd + 4; |
| |
| pu1_src_top = pu1_top - cur_strd - 2; |
| pu1_src_bot = pu1_bot - cur_strd - 2; |
| pu1_dst = pu1_pad; |
| |
| if(0 == col) |
| { |
| num_cols -= 2; |
| pu1_dst += 2; |
| pu1_src_top += 2; |
| pu1_src_bot += 2; |
| } |
| |
| if(0 == row) |
| { |
| num_rows -= 2; |
| pu1_dst += 2 * (BLK_WD + 4); |
| pu1_src_top += cur_strd; |
| pu1_src_bot += cur_strd; |
| } |
| |
| if((num_blks_x - 1) == col) |
| num_cols -= 2; |
| |
| if((num_blks_y - 1) == row) |
| num_rows -= 2; |
| |
| for(i = 0; i < num_rows; i += 2) |
| { |
| memcpy(pu1_dst, pu1_src_top, num_cols); |
| pu1_dst += (BLK_WD + 4); |
| |
| memcpy(pu1_dst, pu1_src_bot, num_cols); |
| pu1_dst += (BLK_WD + 4); |
| |
| pu1_src_top += cur_strd; |
| pu1_src_bot += cur_strd; |
| } |
| |
| |
| /* Pad Left */ |
| if(0 == col) |
| { |
| for(i = 0; i < (BLK_HT + 4); i++) |
| { |
| WORD32 ofst = i * (BLK_WD + 4) + 2; |
| pu1_pad[ofst - 1] = pu1_pad[ofst]; |
| pu1_pad[ofst - 2] = pu1_pad[ofst]; |
| } |
| } |
| |
| /* Pad right */ |
| if((num_blks_x - 1) == col) |
| { |
| for(i = 0; i < (BLK_HT + 4); i++) |
| { |
| WORD32 ofst = i * (BLK_WD + 4) + 2 + blk_wd - 1; |
| WORD32 size = (BLK_WD - blk_wd) + 2; |
| /* Padding on right should include padding for boundary |
| * blocks when width is non-multiple of 8 |
| */ |
| memset(&pu1_pad[ofst + 1], pu1_pad[ofst], size); |
| } |
| } |
| |
| /* Pad Top */ |
| if(0 == row) |
| { |
| WORD32 src_ofst = 2 * (BLK_WD + 4); |
| WORD32 dst_ofst = 0; |
| memcpy(pu1_pad + dst_ofst, pu1_pad + src_ofst, (BLK_WD + 4)); |
| src_ofst += (BLK_WD + 4); |
| dst_ofst += (BLK_WD + 4); |
| memcpy(pu1_pad + dst_ofst, pu1_pad + src_ofst, (BLK_WD + 4)); |
| } |
| |
| /* Pad Bottom */ |
| if((num_blks_y - 1) == row) |
| { |
| WORD32 src_ofst = (0 + blk_ht) * (BLK_WD + 4); |
| WORD32 dst_ofst = (1 + blk_ht) * (BLK_WD + 4); |
| WORD32 size = (BLK_HT - blk_ht) + 2; |
| |
| /* Padding on bottom should include padding for boundary |
| * blocks when height is non-multiple of 8 |
| */ |
| for(i = 0; i < size; i++) |
| { |
| memcpy(pu1_pad + dst_ofst, pu1_pad + src_ofst, (BLK_WD + 4)); |
| dst_ofst += (BLK_WD + 4); |
| } |
| } |
| } |
| |
| /** |
| ******************************************************************************* |
| * |
| * @brief |
| * Performs spatial edge adaptive filtering |
| * |
| * @par Description |
| * Performs spatial edge adaptive filtering by detecting edge direction |
| * |
| * @param[in] pu1_src |
| * Source buffer |
| * |
| * @param[in] pu1_out |
| * Destination buffer |
| * |
| * @param[in] src_strd |
| * Source stride |
| * |
| * @param[in] out_strd |
| * Destination stride |
| |
| * @returns |
| * None |
| * |
| * @remarks |
| * |
| ******************************************************************************* |
| */ |
| void ideint_spatial_filter(UWORD8 *pu1_src, |
| UWORD8 *pu1_out, |
| WORD32 src_strd, |
| WORD32 out_strd) |
| { |
| WORD32 i; |
| WORD32 j; |
| WORD32 k; |
| |
| /*********************************************************************/ |
| /* This loop is for the two halves inside the 8x4 block. */ |
| /*********************************************************************/ |
| for(k = 0; k < 2; k++) |
| { |
| WORD32 adiff[3] = {0, 0, 0}; |
| WORD32 shift; |
| WORD32 dir_45_le_90, dir_45_le_135, dir_135_le_90; |
| UWORD8 *pu1_row_1, *pu1_row_2, *pu1_dst; |
| |
| /*****************************************************************/ |
| /* Direction detection */ |
| /*****************************************************************/ |
| pu1_row_1 = pu1_src; |
| pu1_row_2 = pu1_src + src_strd; |
| |
| /*****************************************************************/ |
| /* Calculating the difference along each of the 3 directions. */ |
| /*****************************************************************/ |
| for(j = 0; j < SUB_BLK_HT; j ++) |
| { |
| for(i = 0; i < SUB_BLK_WD; i++) |
| { |
| adiff[0] += ABS_DIF(pu1_row_1[i], pu1_row_2[i]); /* 90 */ |
| |
| adiff[1] += ABS_DIF(pu1_row_1[i - 1], pu1_row_2[i + 1]); /* 135 */ |
| |
| adiff[2] += ABS_DIF(pu1_row_1[i + 1], pu1_row_2[i - 1]); /* 45 */ |
| } |
| pu1_row_1 += src_strd; |
| pu1_row_2 += src_strd; |
| } |
| |
| /*****************************************************************/ |
| /* Applying bias, to make the diff comparision more robust. */ |
| /*****************************************************************/ |
| adiff[0] *= EDGE_BIAS_0; |
| adiff[1] *= EDGE_BIAS_1; |
| adiff[2] *= EDGE_BIAS_1; |
| |
| /*****************************************************************/ |
| /* comapring the diffs */ |
| /*****************************************************************/ |
| dir_45_le_90 = (adiff[2] <= adiff[0]); |
| dir_45_le_135 = (adiff[2] <= adiff[1]); |
| dir_135_le_90 = (adiff[1] <= adiff[0]); |
| |
| /*****************************************************************/ |
| /* Direction selection. */ |
| /*****************************************************************/ |
| shift = 0; |
| if(1 == dir_45_le_135) |
| { |
| if(1 == dir_45_le_90) |
| shift = 1; |
| } |
| else |
| { |
| if(1 == dir_135_le_90) |
| shift = -1; |
| } |
| |
| /*****************************************************************/ |
| /* Directional interpolation */ |
| /*****************************************************************/ |
| pu1_row_1 = pu1_src + shift; |
| pu1_row_2 = pu1_src + src_strd - shift; |
| pu1_dst = pu1_out; |
| |
| for(j = 0; j < SUB_BLK_HT; j++) |
| { |
| for(i = 0; i < SUB_BLK_WD; i++) |
| { |
| pu1_dst[i] = (UWORD8)AVG(pu1_row_1[i], pu1_row_2[i]); |
| } |
| pu1_row_1 += src_strd; |
| pu1_row_2 += src_strd; |
| pu1_dst += out_strd; |
| } |
| |
| pu1_out += SUB_BLK_WD; |
| pu1_src += SUB_BLK_WD; |
| } |
| } |
| |