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