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