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_plane(GstDeinterlaceMethodGreedyH * self,const GstDeinterlaceField * history,guint history_count,GstVideoFrame * outframe,int cur_field_idx,int plane,ScanlineFunction scanline)720 deinterlace_frame_di_greedyh_plane (GstDeinterlaceMethodGreedyH * self,
721 const GstDeinterlaceField * history, guint history_count,
722 GstVideoFrame * outframe, int cur_field_idx, int plane,
723 ScanlineFunction scanline)
724 {
725 guint8 *Dest = GST_VIDEO_FRAME_COMP_DATA (outframe, plane);
726 gint RowStride = GST_VIDEO_FRAME_COMP_STRIDE (outframe, plane);
727 gint FieldHeight = GST_VIDEO_FRAME_COMP_HEIGHT (outframe, plane) / 2;
728 gint Pitch = RowStride * 2;
729 const guint8 *L1; // ptr to Line1, of 3
730 const guint8 *L2; // ptr to Line2, the weave line
731 const guint8 *L3; // ptr to Line3
732 const guint8 *L2P; // ptr to prev Line2
733 gint InfoIsOdd;
734 gint Line;
735
736 L1 = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx].frame, plane);
737 if (history[cur_field_idx].flags & PICTURE_INTERLACED_BOTTOM)
738 L1 += RowStride;
739
740 L2 = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx + 1].frame, plane);
741 if (history[cur_field_idx + 1].flags & PICTURE_INTERLACED_BOTTOM)
742 L2 += RowStride;
743
744 L3 = L1 + Pitch;
745 L2P = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 1].frame, plane);
746 if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM)
747 L2P += RowStride;
748
749 // copy first even line no matter what, and the first odd line if we're
750 // processing an EVEN field. (note diff from other deint rtns.)
751
752 InfoIsOdd = (history[cur_field_idx + 1].flags == PICTURE_INTERLACED_BOTTOM);
753 if (InfoIsOdd) {
754 // copy first even line
755 memcpy (Dest, L1, RowStride);
756 Dest += RowStride;
757 } else {
758 // copy first even line
759 memcpy (Dest, L1, RowStride);
760 Dest += RowStride;
761 // then first odd line
762 memcpy (Dest, L1, RowStride);
763 Dest += RowStride;
764
765 L2 += Pitch;
766 L2P += Pitch;
767 }
768
769 for (Line = 0; Line < (FieldHeight - 1); ++Line) {
770 scanline (self, L1, L2, L3, L2P, Dest, RowStride);
771 Dest += RowStride;
772 memcpy (Dest, L3, RowStride);
773 Dest += RowStride;
774
775 L1 += Pitch;
776 L2 += Pitch;
777 L3 += Pitch;
778 L2P += Pitch;
779 }
780
781 if (InfoIsOdd) {
782 memcpy (Dest, L2, RowStride);
783 }
784 }
785
786 static void
deinterlace_frame_di_greedyh_packed(GstDeinterlaceMethod * method,const GstDeinterlaceField * history,guint history_count,GstVideoFrame * outframe,int cur_field_idx)787 deinterlace_frame_di_greedyh_packed (GstDeinterlaceMethod * method,
788 const GstDeinterlaceField * history, guint history_count,
789 GstVideoFrame * outframe, int cur_field_idx)
790 {
791 GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (method);
792 GstDeinterlaceMethodGreedyHClass *klass =
793 GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS (self);
794 ScanlineFunction scanline;
795
796 if (cur_field_idx + 2 > history_count || cur_field_idx < 1) {
797 GstDeinterlaceMethod *backup_method;
798
799 backup_method = g_object_new (gst_deinterlace_method_linear_get_type (),
800 NULL);
801
802 gst_deinterlace_method_setup (backup_method, method->vinfo);
803 gst_deinterlace_method_deinterlace_frame (backup_method,
804 history, history_count, outframe, cur_field_idx);
805
806 g_object_unref (backup_method);
807 return;
808 }
809
810 switch (GST_VIDEO_INFO_FORMAT (method->vinfo)) {
811 case GST_VIDEO_FORMAT_YUY2:
812 case GST_VIDEO_FORMAT_YVYU:
813 scanline = klass->scanline_yuy2;
814 break;
815 case GST_VIDEO_FORMAT_UYVY:
816 scanline = klass->scanline_uyvy;
817 break;
818 case GST_VIDEO_FORMAT_AYUV:
819 scanline = klass->scanline_ayuv;
820 break;
821 default:
822 g_assert_not_reached ();
823 return;
824 }
825
826 deinterlace_frame_di_greedyh_plane (self, history, history_count, outframe,
827 cur_field_idx, 0, scanline);
828 }
829
830 static void
deinterlace_frame_di_greedyh_planar(GstDeinterlaceMethod * method,const GstDeinterlaceField * history,guint history_count,GstVideoFrame * outframe,int cur_field_idx)831 deinterlace_frame_di_greedyh_planar (GstDeinterlaceMethod * method,
832 const GstDeinterlaceField * history, guint history_count,
833 GstVideoFrame * outframe, int cur_field_idx)
834 {
835 GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (method);
836 GstDeinterlaceMethodGreedyHClass *klass =
837 GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS (self);
838
839 if (cur_field_idx + 2 > history_count || cur_field_idx < 1) {
840 GstDeinterlaceMethod *backup_method;
841
842 backup_method = g_object_new (gst_deinterlace_method_linear_get_type (),
843 NULL);
844
845 gst_deinterlace_method_setup (backup_method, method->vinfo);
846 gst_deinterlace_method_deinterlace_frame (backup_method,
847 history, history_count, outframe, cur_field_idx);
848
849 g_object_unref (backup_method);
850 return;
851 }
852
853 deinterlace_frame_di_greedyh_plane (self, history, history_count, outframe,
854 cur_field_idx, 0, klass->scanline_planar_y);
855 deinterlace_frame_di_greedyh_plane (self, history, history_count, outframe,
856 cur_field_idx, 1, klass->scanline_planar_uv);
857 deinterlace_frame_di_greedyh_plane (self, history, history_count, outframe,
858 cur_field_idx, 2, klass->scanline_planar_uv);
859 }
860
861 G_DEFINE_TYPE (GstDeinterlaceMethodGreedyH, gst_deinterlace_method_greedy_h,
862 GST_TYPE_DEINTERLACE_METHOD);
863
864 enum
865 {
866 PROP_0,
867 PROP_MAX_COMB,
868 PROP_MOTION_THRESHOLD,
869 PROP_MOTION_SENSE
870 };
871
872 static void
gst_deinterlace_method_greedy_h_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)873 gst_deinterlace_method_greedy_h_set_property (GObject * object, guint prop_id,
874 const GValue * value, GParamSpec * pspec)
875 {
876 GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object);
877
878 switch (prop_id) {
879 case PROP_MAX_COMB:
880 self->max_comb = g_value_get_uint (value);
881 break;
882 case PROP_MOTION_THRESHOLD:
883 self->motion_threshold = g_value_get_uint (value);
884 break;
885 case PROP_MOTION_SENSE:
886 self->motion_sense = g_value_get_uint (value);
887 break;
888 default:
889 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
890 }
891 }
892
893 static void
gst_deinterlace_method_greedy_h_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)894 gst_deinterlace_method_greedy_h_get_property (GObject * object, guint prop_id,
895 GValue * value, GParamSpec * pspec)
896 {
897 GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object);
898
899 switch (prop_id) {
900 case PROP_MAX_COMB:
901 g_value_set_uint (value, self->max_comb);
902 break;
903 case PROP_MOTION_THRESHOLD:
904 g_value_set_uint (value, self->motion_threshold);
905 break;
906 case PROP_MOTION_SENSE:
907 g_value_set_uint (value, self->motion_sense);
908 break;
909 default:
910 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
911 }
912 }
913
914 static void
gst_deinterlace_method_greedy_h_class_init(GstDeinterlaceMethodGreedyHClass * klass)915 gst_deinterlace_method_greedy_h_class_init (GstDeinterlaceMethodGreedyHClass *
916 klass)
917 {
918 GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
919 GObjectClass *gobject_class = (GObjectClass *) klass;
920 #ifdef BUILD_X86_ASM
921 guint cpu_flags =
922 orc_target_get_default_flags (orc_target_get_by_name ("mmx"));
923 #endif
924
925 gobject_class->set_property = gst_deinterlace_method_greedy_h_set_property;
926 gobject_class->get_property = gst_deinterlace_method_greedy_h_get_property;
927
928 g_object_class_install_property (gobject_class, PROP_MAX_COMB,
929 g_param_spec_uint ("max-comb",
930 "Max comb",
931 "Max Comb", 0, 255, 5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
932 );
933
934 g_object_class_install_property (gobject_class, PROP_MOTION_THRESHOLD,
935 g_param_spec_uint ("motion-threshold",
936 "Motion Threshold",
937 "Motion Threshold",
938 0, 255, 25, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
939 );
940
941 g_object_class_install_property (gobject_class, PROP_MOTION_SENSE,
942 g_param_spec_uint ("motion-sense",
943 "Motion Sense",
944 "Motion Sense",
945 0, 255, 30, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
946 );
947
948 dim_class->fields_required = 4;
949 dim_class->name = "Motion Adaptive: Advanced Detection";
950 dim_class->nick = "greedyh";
951 dim_class->latency = 1;
952
953 dim_class->deinterlace_frame_yuy2 = deinterlace_frame_di_greedyh_packed;
954 dim_class->deinterlace_frame_yvyu = deinterlace_frame_di_greedyh_packed;
955 dim_class->deinterlace_frame_uyvy = deinterlace_frame_di_greedyh_packed;
956 dim_class->deinterlace_frame_ayuv = deinterlace_frame_di_greedyh_packed;
957 dim_class->deinterlace_frame_y444 = deinterlace_frame_di_greedyh_planar;
958 dim_class->deinterlace_frame_i420 = deinterlace_frame_di_greedyh_planar;
959 dim_class->deinterlace_frame_yv12 = deinterlace_frame_di_greedyh_planar;
960 dim_class->deinterlace_frame_y42b = deinterlace_frame_di_greedyh_planar;
961 dim_class->deinterlace_frame_y41b = deinterlace_frame_di_greedyh_planar;
962
963 #ifdef BUILD_X86_ASM
964 if (cpu_flags & ORC_TARGET_MMX_MMXEXT) {
965 klass->scanline_yuy2 = greedyh_scanline_MMXEXT_yuy2;
966 klass->scanline_uyvy = greedyh_scanline_MMXEXT_uyvy;
967 } else if (cpu_flags & ORC_TARGET_MMX_3DNOW) {
968 klass->scanline_yuy2 = greedyh_scanline_3DNOW_yuy2;
969 klass->scanline_uyvy = greedyh_scanline_3DNOW_uyvy;
970 } else if (cpu_flags & ORC_TARGET_MMX_MMX) {
971 klass->scanline_yuy2 = greedyh_scanline_MMX_yuy2;
972 klass->scanline_uyvy = greedyh_scanline_MMX_uyvy;
973 } else {
974 klass->scanline_yuy2 = greedyh_scanline_C_yuy2;
975 klass->scanline_uyvy = greedyh_scanline_C_uyvy;
976 }
977 #else
978 klass->scanline_yuy2 = greedyh_scanline_C_yuy2;
979 klass->scanline_uyvy = greedyh_scanline_C_uyvy;
980 #endif
981 /* TODO: MMX implementation of these two */
982 klass->scanline_ayuv = greedyh_scanline_C_ayuv;
983 klass->scanline_planar_y = greedyh_scanline_C_planar_y;
984 klass->scanline_planar_uv = greedyh_scanline_C_planar_uv;
985 }
986
987 static void
gst_deinterlace_method_greedy_h_init(GstDeinterlaceMethodGreedyH * self)988 gst_deinterlace_method_greedy_h_init (GstDeinterlaceMethodGreedyH * self)
989 {
990 self->max_comb = 5;
991 self->motion_threshold = 25;
992 self->motion_sense = 30;
993 }
994