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