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 */
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)92 WORD32 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 */
ideint_weave_blk(UWORD8 * pu1_top,UWORD8 * pu1_bot,UWORD8 * pu1_dst,WORD32 dst_strd,WORD32 src_strd,WORD32 wd,WORD32 ht)185 WORD32 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 */
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)248 void 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 */
ideint_spatial_filter(UWORD8 * pu1_src,UWORD8 * pu1_out,WORD32 src_strd,WORD32 out_strd)389 void 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