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