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