• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer
3  * Copyright (C) 2019 Jan Schmidt <jan@centricular.com>
4  *
5  * Portions of this file extracted from libav
6  * Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include <gst/gst.h>
32 #ifdef HAVE_ORC
33 #include <orc/orc.h>
34 #include <orc/orcsse.h>
35 #endif
36 #include "gstdeinterlacemethod.h"
37 #include "yadif.h"
38 
39 #if    __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) || defined(__clang__)
40 #define ALWAYS_INLINE __attribute__((always_inline)) inline
41 #elif defined(_MSC_VER)
42 #define ALWAYS_INLINE __forceinline
43 #else
44 #define ALWAYS_INLINE inline
45 #endif
46 #ifndef ORC_RESTRICT
47 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
48 #define ORC_RESTRICT restrict
49 #elif defined(__GNUC__) && __GNUC__ >= 4
50 #define ORC_RESTRICT __restrict__
51 #else
52 #define ORC_RESTRICT
53 #endif
54 #endif
55 
56 #define GST_TYPE_DEINTERLACE_METHOD_YADIF	(gst_deinterlace_method_yadif_get_type ())
57 #define GST_IS_DEINTERLACE_METHOD_YADIF(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_YADIF))
58 #define GST_IS_DEINTERLACE_METHOD_YADIF_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_YADIF))
59 #define GST_DEINTERLACE_METHOD_YADIF_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_YADIF, GstDeinterlaceMethodYadifClass))
60 #define GST_DEINTERLACE_METHOD_YADIF(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_YADIF, GstDeinterlaceMethodYadif))
61 #define GST_DEINTERLACE_METHOD_YADIF_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_YADIF, GstDeinterlaceMethodYadifClass))
62 #define GST_DEINTERLACE_METHOD_YADIF_CAST(obj)	((GstDeinterlaceMethodYadif*)(obj))
63 
64 typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodYadif;
65 typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodYadifClass;
66 
67 G_DEFINE_TYPE (GstDeinterlaceMethodYadif,
68     gst_deinterlace_method_yadif, GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
69 
70 static void
71 filter_scanline_yadif (GstDeinterlaceSimpleMethod * self,
72     guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size,
73     int colors, int y_alternates_every);
74 
75 static void
76 filter_scanline_yadif_planar (GstDeinterlaceSimpleMethod * self,
77     guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size);
78 
79 static void
80 filter_scanline_yadif_semiplanar (GstDeinterlaceSimpleMethod * self,
81     guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size);
82 
83 static void
84 filter_scanline_yadif_packed_4 (GstDeinterlaceSimpleMethod * self,
85     guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size);
86 
87 static void
88 filter_scanline_yadif_packed_yvyu (GstDeinterlaceSimpleMethod * self,
89     guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size);
90 
91 static void
92 filter_scanline_yadif_packed_uyvy (GstDeinterlaceSimpleMethod * self,
93     guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size);
94 
95 static void
96 filter_scanline_yadif_packed_3 (GstDeinterlaceSimpleMethod * self,
97     guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size);
98 
99 static void
100 filter_line_c_planar_mode0 (void *ORC_RESTRICT dst,
101     const void *ORC_RESTRICT tzero, const void *ORC_RESTRICT bzero,
102     const void *ORC_RESTRICT mone, const void *ORC_RESTRICT mp,
103     const void *ORC_RESTRICT ttwo, const void *ORC_RESTRICT btwo,
104     const void *ORC_RESTRICT tptwo, const void *ORC_RESTRICT bptwo,
105     const void *ORC_RESTRICT ttone, const void *ORC_RESTRICT ttp,
106     const void *ORC_RESTRICT bbone, const void *ORC_RESTRICT bbp, int w);
107 
108 static void
109 filter_line_c_planar_mode2 (void *ORC_RESTRICT dst,
110     const void *ORC_RESTRICT tzero, const void *ORC_RESTRICT bzero,
111     const void *ORC_RESTRICT mone, const void *ORC_RESTRICT mp,
112     const void *ORC_RESTRICT ttwo, const void *ORC_RESTRICT btwo,
113     const void *ORC_RESTRICT tptwo, const void *ORC_RESTRICT bptwo,
114     const void *ORC_RESTRICT ttone, const void *ORC_RESTRICT ttp,
115     const void *ORC_RESTRICT bbone, const void *ORC_RESTRICT bbp, int w);
116 
117 static void (*filter_mode2) (void *ORC_RESTRICT dst,
118     const void *ORC_RESTRICT tzero, const void *ORC_RESTRICT bzero,
119     const void *ORC_RESTRICT mone, const void *ORC_RESTRICT mp,
120     const void *ORC_RESTRICT ttwo, const void *ORC_RESTRICT btwo,
121     const void *ORC_RESTRICT tptwo, const void *ORC_RESTRICT bptwo,
122     const void *ORC_RESTRICT ttone, const void *ORC_RESTRICT ttp,
123     const void *ORC_RESTRICT bbone, const void *ORC_RESTRICT bbp, int w);
124 
125 static void (*filter_mode0) (void *ORC_RESTRICT dst,
126     const void *ORC_RESTRICT tzero, const void *ORC_RESTRICT bzero,
127     const void *ORC_RESTRICT mone, const void *ORC_RESTRICT mp,
128     const void *ORC_RESTRICT ttwo, const void *ORC_RESTRICT btwo,
129     const void *ORC_RESTRICT tptwo, const void *ORC_RESTRICT bptwo,
130     const void *ORC_RESTRICT ttone, const void *ORC_RESTRICT ttp,
131     const void *ORC_RESTRICT bbone, const void *ORC_RESTRICT bbp, int w);
132 
133 
134 static void
copy_scanline(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * scanlines,guint size)135 copy_scanline (GstDeinterlaceSimpleMethod * self, guint8 * out,
136     const GstDeinterlaceScanlineData * scanlines, guint size)
137 {
138   memcpy (out, scanlines->m0, size);
139 }
140 
141 static void
gst_deinterlace_method_yadif_class_init(GstDeinterlaceMethodYadifClass * klass)142     gst_deinterlace_method_yadif_class_init
143     (GstDeinterlaceMethodYadifClass * klass)
144 {
145   GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
146   GstDeinterlaceSimpleMethodClass *dism_class =
147       (GstDeinterlaceSimpleMethodClass *) klass;
148 
149   dim_class->name = "YADIF Adaptive Deinterlacer";
150   dim_class->nick = "yadif";
151   dim_class->fields_required = 5;
152   dim_class->latency = 2;
153 
154   dism_class->copy_scanline_planar_y = copy_scanline;
155   dism_class->copy_scanline_planar_u = copy_scanline;
156   dism_class->copy_scanline_planar_v = copy_scanline;
157   dism_class->copy_scanline_yuy2 = copy_scanline;
158   dism_class->copy_scanline_yvyu = copy_scanline;
159   dism_class->copy_scanline_uyvy = copy_scanline;
160   dism_class->copy_scanline_ayuv = copy_scanline;
161   dism_class->copy_scanline_argb = copy_scanline;
162   dism_class->copy_scanline_abgr = copy_scanline;
163   dism_class->copy_scanline_rgba = copy_scanline;
164   dism_class->copy_scanline_bgra = copy_scanline;
165   dism_class->copy_scanline_rgb = copy_scanline;
166   dism_class->copy_scanline_bgr = copy_scanline;
167   dism_class->copy_scanline_nv12 = copy_scanline;
168   dism_class->copy_scanline_nv21 = copy_scanline;
169 
170   dism_class->interpolate_scanline_planar_y = filter_scanline_yadif_planar;
171   dism_class->interpolate_scanline_planar_u = filter_scanline_yadif_planar;
172   dism_class->interpolate_scanline_planar_v = filter_scanline_yadif_planar;
173   dism_class->interpolate_scanline_yuy2 = filter_scanline_yadif_packed_yvyu;
174   dism_class->interpolate_scanline_yvyu = filter_scanline_yadif_packed_yvyu;
175   dism_class->interpolate_scanline_uyvy = filter_scanline_yadif_packed_uyvy;
176   dism_class->interpolate_scanline_ayuv = filter_scanline_yadif_packed_4;
177   dism_class->interpolate_scanline_argb = filter_scanline_yadif_packed_4;
178   dism_class->interpolate_scanline_abgr = filter_scanline_yadif_packed_4;
179   dism_class->interpolate_scanline_rgba = filter_scanline_yadif_packed_4;
180   dism_class->interpolate_scanline_bgra = filter_scanline_yadif_packed_4;
181   dism_class->interpolate_scanline_rgb = filter_scanline_yadif_packed_3;
182   dism_class->interpolate_scanline_bgr = filter_scanline_yadif_packed_3;
183   dism_class->interpolate_scanline_nv12 = filter_scanline_yadif_semiplanar;
184   dism_class->interpolate_scanline_nv21 = filter_scanline_yadif_semiplanar;
185 }
186 
187 #define FFABS(a) ABS(a)
188 #define FFMIN(a,b) MIN(a,b)
189 #define FFMAX(a,b) MAX(a,b)
190 #define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c)
191 #define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c)
192 
193 
194 #define CHECK(j)\
195     {   int score = FFABS(stzero[x - colors2 + j] - sbzero[x - colors2 - j])\
196                   + FFABS(stzero[x  + j] - sbzero[x  - j])\
197                   + FFABS(stzero[x + colors2 + j] - sbzero[x + colors2 - j]);\
198         if (score < spatial_score) {\
199             spatial_score= score;\
200             spatial_pred= (stzero[x  + j] + sbzero[x - j])>>1;\
201 
202 /* The is_not_edge argument here controls when the code will enter a branch
203  * which reads up to and including x-3 and x+3. */
204 
205 #define FILTER(start, end, is_not_edge) \
206     for (x = start;  x < end; x++) { \
207         int c = stzero[x]; \
208         int d = (smone[x] + smp[x])>>1; \
209         int e = sbzero[x]; \
210         int temporal_diff0 = FFABS(smone[x] - smp[x]); \
211         int temporal_diff1 =(FFABS(sttwo[x] - c) + FFABS(sbtwo[x] - e) )>>1; \
212         int temporal_diff2 =(FFABS(stptwo[x] - c) + FFABS(sbptwo[x] - e) )>>1; \
213         int diff = FFMAX3(temporal_diff0 >> 1, temporal_diff1, temporal_diff2); \
214         int spatial_pred = (c+e) >> 1; \
215         int colors2 = colors; \
216         if ((y_alternates_every == 1 && (x%2 == 0)) || \
217            (y_alternates_every == 2 && (x%2 == 1))) \
218           colors2 = 2; \
219  \
220         if (is_not_edge) {\
221             int spatial_score = FFABS(stzero[x-colors2] - sbzero[x-colors2]) + FFABS(c-e) \
222                               + FFABS(stzero[x+colors2] - sbzero[x+colors2]); \
223             CHECK(-1 * colors2) CHECK(-2 * colors2) }} }} \
224             CHECK(colors2) CHECK(2 * colors2) }} }} \
225         }\
226  \
227         if (!(mode&2)) { \
228             int b = (sttone[x] + sttp[x])>>1; \
229             int f = (sbbone[x] + sbbp[x])>>1; \
230             int max = FFMAX3(d - e, d - c, FFMIN(b - c, f - e)); \
231             int min = FFMIN3(d - e, d - c, FFMAX(b - c, f - e)); \
232  \
233             diff = FFMAX3(diff, min, -max); \
234         } \
235  \
236         if (spatial_pred > d + diff) \
237            spatial_pred = d + diff; \
238         else if (spatial_pred < d - diff) \
239            spatial_pred = d - diff; \
240  \
241         sdst[x] = spatial_pred; \
242  \
243     }
244 
245 ALWAYS_INLINE static void
filter_line_c(guint8 * sdst,const guint8 * stzero,const guint8 * sbzero,const guint8 * smone,const guint8 * smp,const guint8 * sttwo,const guint8 * sbtwo,const guint8 * stptwo,const guint8 * sbptwo,const guint8 * sttone,const guint8 * sttp,const guint8 * sbbone,const guint8 * sbbp,int w,int colors,int y_alternates_every,int start,int end,int mode)246 filter_line_c (guint8 * sdst, const guint8 * stzero, const guint8 * sbzero,
247     const guint8 * smone, const guint8 * smp, const guint8 * sttwo,
248     const guint8 * sbtwo, const guint8 * stptwo, const guint8 * sbptwo,
249     const guint8 * sttone, const guint8 * sttp, const guint8 * sbbone,
250     const guint8 * sbbp, int w, int colors, int y_alternates_every, int start,
251     int end, int mode)
252 {
253   int x;
254 
255   /* The function is called for processing the middle
256    * pixels of each line, excluding 3 at each end.
257    * This allows the FILTER macro to be
258    * called so that it processes all the pixels normally.  A constant value of
259    * true for is_not_edge lets the compiler ignore the if statement. */
260   FILTER (start, end, 1)
261 }
262 
263 #define MAX_ALIGN 8
264 
265 ALWAYS_INLINE static void
filter_line_c_planar(void * ORC_RESTRICT dst,const void * ORC_RESTRICT tzero,const void * ORC_RESTRICT bzero,const void * ORC_RESTRICT mone,const void * ORC_RESTRICT mp,const void * ORC_RESTRICT ttwo,const void * ORC_RESTRICT btwo,const void * ORC_RESTRICT tptwo,const void * ORC_RESTRICT bptwo,const void * ORC_RESTRICT ttone,const void * ORC_RESTRICT ttp,const void * ORC_RESTRICT bbone,const void * ORC_RESTRICT bbp,int w,int mode)266 filter_line_c_planar (void *ORC_RESTRICT dst, const void *ORC_RESTRICT tzero,
267     const void *ORC_RESTRICT bzero, const void *ORC_RESTRICT mone,
268     const void *ORC_RESTRICT mp, const void *ORC_RESTRICT ttwo,
269     const void *ORC_RESTRICT btwo, const void *ORC_RESTRICT tptwo,
270     const void *ORC_RESTRICT bptwo, const void *ORC_RESTRICT ttone,
271     const void *ORC_RESTRICT ttp, const void *ORC_RESTRICT bbone,
272     const void *ORC_RESTRICT bbp, int w, int mode)
273 {
274   int x;
275   const int start = 0;
276   const int colors = 1;
277   const int y_alternates_every = 0;
278   /* hardcode colors = 1, bpp = 1 */
279   const int end = w;
280   guint8 *sdst = (guint8 *) dst + 3;
281   guint8 *stzero = (guint8 *) tzero + 3;
282   guint8 *sbzero = (guint8 *) bzero + 3;
283   guint8 *smone = (guint8 *) mone + 3;
284   guint8 *smp = (guint8 *) mp + 3;
285   guint8 *sttwo = (guint8 *) ttwo + 3;
286   guint8 *sbtwo = (guint8 *) btwo + 3;
287   guint8 *stptwo = (guint8 *) tptwo + 3;
288   guint8 *sbptwo = (guint8 *) bptwo + 3;
289   guint8 *sttone = (guint8 *) ttone + 3;
290   guint8 *sttp = (guint8 *) ttp + 3;
291   guint8 *sbbone = (guint8 *) bbone + 3;
292   guint8 *sbbp = (guint8 *) bbp + 3;
293   /* The function is called for processing the middle
294    * pixels of each line, excluding 3 at each end.
295    * This allows the FILTER macro to be
296    * called so that it processes all the pixels normally.  A constant value of
297    * true for is_not_edge lets the compiler ignore the if statement. */
298   FILTER (start, end, 1)
299 }
300 
301 ALWAYS_INLINE G_GNUC_UNUSED static void
filter_line_c_planar_mode0(void * ORC_RESTRICT dst,const void * ORC_RESTRICT tzero,const void * ORC_RESTRICT bzero,const void * ORC_RESTRICT mone,const void * ORC_RESTRICT mp,const void * ORC_RESTRICT ttwo,const void * ORC_RESTRICT btwo,const void * ORC_RESTRICT tptwo,const void * ORC_RESTRICT bptwo,const void * ORC_RESTRICT ttone,const void * ORC_RESTRICT ttp,const void * ORC_RESTRICT bbone,const void * ORC_RESTRICT bbp,int w)302 filter_line_c_planar_mode0 (void *ORC_RESTRICT dst,
303     const void *ORC_RESTRICT tzero, const void *ORC_RESTRICT bzero,
304     const void *ORC_RESTRICT mone, const void *ORC_RESTRICT mp,
305     const void *ORC_RESTRICT ttwo, const void *ORC_RESTRICT btwo,
306     const void *ORC_RESTRICT tptwo, const void *ORC_RESTRICT bptwo,
307     const void *ORC_RESTRICT ttone, const void *ORC_RESTRICT ttp,
308     const void *ORC_RESTRICT bbone, const void *ORC_RESTRICT bbp, int w)
309 {
310   filter_line_c_planar (dst, tzero, bzero, mone, mp, ttwo, btwo, tptwo, bptwo,
311       ttone, ttp, bbone, bbp, w, 0);
312 }
313 
314 ALWAYS_INLINE G_GNUC_UNUSED static void
filter_line_c_planar_mode2(void * ORC_RESTRICT dst,const void * ORC_RESTRICT tzero,const void * ORC_RESTRICT bzero,const void * ORC_RESTRICT mone,const void * ORC_RESTRICT mp,const void * ORC_RESTRICT ttwo,const void * ORC_RESTRICT btwo,const void * ORC_RESTRICT tptwo,const void * ORC_RESTRICT bptwo,const void * ORC_RESTRICT ttone,const void * ORC_RESTRICT ttp,const void * ORC_RESTRICT bbone,const void * ORC_RESTRICT bbp,int w)315 filter_line_c_planar_mode2 (void *ORC_RESTRICT dst,
316     const void *ORC_RESTRICT tzero, const void *ORC_RESTRICT bzero,
317     const void *ORC_RESTRICT mone, const void *ORC_RESTRICT mp,
318     const void *ORC_RESTRICT ttwo, const void *ORC_RESTRICT btwo,
319     const void *ORC_RESTRICT tptwo, const void *ORC_RESTRICT bptwo,
320     const void *ORC_RESTRICT ttone, const void *ORC_RESTRICT ttp,
321     const void *ORC_RESTRICT bbone, const void *ORC_RESTRICT bbp, int w)
322 {
323   filter_line_c_planar (dst, tzero, bzero, mone, mp, ttwo, btwo, tptwo, bptwo,
324       ttone, ttp, bbone, bbp, w, 2);
325 }
326 
327 ALWAYS_INLINE static void
filter_edges(guint8 * sdst,const guint8 * stzero,const guint8 * sbzero,const guint8 * smone,const guint8 * smp,const guint8 * sttwo,const guint8 * sbtwo,const guint8 * stptwo,const guint8 * sbptwo,const guint8 * sttone,const guint8 * sttp,const guint8 * sbbone,const guint8 * sbbp,int w,int colors,int y_alternates_every,int mode,const int bpp)328 filter_edges (guint8 * sdst, const guint8 * stzero, const guint8 * sbzero,
329     const guint8 * smone, const guint8 * smp, const guint8 * sttwo,
330     const guint8 * sbtwo, const guint8 * stptwo, const guint8 * sbptwo,
331     const guint8 * sttone, const guint8 * sttp, const guint8 * sbbone,
332     const guint8 * sbbp, int w, int colors, int y_alternates_every,
333     int mode, const int bpp)
334 {
335   int x;
336   const int edge = colors * (MAX_ALIGN / bpp);
337   const int border = 3 * colors;
338 
339   /* Only edge pixels need to be processed here.  A constant value of false
340    * for is_not_edge should let the compiler ignore the whole branch. */
341   FILTER (0, border, 0)
342       FILTER (w - edge, w - border, 1)
343       FILTER (w - border, w, 0)
344 }
345 
346 static void
filter_scanline_yadif_semiplanar(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * s_orig,guint size)347 filter_scanline_yadif_semiplanar (GstDeinterlaceSimpleMethod * self,
348     guint8 * out, const GstDeinterlaceScanlineData * s_orig, guint size)
349 {
350   filter_scanline_yadif (self, out, s_orig, size, 2, 0);
351 }
352 
353 static void
filter_scanline_yadif_packed_3(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * s_orig,guint size)354 filter_scanline_yadif_packed_3 (GstDeinterlaceSimpleMethod * self,
355     guint8 * out, const GstDeinterlaceScanlineData * s_orig, guint size)
356 {
357   filter_scanline_yadif (self, out, s_orig, size, 3, 0);
358 }
359 
360 static void
filter_scanline_yadif_packed_4(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * s_orig,guint size)361 filter_scanline_yadif_packed_4 (GstDeinterlaceSimpleMethod * self,
362     guint8 * out, const GstDeinterlaceScanlineData * s_orig, guint size)
363 {
364   filter_scanline_yadif (self, out, s_orig, size, 4, 0);
365 }
366 
367 static void
filter_scanline_yadif_packed_yvyu(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * s_orig,guint size)368 filter_scanline_yadif_packed_yvyu (GstDeinterlaceSimpleMethod * self,
369     guint8 * out, const GstDeinterlaceScanlineData * s_orig, guint size)
370 {
371   filter_scanline_yadif (self, out, s_orig, size, 4, 1);
372 }
373 
374 static void
filter_scanline_yadif_packed_uyvy(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * s_orig,guint size)375 filter_scanline_yadif_packed_uyvy (GstDeinterlaceSimpleMethod * self,
376     guint8 * out, const GstDeinterlaceScanlineData * s_orig, guint size)
377 {
378   filter_scanline_yadif (self, out, s_orig, size, 4, 2);
379 }
380 
381 ALWAYS_INLINE static void
filter_scanline_yadif(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * s_orig,guint size,int colors,int y_alternates_every)382 filter_scanline_yadif (GstDeinterlaceSimpleMethod * self,
383     guint8 * out, const GstDeinterlaceScanlineData * s_orig, guint size,
384     int colors, int y_alternates_every)
385 {
386   guint8 *dst = out;
387   const int bpp = 1;            // Hard code 8-bit atm
388   int w = size / bpp;
389   int edge = colors * MAX_ALIGN / bpp;
390   GstDeinterlaceScanlineData s = *s_orig;
391 
392   int mode = (s.tt1 == NULL || s.bb1 == NULL || s.ttp == NULL
393       || s.bbp == NULL) ? 2 : 0;
394 
395   /* When starting up, some data might not yet be available, so use the current frame */
396   if (s.m1 == NULL)
397     s.m1 = s.mp;
398   if (s.tt1 == NULL)
399     s.tt1 = s.ttp;
400   if (s.bb1 == NULL)
401     s.bb1 = s.bbp;
402   if (s.t2 == NULL)
403     s.t2 = s.tp2;
404   if (s.b2 == NULL)
405     s.b2 = s.bp2;
406 
407   filter_edges (dst, s.t0, s.b0, s.m1, s.mp, s.t2, s.b2, s.tp2, s.bp2, s.tt1,
408       s.ttp, s.bb1, s.bbp, w, colors, y_alternates_every, mode, bpp);
409   filter_line_c (dst, s.t0, s.b0, s.m1, s.mp, s.t2, s.b2, s.tp2, s.bp2, s.tt1,
410       s.ttp, s.bb1, s.bbp, w, colors, y_alternates_every, colors * 3, w - edge,
411       mode);
412 }
413 
414 ALWAYS_INLINE static void
filter_scanline_yadif_planar(GstDeinterlaceSimpleMethod * self,guint8 * out,const GstDeinterlaceScanlineData * s_orig,guint size)415 filter_scanline_yadif_planar (GstDeinterlaceSimpleMethod * self,
416     guint8 * out, const GstDeinterlaceScanlineData * s_orig, guint size)
417 {
418   guint8 *dst = out;
419   const int bpp = 1;            // Hard code 8-bit atm
420   int w = size / bpp;
421   int edge = MAX_ALIGN / bpp;
422   GstDeinterlaceScanlineData s = *s_orig;
423 
424   int mode = (s.tt1 == NULL || s.bb1 == NULL || s.ttp == NULL
425       || s.bbp == NULL) ? 2 : 0;
426 
427   /* When starting up, some data might not yet be available, so use the current frame */
428   if (s.m1 == NULL)
429     s.m1 = s.mp;
430   if (s.tt1 == NULL)
431     s.tt1 = s.ttp;
432   if (s.bb1 == NULL)
433     s.bb1 = s.bbp;
434   if (s.t2 == NULL)
435     s.t2 = s.tp2;
436   if (s.b2 == NULL)
437     s.b2 = s.bp2;
438 
439   filter_edges (dst, s.t0, s.b0, s.m1, s.mp, s.t2, s.b2, s.tp2, s.bp2, s.tt1,
440       s.ttp, s.bb1, s.bbp, w, 1, 0, mode, bpp);
441   if (mode == 0)
442     filter_mode0 (dst, (void *) s.t0, (void *) s.b0, (void *) s.m1,
443         (void *) s.mp, (void *) s.t2, (void *) s.b2, (void *) s.tp2,
444         (void *) s.bp2, (void *) s.tt1, (void *) s.ttp, (void *) s.bb1,
445         (void *) s.bbp, w - edge);
446   else
447     filter_mode2 (dst, (void *) s.t0, (void *) s.b0, (void *) s.m1,
448         (void *) s.mp, (void *) s.t2, (void *) s.b2, (void *) s.tp2,
449         (void *) s.bp2, (void *) s.tt1, (void *) s.ttp, (void *) s.bb1,
450         (void *) s.bbp, w - edge);
451 }
452 
453 static void
gst_deinterlace_method_yadif_init(GstDeinterlaceMethodYadif * self)454 gst_deinterlace_method_yadif_init (GstDeinterlaceMethodYadif * self)
455 {
456 #if (defined __x86_64__ || defined _M_X64) && defined HAVE_NASM
457   if (
458 #  if defined HAVE_ORC
459       orc_sse_get_cpu_flags () & ORC_TARGET_SSE_SSSE3
460 #  elif defined __SSSE3__
461       TRUE
462 #  else
463       FALSE
464 #  endif
465       ) {
466     GST_DEBUG ("SSSE3 optimization enabled");
467     filter_mode0 = gst_yadif_filter_line_mode0_ssse3;
468     filter_mode2 = gst_yadif_filter_line_mode2_ssse3;
469   } else {
470     GST_DEBUG ("SSE2 optimization enabled");
471     filter_mode0 = gst_yadif_filter_line_mode0_sse2;
472     filter_mode2 = gst_yadif_filter_line_mode2_sse2;
473   }
474 #else
475   {
476     GST_DEBUG ("SSE optimization disabled");
477     filter_mode0 = filter_line_c_planar_mode0;
478     filter_mode2 = filter_line_c_planar_mode2;
479   }
480 #endif
481 }
482