1 /*
2 *
3 * GStreamer
4 * Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
5 * Copyright (C) 2008,2010 Sebastian Dröge <slomo@collabora.co.uk>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 /*
24 * Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
25 * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
26 */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include "greedyhmacros.h"
33
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include <gst/gst.h>
38 #include "plugins.h"
39 #include "gstdeinterlacemethod.h"
40 #ifdef HAVE_ORC
41 #include <orc/orc.h>
42 #endif
43
44 #define GST_TYPE_DEINTERLACE_METHOD_GREEDY_H (gst_deinterlace_method_greedy_h_get_type ())
45 #define GST_IS_DEINTERLACE_METHOD_GREEDY_H(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H))
46 #define GST_IS_DEINTERLACE_METHOD_GREEDY_H_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H))
47 #define GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H, GstDeinterlaceMethodGreedyHClass))
48 #define GST_DEINTERLACE_METHOD_GREEDY_H(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H, GstDeinterlaceMethodGreedyH))
49 #define GST_DEINTERLACE_METHOD_GREEDY_H_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H, GstDeinterlaceMethodGreedyHClass))
50 #define GST_DEINTERLACE_METHOD_GREEDY_H_CAST(obj) ((GstDeinterlaceMethodGreedyH*)(obj))
51
52 typedef struct
53 {
54 GstDeinterlaceMethod parent;
55
56 guint max_comb, motion_threshold, motion_sense;
57 } GstDeinterlaceMethodGreedyH;
58
59 typedef void (*ScanlineFunction) (GstDeinterlaceMethodGreedyH * self,
60 const guint8 * L2, const guint8 * L1, const guint8 * L3, const guint8 * L2P,
61 guint8 * Dest, gint width);
62
63 typedef struct
64 {
65 GstDeinterlaceMethodClass parent_class;
66 ScanlineFunction scanline_yuy2; /* This is for YVYU too */
67 ScanlineFunction scanline_uyvy;
68 ScanlineFunction scanline_ayuv;
69 ScanlineFunction scanline_planar_y;
70 ScanlineFunction scanline_planar_uv;
71 } GstDeinterlaceMethodGreedyHClass;
72
73 static void
greedyh_scanline_C_ayuv(GstDeinterlaceMethodGreedyH * self,const guint8 * L1,const guint8 * L2,const guint8 * L3,const guint8 * L2P,guint8 * Dest,gint width)74 greedyh_scanline_C_ayuv (GstDeinterlaceMethodGreedyH * self, const guint8 * L1,
75 const guint8 * L2, const guint8 * L3, const guint8 * L2P, guint8 * Dest,
76 gint width)
77 {
78 gint Pos, Comp;
79 guint8 l1, l1_1, l3, l3_1;
80 guint8 avg, avg_1;
81 guint8 avg__1[4] = { 0, };
82 guint8 avg_s;
83 guint8 avg_sc;
84 guint8 best;
85 guint16 mov;
86 guint8 out;
87 guint8 l2, lp2;
88 guint8 l2_diff, lp2_diff;
89 guint8 min, max;
90 guint max_comb = self->max_comb;
91 guint motion_sense = self->motion_sense;
92 guint motion_threshold = self->motion_threshold;
93
94 width /= 4;
95 for (Pos = 0; Pos < width; Pos++) {
96 for (Comp = 0; Comp < 4; Comp++) {
97 l1 = L1[0];
98 l3 = L3[0];
99
100 if (Pos == width - 1) {
101 l1_1 = l1;
102 l3_1 = l3;
103 } else {
104 l1_1 = L1[4];
105 l3_1 = L3[4];
106 }
107
108 /* Average of L1 and L3 */
109 avg = (l1 + l3) / 2;
110
111 if (Pos == 0) {
112 avg__1[Comp] = avg;
113 }
114
115 /* Average of next L1 and next L3 */
116 avg_1 = (l1_1 + l3_1) / 2;
117
118 /* Calculate average of one pixel forward and previous */
119 avg_s = (avg__1[Comp] + avg_1) / 2;
120
121 /* Calculate average of center and surrounding pixels */
122 avg_sc = (avg + avg_s) / 2;
123
124 /* move forward */
125 avg__1[Comp] = avg;
126
127 /* Get best L2/L2P, i.e. least diff from above average */
128 l2 = L2[0];
129 lp2 = L2P[0];
130
131 l2_diff = ABS (l2 - avg_sc);
132
133 lp2_diff = ABS (lp2 - avg_sc);
134
135 if (l2_diff > lp2_diff)
136 best = lp2;
137 else
138 best = l2;
139
140 /* Clip this best L2/L2P by L1/L3 and allow to differ by GreedyMaxComb */
141 max = MAX (l1, l3);
142 min = MIN (l1, l3);
143
144 if (max < 256 - max_comb)
145 max += max_comb;
146 else
147 max = 255;
148
149 if (min > max_comb)
150 min -= max_comb;
151 else
152 min = 0;
153
154 out = CLAMP (best, min, max);
155
156 if (Comp < 2) {
157 /* Do motion compensation for luma, i.e. how much
158 * the weave pixel differs */
159 mov = ABS (l2 - lp2);
160 if (mov > motion_threshold)
161 mov -= motion_threshold;
162 else
163 mov = 0;
164
165 mov = mov * motion_sense;
166 if (mov > 256)
167 mov = 256;
168
169 /* Weighted sum on clipped weave pixel and average */
170 out = (out * (256 - mov) + avg_sc * mov) / 256;
171 }
172
173 Dest[0] = out;
174
175 Dest += 1;
176 L1 += 1;
177 L2 += 1;
178 L3 += 1;
179 L2P += 1;
180 }
181 }
182 }
183
184 static void
greedyh_scanline_C_yuy2(GstDeinterlaceMethodGreedyH * self,const guint8 * L1,const guint8 * L2,const guint8 * L3,const guint8 * L2P,guint8 * Dest,gint width)185 greedyh_scanline_C_yuy2 (GstDeinterlaceMethodGreedyH * self, const guint8 * L1,
186 const guint8 * L2, const guint8 * L3, const guint8 * L2P, guint8 * Dest,
187 gint width)
188 {
189 gint Pos;
190 guint8 l1_l, l1_1_l, l3_l, l3_1_l;
191 guint8 l1_c, l1_1_c, l3_c, l3_1_c;
192 guint8 avg_l, avg_c, avg_l_1, avg_c_1;
193 guint8 avg_l__1 = 0, avg_c__1 = 0;
194 guint8 avg_s_l, avg_s_c;
195 guint8 avg_sc_l, avg_sc_c;
196 guint8 best_l, best_c;
197 guint16 mov_l;
198 guint8 out_l, out_c;
199 guint8 l2_l, l2_c, lp2_l, lp2_c;
200 guint8 l2_l_diff, l2_c_diff, lp2_l_diff, lp2_c_diff;
201 guint8 min_l, min_c, max_l, max_c;
202 guint max_comb = self->max_comb;
203 guint motion_sense = self->motion_sense;
204 guint motion_threshold = self->motion_threshold;
205
206 width /= 2;
207 for (Pos = 0; Pos < width; Pos++) {
208 l1_l = L1[0];
209 l1_c = L1[1];
210 l3_l = L3[0];
211 l3_c = L3[1];
212
213 if (Pos == width - 1) {
214 l1_1_l = l1_l;
215 l1_1_c = l1_c;
216 l3_1_l = l3_l;
217 l3_1_c = l3_c;
218 } else {
219 l1_1_l = L1[2];
220 l1_1_c = L1[3];
221 l3_1_l = L3[2];
222 l3_1_c = L3[3];
223 }
224
225 /* Average of L1 and L3 */
226 avg_l = (l1_l + l3_l) / 2;
227 avg_c = (l1_c + l3_c) / 2;
228
229 if (Pos == 0) {
230 avg_l__1 = avg_l;
231 avg_c__1 = avg_c;
232 }
233
234 /* Average of next L1 and next L3 */
235 avg_l_1 = (l1_1_l + l3_1_l) / 2;
236 avg_c_1 = (l1_1_c + l3_1_c) / 2;
237
238 /* Calculate average of one pixel forward and previous */
239 avg_s_l = (avg_l__1 + avg_l_1) / 2;
240 avg_s_c = (avg_c__1 + avg_c_1) / 2;
241
242 /* Calculate average of center and surrounding pixels */
243 avg_sc_l = (avg_l + avg_s_l) / 2;
244 avg_sc_c = (avg_c + avg_s_c) / 2;
245
246 /* move forward */
247 avg_l__1 = avg_l;
248 avg_c__1 = avg_c;
249
250 /* Get best L2/L2P, i.e. least diff from above average */
251 l2_l = L2[0];
252 l2_c = L2[1];
253 lp2_l = L2P[0];
254 lp2_c = L2P[1];
255
256 l2_l_diff = ABS (l2_l - avg_sc_l);
257 l2_c_diff = ABS (l2_c - avg_sc_c);
258
259 lp2_l_diff = ABS (lp2_l - avg_sc_l);
260 lp2_c_diff = ABS (lp2_c - avg_sc_c);
261
262 if (l2_l_diff > lp2_l_diff)
263 best_l = lp2_l;
264 else
265 best_l = l2_l;
266
267 if (l2_c_diff > lp2_c_diff)
268 best_c = lp2_c;
269 else
270 best_c = l2_c;
271
272 /* Clip this best L2/L2P by L1/L3 and allow to differ by GreedyMaxComb */
273 max_l = MAX (l1_l, l3_l);
274 min_l = MIN (l1_l, l3_l);
275
276 if (max_l < 256 - max_comb)
277 max_l += max_comb;
278 else
279 max_l = 255;
280
281 if (min_l > max_comb)
282 min_l -= max_comb;
283 else
284 min_l = 0;
285
286 max_c = MAX (l1_c, l3_c);
287 min_c = MIN (l1_c, l3_c);
288
289 if (max_c < 256 - max_comb)
290 max_c += max_comb;
291 else
292 max_c = 255;
293
294 if (min_c > max_comb)
295 min_c -= max_comb;
296 else
297 min_c = 0;
298
299 out_l = CLAMP (best_l, min_l, max_l);
300 out_c = CLAMP (best_c, min_c, max_c);
301
302 /* Do motion compensation for luma, i.e. how much
303 * the weave pixel differs */
304 mov_l = ABS (l2_l - lp2_l);
305 if (mov_l > motion_threshold)
306 mov_l -= motion_threshold;
307 else
308 mov_l = 0;
309
310 mov_l = mov_l * motion_sense;
311 if (mov_l > 256)
312 mov_l = 256;
313
314 /* Weighted sum on clipped weave pixel and average */
315 out_l = (out_l * (256 - mov_l) + avg_sc_l * mov_l) / 256;
316
317 Dest[0] = out_l;
318 Dest[1] = out_c;
319
320 Dest += 2;
321 L1 += 2;
322 L2 += 2;
323 L3 += 2;
324 L2P += 2;
325 }
326 }
327
328 static void
greedyh_scanline_C_uyvy(GstDeinterlaceMethodGreedyH * self,const guint8 * L1,const guint8 * L2,const guint8 * L3,const guint8 * L2P,guint8 * Dest,gint width)329 greedyh_scanline_C_uyvy (GstDeinterlaceMethodGreedyH * self, const guint8 * L1,
330 const guint8 * L2, const guint8 * L3, const guint8 * L2P, guint8 * Dest,
331 gint width)
332 {
333 gint Pos;
334 guint8 l1_l, l1_1_l, l3_l, l3_1_l;
335 guint8 l1_c, l1_1_c, l3_c, l3_1_c;
336 guint8 avg_l, avg_c, avg_l_1, avg_c_1;
337 guint8 avg_l__1 = 0, avg_c__1 = 0;
338 guint8 avg_s_l, avg_s_c;
339 guint8 avg_sc_l, avg_sc_c;
340 guint8 best_l, best_c;
341 guint16 mov_l;
342 guint8 out_l, out_c;
343 guint8 l2_l, l2_c, lp2_l, lp2_c;
344 guint8 l2_l_diff, l2_c_diff, lp2_l_diff, lp2_c_diff;
345 guint8 min_l, min_c, max_l, max_c;
346 guint max_comb = self->max_comb;
347 guint motion_sense = self->motion_sense;
348 guint motion_threshold = self->motion_threshold;
349
350 width /= 2;
351 for (Pos = 0; Pos < width; Pos++) {
352 l1_l = L1[1];
353 l1_c = L1[0];
354 l3_l = L3[1];
355 l3_c = L3[0];
356
357 if (Pos == width - 1) {
358 l1_1_l = l1_l;
359 l1_1_c = l1_c;
360 l3_1_l = l3_l;
361 l3_1_c = l3_c;
362 } else {
363 l1_1_l = L1[3];
364 l1_1_c = L1[2];
365 l3_1_l = L3[3];
366 l3_1_c = L3[2];
367 }
368
369 /* Average of L1 and L3 */
370 avg_l = (l1_l + l3_l) / 2;
371 avg_c = (l1_c + l3_c) / 2;
372
373 if (Pos == 0) {
374 avg_l__1 = avg_l;
375 avg_c__1 = avg_c;
376 }
377
378 /* Average of next L1 and next L3 */
379 avg_l_1 = (l1_1_l + l3_1_l) / 2;
380 avg_c_1 = (l1_1_c + l3_1_c) / 2;
381
382 /* Calculate average of one pixel forward and previous */
383 avg_s_l = (avg_l__1 + avg_l_1) / 2;
384 avg_s_c = (avg_c__1 + avg_c_1) / 2;
385
386 /* Calculate average of center and surrounding pixels */
387 avg_sc_l = (avg_l + avg_s_l) / 2;
388 avg_sc_c = (avg_c + avg_s_c) / 2;
389
390 /* move forward */
391 avg_l__1 = avg_l;
392 avg_c__1 = avg_c;
393
394 /* Get best L2/L2P, i.e. least diff from above average */
395 l2_l = L2[1];
396 l2_c = L2[0];
397 lp2_l = L2P[1];
398 lp2_c = L2P[0];
399
400 l2_l_diff = ABS (l2_l - avg_sc_l);
401 l2_c_diff = ABS (l2_c - avg_sc_c);
402
403 lp2_l_diff = ABS (lp2_l - avg_sc_l);
404 lp2_c_diff = ABS (lp2_c - avg_sc_c);
405
406 if (l2_l_diff > lp2_l_diff)
407 best_l = lp2_l;
408 else
409 best_l = l2_l;
410
411 if (l2_c_diff > lp2_c_diff)
412 best_c = lp2_c;
413 else
414 best_c = l2_c;
415
416 /* Clip this best L2/L2P by L1/L3 and allow to differ by GreedyMaxComb */
417 max_l = MAX (l1_l, l3_l);
418 min_l = MIN (l1_l, l3_l);
419
420 if (max_l < 256 - max_comb)
421 max_l += max_comb;
422 else
423 max_l = 255;
424
425 if (min_l > max_comb)
426 min_l -= max_comb;
427 else
428 min_l = 0;
429
430 max_c = MAX (l1_c, l3_c);
431 min_c = MIN (l1_c, l3_c);
432
433 if (max_c < 256 - max_comb)
434 max_c += max_comb;
435 else
436 max_c = 255;
437
438 if (min_c > max_comb)
439 min_c -= max_comb;
440 else
441 min_c = 0;
442
443 out_l = CLAMP (best_l, min_l, max_l);
444 out_c = CLAMP (best_c, min_c, max_c);
445
446 /* Do motion compensation for luma, i.e. how much
447 * the weave pixel differs */
448 mov_l = ABS (l2_l - lp2_l);
449 if (mov_l > motion_threshold)
450 mov_l -= motion_threshold;
451 else
452 mov_l = 0;
453
454 mov_l = mov_l * motion_sense;
455 if (mov_l > 256)
456 mov_l = 256;
457
458 /* Weighted sum on clipped weave pixel and average */
459 out_l = (out_l * (256 - mov_l) + avg_sc_l * mov_l) / 256;
460
461 Dest[1] = out_l;
462 Dest[0] = out_c;
463
464 Dest += 2;
465 L1 += 2;
466 L2 += 2;
467 L3 += 2;
468 L2P += 2;
469 }
470 }
471
472 static void
greedyh_scanline_C_planar_y(GstDeinterlaceMethodGreedyH * self,const guint8 * L1,const guint8 * L2,const guint8 * L3,const guint8 * L2P,guint8 * Dest,gint width)473 greedyh_scanline_C_planar_y (GstDeinterlaceMethodGreedyH * self,
474 const guint8 * L1, const guint8 * L2, const guint8 * L3, const guint8 * L2P,
475 guint8 * Dest, gint width)
476 {
477 gint Pos;
478 guint8 l1, l1_1, l3, l3_1;
479 guint8 avg, avg_1;
480 guint8 avg__1 = 0;
481 guint8 avg_s;
482 guint8 avg_sc;
483 guint8 best;
484 guint16 mov;
485 guint8 out;
486 guint8 l2, lp2;
487 guint8 l2_diff, lp2_diff;
488 guint8 min, max;
489 guint max_comb = self->max_comb;
490 guint motion_sense = self->motion_sense;
491 guint motion_threshold = self->motion_threshold;
492
493 for (Pos = 0; Pos < width; Pos++) {
494 l1 = L1[0];
495 l3 = L3[0];
496
497 if (Pos == width - 1) {
498 l1_1 = l1;
499 l3_1 = l3;
500 } else {
501 l1_1 = L1[1];
502 l3_1 = L3[1];
503 }
504
505 /* Average of L1 and L3 */
506 avg = (l1 + l3) / 2;
507
508 if (Pos == 0) {
509 avg__1 = avg;
510 }
511
512 /* Average of next L1 and next L3 */
513 avg_1 = (l1_1 + l3_1) / 2;
514
515 /* Calculate average of one pixel forward and previous */
516 avg_s = (avg__1 + avg_1) / 2;
517
518 /* Calculate average of center and surrounding pixels */
519 avg_sc = (avg + avg_s) / 2;
520
521 /* move forward */
522 avg__1 = avg;
523
524 /* Get best L2/L2P, i.e. least diff from above average */
525 l2 = L2[0];
526 lp2 = L2P[0];
527
528 l2_diff = ABS (l2 - avg_sc);
529
530 lp2_diff = ABS (lp2 - avg_sc);
531
532 if (l2_diff > lp2_diff)
533 best = lp2;
534 else
535 best = l2;
536
537 /* Clip this best L2/L2P by L1/L3 and allow to differ by GreedyMaxComb */
538 max = MAX (l1, l3);
539 min = MIN (l1, l3);
540
541 if (max < 256 - max_comb)
542 max += max_comb;
543 else
544 max = 255;
545
546 if (min > max_comb)
547 min -= max_comb;
548 else
549 min = 0;
550
551 out = CLAMP (best, min, max);
552
553 /* Do motion compensation for luma, i.e. how much
554 * the weave pixel differs */
555 mov = ABS (l2 - lp2);
556 if (mov > motion_threshold)
557 mov -= motion_threshold;
558 else
559 mov = 0;
560
561 mov = mov * motion_sense;
562 if (mov > 256)
563 mov = 256;
564
565 /* Weighted sum on clipped weave pixel and average */
566 out = (out * (256 - mov) + avg_sc * mov) / 256;
567
568 Dest[0] = out;
569
570 Dest += 1;
571 L1 += 1;
572 L2 += 1;
573 L3 += 1;
574 L2P += 1;
575 }
576 }
577
578 static void
greedyh_scanline_C_planar_uv(GstDeinterlaceMethodGreedyH * self,const guint8 * L1,const guint8 * L2,const guint8 * L3,const guint8 * L2P,guint8 * Dest,gint width)579 greedyh_scanline_C_planar_uv (GstDeinterlaceMethodGreedyH * self,
580 const guint8 * L1, const guint8 * L2, const guint8 * L3, const guint8 * L2P,
581 guint8 * Dest, gint width)
582 {
583 gint Pos;
584 guint8 l1, l1_1, l3, l3_1;
585 guint8 avg, avg_1;
586 guint8 avg__1 = 0;
587 guint8 avg_s;
588 guint8 avg_sc;
589 guint8 best;
590 guint8 out;
591 guint8 l2, lp2;
592 guint8 l2_diff, lp2_diff;
593 guint8 min, max;
594 guint max_comb = self->max_comb;
595
596 for (Pos = 0; Pos < width; Pos++) {
597 l1 = L1[0];
598 l3 = L3[0];
599
600 if (Pos == width - 1) {
601 l1_1 = l1;
602 l3_1 = l3;
603 } else {
604 l1_1 = L1[1];
605 l3_1 = L3[1];
606 }
607
608 /* Average of L1 and L3 */
609 avg = (l1 + l3) / 2;
610
611 if (Pos == 0) {
612 avg__1 = avg;
613 }
614
615 /* Average of next L1 and next L3 */
616 avg_1 = (l1_1 + l3_1) / 2;
617
618 /* Calculate average of one pixel forward and previous */
619 avg_s = (avg__1 + avg_1) / 2;
620
621 /* Calculate average of center and surrounding pixels */
622 avg_sc = (avg + avg_s) / 2;
623
624 /* move forward */
625 avg__1 = avg;
626
627 /* Get best L2/L2P, i.e. least diff from above average */
628 l2 = L2[0];
629 lp2 = L2P[0];
630
631 l2_diff = ABS (l2 - avg_sc);
632
633 lp2_diff = ABS (lp2 - avg_sc);
634
635 if (l2_diff > lp2_diff)
636 best = lp2;
637 else
638 best = l2;
639
640 /* Clip this best L2/L2P by L1/L3 and allow to differ by GreedyMaxComb */
641 max = MAX (l1, l3);
642 min = MIN (l1, l3);
643
644 if (max < 256 - max_comb)
645 max += max_comb;
646 else
647 max = 255;
648
649 if (min > max_comb)
650 min -= max_comb;
651 else
652 min = 0;
653
654 out = CLAMP (best, min, max);
655
656 Dest[0] = out;
657
658 Dest += 1;
659 L1 += 1;
660 L2 += 1;
661 L3 += 1;
662 L2P += 1;
663 }
664 }
665
666 #ifdef BUILD_X86_ASM
667
668 #define IS_MMXEXT
669 #define SIMD_TYPE MMXEXT
670 #define C_FUNCT_YUY2 greedyh_scanline_C_yuy2
671 #define C_FUNCT_UYVY greedyh_scanline_C_uyvy
672 #define C_FUNCT_PLANAR_Y greedyh_scanline_C_planar_y
673 #define C_FUNCT_PLANAR_UV greedyh_scanline_C_planar_uv
674 #define FUNCT_NAME_YUY2 greedyh_scanline_MMXEXT_yuy2
675 #define FUNCT_NAME_UYVY greedyh_scanline_MMXEXT_uyvy
676 #define FUNCT_NAME_PLANAR_Y greedyh_scanline_MMXEXT_planar_y
677 #define FUNCT_NAME_PLANAR_UV greedyh_scanline_MMXEXT_planar_uv
678 #include "greedyh.asm"
679 #undef SIMD_TYPE
680 #undef IS_MMXEXT
681 #undef FUNCT_NAME_YUY2
682 #undef FUNCT_NAME_UYVY
683 #undef FUNCT_NAME_PLANAR_Y
684 #undef FUNCT_NAME_PLANAR_UV
685
686 #define IS_3DNOW
687 #define SIMD_TYPE 3DNOW
688 #define FUNCT_NAME_YUY2 greedyh_scanline_3DNOW_yuy2
689 #define FUNCT_NAME_UYVY greedyh_scanline_3DNOW_uyvy
690 #define FUNCT_NAME_PLANAR_Y greedyh_scanline_3DNOW_planar_y
691 #define FUNCT_NAME_PLANAR_UV greedyh_scanline_3DNOW_planar_uv
692 #include "greedyh.asm"
693 #undef SIMD_TYPE
694 #undef IS_3DNOW
695 #undef FUNCT_NAME_YUY2
696 #undef FUNCT_NAME_UYVY
697 #undef FUNCT_NAME_PLANAR_Y
698 #undef FUNCT_NAME_PLANAR_UV
699
700 #define IS_MMX
701 #define SIMD_TYPE MMX
702 #define FUNCT_NAME_YUY2 greedyh_scanline_MMX_yuy2
703 #define FUNCT_NAME_UYVY greedyh_scanline_MMX_uyvy
704 #define FUNCT_NAME_PLANAR_Y greedyh_scanline_MMX_planar_y
705 #define FUNCT_NAME_PLANAR_UV greedyh_scanline_MMX_planar_uv
706 #include "greedyh.asm"
707 #undef SIMD_TYPE
708 #undef IS_MMX
709 #undef FUNCT_NAME_YUY2
710 #undef FUNCT_NAME_UYVY
711 #undef FUNCT_NAME_PLANAR_Y
712 #undef FUNCT_NAME_PLANAR_UV
713 #undef C_FUNCT_YUY2
714 #undef C_FUNCT_PLANAR_Y
715 #undef C_FUNCT_PLANAR_UV
716
717 #endif
718
719 static void
deinterlace_frame_di_greedyh_packed(GstDeinterlaceMethod * method,const GstDeinterlaceField * history,guint history_count,GstVideoFrame * outframe,int cur_field_idx)720 deinterlace_frame_di_greedyh_packed (GstDeinterlaceMethod * method,
721 const GstDeinterlaceField * history, guint history_count,
722 GstVideoFrame * outframe, int cur_field_idx)
723 {
724 GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (method);
725 GstDeinterlaceMethodGreedyHClass *klass =
726 GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS (self);
727 gint InfoIsOdd = 0;
728 gint Line;
729 gint RowStride = GST_VIDEO_FRAME_COMP_STRIDE (outframe, 0);
730 gint FieldHeight = GST_VIDEO_FRAME_HEIGHT (outframe) / 2;
731 gint Pitch = RowStride * 2;
732 const guint8 *L1; // ptr to Line1, of 3
733 const guint8 *L2; // ptr to Line2, the weave line
734 const guint8 *L3; // ptr to Line3
735 const guint8 *L2P; // ptr to prev Line2
736 guint8 *Dest = GST_VIDEO_FRAME_COMP_DATA (outframe, 0);
737 ScanlineFunction scanline;
738
739 if (cur_field_idx + 2 > history_count || cur_field_idx < 1) {
740 GstDeinterlaceMethod *backup_method;
741
742 backup_method = g_object_new (gst_deinterlace_method_linear_get_type (),
743 NULL);
744
745 gst_deinterlace_method_setup (backup_method, method->vinfo);
746 gst_deinterlace_method_deinterlace_frame (backup_method,
747 history, history_count, outframe, cur_field_idx);
748
749 g_object_unref (backup_method);
750 return;
751 }
752
753 cur_field_idx += 2;
754
755 switch (GST_VIDEO_INFO_FORMAT (method->vinfo)) {
756 case GST_VIDEO_FORMAT_YUY2:
757 case GST_VIDEO_FORMAT_YVYU:
758 scanline = klass->scanline_yuy2;
759 break;
760 case GST_VIDEO_FORMAT_UYVY:
761 scanline = klass->scanline_uyvy;
762 break;
763 case GST_VIDEO_FORMAT_AYUV:
764 scanline = klass->scanline_ayuv;
765 break;
766 default:
767 g_assert_not_reached ();
768 return;
769 }
770
771 // copy first even line no matter what, and the first odd line if we're
772 // processing an EVEN field. (note diff from other deint rtns.)
773
774 if (history[cur_field_idx - 1].flags == PICTURE_INTERLACED_BOTTOM) {
775 InfoIsOdd = 1;
776
777 L1 = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 2].frame, 0);
778 if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM)
779 L1 += RowStride;
780
781 L2 = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 1].frame, 0);
782 if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM)
783 L2 += RowStride;
784
785 L3 = L1 + Pitch;
786 L2P = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 3].frame, 0);
787 if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM)
788 L2P += RowStride;
789
790 // copy first even line
791 memcpy (Dest, L1, RowStride);
792 Dest += RowStride;
793 } else {
794 InfoIsOdd = 0;
795 L1 = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 2].frame, 0);
796 if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM)
797 L1 += RowStride;
798
799 L2 = (guint8 *) GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx -
800 1].frame, 0) + Pitch;
801 if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM)
802 L2 += RowStride;
803
804 L3 = L1 + Pitch;
805 L2P =
806 (guint8 *) GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 3].frame,
807 0) + Pitch;
808 if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM)
809 L2P += RowStride;
810
811 // copy first even line
812 memcpy (Dest, L1, RowStride);
813 Dest += RowStride;
814 // then first odd line
815 memcpy (Dest, L1, RowStride);
816 Dest += RowStride;
817 }
818
819 for (Line = 0; Line < (FieldHeight - 1); ++Line) {
820 scanline (self, L1, L2, L3, L2P, Dest, RowStride);
821 Dest += RowStride;
822 memcpy (Dest, L3, RowStride);
823 Dest += RowStride;
824
825 L1 += Pitch;
826 L2 += Pitch;
827 L3 += Pitch;
828 L2P += Pitch;
829 }
830
831 if (InfoIsOdd) {
832 memcpy (Dest, L2, RowStride);
833 }
834 }
835
836 static void
deinterlace_frame_di_greedyh_planar_plane(GstDeinterlaceMethodGreedyH * self,const guint8 * L1,const guint8 * L2,const guint8 * L3,const guint8 * L2P,guint8 * Dest,gint RowStride,gint FieldHeight,gint Pitch,gint InfoIsOdd,ScanlineFunction scanline)837 deinterlace_frame_di_greedyh_planar_plane (GstDeinterlaceMethodGreedyH * self,
838 const guint8 * L1, const guint8 * L2, const guint8 * L3, const guint8 * L2P,
839 guint8 * Dest, gint RowStride, gint FieldHeight, gint Pitch, gint InfoIsOdd,
840 ScanlineFunction scanline)
841 {
842 gint Line;
843
844 // copy first even line no matter what, and the first odd line if we're
845 // processing an EVEN field. (note diff from other deint rtns.)
846
847 if (InfoIsOdd) {
848 // copy first even line
849 memcpy (Dest, L1, RowStride);
850 Dest += RowStride;
851 } else {
852 // copy first even line
853 memcpy (Dest, L1, RowStride);
854 Dest += RowStride;
855 // then first odd line
856 memcpy (Dest, L1, RowStride);
857 Dest += RowStride;
858 }
859
860 for (Line = 0; Line < (FieldHeight - 1); ++Line) {
861 scanline (self, L1, L2, L3, L2P, Dest, RowStride);
862 Dest += RowStride;
863 memcpy (Dest, L3, RowStride);
864 Dest += RowStride;
865
866 L1 += Pitch;
867 L2 += Pitch;
868 L3 += Pitch;
869 L2P += Pitch;
870 }
871
872 if (InfoIsOdd) {
873 memcpy (Dest, L2, RowStride);
874 }
875 }
876
877 static void
deinterlace_frame_di_greedyh_planar(GstDeinterlaceMethod * method,const GstDeinterlaceField * history,guint history_count,GstVideoFrame * outframe,int cur_field_idx)878 deinterlace_frame_di_greedyh_planar (GstDeinterlaceMethod * method,
879 const GstDeinterlaceField * history, guint history_count,
880 GstVideoFrame * outframe, int cur_field_idx)
881 {
882 GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (method);
883 GstDeinterlaceMethodGreedyHClass *klass =
884 GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS (self);
885 gint InfoIsOdd;
886 gint RowStride;
887 gint FieldHeight;
888 gint Pitch;
889 const guint8 *L1; // ptr to Line1, of 3
890 const guint8 *L2; // ptr to Line2, the weave line
891 const guint8 *L3; // ptr to Line3
892 const guint8 *L2P; // ptr to prev Line2
893 guint8 *Dest;
894 gint i;
895 ScanlineFunction scanline;
896
897 if (cur_field_idx + 2 > history_count || cur_field_idx < 1) {
898 GstDeinterlaceMethod *backup_method;
899
900 backup_method = g_object_new (gst_deinterlace_method_linear_get_type (),
901 NULL);
902
903 gst_deinterlace_method_setup (backup_method, method->vinfo);
904 gst_deinterlace_method_deinterlace_frame (backup_method,
905 history, history_count, outframe, cur_field_idx);
906
907 g_object_unref (backup_method);
908 return;
909 }
910
911 cur_field_idx += 2;
912
913 for (i = 0; i < 3; i++) {
914 InfoIsOdd = (history[cur_field_idx - 1].flags == PICTURE_INTERLACED_BOTTOM);
915 RowStride = GST_VIDEO_FRAME_COMP_STRIDE (outframe, i);
916 FieldHeight = GST_VIDEO_FRAME_COMP_HEIGHT (outframe, i) / 2;
917 Pitch = RowStride * 2;
918
919 if (i == 0)
920 scanline = klass->scanline_planar_y;
921 else
922 scanline = klass->scanline_planar_uv;
923
924 Dest = GST_VIDEO_FRAME_COMP_DATA (outframe, i);
925
926 L1 = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 2].frame, i);
927 if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM)
928 L1 += RowStride;
929
930 L2 = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 1].frame, i);
931 if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM)
932 L2 += RowStride;
933
934 L3 = L1 + Pitch;
935 L2P = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 3].frame, i);
936 if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM)
937 L2P += RowStride;
938
939 deinterlace_frame_di_greedyh_planar_plane (self, L1, L2, L3, L2P, Dest,
940 RowStride, FieldHeight, Pitch, InfoIsOdd, scanline);
941 }
942 }
943
944 G_DEFINE_TYPE (GstDeinterlaceMethodGreedyH, gst_deinterlace_method_greedy_h,
945 GST_TYPE_DEINTERLACE_METHOD);
946
947 enum
948 {
949 PROP_0,
950 PROP_MAX_COMB,
951 PROP_MOTION_THRESHOLD,
952 PROP_MOTION_SENSE
953 };
954
955 static void
gst_deinterlace_method_greedy_h_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)956 gst_deinterlace_method_greedy_h_set_property (GObject * object, guint prop_id,
957 const GValue * value, GParamSpec * pspec)
958 {
959 GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object);
960
961 switch (prop_id) {
962 case PROP_MAX_COMB:
963 self->max_comb = g_value_get_uint (value);
964 break;
965 case PROP_MOTION_THRESHOLD:
966 self->motion_threshold = g_value_get_uint (value);
967 break;
968 case PROP_MOTION_SENSE:
969 self->motion_sense = g_value_get_uint (value);
970 break;
971 default:
972 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
973 }
974 }
975
976 static void
gst_deinterlace_method_greedy_h_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)977 gst_deinterlace_method_greedy_h_get_property (GObject * object, guint prop_id,
978 GValue * value, GParamSpec * pspec)
979 {
980 GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object);
981
982 switch (prop_id) {
983 case PROP_MAX_COMB:
984 g_value_set_uint (value, self->max_comb);
985 break;
986 case PROP_MOTION_THRESHOLD:
987 g_value_set_uint (value, self->motion_threshold);
988 break;
989 case PROP_MOTION_SENSE:
990 g_value_set_uint (value, self->motion_sense);
991 break;
992 default:
993 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
994 }
995 }
996
997 static void
gst_deinterlace_method_greedy_h_class_init(GstDeinterlaceMethodGreedyHClass * klass)998 gst_deinterlace_method_greedy_h_class_init (GstDeinterlaceMethodGreedyHClass *
999 klass)
1000 {
1001 GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
1002 GObjectClass *gobject_class = (GObjectClass *) klass;
1003 #ifdef BUILD_X86_ASM
1004 guint cpu_flags =
1005 orc_target_get_default_flags (orc_target_get_by_name ("mmx"));
1006 #endif
1007
1008 gobject_class->set_property = gst_deinterlace_method_greedy_h_set_property;
1009 gobject_class->get_property = gst_deinterlace_method_greedy_h_get_property;
1010
1011 g_object_class_install_property (gobject_class, PROP_MAX_COMB,
1012 g_param_spec_uint ("max-comb",
1013 "Max comb",
1014 "Max Comb", 0, 255, 5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
1015 );
1016
1017 g_object_class_install_property (gobject_class, PROP_MOTION_THRESHOLD,
1018 g_param_spec_uint ("motion-threshold",
1019 "Motion Threshold",
1020 "Motion Threshold",
1021 0, 255, 25, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
1022 );
1023
1024 g_object_class_install_property (gobject_class, PROP_MOTION_SENSE,
1025 g_param_spec_uint ("motion-sense",
1026 "Motion Sense",
1027 "Motion Sense",
1028 0, 255, 30, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
1029 );
1030
1031 dim_class->fields_required = 4;
1032 dim_class->name = "Motion Adaptive: Advanced Detection";
1033 dim_class->nick = "greedyh";
1034 dim_class->latency = 1;
1035
1036 dim_class->deinterlace_frame_yuy2 = deinterlace_frame_di_greedyh_packed;
1037 dim_class->deinterlace_frame_yvyu = deinterlace_frame_di_greedyh_packed;
1038 dim_class->deinterlace_frame_uyvy = deinterlace_frame_di_greedyh_packed;
1039 dim_class->deinterlace_frame_ayuv = deinterlace_frame_di_greedyh_packed;
1040 dim_class->deinterlace_frame_y444 = deinterlace_frame_di_greedyh_planar;
1041 dim_class->deinterlace_frame_i420 = deinterlace_frame_di_greedyh_planar;
1042 dim_class->deinterlace_frame_yv12 = deinterlace_frame_di_greedyh_planar;
1043 dim_class->deinterlace_frame_y42b = deinterlace_frame_di_greedyh_planar;
1044 dim_class->deinterlace_frame_y41b = deinterlace_frame_di_greedyh_planar;
1045
1046 #ifdef BUILD_X86_ASM
1047 if (cpu_flags & ORC_TARGET_MMX_MMXEXT) {
1048 klass->scanline_yuy2 = greedyh_scanline_MMXEXT_yuy2;
1049 klass->scanline_uyvy = greedyh_scanline_MMXEXT_uyvy;
1050 } else if (cpu_flags & ORC_TARGET_MMX_3DNOW) {
1051 klass->scanline_yuy2 = greedyh_scanline_3DNOW_yuy2;
1052 klass->scanline_uyvy = greedyh_scanline_3DNOW_uyvy;
1053 } else if (cpu_flags & ORC_TARGET_MMX_MMX) {
1054 klass->scanline_yuy2 = greedyh_scanline_MMX_yuy2;
1055 klass->scanline_uyvy = greedyh_scanline_MMX_uyvy;
1056 } else {
1057 klass->scanline_yuy2 = greedyh_scanline_C_yuy2;
1058 klass->scanline_uyvy = greedyh_scanline_C_uyvy;
1059 }
1060 #else
1061 klass->scanline_yuy2 = greedyh_scanline_C_yuy2;
1062 klass->scanline_uyvy = greedyh_scanline_C_uyvy;
1063 #endif
1064 /* TODO: MMX implementation of these two */
1065 klass->scanline_ayuv = greedyh_scanline_C_ayuv;
1066 klass->scanline_planar_y = greedyh_scanline_C_planar_y;
1067 klass->scanline_planar_uv = greedyh_scanline_C_planar_uv;
1068 }
1069
1070 static void
gst_deinterlace_method_greedy_h_init(GstDeinterlaceMethodGreedyH * self)1071 gst_deinterlace_method_greedy_h_init (GstDeinterlaceMethodGreedyH * self)
1072 {
1073 self->max_comb = 5;
1074 self->motion_threshold = 25;
1075 self->motion_sense = 30;
1076 }
1077