Tizen 2.0 Release
[framework/multimedia/gst-plugins-good0.10.git] / gst / deinterlace / tvtime / greedyh.c
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., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, 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
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
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
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
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
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
720 deinterlace_frame_di_greedyh_packed (GstDeinterlaceMethod * method,
721     const GstDeinterlaceField * history, guint history_count,
722     GstBuffer * outbuf, 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 = method->row_stride[0];
730   gint FieldHeight = method->frame_height / 2;
731   gint Pitch = method->row_stride[0] * 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_BUFFER_DATA (outbuf);
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->format,
746         method->frame_width, method->frame_height);
747     gst_deinterlace_method_deinterlace_frame (backup_method,
748         history, history_count, outbuf, cur_field_idx);
749
750     g_object_unref (backup_method);
751     return;
752   }
753
754   cur_field_idx += 2;
755
756   switch (method->format) {
757     case GST_VIDEO_FORMAT_YUY2:
758     case GST_VIDEO_FORMAT_YVYU:
759       scanline = klass->scanline_yuy2;
760       break;
761     case GST_VIDEO_FORMAT_UYVY:
762       scanline = klass->scanline_uyvy;
763       break;
764     case GST_VIDEO_FORMAT_AYUV:
765       scanline = klass->scanline_ayuv;
766       break;
767     default:
768       g_assert_not_reached ();
769       return;
770   }
771
772   // copy first even line no matter what, and the first odd line if we're
773   // processing an EVEN field. (note diff from other deint rtns.)
774
775   if (history[cur_field_idx - 1].flags == PICTURE_INTERLACED_BOTTOM) {
776     InfoIsOdd = 1;
777
778     L1 = GST_BUFFER_DATA (history[cur_field_idx - 2].buf);
779     if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM)
780       L1 += RowStride;
781
782     L2 = GST_BUFFER_DATA (history[cur_field_idx - 1].buf);
783     if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM)
784       L2 += RowStride;
785
786     L3 = L1 + Pitch;
787     L2P = GST_BUFFER_DATA (history[cur_field_idx - 3].buf);
788     if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM)
789       L2P += RowStride;
790
791     // copy first even line
792     memcpy (Dest, L1, RowStride);
793     Dest += RowStride;
794   } else {
795     InfoIsOdd = 0;
796     L1 = GST_BUFFER_DATA (history[cur_field_idx - 2].buf);
797     if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM)
798       L1 += RowStride;
799
800     L2 = GST_BUFFER_DATA (history[cur_field_idx - 1].buf) + Pitch;
801     if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM)
802       L2 += RowStride;
803
804     L3 = L1 + Pitch;
805     L2P = GST_BUFFER_DATA (history[cur_field_idx - 3].buf) + Pitch;
806     if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM)
807       L2P += RowStride;
808
809     // copy first even line
810     memcpy (Dest, L1, RowStride);
811     Dest += RowStride;
812     // then first odd line
813     memcpy (Dest, L1, RowStride);
814     Dest += RowStride;
815   }
816
817   for (Line = 0; Line < (FieldHeight - 1); ++Line) {
818     scanline (self, L1, L2, L3, L2P, Dest, RowStride);
819     Dest += RowStride;
820     memcpy (Dest, L3, RowStride);
821     Dest += RowStride;
822
823     L1 += Pitch;
824     L2 += Pitch;
825     L3 += Pitch;
826     L2P += Pitch;
827   }
828
829   if (InfoIsOdd) {
830     memcpy (Dest, L2, RowStride);
831   }
832 }
833
834 static void
835 deinterlace_frame_di_greedyh_planar_plane (GstDeinterlaceMethodGreedyH * self,
836     const guint8 * L1, const guint8 * L2, const guint8 * L3, const guint8 * L2P,
837     guint8 * Dest, gint RowStride, gint FieldHeight, gint Pitch, gint InfoIsOdd,
838     ScanlineFunction scanline)
839 {
840   gint Line;
841
842   // copy first even line no matter what, and the first odd line if we're
843   // processing an EVEN field. (note diff from other deint rtns.)
844
845   if (InfoIsOdd) {
846     // copy first even line
847     memcpy (Dest, L1, RowStride);
848     Dest += RowStride;
849   } else {
850     // copy first even line
851     memcpy (Dest, L1, RowStride);
852     Dest += RowStride;
853     // then first odd line
854     memcpy (Dest, L1, RowStride);
855     Dest += RowStride;
856   }
857
858   for (Line = 0; Line < (FieldHeight - 1); ++Line) {
859     scanline (self, L1, L2, L3, L2P, Dest, RowStride);
860     Dest += RowStride;
861     memcpy (Dest, L3, RowStride);
862     Dest += RowStride;
863
864     L1 += Pitch;
865     L2 += Pitch;
866     L3 += Pitch;
867     L2P += Pitch;
868   }
869
870   if (InfoIsOdd) {
871     memcpy (Dest, L2, RowStride);
872   }
873 }
874
875 static void
876 deinterlace_frame_di_greedyh_planar (GstDeinterlaceMethod * method,
877     const GstDeinterlaceField * history, guint history_count,
878     GstBuffer * outbuf, int cur_field_idx)
879 {
880   GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (method);
881   GstDeinterlaceMethodGreedyHClass *klass =
882       GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS (self);
883   gint InfoIsOdd;
884   gint RowStride;
885   gint FieldHeight;
886   gint Pitch;
887   const guint8 *L1;             // ptr to Line1, of 3
888   const guint8 *L2;             // ptr to Line2, the weave line
889   const guint8 *L3;             // ptr to Line3
890   const guint8 *L2P;            // ptr to prev Line2
891   guint8 *Dest;
892   gint i;
893   gint Offset;
894   ScanlineFunction scanline;
895
896   if (cur_field_idx + 2 > history_count || cur_field_idx < 1) {
897     GstDeinterlaceMethod *backup_method;
898
899     backup_method = g_object_new (gst_deinterlace_method_linear_get_type (),
900         NULL);
901
902     gst_deinterlace_method_setup (backup_method, method->format,
903         method->frame_width, method->frame_height);
904     gst_deinterlace_method_deinterlace_frame (backup_method,
905         history, history_count, outbuf, 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     Offset = method->offset[i];
915
916     InfoIsOdd = (history[cur_field_idx - 1].flags == PICTURE_INTERLACED_BOTTOM);
917     RowStride = method->row_stride[i];
918     FieldHeight = method->height[i] / 2;
919     Pitch = method->row_stride[i] * 2;
920
921     if (i == 0)
922       scanline = klass->scanline_planar_y;
923     else
924       scanline = klass->scanline_planar_uv;
925
926     Dest = GST_BUFFER_DATA (outbuf) + Offset;
927
928     L1 = GST_BUFFER_DATA (history[cur_field_idx - 2].buf) + Offset;
929     if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM)
930       L1 += RowStride;
931
932     L2 = GST_BUFFER_DATA (history[cur_field_idx - 1].buf) + Offset;
933     if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM)
934       L2 += RowStride;
935
936     L3 = L1 + Pitch;
937     L2P = GST_BUFFER_DATA (history[cur_field_idx - 3].buf) + Offset;
938     if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM)
939       L2P += RowStride;
940
941     deinterlace_frame_di_greedyh_planar_plane (self, L1, L2, L3, L2P, Dest,
942         RowStride, FieldHeight, Pitch, InfoIsOdd, scanline);
943   }
944 }
945
946 G_DEFINE_TYPE (GstDeinterlaceMethodGreedyH, gst_deinterlace_method_greedy_h,
947     GST_TYPE_DEINTERLACE_METHOD);
948
949 enum
950 {
951   PROP_0,
952   PROP_MAX_COMB,
953   PROP_MOTION_THRESHOLD,
954   PROP_MOTION_SENSE
955 };
956
957 static void
958 gst_deinterlace_method_greedy_h_set_property (GObject * object, guint prop_id,
959     const GValue * value, GParamSpec * pspec)
960 {
961   GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object);
962
963   switch (prop_id) {
964     case PROP_MAX_COMB:
965       self->max_comb = g_value_get_uint (value);
966       break;
967     case PROP_MOTION_THRESHOLD:
968       self->motion_threshold = g_value_get_uint (value);
969       break;
970     case PROP_MOTION_SENSE:
971       self->motion_sense = g_value_get_uint (value);
972       break;
973     default:
974       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
975   }
976 }
977
978 static void
979 gst_deinterlace_method_greedy_h_get_property (GObject * object, guint prop_id,
980     GValue * value, GParamSpec * pspec)
981 {
982   GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object);
983
984   switch (prop_id) {
985     case PROP_MAX_COMB:
986       g_value_set_uint (value, self->max_comb);
987       break;
988     case PROP_MOTION_THRESHOLD:
989       g_value_set_uint (value, self->motion_threshold);
990       break;
991     case PROP_MOTION_SENSE:
992       g_value_set_uint (value, self->motion_sense);
993       break;
994     default:
995       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
996   }
997 }
998
999 static void
1000 gst_deinterlace_method_greedy_h_class_init (GstDeinterlaceMethodGreedyHClass *
1001     klass)
1002 {
1003   GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
1004   GObjectClass *gobject_class = (GObjectClass *) klass;
1005 #ifdef BUILD_X86_ASM
1006   guint cpu_flags =
1007       orc_target_get_default_flags (orc_target_get_by_name ("mmx"));
1008 #endif
1009
1010   gobject_class->set_property = gst_deinterlace_method_greedy_h_set_property;
1011   gobject_class->get_property = gst_deinterlace_method_greedy_h_get_property;
1012
1013   g_object_class_install_property (gobject_class, PROP_MAX_COMB,
1014       g_param_spec_uint ("max-comb",
1015           "Max comb",
1016           "Max Comb", 0, 255, 5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
1017       );
1018
1019   g_object_class_install_property (gobject_class, PROP_MOTION_THRESHOLD,
1020       g_param_spec_uint ("motion-threshold",
1021           "Motion Threshold",
1022           "Motion Threshold",
1023           0, 255, 25, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
1024       );
1025
1026   g_object_class_install_property (gobject_class, PROP_MOTION_SENSE,
1027       g_param_spec_uint ("motion-sense",
1028           "Motion Sense",
1029           "Motion Sense",
1030           0, 255, 30, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
1031       );
1032
1033   dim_class->fields_required = 4;
1034   dim_class->name = "Motion Adaptive: Advanced Detection";
1035   dim_class->nick = "greedyh";
1036   dim_class->latency = 1;
1037
1038   dim_class->deinterlace_frame_yuy2 = deinterlace_frame_di_greedyh_packed;
1039   dim_class->deinterlace_frame_yvyu = deinterlace_frame_di_greedyh_packed;
1040   dim_class->deinterlace_frame_uyvy = deinterlace_frame_di_greedyh_packed;
1041   dim_class->deinterlace_frame_ayuv = deinterlace_frame_di_greedyh_packed;
1042   dim_class->deinterlace_frame_y444 = deinterlace_frame_di_greedyh_planar;
1043   dim_class->deinterlace_frame_i420 = deinterlace_frame_di_greedyh_planar;
1044   dim_class->deinterlace_frame_yv12 = deinterlace_frame_di_greedyh_planar;
1045   dim_class->deinterlace_frame_y42b = deinterlace_frame_di_greedyh_planar;
1046   dim_class->deinterlace_frame_y41b = deinterlace_frame_di_greedyh_planar;
1047
1048 #ifdef BUILD_X86_ASM
1049   if (cpu_flags & ORC_TARGET_MMX_MMXEXT) {
1050     klass->scanline_yuy2 = greedyh_scanline_MMXEXT_yuy2;
1051     klass->scanline_uyvy = greedyh_scanline_MMXEXT_uyvy;
1052   } else if (cpu_flags & ORC_TARGET_MMX_3DNOW) {
1053     klass->scanline_yuy2 = greedyh_scanline_3DNOW_yuy2;
1054     klass->scanline_uyvy = greedyh_scanline_3DNOW_uyvy;
1055   } else if (cpu_flags & ORC_TARGET_MMX_MMX) {
1056     klass->scanline_yuy2 = greedyh_scanline_MMX_yuy2;
1057     klass->scanline_uyvy = greedyh_scanline_MMX_uyvy;
1058   } else {
1059     klass->scanline_yuy2 = greedyh_scanline_C_yuy2;
1060     klass->scanline_uyvy = greedyh_scanline_C_uyvy;
1061   }
1062 #else
1063   klass->scanline_yuy2 = greedyh_scanline_C_yuy2;
1064   klass->scanline_uyvy = greedyh_scanline_C_uyvy;
1065 #endif
1066   /* TODO: MMX implementation of these two */
1067   klass->scanline_ayuv = greedyh_scanline_C_ayuv;
1068   klass->scanline_planar_y = greedyh_scanline_C_planar_y;
1069   klass->scanline_planar_uv = greedyh_scanline_C_planar_uv;
1070 }
1071
1072 static void
1073 gst_deinterlace_method_greedy_h_init (GstDeinterlaceMethodGreedyH * self)
1074 {
1075   self->max_comb = 5;
1076   self->motion_threshold = 25;
1077   self->motion_sense = 30;
1078 }